Setting RTC using NTP

Hi,

Can anyone offer any guidance or point to an example on how I might go about setting a DS3231 RTC using NTP? I'm using an ESP32 Wroom 32D

I thought it would be a straightforward process but it doesn't seem to be turning out like that. I currently don't have any example code of my own at the moment as I'm really struggling to figure out the best method.

The 'getTime' example I'm looking at is the following off the shelf example from the IDE, however I can't figure out how to assign the time variables to the RTC.

#include <WiFi.h>
#include "time.h"

const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void setup()
{
  Serial.begin(115200);
  
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop()
{
  delay(1000);
  printLocalTime();
}

Thank you in advance :slight_smile:

in your printLocalTime() function you go grab the local time by doing getLocalTime(&timeinfo)

timeinfois a tm structure, and assuming you use Adafruit's library (#include <RTClib.h>) and the RTC is correctly initialized in the setup then you could do

rtc.adjust(DateTime(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec));

There is no point doing that often though, if the internet access work, then you might not need the RTC at all.

1 Like

Thanks for the reply, sorry, yes, I'm using the library you mentioned above,

I'll give it a go when I'm back home.

You're right, I won't be doing it often at all, maybe once a day. I know the drift on the DS3231 is very small, but I thought it would be a nice exercise to get it sync'd with the NTP server.

but if you have Wi-Fi you can use the ESP32 time function directly. It will sync up every hour with your NTP server and the external RTC might not be needed

here is a version that uses your local WLAN-Router as NTP-server
It includes some standard-functions I use in every sketch

#include <WiFi.h>

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;

//const char *ssid     = "WLANBuero_EXT"; 
const   char *ssid     = "FRITZ!Box 7490";

const char *password = "";

const char* ntpServer = "fritz.box";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 7200;

#include <time.h>                   // time() ctime()
time_t now;                         // this is the epoch
tm myTimeInfo;                      // the structure tm holds time information in a more convient way

void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);           // update the structure tm with the current time
  Serial.print("year:");
  Serial.print(myTimeInfo.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(myTimeInfo.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(myTimeInfo.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(myTimeInfo.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(myTimeInfo.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(myTimeInfo.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(myTimeInfo.tm_wday);         // days since Sunday 0-6
  if (myTimeInfo.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");
    
  Serial.println();
}

void connectToWifi() {
  Serial.print("Connecting to "); 
  Serial.println(ssid);

  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    BlinkHeartBeatLED(OnBoard_LED, 333);
    delay(332);
    Serial.print(".");
  }
  Serial.print("\n connected.");
  Serial.println(WiFi.localIP() );

}

void synchroniseWith_NTP_Time() {
  Serial.print("configTime uses ntpServer ");
  Serial.println(ntpServer);
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("synchronising time");
  
  while (myTimeInfo.tm_year + 1900 < 2000 ) {
    time(&now);                       // read the current time
    localtime_r(&now, &myTimeInfo);
    BlinkHeartBeatLED(OnBoard_LED, 100);
    delay(100);
    Serial.print(".");
  }
  Serial.print("\n time synchronsized \n");
  showTime();    
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println(__FILE__);
  Serial.print( F("  compiled ") );
  Serial.print(__DATE__);
  Serial.print( F(" ") );
  Serial.println(__TIME__);  
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);
  
  if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
    digitalWrite(IO_Pin,!digitalRead(IO_Pin) ); 
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();
  
  connectToWifi();
  synchroniseWith_NTP_Time();
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED,100);

  if ( TimePeriodIsOver(MyTestTimer,1000) ) {
    showTime();    
  }  
}

best regards Stefan

1 Like

I quite like the redundancy of the RTC, just in case there is a power failure and can't reconnect for whatever reason, then at least the rest of the system will still function and have 'more or less' the correct time - until we can reconnect.

Maybe I could remove it, I'll have to see how things go

fair enough - better safe than sorry :wink:

1 Like

Thanks Stefan, I'll have read over this also :slight_smile:

that is a famous wording among all RC fans that use SAFE-receivers

SAFE S)ensor A)ssisted F)flight E)nvelope Better SAFE than sorry

With this receiver the plane almost flies on itself.
best regards Stefan

cool what technology can do for you :wink:

Did you have to do something special to get your router to be a NTP server?

no nothing at all. The manufacturer "AVM" who produces the "Fritz!box" is very innovative.
They include more and more useful features in their routers.
phonebook for their DECT-telefones, blocking list, call-handling like forwarding or different ringtones
DECT/and Powerline smarthome-functions and a lot of more things
best regards Stefan

Cheers @J-M-L

I had to create some variables as it didn't want to function for whatever reason, but this works a treat.

#include <Wire.h>
#include <WiFi.h>
#include "RTClib.h"
#include "time.h"

//========================================================================

//WiFi Details
const char* ssid       = "The Internet";
const char* password   = "The Password";

//-RTC-
RTC_DS3231 rtc;

int yr = 0;
int mt = 0;
int dy = 0;
int hr = 0;
int mi = 0;
int se = 0;



// NTP server to request time
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 0;


// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}


// Function that gets time from NTP Server and syncs RTC clock
unsigned long getTime() {

  struct tm timeinfo;
  getLocalTime(&timeinfo);

  yr = timeinfo.tm_year + 1900;
  mt = timeinfo.tm_mon + 1;
  dy = timeinfo.tm_mday;
  hr = timeinfo.tm_hour;
  mi = timeinfo.tm_min;
  se = timeinfo.tm_sec;

  rtc.adjust(DateTime(yr, mt, dy, hr, mi, se));

    //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

}

void setup() {


  Serial.begin(115200);
  rtc.begin(); //Start RCT

  //Wifi
  initWiFi();

  //Time Server
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  getTime();


}


void loop() {

  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.println();
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();

  Serial.print(now.unixtime());
  Serial.println();

  delay(1000);

}

Is it possible to get timeinfo until millisecond or microsecond? Thanks

Is it possible to get timeinfo until millisecond or microsecond? Or there is another way?

NTP is a network protocol, you can't guarantee the latency over the network, so it would be hard to guarantee you have time accuracy at the ms level or even more at µs level.

Aah.. isee thanks..

I need to add timeinfo h:m:s:ms(with 5 digit) to calculate delay between sender and reciever. Timestamp in serial monitor only can show 3 digit of ms..

Do you have any suggestion how to get 5 digit ms ? Thankyou

what's the code?

you could use micros() to measure a round trip cost

1 Like

Yes, use a GPS.

Assuming the GPS has received the leap seconds update, the reported seconds will be inline with UTC. Then the rising edge of the 1PPS signal will be within a handful of nS.

1 Like

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.