I have been struggling with this problem for a couple of days without finding a good solution, can someone advice?
In my sketch for an Adafruit Huzzah breakout device using ESP-12 I have a number of things that will happen on a schedule with varying time intervals. It has been done in the recommended way, i.e. to have this construct in the loop() function:
unsigned long lastdbreport = 0;
void loop()
{
unsigned long now = millis();
if ((now - lastdbreport) > DB_UPDATE_INTERVAL) // This is 36000000, i.e. 1 hour
{
lastdbreport = now;
ReportMeterData();
}
//Other similar tasks are also defined here.
}
This has the effect of executing the report with a constant interval (within the millis() accuracy) of 1 hour .
I also have NTP time function running in my sketch via the time.h include.
So I can get a current local timestamp using this function in an utils.cpp file:
time_t now;
struct tm * timeinfo;
void getLocalTime(char buf[], int buflen)
{
time(&now); // read the current time
timeinfo = localtime(&now); //Convert to local
strftime(buf, buflen, "%Y-%m-%d %H:%M:%S", timeinfo);
}
What I want is to make sure that the execution of my ReportMeterData() function happens at the very beginning of the hour, i.e. it should be starting at the time the new hour starts.
But I cannot wrap my head around how this can be done in loop()...
In fact the only thing needed is to be able to once sync the execution to the hour switch because from then on my loop using millis() will work just fine.
But the millis() is hooked to the start/reset of the device, which is random with respect to calendar time.
...........................................................................
Help us help you.
Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'
Use code tags (the </> icon above the compose window) to make it easier to read and copy for examination
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.
Include the entire error message. It is easy to do. There is a button (lower right of the IDE window) called "copy error message". Copy the error and paste into a post in code tags. Paraphrasing the error message leaves out important information.
Post a schematic.
Post an image of your project.
Which Micro Controller are you using?
Is this simulator code?
Please describe the problem better then you just did.
...............................................................................................................................................
Serial Input basics.
The events portrayed in this post are not all true. The names are not real names of real people and real organizations.
..............................................................................
So NTP cannot get time until WiFi is connected, which happens about 15-16 seconds after millis start counting.
At that time loop() is running already.
The DB_UPDATE_INTERVAL value is a define in the setup.h file, but I guess that if I make it a long instead then the value could be changed to something that will trigger the first run on an even hour and then I can return 3600000 to it for future use...
But I cannot do that until the WiFi is connected and NTP has had time to sync.
I have created a function that calculates the millis when next hour starts
I have put in a delay in setup() such that the WiFi is online when I reach the end of setup() it should be on line.
I have created a new variable db_update_interval which is set to the define as a default.
After the delay in setup() I set the interval to the millis for the next hour.
In loop I am resetting the test value to the define the first time I reach the function so the next interval will be exactly 3600000 ms.
With this in place I started the device at 18:02 and it reported its data at 19:00:00 and the next time at 20:00:00!
Code snippets:
The new function:
//Get the offset from UTC hour start to millis()
unsigned long MillisAtNextHour()
{
time(&now); // read the current time
timeinfo = localtime(&now); //Convert to local
if (timeinfo->tm_year < 100) return(0); //if WiFi cannot connect
unsigned long justnow = millis();
unsigned long millisecsinutc = ((timeinfo->tm_min * 60 + timeinfo->tm_sec)) * 1000; //milliseconds into UTC hour
unsigned long nexthourmillis = justnow + 3600000 - millisecsinutc;
return (nexthourmillis);
}
At the end of setup():
db_update_interval = MillisAtNextHour();
if (db_update_interval == 0) {db_update_interval = DB_UPDATE_INTERVAL; //If NTP time could not be read
Serial.print("Setting db_update_interval = ");
Serial.println(db_update_interval);
Inside loop()
//Check if we should send meter data to the database
#ifdef DB_UPDATE_INTERVAL
if ((now - lastdbreport) > db_update_interval)
{
lastdbreport = now;
printLocalTime();
ReportMeterData();
db_update_interval = DB_UPDATE_INTERVAL;
}
#endif
in vague generic terms, without writing actual code: divide the hour by two and see if there is a remainder
when minutes = 00;
get the time;
float eventhour = ( hour / 2 );
if eventhour hour == round (eventhour); // if there is a remainder it's an odd number; no remainder is an even number
{
do the thing
}
else
move on to what comes next
You misunderstood me here...
When I wrote even hours I meant time ending in 00 seconds, not that the hours should be even like in (0-2-4-6...).
Right now my sketch has been running for 18 hours and the timestamps in the database is 4 seconds past the hour on all 18 entries.
In my debug window I can see that the millis() when the call is sent to the database is within one count for all 18 of them.
So:
My code works to sync up the database updates.
There is probably a short delay when the database is updated via the web call or else the database server clock is off a bit in order to account for the 4s difference.
And the ESP-12 clock seems to be pretty accurate
Note: I have yet to add a follow-up sync down the line if the times would drift due to the inaccuracy of he millis() clock.
Right now it is OK for me. But if needed I could insert a sync at the 30s mark some days or weeks into the future.
But I really do not need that kind of accuracy on the readings.