How to use built-in RTC of ESP32 with deep sleep

We talked about ESP’s built-in RTC for time stamping and storing data locally in this thread: Messdaten vor dem Schreiben in die InfluxDB im Flashspeicher des nodes puffern

I’d like to develop some example code for the RTC part of this scenario, the goal is:

  • set the RTC time via internet connection to a NTP server
  • in case a timezone / UTC offset / summer time is configured how can this values survive deep sleep phase?

Starting with this example it is easy to set the local RTC via configTime() with a time gathered from a NTP server. Local time can be put out via getLocalTime(&timeinfo)

In case you want to use timezones and daylight saving time in your (local) time stamps (btw we would not recommend this better make the magic on the server output) have a look at this tutorial

… and use configTzTime() instead of configTime()

Now we can add deep sleep timer wake-up along this example

All seems to be ok at the first run after setting up the RTC but after the first deep sleep we see that the configured timezone has no effect. Seems that RTC recognize time after deep sleep, but forget the timezone values. See:

https://esp32-server.de/ntp/

Einziges was fehlt ist die Einstellung der Zeitzone. Die Zeitzone muss nach dem wakeup neu eingestellt werden.

So we have to do this via

setenv("TZ",timeZone,1);  //  set timezone 
tzset();

The final code looks like that and works:

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

// deep sleep 
#define TIME_TO_SLEEP  10       // sleep delay (in seconds)
#define uS_TO_S_FACTOR 1000000  // factor to convert ms to s

// Wifi credentials
const char* ssid       = "[your-ssid]";
const char* password   = "[your-pw]";

// time server and time settings
//const char* ntpServer = "pool.ntp.org";     // NTP pool international
const char* ntpServer = "de.pool.ntp.org";  // NTP pool DE 
// define timezone see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html and https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
//const char* timeZone = "CET-1CEST,M3.5.0,M10.5.0/3";  // Central European Time (CET) / Europe/Berlin
const char* timeZone = "UTC0";  // UTC

struct tm timeinfo;  // time struct

  
// functions
void getNtpTime(){
  //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, get NTP time, set RTC
  configTzTime(timeZone,  ntpServer);

  // debug 
  Serial.print("get NTP time, RTC set to: ");
  printLocalTime();
  Serial.println();

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

void setTimezone(){
  Serial.print("set timezone to ");
  Serial.println(timeZone);
  setenv("TZ",timeZone,1);  //  set timezone 
  tzset();
}

void printLocalTime(){ 
  if(!getLocalTime(&timeinfo)){
    Serial.println("failed to obtain time");
    return;
  }

  // print time human readable
//  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
  Serial.println(&timeinfo, "%Y-%m-%d %H:%M:%S");

  // print epoch time 
  time_t epoch_ts = mktime(&timeinfo);  // get epoch time from struct
  Serial.println("epoch time is " + String(epoch_ts));
}


void setup(){
  Serial.begin(115200);
  Serial.println();

  // check if RTC is set 
  if (!getLocalTime(&timeinfo)) {
    Serial.println("RTC is not set");
    // set time via NTP 
    getNtpTime();    
  }

  // after deep sleep and without getNtpTime() / configTzTime() we have to set the timezone manually again see https://esp32-server.de/ntp/
  setTimezone(); 
}

void loop(){
  Serial.print("current time: ");
  printLocalTime();

  // delay(5 * 1000);

  Serial.println("deep sleep for " + String(TIME_TO_SLEEP) + " s");
  Serial.flush(); 
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
}

additional Ressources

3 Likes

The lack of TZ correction after a sleep seems like it would be a bug in core. That said, my personal belief is computing should be in UTC and the UI should handle local time/daylight saving.

I work with medical software and an early decision to use timezones on the backend leads to fun twice a year guesses about prescription dispenses.

2 Likes