I'll get straight to the point: on startup the RTC is set by calling a NTPCLient with offset. This works fine everytime. After 24h the same client is called for an update with the same parameters to update the RTC. However now the RTC is set without (it would seem) the gmtOffset.
What's happening?
The full code is over 2000 lines, if required I can post that as well, but I think it should be in this part of the code:
//NTP and RTC
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
NTPClient ntpClient(Udp, "nl.pool.ntp.org"); //, 3600); moved to gmtOffset
const long gmtOffset = 3600; // Offset from UTC in seconds (3600 seconds = 1h) -- UTC+1 (Central European Winter Time)
unsigned long daylightOffset = 0; // 0 for wintertime 3600 for summertime
unsigned long nextUpdate;
unsigned long printNow;
bool setRTC = false;
TimeChangeRule mySTD = {"EST", First, Sun, Nov, 2, 60}; // Standard time = UTC +1 hours
TimeChangeRule myDST = {"EDT", Second, Sun, Mar, 2, 120}; // Daylight saving time = UTC +2 hours
Timezone myTZ(myDST, mySTD);
void setup() {
Serial.begin(115200);
delay(1000);
ntpClient.begin();
}
void loop() {
if (ArduinoCloud.connected() && setRTC == false) { // Set RTC once on startup
updateTime();
Serial.println("RTC is set");
setRTC = true;
}
if (millis() - nextUpdate >= 60 * 60 * 24 * 1000) { // Update RTC every 24hrs
updateTime();
nextUpdate = millis();
}
}
void updateTime() {
ntpClient.update();
setDST();
const unsigned long epoch = (ntpClient.getEpochTime() + gmtOffset + daylightOffset);
set_time(epoch);
//Serial.println(getLocalTime());
}
void setDST() {
time_t utcTime = now(); // Get current UTC time
TimeChangeRule *tcr; // Convert UTC time to local time
time_t localTime = myTZ.toLocal(utcTime, &tcr);
if (tcr == &myDST) { //check TimeChangeRule
daylightOffset = 3600;
}
if (tcr == &mySTD) {
daylightOffset = 0;
}
}
The code is running on an Arduino Giga. I've read the timezone library might not work correctly with the mbed of the giga but it is purely used to determine daylight saving time. I'm not sure yet if it works but regardless, it should not influence the gmtOffset or set_time(epoch);
I was using NTPClient ntpClient(Udp, "nl.pool.ntp.org", 3600) before, but with the same result. After 24 hours my clock goes back to UTC time.
I posted this in the French tutorial part of the forum, the code is pretty self explanatory. May be that could give you some ideas? (it's for the ESP32, not sure if the Giga has the same WiFi callbacks capabilities)
These two statements may not be doing what you perhaps might think they are. TimeChangeRule is a struct and tcr is a pointer holding the memory address of that struct. These statements compare the value of the pointer tcr with the addresses of the structs called myDST and mySTD. The results will always be false since the addresses of where each struct is held in memory are different. Comparing the content of structs is a little more complex:
@J-M-L
I'm having trouble getting the esp_sntp.h library to work. I'm using the IDE library manager and installed the only hit (ESPPerfectTime.h) but this does not compile because it's missing something else. I'm now trying to tie in the file from the esp-idf/components/lwip/include/apps/esp_sntp.h at v5.2 · espressif/esp-idf · GitHub link but it seems I need to install the whole esp-idf library?
@BitSeeker
I was indeed unaware of this. Back to the drawinboard
But if I compare utcTime to localTime, and I might have this backwards, won't that require me to set DST before knowing if DST should be applied or not? Since etcTime will never account for DST, that would mean my localTime would be the indicator. But how would it be adjusted for DST unless I tell it to?
Unless the RTC/localTime does indeed know and automatically apply DST, and I have been oblivious to this and wasting many, many hours trying to do something pointless...
My understanding is that once a timezone rule has been set up, as is the case at the start of your code, then .toLocal() will apply that timezone rule to the supplied time value and therefore return the corresponding local time value. I might, of course, be wrong....
so then if I get epoch time from the ntpClient.update() and change that to localtime with the timeZone .toLocal it should be all I need.
something like (i'm being hasty and posting my idea before testing)
void updateTime() {
ntpClient.update();
const unsigned long epoch = ntpClient.getEpochTime();
set_time(epoch);
//Serial.println(epoch);
time_t utcTime = now(); // Get current UTC time from the RTC
TimeChangeRule *tcr; // Convert UTC time to local time
time_t localTime = myTZ.toLocal(utcTime, &tcr);
//Serial.println(localTime);
}
So many things didn't work that I came to the conclusion the simplest way would be to set the RTC with the unix time, convert it with myTZ.toLocal() and immediately overwrite the RTC again.
I don't know why but it makes me a little sad to implement it like this. I lack the skill to find a better solution but if it works, it works. I'll get over it eventually