ESP32 keep accurate time with deep sleep

Hi
I'm trying to use the time.h library on ESP32. I want to update the time contained in

struct tm * timeinfo;

Can I do such thing as

timeinfo ++;

to add one second? If yes, does it automatically take care of the change in minutes, hours and days?

I want to do this because I've seen that the time accuracy is not good when using deep sleep ...
Otherwise, how can I increment the time of 1 second?

What I'm currently doing is this:

void updateTime () {
  firstMils += millis();
  if (firstMils > 1000) {
    firstMils -= 1000;
    firstSecs++;
    if (firstSecs > 60) {
      firstSecs -= 60;
      firstMins ++;
      if (firstMins > 60) {
        firstMins -= 60;
        firstHour ++;
        if (firstHour > 23) firstHour = 0;
      }
    }
  }
  timeinfo->tm_sec = firstSecs;
  timeinfo->tm_min = firstMins;
  timeinfo->tm_hour = firstHour;
}

This doesn't take care of the day, and it would be much simpler to only do

void updateTime () {
  firstMils += millis();
  if (firstMils > 1000) {
    firstMils -= 1000;
    timeinfo->tm_sec++;
  }
}

If would be a lot easier to use the now() function to get the current time in seconds, increment it as much as you need and then convert it back with the setTime() function.

I can't find any setTime function. Here is what I tried but the time does not update:

void updateTime (uint64_t elapsedTime) { // elapsedTime in us
  Serial.print("updateTime ");
  if (elapsedTime == 0) Mics += micros();
  else Mics += elapsedTime;
  Serial.printf(" %u \n",Mics / 1000000ull);
  if (Mics > 1000000) {
    Mics = Mics % 1000000;
    now += Mics / 1000000;
  }
  timeinfo = localtime (&now);
}

This should simply add 'Mics / 1000000' seconds to the current time. But timeinfo stays the same although it should add 9 seconds in my test case.

i figure the easiest would be to use timelib.h 's time_t (as number of seconds since 1st of Jan 1970) and yes that you can increment.

OK, I found it.
The setTime command is :

time(&now);

If anyone is interested, here is my code: I’ll let it run through the night (10-11 hours long) and see if I get some time drift.

#include <WiFi.h>
#include "time.h"
#define sleepPeriod 10000000ul  // 10 seconds sleep
#define OFFSET 0  // us (tient compte du temps d'exécution de updateTime)

const char* ssid       = "xx";
const char* password   = "xx";

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

RTC_DATA_ATTR byte bootCount = 0;
RTC_DATA_ATTR time_t now;
RTC_DATA_ATTR uint64_t Mics = 0;
RTC_DATA_ATTR struct tm * timeinfo;

void printLocalTime() {
  time(&now);
  timeinfo = localtime (&now);
  Serial.printf ("%s\n", asctime(timeinfo));
  delay(2); // 26 bytes @ 115200 baud is less than 2 ms
}

void updateTime (uint64_t elapsedTime) { // elapsedTime in us
  if (elapsedTime == 0) Mics += micros();
  else Mics += elapsedTime;
  if (Mics > 1000000) {
    Mics = Mics % 1000000;
    now += Mics / 1000000;
  }
}

void sommeil (unsigned long chrono) {
  updateTime (sleepPeriod - (micros() - chrono) + OFFSET);
  esp_sleep_enable_timer_wakeup(sleepPeriod - (micros() - chrono));
  esp_deep_sleep_start();
}

void setup()
{
  Serial.begin(115200);
  if (bootCount == 0) { // First boot
    //connect to WiFi
    int wifiCounter = 0;
    Serial.printf("Connecting to %s ", ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
      if (++wifiCounter > 30) ESP.restart(); // restart after 15 s
    }
    Serial.println(" CONNECTED");
    //init and get the time
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    delay(1000);
    printLocalTime();
    unsigned long chrono = micros();
    //disconnect WiFi as it's no longer needed
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
    bootCount++;
    sommeil (chrono);
  }

  updateTime (0); // Mise à jour pour utilisation pendant l'éveil
  unsigned long chrono = micros();
  /*
   * do what you want here
   */
  printLocalTime(); // This sets the internal clock
  sommeil (chrono);
}

void loop() {}

It sets the time via ntp at first boot, then goes to deep sleep for 10 seconds. And wakes up and goes to sleep every 10 seconds. I hope the time will remain accurate after the night.

The parameter OFFSET is to be set later, if this works well

OK, it's not good at all: I get 5 or 6 seconds advance in 15 minutes run!
Does anyone knw how I can keep some accuracy (I'd be glad to have 1 or 2 seconds drift per hour) while using the deep sleep?

It sets the time via ntp at first boot, then goes to deep sleep for 10 seconds. And wakes up and goes to sleep every 10 seconds.

OK, it's not good at all: I get 5 or 6 seconds advance in 15 minutes run!

If the internal timer and adjustment to now is not providing accurate time across sleep periods the job could be handled with a DS3231 rtc. It's alarm interrupt can wake the ESP32, and while it is very accurate by itself, it can be synchronized with the NTP time once an hour, or once a day.

The ESP32 has a built in Real Time Clock (RTC) not to be confused with RTC ram which is used by the ULP ( Ultra Low Power core). Using the ESP32 ULP core (that's core #3) you can get accurate deep sleep GPIO thingies.

Idahowalker:
The ESP32 has a built in Real Time Clock (RTC) not to be confused with RTC ram which is used by the ULP ( Ultra Low Power core). Using the ESP32 ULP core (that's core #3) you can get accurate deep sleep GPIO thingies.

Thanks Idahowalker. As I don't want to use an external (DS3231 for example) RTC, I'd like to know lire about this. I've never heard about this, I thought there were only 2 cores. Do you know how to use it in the Arduino framework?

EDIT: I think it's what I'm doing right now. These instructions

RTC_DATA_ATTR byte bootCount = 0;
RTC_DATA_ATTR time_t now;
RTC_DATA_ATTR uint64_t Mics = 0;
RTC_DATA_ATTR struct tm * timeinfo;

save some data in the RTC module's RAM and

  esp_sleep_enable_timer_wakeup(sleepPeriod - (micros() - chrono));
  esp_deep_sleep_start();

put the ESP32 in deepsleep mode, where only that RTC is "alive". So what else can I do to make it more accurate?

ULP core with Arduino ide. Tutorial by Andreas Spiess

cattledog:
ULP core with Arduino ide. Tutorial by Andreas Spiess

#252 ESP32 Ultra Low Power (ULP) core made easy in the Arduino IDE including 100$ challenge - YouTube

Thanks, I'll have look !

Hey, man!
Did you have success using the internal RTC?
Cheers.