I have the code segment below that reads sensors between the hours of 13 and 24. Everything works fine looping around every hour. The problem aries at the end of the day because as the day progressed with the built in delays each hour the code is running a few minutes later in time so if I set the sleep at the XXXX point in the code for 13 hours the unit will not wake up exactly at 13 but the number of minutes that got delayed from the previous day. Eventually over a few days the unit is waking up later and later. If you look at a snap shot of my log for one period of time the unit came online at 10:35:19 and went offline at 10:36:27.
The next iteration the unit will come on two minutes later and so on and so on.
What I am looking for is something similar to in the electric imp API server.sleepuntil(13, 0) where I am guaranteed that the
unit will wakeup at hour 13.
if ((Time.hour() >= 13) && (Time.hour() <= 24) )
{
.
.
.
delay(10000); // to get ready for sensors
.
.
.
delay(10000); // Let sensors read values
Serial.println("Read Sensors...");
.
.
.
delay(10000);
.
.
.
// Contact IFTTT
delay(10000);
.
.
.
System.sleep(SLEEP_MODE_DEEP,3600); // Sleep for one hour
//*********************************
.
.
.
// Start process all over
else
{
**System.sleep(SLEEP_MODE_DEEP,XXX); // I would Like XXX to be a sleep until and wakeup at the start time of 13**
}//time loop
A quick solution might be to do 24*3600-(combined delay time) then it should wake at the same time. Alternatively, you could calculate the time difference between the current time and the time of the next wakeup, and use that to set the sleep time.
I’d definetly go with @Moors7’s aproach as this is the easiest and already for everybody doable way, with enough precision.
But just for completeness, if you had a battery backup for the RTC there would even be a wake-on-RTC possible for the STM32 µC, but it’s not (yet) baked into a nice and easy API.
The wake on RTC is how the sleep for X seconds is implemented. For now, calculating the difference between your desired wake up time and the current time is the simplest approach.
In future, we might have an API like:
System.sleepUntil(time);
But this would just be syntactic sugar for calling System.sleep() with a duration.
How can I determine the integer value for a particular hour. For example in the documentation:
// Print the hour for the given time, in this case: 4
Serial.println(Time.hour(1400647897));
What would the integer value be for hour 13 or 14? What is the formula to determine the integer value of a particular hour?
The “UNIX epoch time” used here is a count of seconds since midnight 1/1/1970 (with no account for leap seconds).
There are some C functions (like localtime and its relatives) you could use, or you do the relative maths with the functions you get with the Time library (e.g. (Time.now()) - (Time.now() % 86400) + (86400) + (14*3600) = “current second” - “seconds since midnight” + “seconds of one day” + “seconds of fourteen hours”)
If you want to wake at a given time (hh:mm:ss) on the following day, you would do something like this
// ( till midnight ) and ( another x seconds )
int secs2sleep = (86400 - Time.now() % 86400) + (hh * 3600 + mm * 60 + ss);
System.sleep(SLEEP_MODE_DEEP, secs2sleep);
I would use UTC or Epoch which is seconds based and while the numbers can be large the math is simple. Here is some untested code similar to something I did in one of my apps. I am sure there are more elegant ways but hopefully this helps.
uint32_t wakeUpUTC;
uint32_t wakeUpSecs;
//When you first enter your testing period at 1300
void setWakeup(){
wakeUpUTC = Time.now() + 24*3600;
}
//When you exit the last check at 2300
void calcWakeupSecs(){
wakeUpSecs = wakeUpUTC - Time.now();
}
else
{
System.sleep(SLEEP_MODE_DEEP,wakeUpSecs); // I would Like XXX to be a sleep until and wakeup at the start time of 13**
}//time loop
I am getting an erroneous result and consequently the Photon is not waking up at 13 (8:00 am local time).
Last night secs2sleep returned the following:
The previous night I did not use “String(Time.second” and the result was a large number of seconds which when divided by 60 multiple times came out to the number 35.
What I am I doing wrong and what needs to be done to return the the correct number of sleeps seconds to wakeup at 13?
I’m not sure what time zone you are in, but while Time.hh() returns the hour of your local zone set in setup()Time.now() returns the epoch time relative to UTC/GMT (zone 0).
And the whole setup only works after your RTC has at least synced once before.
I am in the Eastern time zone - US. I assume since the original setup of the Photon that RTC has at least synced once. How can I force a sync?
This morning when I removed power to the Photon, after it never woke up, the code started executing where it recognized that the time was >= 13. What do suggest I do?
@ScruffR I think I got it to work in trial runs. I will know for sure tomorrow morning if it wakes up at the proper time in an actual run.
Thanks for all of your help and insight.
Particle.publish("After Hours - Store Closed", String(Time.second(secs2sleep));
If you wanted to know how many seconds your device will sleep, you’d rather write
Particle.publish("After Hours - Store Closed", String(secs2sleep));
The way you did it you’d just get the seconds part of the time that is secs2sleepseconds past midnight 1/1/1970 which would be the same as secs2sleep % 60.
If you wanted to publish the time string your device will wake you’d something like this
float timeZone = +5.0; // your local time offset (without DST)
void setup()
{
...
Time.zone(timeZone);
if (Time.year() <= 1970) Particle.syncTime();
}
void loop()
{
uint32_t _now = Time.now();
// ( till midnight UTC ) and ( time to wake but UTC ) and ( make local )
int _secs2sleep = (86400 - _now % 86400) + (12 * 3600 + 00 * 60 + 00) + (timeZone * 3600);
Particle.publish("After Hours - Store Closed", Time.format(_now + _secs2sleep));
System.sleep(SLEEP_MODE_DEEP, _secs2sleep);
}
One thing to be aware of.
Since the “midnight finding” is done on the UTC side, you might find that the above will not wake on the first day if you do this after midnight UTC (so after 7pm your time).
To deal with that you’d have to add the time zone correction to _now but might have to correct other bits of above code accordingly.