user37223: Libraries

NTPClient

Board
Olimex ESP32-POE board
Behaviour
I have written a code that connects the board to a local NTP Server (which is an embedded board). I tried assigning the IP Address of the above NTP Server using IPAddress and then convert it to c_str() to pass into the NTPClient constructor as follows:

 WiFiUDP ntpUDP; // udp socket object for NTP

 IPAddress NTPServer(192.168.3.11); // Local NTP Server IP Address

 NTPClient timeClient(ntpUDP, NTPServer.toString().c_str(), 0, 60000);

The reason for this is because the NTPClient class uses const char* for the IP Address of the NTP Server.
The values that are obtained once the code is flashed on the board are wrong because the timestamps are have the year 2106.
On the contrary, when I use
 NTPClient timeClient(ntpUDP, "192.168.3.11", 0, 60000);

and run the code on the board, this provides me perfect values of UTC time.
Why is there some discrepancy here?
Code
#include <Wire.h>
#include <ETH.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <RTClib.h>

WiFiUDP ntpUDP;
/* IP CONF for NODE */
///////// >>>> MODIFY Values Here <<<< ////////
const IPAddress node_static_ip(192, 168, 3, 101);
const IPAddress default_gateway(192, 168, 3, 250);
const IPAddress subnet_mask(255, 255, 255, 0);
const IPAddress dns_add(192, 168, 3, 250);
const IPAddress NTPServer(192, 168, 3, 11);

NTPClient timeClient(ntpUDP, "192.168.3.11", 0, 60000); // This works
NTPClient timeClient(ntpUDP, NTPServer.toString().c_str(), 0, 60000); // This won't (provides timestamps of 2106)

void setup() {
  // put your setup code here, to run once:
  Wire.begin(I2C_SDA, I2C_SCL);
  Serial.begin(115200);
  ETH.begin();
  ETH.config(node_static_ip, default_gateway, subnet_mask, dns_add);
  delay(1000);
  if (!rtc.begin()) {
    Serial.println("No RTC");
  }
  timeClient.begin();

}
void loop() {
  // put your main code here, to run repeatedly:
  timeClient.update();
  Serial.println(timeClient.getEpochTime());
  DateTime now_time(timeClient.getEpochTime());
  Serial.print(now_time.year(), DEC);
    Serial.print('/');
    Serial.print(now_time.month(), DEC);
    Serial.print('/');
    Serial.print(now_time.day(), DEC);
    Serial.print(now_time.hour(), DEC);
    Serial.print(':');
    Serial.print(now_time.minute(), DEC);
    Serial.print(':');
    Serial.print(now_time.second(), DEC);
Serial.println();

  delay(2000);

}


user37622: The String object created as return from IPAddress.toString() as parameter to constructor of NtpClient is temporary. It contains the char array returned by c_str(). NTPClient doesn't copy the string, only stores a reference to it. And the referenced string (char array) doesn't exist at the time the NTPClient wants to use it.
class TestClass {
public:
  TestClass(const char* _ip) : ip(_ip) { }

  void test() {
    Serial.println("--");
    Serial.println(ip);
    Serial.println("--");
  }

private:
  const char* ip;
};


//String s("abc");
//TestClass Test(s.c_str()); <- this works

TestClass Test(String("abc").c_str()); // <- this can't work

void setup() {
  Serial.begin(9600);
  Test.test();
}


37223: <h2>Libraries</h2>

<ul>
<li><a href="https://github.com/arduino-libraries/NTPClient" rel="nofollow noreferrer">NTPClient</a></li>
</ul>

<h2>Board</h2>

<p>Olimex ESP32-POE board</p>

<h2>Behaviour</h2>

<p>I have written a code that connects the board to a local NTP Server (which is an embedded board). I tried assigning the IP Address of the above NTP Server using <code>IPAddress</code> and then convert it to <code>c_str()</code> to pass into the <code>NTPClient</code> constructor as follows:
</p>

<pre class="lang-cpp prettyprint-override"><code> WiFiUDP ntpUDP; // udp socket object for NTP

 IPAddress NTPServer(192.168.3.11); // Local NTP Server IP Address

 NTPClient timeClient(ntpUDP, NTPServer.toString().c_str(), 0, 60000);
</code></pre>

<p>The reason for this is because the <code>NTPClient</code> class uses <code>const char*</code> for the IP Address of the NTP Server.</p>

<p>The values that are obtained once the code is flashed on the board are wrong because the timestamps are have the year <code>2106</code>.</p>

<p>On the contrary, when I use</p>

<pre class="lang-cpp prettyprint-override"><code> NTPClient timeClient(ntpUDP, "192.168.3.11", 0, 60000);
</code></pre>

<p>and run the code on the board, this provides me perfect values of UTC time.</p>

<p>Why is there some discrepancy here?</p>

<h1>Code</h1>

<pre class="lang-cpp prettyprint-override"><code>#include &lt;Wire.h&gt;
#include &lt;ETH.h&gt;
#include &lt;WiFiUdp.h&gt;
#include &lt;NTPClient.h&gt;
#include &lt;RTClib.h&gt;

WiFiUDP ntpUDP;
/* IP CONF for NODE */
///////// &gt;&gt;&gt;&gt; MODIFY Values Here &lt;&lt;&lt;&lt; ////////
const IPAddress node_static_ip(192, 168, 3, 101);
const IPAddress default_gateway(192, 168, 3, 250);
const IPAddress subnet_mask(255, 255, 255, 0);
const IPAddress dns_add(192, 168, 3, 250);
const IPAddress NTPServer(192, 168, 3, 11);

NTPClient timeClient(ntpUDP, "192.168.3.11", 0, 60000); // This works
NTPClient timeClient(ntpUDP, NTPServer.toString().c_str(), 0, 60000); // This won't (provides timestamps of 2106)

void setup() {
  // put your setup code here, to run once:
  Wire.begin(I2C_SDA, I2C_SCL);
  Serial.begin(115200);
  ETH.begin();
  ETH.config(node_static_ip, default_gateway, subnet_mask, dns_add);
  delay(1000);
  if (!rtc.begin()) {
    Serial.println("No RTC");
  }
  timeClient.begin();

}
void loop() {
  // put your main code here, to run repeatedly:
  timeClient.update();
  Serial.println(timeClient.getEpochTime());
  DateTime now_time(timeClient.getEpochTime());
  Serial.print(now_time.year(), DEC);
    Serial.print('/');
    Serial.print(now_time.month(), DEC);
    Serial.print('/');
    Serial.print(now_time.day(), DEC);
    Serial.print(now_time.hour(), DEC);
    Serial.print(':');
    Serial.print(now_time.minute(), DEC);
    Serial.print(':');
    Serial.print(now_time.second(), DEC);
Serial.println();

  delay(2000);

}
</code></pre>
 37622: <p>The String object created as return from IPAddress.toString() as parameter to constructor of NtpClient is temporary. It contains the char array returned by c_str(). NTPClient doesn't copy the string, only stores a reference to it. And the referenced string (char array) doesn't exist at the time the NTPClient wants to use it.</p>

<pre><code>class TestClass {
public:
  TestClass(const char* _ip) : ip(_ip) { }

  void test() {
    Serial.println("--");
    Serial.println(ip);
    Serial.println("--");
  }

private:
  const char* ip;
};


//String s("abc");
//TestClass Test(s.c_str()); &lt;- this works

TestClass Test(String("abc").c_str()); // &lt;- this can't work

void setup() {
  Serial.begin(9600);
  Test.test();
}
</code></pre>
