Mitigating sleep "DRIFT"?

I put the Boron to sleep for 12 hours in a project, and I want it to wake up a little under 12 hours later, ideally something like:

compensatedSleepInterval = 43200000 - (time to connect) - (time to run through code before going back to sleep).

Without this, if the Boron is powered on at 12 noon on the dot, it will wake up at midnight + the time it takes for all the other stuff. And then, the next day, it will wake up at noon + the time it takes to connect/run through loop, etc. Eventually, that 12-noon initial measurement “drifts” further and further away from the 12 noon mark, and I am not sure how best to fix it. I have tried something like this, but it does not appear to work:

SYSTEM_THREAD(ENABLED);
SystemSleepConfiguration config;

int wakems;
int msdifference;
int cSleepInterval; //compensated sleep interval
int SleepInterval = 3600000; //1 hour

void setup() 
{
    config.mode(SystemSleepMode::ULTRA_LOW_POWER);
    //config.duration(SleepInterval);
}

void loop() 
{
    wakems = millis(); //update the running time of the program in ms
    
    //poll sensors and measure data, almost time to go back to sleep
    
    msdifference = millis() - wakems; /* msdifference is the difference between how long it takes to connect to the cloud/run through the loop - the time at which 
    the boron wakes up for this measurement cycyle 
    */
    
    cSleepInterval = SleepInterval - msdifference;
    config.duration(cSleepInterval); 
    System.sleep(config);
}

In the code above, cSleepInterval is an attempt at subtracting the time it takes to connect/run through the code from one hour in ms.

The config.duration(SleepInterval) in the setup is what I normally do, but I have been experimenting with moving it to the loop and it does not appear to work. What’s the best way to do this? I’m considering a dedicated external timer that is independent of the Boron and outputting a HIGH to a Boron pin at this point :expressionless:, but I would prefer to do this all in code if possible.

One solution is to use the built-in real-time clock if possible. In other words, instead of waking every 12 hours, for example wake at 0400 and 1600 UTC. You do need to wait until you have the RTC set from the cloud the first time, but after that the calculations are significantly easier. Before going to sleep you use Time.now() to find the number seconds past epoch (January 1, 1970 UTC) and calculate amount of time you want to sleep. Storing this in retained memory, EEPROM, or a file on the file system is a good option.

If you want to get really fancy the SleepHelper library allows complex scheduling, including scheduling based on local time with support for daylight saving with automatic switching, and things like different schedules on weekends.

One of the reasons your calculation does not work is that it’s not taking into account the time it takes to connect to the cloud, which could be anywhere from 10 seconds to several minutes, and you’ll keep losing that on each wake cycle.

1 Like

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