← NTP-Synced Hardware RTC on an ESP32 PLC for Timestamps
Textile monitoring (weaving)ESP32 PLCNTPResilience / OTA
NTP-Synced Hardware RTC on an ESP32 PLC for Timestamps — full example
Sync the hardware RTC of an ESP32 PLC over NTP with retries and periodic resync, so industrial datalogging timestamps stay correct through outages.
Complete, runnable program for the ESP32 PLC (rtc-ntp-synchronization.ino): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
/*
* COMPLETE EXAMPLE — Hardware RTC synchronized via NTP
*
* Hardware: ESP32 PLC (Industrial Shields, with integrated RTC chip and WiFi)
* Based on: textile monitoring project, modul_RTC.h
*
* Network:
* Plant WiFi with internet access (pool.ntp.org) — without internet
* access, point to a local NTP server on the concentrator
*
* Architecture:
* 1. At startup (with network) the time is requested via NTP with retries
* 2. The time is written to the physical RTC chip -> it survives reboots
* and network outages: the datalogging timestamps are never garbage
* 3. Periodic resynchronization (every 12 h) to correct drift
* 4. The timestamp of the last successful synchronization is recorded,
* exposed as a diagnostic by the webserver and the MQTT commands
*
* Works together with other catalog examples:
* - sd-daily-file-datalogging.ino (file names /YYYY-MM-DD.json)
* - mqtt-events-sd-buffering.ino (messageID with real timestamp)
* - webserver-ota-firmware.ino (status page)
*/
#include
#include // integrated RTC of the PLC (Industrial Shields library)
#include
const char *WIFI_SSID = "WIFI_SSID";
const char *WIFI_PASS = "WIFI_PASS";
const char *NTP_SERVER = "pool.ntp.org";
const long GMT_OFFSET_SEC = 3600; // CET
const int DST_OFFSET_SEC = 3600; // daylight saving time
const uint32_t RESYNC_MS = 12UL * 3600UL * 1000UL; // every 12 h
uint32_t lastSyncOK = 0; // epoch of the last successful sync
uint32_t tResync = 0, tWifi = 0, tPrint = 0;
// ------------------------------------------------- NTP -> RTC synchronization
// Returns true if the RTC chip was updated
bool syncRTC() {
if (WiFi.status() != WL_CONNECTED) return false;
configTime(GMT_OFFSET_SEC, DST_OFFSET_SEC, NTP_SERVER);
struct tm timeinfo;
int attempts = 0;
while (!getLocalTime(&timeinfo, 1000) && attempts < 10) {
attempts++;
Serial.println("NTP: retry " + String(attempts));
}
if (attempts >= 10) return false; // no NTP: keep running on RTC time
time_t now = mktime(&timeinfo);
RTC.setTime((uint32_t)now); // write to the physical chip
RTC.write();
lastSyncOK = (uint32_t)now;
Serial.println("RTC synchronized: " + String((uint32_t)now));
return true;
}
void checkWiFi() { // non-blocking, see the dedicated sheet
if (WiFi.status() == WL_CONNECTED) return;
if (millis() - tWifi < 10000) return;
tWifi = millis();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
}
void setup() {
Serial.begin(115200);
RTC.begin(); // the chip time is already usable at boot
checkWiFi();
uint32_t t0 = millis(); // initial WiFi wait (max 15 s)
while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) delay(500);
if (!syncRTC())
Serial.println("No NTP at startup: using previous hardware RTC time");
}
void loop() {
checkWiFi();
// Periodic resynchronization to correct crystal drift
if (millis() - tResync >= RESYNC_MS) {
tResync = millis();
syncRTC();
}
// Demo: print the real time every 10 s (the one the datalogger would use)
if (millis() - tPrint >= 10000) {
tPrint = millis();
if (RTC.read()) {
char buf[32];
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
RTC.getYear(), RTC.getMonth(), RTC.getMonthDay(),
RTC.getHour(), RTC.getMinute(), RTC.getSecond());
Serial.print("RTC time: ");
Serial.print(buf);
Serial.println(" (last NTP sync: " + String(lastSyncOK) + ")");
}
}
delay(50);
}
Download the full project pack — freeThis example + the related ones + bill of materials