Made a bit of a breakthrough last night with my time sync inaccuracy problem. Whereby the time was out by about two minutes.
I noticed a time triggered event fired two minutes before 10pm. I unplugged the device (a Core) and reconnected it. I then noticed that, presumably due to the recent handshake with the cloud, the even fired correctly at 1pm.
Strangely, I ensure in my code that I resync the time regularly with the Particle cloud.
Any ideas why this might not be happening/working?
I can post my full code if this would be desirable, but I call Particle.syncTime(); three times a day via Alarm.alarmRepeat using @bkoâs TimeAlarms/TimeAlarms.h which I know works because other, audible, alerts work swell.
Any ideas??
TLDR: Only powercycling the Core caused the Time to sync accurately, doing scheduled/periodic syncs in my code doesnât have the same effect.
Interesting. It turns out that not only does my time sync not work at all, but Iâve just found out that âmyâ DST code doesnât work either. Iâm extremely confused. I had been calling this via a TimeAlarm
void setZone() {
Particle.syncTime();
int month = Time.month();
int day = Time.day();
int weekday = Time.weekday();
int previousSunday = day - weekday + 1;
if (month < 3 || month > 11) {
Time.zone(0);
} else if (month > 3 && month < 11) {
Time.zone(1);
} else if (month == 3) {
int offset = (previousSunday >= 8) ? 1 : 0;
Time.zone(offset);
} else {
int offset = (previousSunday <= 0) ? 1 : 0;
Time.zone(offset);
}
}
but neither the time sync nor the DST bit seem to have any effect. Clutching at straws:
Do they both need to get executed in loop?? Or does the DST bit need to be executed in setup only? Help would be much appreciated. Or a pointer.
Thanks
Looking at the above code, it looks more and more like I might have used a code snippet intended for North America rather than Europe. But that still doesnât explain why âsync timeâ doesnât ever seem to execute?
Iâm trying now to adapt @scruffrâs code from here but the compiler seems really unhappy - seems to conflict with the timealarms library?
deviceone.ino: In function 'void loop()':
deviceone.ino:172:72: error: 'IsDST' was not declared in this scope
bool daylightSavings = IsDST(Time.day(), Time.month(), Time.weekday());
^
In file included from deviceone.ino:87:0:
deviceone.ino: In function 'bool isDST()':
TimeAlarms/TimeAlarms.h:14:15: error: expected unqualified-id before '(' token
#define now() (Time.now()+time_zone_cache)
^
deviceone.ino:453:34: note: in expansion of macro 'now'
int secSinceMidnightUTC = Time.now() % 86400;
The problem with the #define now is unfortunately a known bug that I inherited from the original TimeAlarms library. It is hard to fix without rewriting the original library, so for now the best solution is as @ScruffR said to do #undefine now() right after the #include for TimeAlarms.
Iâm still confused why my Particle.syncTime(); which I called from a TimeAlarm had seemingly no effect. There should be no reason why the code which followed that call would have rendered it inoperative, is there?
In full:
void setZone() {
Particle.syncTime();
int month = Time.month();
int day = Time.day();
int weekday = Time.weekday();
int previousSunday = day - weekday + 1;
if (month < 3 || month > 11) {
Time.zone(0);
} else if (month > 3 && month < 11) {
Time.zone(1);
} else if (month == 3) {
int offset = (previousSunday >= 8) ? 1 : 0;
Time.zone(offset);
} else {
int offset = (previousSunday <= 0) ? 1 : 0;
Time.zone(offset);
}
}
called via Alarm.alarmRepeat(18, 00, 00, setZone); and, as I say, other âalarmsâ both before and after (which are audible) work! Any ideas âŚanyone? Thanks
If no joy I suppose I could just schedule a restart every night in the middle of the night to get the correct time but seems like it should be avoidable.
@daneboomer, you are aware that calling Particle.syncTime() doesn't sync the time immediately. As per the docs:
Note that this function sends a request message to the Cloud and then returns. The time on the device will not be synchronized until some milliseconds later when the Cloud responds with the current time between calls to your loop. See Particle.syncTimeDone(), Particle.timeSyncedLast(), Time.isValid() and Particle.syncTimePending() for information on how to wait for request to be finished.
Again, as per the docs, the following bit of code is suggested:
// Request time synchronization from the Particle Device Cloud
Particle.syncTime();
// Wait until Photon receives time from Particle Device Cloud (or connection to Particle Device Cloud is lost)
waitUntil(Particle.syncTimeDone);
Another thing you can do is set the alarm for 1 minute past midnight to be sure the time has changed to the new day.
If I'm understanding you correctly, you're warning that the actual time sync doesn't happen instantaneously? That's OK. The problem in my case is it doesn't seem to be happening at all. Or are you saying my code has to wait for the time sync to complete in order for it to complete?
Sorry for not following...
Sorry to bother you all. Can anyone confirm if it is necessary to WAIT in code for the syncTime to return before proceeding in order for the time to actually sync?
If it is NOT necessary to wait, can anyone confirm that doing a syncTime with a Core actually works? I have a Core running 24/7 and over the course of weeks and months the time drifts by two minutes+ and despite calls to syncTime on a daily basis, the time never self corrects.
However if I reset the Core the time instantly corrects itself. But then - at the moment Iâm just calling Particle.syncTime(); without any wait. I wasnât aware a wait was necessary, but maybe it is on a Core and not a Photon?
Again, sorry for the irritation.
No, but if you expect the time to be correct for further use, you should.
Unfortunately I've not got any Cores left to test how they behave with the most recent versions, but I know it did work back in the days.
For the sake of testing Particle.syncTime() you won't need to wait weeks, you could just set the time in code to something wrong and then try syncing again.
I have done some experimenting and have implemented this code:-
time_t lastSyncTimestamp;
unsigned long lastSync = Particle.timeSyncedLast(lastSyncTimestamp);
if (syncnow == 2 || millis() - lastSync > ONE_DAY_MILLIS) {
unsigned long cur = millis();
//Serial.printlnf("Time was last synchronized %lu milliseconds ago", millis() - lastSync);
if (lastSyncTimestamp > 0) {
Particle.publish(DEVICE_NAME, "Time received from Particle Device Cloud was: ", 60, PRIVATE);
Particle.publish(DEVICE_NAME, Time.timeStr(lastSyncTimestamp), 60, PRIVATE);
}
// Request time synchronization from Particle Device Cloud
Particle.syncTime();
// Wait until Core receives time from Particle Device Cloud (or connection to Particle Device Cloud is lost)
waitUntil(Particle.syncTimeDone);
// Check if synchronized successfully
if (Particle.timeSyncedLast() >= cur) {
// Print current time
Particle.publish(DEVICE_NAME, Time.timeStr(), 60, PRIVATE);
}
syncnow = 3;
}
and what I get in return on the console is:
Time received from Particle Device Cloud was:
Fri Nov 2 16:24:55 2018
Fri Nov 2 16:25:45 2018
So firstly I think there might be an error in the example on the Particle website because the first timestamp doesnât appear to me to be the time received from Particle device cloud at all but actually the time the device was last synced with the device cloud! Am I right?
Also the second timestamp showed about a fifteen second deviation from Time.is - again, trying to think this throughâŚis this because the firmware tries to update the time gradually rather than in one big jump? This seems plausible because the time on the web dashboard is +/- 2 second accurate to Time.is.
(syncnow is something I call via a Particle function to trigger the sync rather than wait a day)
I don't really see a contradiction in that. To my understanding the time the device was last synced and the time the device was synced to (aka received by the cloud) should be the same thing (give or take the network latency).
There is no one vs. other if both are suppoesed to be the same.
What is the source of "Time.is"?
You could also use Particle.syncTime() twice in a row. I think to remember (somewhat hazy) that there was talk about it considering network latency between two calls.
However, latency is a complete different issue that Particle.syncTime() not working at all which you seemed having implied earlier in the thread. And in order to tell the one from the other, I have suggested ...
Have you tried that?
BTW, if you want to debug timing issues, introducing the cloud latency for Particle.publish() and console output is rarely helpful. I'd suggest you'd rather use Serial.print() for that. It still adds some latency, but definetly not as much as going round the globe
Not working at all is something I'm still looking into. It was with my previous use of the sole call Particle.syncTime(). As opposed to my recent use of waitUntil...syncTimeDone.
I'll do some more looking into it, to the best of my ability, but things still seem odd to me! The particle publishes appeared more or less instantly so don't account for the fifteen difference between the Core and Time.is "which is an online clock synchronised to an atomic clock".
Thanks for all your help so far. Really appreciated.