#include "network.h" #include #include #include "config.h" #include "rtc.h" namespace { bool g_synced = false; uint32_t g_lastAttemptMs = 0; uint32_t g_lastSyncMs = 0; bool g_connecting = false; void startConnect() { Serial.printf("[net] connecting to %s\n", WIFI_SSID); WiFi.disconnect(); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); g_lastAttemptMs = millis(); g_connecting = true; } } // namespace namespace network { void begin() { WiFi.mode(WIFI_STA); WiFi.setHostname(WIFI_HOSTNAME); WiFi.setAutoReconnect(true); WiFi.setSleep(true); // the display is idle most of the time // Timezone is applied to the system clock regardless of connectivity, so the // RTC-derived time renders correctly offline. setenv("TZ", TIMEZONE_POSIX, 1); tzset(); startConnect(); } void loop() { const uint32_t nowMs = millis(); if (WiFi.status() == WL_CONNECTED) { if (g_connecting) { g_connecting = false; Serial.printf("[net] connected, ip=%s\n", WiFi.localIP().toString().c_str()); syncTimeNow(); } if (g_synced && nowMs - g_lastSyncMs >= NTP_RESYNC_MS) { syncTimeNow(); } return; } // Not connected: retry, but never more often than WIFI_RETRY_MS. const uint32_t since = nowMs - g_lastAttemptMs; if (g_connecting && since < WIFI_CONNECT_TIMEOUT_MS) { return; } if (since >= WIFI_RETRY_MS || (g_connecting && since >= WIFI_CONNECT_TIMEOUT_MS)) { if (g_connecting) { Serial.println("[net] connect attempt timed out"); g_connecting = false; g_lastAttemptMs = nowMs; // hold off for WIFI_RETRY_MS before retrying return; } startConnect(); } } bool isConnected() { return WiFi.status() == WL_CONNECTED; } bool syncTimeNow() { if (!isConnected()) { return false; } configTzTime(TIMEZONE_POSIX, NTP_SERVER_1, NTP_SERVER_2); // Wait briefly for the first SNTP response. A plausible year means the // system clock has been set from the network rather than left at the epoch. struct tm local = {}; const uint32_t deadline = millis() + 10000UL; bool got = false; while (millis() < deadline) { if (getLocalTime(&local, 200) && local.tm_year + 1900 >= 2024) { got = true; break; } delay(100); } if (!got) { Serial.println("[net] NTP sync failed"); return false; } // Persist UTC into the RTC so timekeeping survives the next outage. const time_t utcNow = time(nullptr); struct tm utc; gmtime_r(&utcNow, &utc); if (!rtc::setTime(utc)) { Serial.println("[net] NTP ok but RTC write failed"); } g_synced = true; g_lastSyncMs = millis(); Serial.printf("[net] time synced: %04d-%02d-%02d %02d:%02d local\n", local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, local.tm_hour, local.tm_min); return true; } bool hasSyncedTime() { return g_synced; } } // namespace network