NTP and Deep Sleep Accuracy Issues

Hi,

I am working on a project running on an ESP32 which opens a pet door in the morning at sunrise and closes 30 minutes after sunset. This has been working fine until I have decided to make it battery powered and as such want to utilize deep sleep. I now have a large amount of clock drift. It appears that there is no NTP updates occurring after initial boot

I have simplified my code to just the time and deep sleep to remove other variables but still have the issue. What I want to know is how can I force a NTP update at some sort of regular interval.

I don't need it to be hugely accurate but ideally to stay within 5 minutes of the correct time. As such if I could force the NTP to refresh every 3 to 4 hours should easily manage this.

#include <WiFi.h>

#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 60

RTC_DATA_ATTR long bootcnt = 0;
long startTime;

const char* ssid = "myssid";
const char* password = "mypasswd";

const char* ntpServer = "pool.ntp.org";
const char* TZ_INFO    = "EST-10EDT-11,M10.1.0/02:00:00,M4.1.0/03:00:00";

void TimeCalcs();          //Needed for compiling in VSCode.

void TimeCalcs()
{
  struct tm time;
  if(!getLocalTime(&time))
  {
    Serial.println("Could not obtain time info");
    return;
  }
  Serial.print("Current Time: "); Serial.println(asctime(&time)); 
  Serial.print("---------\n");
}


void setup()
{
  Serial.begin(115200);
  bootcnt++;
  Serial.println("Boot Count: " + String(bootcnt));   
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  WiFi.begin(ssid, password);
  startTime = millis();
  while (WiFi.status() != WL_CONNECTED && (millis() - startTime) <= 8000) // try for 8 seconds
  {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("\nWiFi failed to Connect\n");
  } else
  {
    Serial.print("\nWiFi Connected\n");
  }
  configTime(0, 3600, ntpServer);
  setenv("TZ", TZ_INFO, 1);
  TimeCalcs();
  Serial.println("Going to sleep");
  Serial.flush();
  esp_deep_sleep_start();   //Anything after this will never run   
}

void loop()
{
  Serial.print("Code here should never run");
}

One might require additional wait time before doing the go to sleep thing.

Have put in a 1 second delay (delay 1000) just before it. Will run for a few hours and see if that makes any real difference.

Not sure if this has pretty much fixed it or just greatly reduced it. I have had it running for over 12 hours and it is currently approximately 5 seconds off.

Is it that the 1 second delay has made the RTC more accurate or is it that the delay is giving it time to resync the time. If it is the first option whilst it means I won't have an issue after a few hours (be more like about once a month I still need to find out how to get it to resync with ntp to have a very long term solution.

make a connect to ntp thingy function.

unsigned long whentoconnect = 100000;
unsigned long lastconnect=millis();
int count=0;

voiding somefunction( void * pvparemeters )
{

for(;;)
{

if( (millis()-lastconnect) >= whentoconnect )
{
count++;
lastconnect=millis()
}

if( count > 100000000 )
{
//do the ntp thing here
connecttontpfunction();.
count = 0;
}

}
}

or something like that.

I get how to set up a function and the various ways I could make a command run at certain times. I suppose to make my question clearer is "What is the command / function call to update it".

I have since found some more information which has helped me to find a solution (well kind of). I was using ESP32 core version 1.0.6 from expressif repository but found there was a Version 2.0.4 available through another repository.

This has some more functions in regards to SNTP however it appears still buggy (well for me anyway and found references to others having issues).

In particular there is a function

sntp_set_sync_interval(900*1000);

