Code example demo ESP8266 / ESP32 synchronise with NTP-time

Hello,
here is a code-example and democode that demonstrates how to connect to a WiFi and how to synchronise with a NTP time server

/* Example Demo-Code for ESP8266 and ESP32
  Showing how to
  - organise code well structured into functions
  - connecting to a WiFi
  - synchronise time with an NTP-server
  - if connecting fails how to scan and print available WiFi-networks
  - how to use minuteOfDay and secondOfDay which make it easier to compare
  - the actual time with a certain point of time
  - a tricky way to use the serial monitor similar to a LC-Display
  - non-blocking timing based on function millis() with a helper-function
  - how to print a timestamp when the code was compiled
  written by user StefanL38
*/

#if defined(ESP32)
#include <WiFi.h>
char deviceType[] = "ESP32";
#else
#include <ESP8266WiFi.h>
char deviceType[] = "ESP8266";
#endif

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;
int connectCounter = 0;
int NoOfWiFis;
long minuteOfDay;
long secondOfDay;

const   char *ssid     = "your SSID";
const char *password = "your password";

const char dayOfWeek[][16] = {"sunday",
                              "monday",
                              "tuesday",
                              "wednesday",
                              "thursday",
                              "friday",
                              "saturday"
                             };

// a lot of home-wlan-routers can be used as a NTP-server too
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
int Year;
int Month;
int Day;
int Hour;
int Minute;
int Second;
int DayIndex;


void updateMyTimeVars() {
 Year   = myTimeInfo.tm_year + 1900; // years since 1900
 Month  = myTimeInfo.tm_mon + 1;     // January = 0 (!)
 Day    = myTimeInfo.tm_mday;
 Hour   = myTimeInfo.tm_hour;
 Minute = myTimeInfo.tm_min;
 Second = myTimeInfo.tm_sec; 
 DayIndex = myTimeInfo.tm_wday;
}


void clearSerialMonitor() {
  for (int i = 0; i < 50; i++) {
    Serial.println();  // print 50 empty lines
  }
}


void showTime() {
  time(&now);                       // read the current time
  localtime_r(&now, &myTimeInfo);   // update the structure tm with the current time
  updateMyTimeVars();
    
  Serial.print("year:");
  Serial.print(Year);  

  Serial.print(" month:");
  if (Month < 10) {
    Serial.print("0");
  }
  Serial.print(Month);      

  Serial.print(" day:");
  if (Day < 10) {
    Serial.print("0");
  }
  Serial.print(Day);         // day of month

  Serial.print(" hour:");
  if (Hour < 10) {
    Serial.print("0");
  }
  Serial.print(Hour);         // hours since midnight  0-23

  Serial.print(" min:");
  if (Minute < 10) {
    Serial.print("0");
  }
  Serial.print(Minute);          // minutes after the hour  0-59

  Serial.print(" sec:");
  if (Second < 10) {
    Serial.print("0");
  }
  Serial.print(Second);          // seconds after the minute  0-61*
  Serial.print(" DayIndex:");

  Serial.print(DayIndex);         // days since Sunday 0-6

  Serial.print(" name of day ");
  Serial.print(dayOfWeek[DayIndex]);

  minuteOfDay = Hour *   60 + Minute;
  secondOfDay = Hour * 3600 + Minute * 60 + Second;
  Serial.println();
  Serial.println();

  Serial.print("minuteOfDay ");
  Serial.print(minuteOfDay);

  Serial.print(" secondOfDay ");
  Serial.print(secondOfDay);

  //                 12 hours    4 minutes  59 seconds = 12:04:59
  if (secondOfDay < (12 * 3600 + 4 * 60   + 59) ) {
    Serial.println(" actual time is before 12:04:59");
  }
  else {
    Serial.println(" actual time is AFTER 12:04:59");
  }
  Serial.println();
  Serial.println();
}


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

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

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    yield(); // very important to have this function call to enable backround-processes
    BlinkHeartBeatLED(OnBoard_LED, 333);

    if ( TimePeriodIsOver(MyTestTimer, 500) ) {
      Serial.print(".");
      connectCounter++;
      if (connectCounter % 20 == 0) {
        Serial.println();
      }
    }

    if (connectCounter > 120) {
      break;
    }
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("\n connected.");
    Serial.println(WiFi.localIP() );
  }
  else {
    Serial.print("\n unable to connect to WiFi with name #");
    Serial.print(ssid);
    Serial.println("#");
    ScanWiFis();
    Serial.print("\n code stopped with while(true) yield() ");
    while (true) {
      yield();
    }
  }
}

void ScanWiFis() {
  int WiFiIdx;

  Serial.println("Startscanning for networks");
  NoOfWiFis = WiFi.scanNetworks();
  Serial.println("scanning done List of SSIDs");
  Serial.print("found number of networks ");
  Serial.println(NoOfWiFis);

  for (WiFiIdx = 0; WiFiIdx < NoOfWiFis; WiFiIdx++) {
    // Print SSID and RSSI for each network found
    Serial.print(WiFiIdx);
    Serial.print(" #");
    Serial.print( String( WiFi.SSID(WiFiIdx) ) );
    Serial.print("# RSSI ");
    Serial.print( String (WiFi.RSSI(WiFiIdx)) );
    Serial.print(" dB");
    Serial.println();
  }
}


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);
  delay(2000);
  Serial.println("\n Setup-Start \n");
  PrintFileNameDateTime();

  connectToWifi();
  synchroniseWith_NTP_Time();
}

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

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

best regards Stefan

3 Likes

Thanks, I was just getting ready to do something like this with CAN as my time server on the home automation system. The code compiled no errors but I need to upload it to an Arduino which is not on this machine at the current time.

I would like to add two external links to slightly shorter versions:

NTP with Daylight Saving Time for the ESP8266
https://werner.rothschopf.net/202011_arduino_esp8266_ntp_en.htm

and a version to be used with ESP32 or ESP8266
https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm

I would like to point out, that the base of these examples is the original
ESP8266 / NTP-TZ-DST
example as provided with the ESP core.

P.S.: There is still an outdated example ESP8266Wifi/NTPClient in the Arduino IDE. Use that only as example for UDP communication in general. For NTP follow ESP8266/ NTP-TZ-DST or the bare minimum in the provided links.

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