#include "net.h" #include #include #include #include "settings.h" namespace { bool synced = false; bool wasConnected = false; // The device cannot be running before its own firmware was compiled, so the build // timestamp is a safe floor. Certificate validity checks fail against 1970, and this // makes them pass before SNTP has answered. mktime reads it as UTC while the build // machine wrote local time; a few hours of error is irrelevant for a lower bound. time_t buildTime() { static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; char month[4] = {__DATE__[0], __DATE__[1], __DATE__[2], '\0'}; const char* found = strstr(months, month); struct tm parts = {}; parts.tm_mon = found ? (found - months) / 3 : 0; parts.tm_mday = atoi(__DATE__ + 4); parts.tm_year = atoi(__DATE__ + 7) - 1900; parts.tm_hour = atoi(__TIME__); parts.tm_min = atoi(__TIME__ + 3); parts.tm_sec = atoi(__TIME__ + 6); return mktime(&parts); } // Latched, because sntp_get_sync_status() reports COMPLETED only briefly before // resetting to wait for the next cycle; polling it would flap. void onTimeSync(struct timeval*) { synced = true; Serial.printf("[net] clock synced: %lu\n", (unsigned long)time(nullptr)); } } // namespace void net::applyTimezone() { setenv("TZ", settings.timezone.c_str(), 1); tzset(); } void net::begin() { applyTimezone(); time_t floor = buildTime(); if (time(nullptr) < floor) { struct timeval seed = {.tv_sec = floor, .tv_usec = 0}; settimeofday(&seed, nullptr); } sntp_set_time_sync_notification_cb(onTimeSync); WiFi.persistent(false); if (settings.wifiSsid.length()) { WiFi.mode(WIFI_STA); WiFi.begin(settings.wifiSsid.c_str(), settings.wifiPassword.c_str()); } } void net::loop() { bool connected = WiFi.status() == WL_CONNECTED; if (connected == wasConnected) return; wasConnected = connected; if (!connected) return; // Started per join rather than once at boot: a fresh lease may hand us a different // NTP server, and the daemon re-syncs on its own hourly from here. sntp_servermode_dhcp(1); configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC; the UI decides how to show it Serial.println("[net] wifi up, sntp started"); } bool net::clockSynced() { return synced; }