Using c_str() on String for IPAddress with NTPClient provides wrong values 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 &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);

}
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()); &lt;- this works

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

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