No, the operation of the RTC here is pretty lame. You have to begin it, and then set it.
The internal fields of an RTCTime are initialized as 2020-01-01 00:00:00, so without doing anything else, when it gets converted to String to print, that's what you see. But the internal struct tm, which is
class RTCTime {
private:
stime_t stime;
is not initialized. (Its effective value can be seen with getUnixTime.) If passed to getTime
bool RTClock::getTime(RTCTime &t) {
struct tm present;
if(is_initialized) {
if( getRtcTime(present) ) {
t.setTM(present);
return true;
}
}
return false;
}
nothing happens to it if the RTC is not initialized
bool RTClock::begin() {
if(openRtc()) {
is_initialized = true;
}
else {
is_initialized = false;
}
return is_initialized;
}
by "opening" successfully. And as we've seen, the clock does not "tick" until it has been set. If you care that the time is the actual time -- instead of just using the RTC to fire periodically -- then you need to set the actual time, which has to come from somewhere. So that's
- manually, like a (non-smart) watch, microwave, or VCR
- e.g. fun exercise: attach a microphone and write code to detect clapping out the time in Morse code
- over WiFi or Ethernet
- with an internet connection, NTP is the obvious choice
- any decent web server response contains a
Date header, which you can parse and then the clock will be off by a second or so
- some more custom pull or push on your local intranet
which has to be done every time the MCU restarts. Lame.
But as I mentioned earlier, the time (from NTP) set on the RTC survived one restart. In fact, with the loop printing the time, the first time after restart was several seconds after the last time shown. The RTC is ticking up until it the next begin, at which point it stops. With that in mind, how about "reasserting" the time at startup, as with this modification of RTC_NTPSync
void setup(){
Serial.begin(115200);
while (!Serial);
RTC.begin();
RTCTime timeToSet;
RTC.getTime(timeToSet);
if (timeToSet.getYear() < 2024) {
Serial.print("\nIt's probably not ");
Serial.print(timeToSet);
Serial.println("\nStarting connection to server...");
connectToWiFi();
timeClient.begin();
timeClient.update();
// Get the current date and time from an NTP server and convert
// it to UTC +2 by passing the time zone offset in hours.
// You may change the time zone offset to your local one.
auto timeZoneOffsetHours = 2;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
timeToSet = RTCTime(unixTime);
} else {
Serial.print("\nContinuing with existing RTC time ");
Serial.println(timeToSet);
}
RTC.setTime(timeToSet);
}
void loop(){
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println(currentTime);
delay(1000);
}
I even made the connectToWiFi conditional. If you use WiFi anyway, then leave it where it is. Anyway, the check condition < 2024 is pretty simple. Can the RTC return a bogus time in the future? It seems that after a power cycle, it returns a proper 2000-Jan-1.
Also, on my particular R4, the RTC is not good at keeping time. Here's the initial time from NTP
12:24:44.873 -> Unix time = 1721337884
12:24:44.873 -> 2024-07-18T21:24:44
after restart, a minute later
12:25:59.854 -> 2024-07-18T21:26:00
12:26:00.886 -> 2024-07-18T21:26:01
After running for 44 minutes
13:10:00.238 -> 2024-07-18T22:10:53
the RTC has advanced 53 extra seconds. So if the time is important, you may need to do regular NTP syncs anyway.