Hi,
I’ve been fighting with updating my rtc-module from ntp-server.
My code gives a correct timestamp back (can be checked on various conversion sites) but when using timelib.h to convert from unix epoch to human readable time I get very strange values.
I want 2018-12-31 10:10:15
but I get 2018-8-173 10:10:15
I have stared at this problem long now, but I can’t figure out whats wrong. Down code contains a lot of logging to serial due to my efforts to figure out the problem, but basically, at startup it retreives a NTP timestamp, converts it to unix epoch and also to y2k epoch (to be able to compare timestamp wiht local arduino time) and when it finds a difference I want to set rtc to ntp time. But the conversion from unix epoch to human readable time using timelib gets all screwed up…
The code is
#include <RtcDS3231.h>
#include <SoftwareSerial.h> // Since we want to use hw-serial for debugging
#include <Wire.h>
#include <TimeLib.h>
#include <WiFiEsp.h>
#include <WifiEspUdp.h>
const char ssid[] = "myssid"; // your network SSID (name)
const char pass[] = "mypass"; // your network password
// NTP settings
char timeServer[] = "se.pool.ntp.org";
unsigned int localPort = 2390; // local port to listen for UDP packets
const int NTP_PACKET_SIZE = 48; // NTP timestamp is in the first 48 bytes of the message
const int UDP_TIMEOUT = 2000; // timeout in miliseconds to wait for an UDP packet to arrive
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
const int timeZone = 1; // Central European Time
// RTC module object
RtcDS3231<TwoWire> rtcModule(Wire);
// Wifi client object
WiFiEspClient client;
// SoftwareSerial object for Wifi module on pin 6 (RX) and 7 (TX).
// Wifi card needs to be preset to 9600b I.E. SoftwareSerials speed limit.
SoftwareSerial Serial1(6, 7);
// Set radio status
int status = WL_IDLE_STATUS;
// A UDP instance to let us send and receive packets over UDP (for NTP)
WiFiEspUDP Udp;
// Set up timelib
tmElements_t tm;
int Year, Month, Day, Hour, Minute, Second;
void setup()
{
Serial.println();
Serial.println("TimeNTP Lab");
// Enable IC2 communication
Wire.begin();
Serial.begin(115200);
// Start rtc module
rtcModule.Begin();
// Initialise serial for ESP module
Serial1.begin(9600);
WiFi.init(&Serial1);
// Check for the presence of the shield
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// Dont continue
while (true);
}
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("IP number assigned by DHCP is ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.println("waiting for sync");
setSyncProvider(getNTPTime);
setSyncInterval(300); // 300 sec = 5 min
// Set clock to compile time to have a starting point
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
rtcModule.SetDateTime(compiled);
setRTCTime();
}
time_t prevDisplay = 0; // when the digital clock was displayed
void loop()
{
if (timeStatus() != timeNotSet) {
if (now() != prevDisplay) { //update the display only if time has changed
prevDisplay = now();
Serial.print("NTP time is ");
digitalClockDisplay();
RtcDateTime localNow = rtcModule.GetDateTime();
char localTimeString[19];
sprintf(localTimeString, "%04d-%02d-%02d %02d:%02d:%02d", localNow.Year() , localNow.Month(), localNow.Day(), localNow.Hour(), localNow.Minute(), localNow.Second());
Serial.print("Local time is ");
Serial.println(localTimeString);
Serial.println();
}
}
}
void setRTCTime() {
// Compare local time with NTP time
unsigned long currentTime = now(); // unix epoch
//time_t currentTime = now(); // unix epoch
if (currentTime > 0) {
Serial.print("NTP Time in unix epoch is ");
Serial.println(currentTime);
unsigned long epoch2k = currentTime - 946684800;
Serial.print("NTP time in epoch2k is ");
Serial.println(epoch2k);
RtcDateTime localNow = rtcModule.GetDateTime();
Serial.print("Local Time in epoch2k is ");
Serial.println(localNow);
if (localNow != epoch2k) {
Serial.println();
Serial.println("Setting time...");
Serial.print("NTP time is ");
digitalClockDisplay();
char timeString[19];
//sprintf(timeString, "%02d/%02d/%04d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
sprintf(timeString, "%04d-%02d-%02d %02d:%02d:%02d", year(), month(), day(), hour(), minute(), second());
char localTimeString[19];
sprintf(localTimeString, "%04d-%02d-%02d %02d:%02d:%02d", localNow.Year() , localNow.Month(), localNow.Day(), localNow.Hour(), localNow.Minute(), localNow.Second());
Serial.print("Local time is ");
Serial.println(localTimeString);
Serial.print("Trying to set local time to ");
Serial.println(timeString);
createElements(timeString);
setTime(makeTime(tm));
Serial.println();
//setTime(currentTime);
setTime(currentTime);
//rtcModule.SetDateTime(timeString);
} else {
Serial.println("Fick inget svar från NTP-tjänsten. Provar senare...");
}
}
}
void digitalClockDisplay()
{
// digital clock display of the time
Serial.print(year());
Serial.print("-");
Serial.print(month());
Serial.print("-");
Serial.print(day());
Serial.print(" ");
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.println();
}
void printDigits(int digits)
{
// utility for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
long getNTPTime() {
sendNTPpacket(timeServer); // send a NTP packet to the time server
// wait for a reply for UDP_TIMEOUT miliseconds
unsigned long startMs = millis();
while (!Udp.available() && (millis() - startMs) < UDP_TIMEOUT) {}
Serial.println(Udp.parsePacket());
if (Udp.parsePacket()) {
Serial.println("packet received");
// We've received a packet, read the data from it and put it into the buffer
Udp.read(packetBuffer, NTP_PACKET_SIZE);
// the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, extract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long ntp_timestamp = highWord << 16 | lowWord;
unsigned long epoch = ntp_timestamp - 2208988800UL + timeZone * SECS_PER_HOUR;
return epoch;
}
return 0; // Failed to get time or parse the packet
}
void sendNTPpacket(char *ntpSrv)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now send a packet requesting the timestamp:
Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void createElements(const char *str)
{
sscanf(str, "%d-%d-%d %d:%d:%d", &Year, &Month, &Day, &Hour, &Minute, &Second);
tm.Year = CalendarYrToTm(Year);
tm.Month = Month;
tm.Day = Day;
tm.Hour = Hour;
tm.Minute = Minute;
tm.Second = Second;
}