Universal Framework for Time functions on ESP32 and ESP8266

Hi, there is a lot of confusion around, regarding many different time libraries coupled with NTP.

There are many different libraries named time.h that are not always doing the same things and a lot of examples working for one architecture and not for another one, or requiring to install additional libraries that break others or subsequent code.
Also different library use different methods and data models to provide the data information.
And most of them frequently limit themselves to provide a serial print example only.

I am making an attempt to write a better didactic example to start with, that must:

  • be simple to use and to understand for beginners,
  • run without modification on different architectures ESP32, ESP8266 and Arduinos…
  • run a while without network connection
  • use only one or two existing, well defined, standard libraries form the Arduino IDE, NOT a new one!
  • provide individually breakdown information as of hour, minute, seconds and so on…
  • provide the individual subroutines:
    -getWiFi()
  • getNTP()
  • getEpoch()
  • getTimeData()
  • provide the time info according to Posix in the structure struct tm timeinfo.
  • provide a breakdown information as strings AND as char to be usable by display libraries that cannot cope with strings only.
  • keep being sleek and resource saving.
  • use variable names compatible with the main ESP examples provided in the IDE.

My current version works based on:

  • TimeLib.h //Time by Michael Margolis now maintained by Paul Stoffregen
  • NTPClient… // NTP Client by Fabrice Weinberg

I think however that my current approach to populate manually the structure struct tm timeinfo is sub optimal and it should be done at once much easier with the c++ method:

timeinfo  = localtime ( &Epoch);

but currently my code breaks there with:
no match for ‘operator=’ (operand types are ‘tm’ and ‘tm*’)

and I cannot figure out why.

Can someone help to do it the right way?

( once that is done and works, I am considering to replace the instructions between line 86 and 93 with macro definitions to retrieve the information from the structure struct tm timeinfo
even if the user writes e.g. a trivial “Second” instead of “timeinfo.tm_sec”.

Thank you for your help, here is my current code:

//Didactic Time with Date Example that works with ESP 8266, ESP32 and should work with Arduinos as well...


#include <TimeLib.h>      //Time by Michael Margolis now maintained by Paul Stoffregen
//Initial examples with getNTPTime and sendNTP packets abandonned, being superseeded by Espressifs code.
#include <time.h>

#include <NTPClient.h>    // NTP Client by Fabrice Weinberg
#if defined(ESP8266)
#include <ESP8266WiFi.h>  // default from Espressif
#include <WiFiUdp.h>      // default from Espressif  
#elif defined(ESP32)
#include <WiFi.h>         // default from Espressif
#endif

#define WIFI_SSID "MySSID"
#define WIFI_PASS "MyPassword"
#define HOST_NAME "ESP-IoT"
#define TZ            2               // (utc+) TZ in hours
#define DST_MN        60              // use 60mn for summer time in some countries
#define GMT_OFFSET_SEC 3600 * TZ      // Do not change here...
#define DAIYLIGHT_OFFSET_SEC 60 * DST_MN // Do not change here...
#define NTP_SERVER "de.pool.ntp.org"
char daysOfTheWeek[8][4] = {"???", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // Function begins with 1
char monthsOfTheYear[13][4] = {"???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // Function begins with 1

// Variables for Time
static int lastSecond;
struct tm  timeinfo;
static int Second;
static int Minute;
static int Hour;
static int Day;
static int Month;
static int Year;
static int Weekday;
char *     DayName;
char *     MonthName;
String     Time;
String     Today;
time_t     Epoch;

static IPAddress ip;

//*** Buffers ***
static char charbuff[64];    //Char buffer for many functions
//String text;                 //String buffer for many functions


// Constructors
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_SERVER, GMT_OFFSET_SEC);

void getWiFi()
{
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while ( WiFi.status() != WL_CONNECTED )
  {
    delay ( 500 );
    Serial.print ( "." );
  }
  ip = WiFi.localIP();
  sprintf(charbuff, "Connected to IP: %03d.%03d.%03d.%03d", ip[0], ip[1], ip[2], ip[3]);
  Serial.println(charbuff);
}

void getNTP()
{
  timeClient.begin();
  timeClient.update();
  Serial.print(timeClient.getFormattedTime());
}
void getEpoch()
{
  Epoch   = timeClient.getEpochTime();
}
void getTimeData()
{
  Second    = second(Epoch);
  Minute    = minute(Epoch);
  Hour      = hour(Epoch);
  Weekday   = weekday(Epoch);
  Day       = day(Epoch);
  Month     = month(Epoch);
  Year      = year(Epoch);
  DayName   = daysOfTheWeek[Weekday];
  MonthName = monthsOfTheYear[Month];
  Time      = timeClient.getFormattedTime();
  sprintf(charbuff, "%02d/%02d/%04d", Day , Month, Year);
  Today     = charbuff;
timeinfo  = localtime ( &Epoch);
  /*
  timeinfo.tm_sec = Second;
  timeinfo.tm_min = Minute;
  timeinfo.tm_hour = Hour;
  timeinfo.tm_mday = Day;
  timeinfo.tm_mon = Month -1;
  timeinfo.tm_year = Year - 1900;
  timeinfo.tm_wday = Weekday - 1;
  */
  
}

void setup()
{
  Serial.begin(115200);
  getWiFi();
  getNTP();

}
void loop()
{
  timeClient.update();   // should be called from time to time to refresh NTP when expired, does nothing most of the time.
  getEpoch();            // writes the Epoch (Numbers of seconds till 1.1.1970...
  getTimeData();         // breaks down the Epoch into discrete values.

  // Examples with Strings
  Serial.print(F("Thanks God, it is: "));
  Serial.print( DayName );
  Serial.print(F("! Today is "));
  Serial.print( Today );
  Serial.print(F(" and Time is "));
  Serial.println( Time );

  // Examples with a character buffer (can be used for displays as well)
  sprintf(charbuff, "Now is %02d hour, %02d minutes and %02d seconds. The Epoch is: %10d" , Hour , Minute, Second, Epoch);
  Serial.println(charbuff);
  sprintf(charbuff, "Today is %03s, %02d %03s %04d ", DayName , Day , MonthName, Year);
  Serial.println(charbuff);
  Serial.println();

  delay(1000);
}