however that was failing to work for me but after updating to the 2.0 version core could at least compile it. I then found that adding the following few lines seemed to force it (however it happened intermittently (but at least it is working).

  sntp_set_time_sync_notification_cb(timeSyncCallback);
  sntp_restart();   

void timeSyncCallback(struct timeval *tv)
{
  Serial.println("\n----Time Sync Has Occurred-----");
  Serial.println(tv->tv_sec);
  Serial.println(ctime(&tv->tv_sec));
}

Overall I am now getting an intermittent output as follows when it does a sync. In this case it corrected time by 5 seconds

Boot Count: 159
.
WiFi Connected
Current Time: Wed Jul 13 09:02:12 2022
----Time Sync----- Time should have been verified
1657666927
Wed Jul 13 09:02:07 2022

Going to sleep

The above information I found was from a range of websites but particularly used https://techtutorialsx.com/2021/09/03/esp32-sntp-additional-features/#Setting_the_SNTP_sync_interval

As such a lot closer to the solution. Feel the last part is refining it most likely due to the device being in deep sleep but in tests so far it appears to do a sync between 5 and 10 an hour. When I push my code out to deep sleep for 20 minutes I feel it will still update within the timeframe I need (+/-5minute accuracy). Just going to work on fine tuning it a bit and see if I can make it more consistent as to when it runs

Seem to have a solution that works as intended 97% of 300 resets and other 3% were either it didn't succeed in connecting to WiFi or some odd reason. Have changed the code around and added a series of delays which I am guessing has been the key detail that has made it work so consistently. I would have expected though that NTP commands would have waited for them to complete before proceeding to the next line. Also added sntp_stop() with a delay

My next step will be to modify the code by reducing / removing some of these delays until it starts to affect the consistency that it works.

My code currently for those that have similar issues is as follows

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

#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 90

RTC_DATA_ATTR long bootcnt = 0;
RTC_DATA_ATTR long ClockCnt = 0;

long startTime;

const char* ssid = "myssid";
const char* password = "myPassword";

const char* ntpServer = "pool.ntp.org";
const char* TZ_INFO    = "EST-10EDT-11,M10.1.0/02:00:00,M4.1.0/03:00:00";

void setup()
{
  bootcnt++;
  ClockCnt++;
  struct tm timeinfo;
  sntp_set_time_sync_notification_cb(timeSyncCallback);
  Serial.begin(115200);
  Serial.println("Boot Count: " + String(bootcnt) + ". ClockCnt: " + String(ClockCnt));   
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  WiFi.begin(ssid, password);
  startTime = millis();
  while (WiFi.status() != WL_CONNECTED && (millis() - startTime) <= 8000) // try for 8 seconds
  {
    delay(500);
    Serial.print(".");
  }
  if (WiFi.status() == WL_CONNECTED)
  {
    Serial.print("\nWiFi Connected\n");
    sntp_stop();    
    delay(2000);
    if (bootcnt == 1)
    {
      TimeSync();
    } else
    {
      if (ClockCnt > 3)
      {
        TimeSync();
      }
    }    
  } else
  {
    if (bootcnt == 1)
    {
      Serial.print("\nWiFi failed to Connect. About to reboot\n");
      ESP.restart();
    }
  } 

  if(!getLocalTime(&timeinfo))
  {
    Serial.println("Could not obtain time info");
    return;
  }
  Serial.print("Current Time: "); Serial.println(asctime(&timeinfo)); 
  delay(5000);
  Serial.println("Going to sleep. Current ClockCnt: " + String(ClockCnt));
  Serial.flush();

  delay(1000);      //Added as per advice on forum. With this had about 5 seconds in 12 hours
  esp_deep_sleep_start();   //Anything after this will never run   
}


void timeSyncCallback(struct timeval *tv)
{
  Serial.println("\n----Time Sync----- Time should have been verified and updated if needed");
  Serial.println(tv->tv_sec);
  Serial.println(ctime(&tv->tv_sec));
  ClockCnt = 0;
 }

void TimeSync()
{
  configTime(0, 3600, ntpServer);
  delay(1000);
  setenv("TZ", TZ_INFO, 1);
  delay(1000);
  tzset();
  delay(1000);  
}

void loop()
{
  Serial.print("Code here should never run");
}

Actually just discovered this solution doesn't work. It is syncing the time but noticed that between Clock Syncs it is showing time as UTC not GMT10.

Any idea how to resolve this?

Ok. Happy I have now solved it. Solution was to put this in the setup routine (Note: No NTP server) and then have the same in the called routine on first boot and every 4th boot but with a NTP server stated in this called routine.

  configTime(0, 0, ""); 
  setenv("TZ", MY_TZ, 1);
  tzset();    

Got another solution which I have now tested and also appears to work just as well.
Remove the setenv() and tzset() calls from timeSync() function, and place them in setup() before calling getLocalTime().

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