network.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #include "network.h"
  2. #include <WiFi.h>
  3. #include <time.h>
  4. #include "config.h"
  5. #include "rtc.h"
  6. namespace {
  7. bool g_synced = false;
  8. uint32_t g_lastAttemptMs = 0;
  9. uint32_t g_lastSyncMs = 0;
  10. bool g_connecting = false;
  11. void startConnect()
  12. {
  13. Serial.printf("[net] connecting to %s\n", WIFI_SSID);
  14. WiFi.disconnect();
  15. WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  16. g_lastAttemptMs = millis();
  17. g_connecting = true;
  18. }
  19. } // namespace
  20. namespace network {
  21. void begin()
  22. {
  23. WiFi.mode(WIFI_STA);
  24. WiFi.setHostname(WIFI_HOSTNAME);
  25. WiFi.setAutoReconnect(true);
  26. WiFi.setSleep(true); // the display is idle most of the time
  27. // Timezone is applied to the system clock regardless of connectivity, so the
  28. // RTC-derived time renders correctly offline.
  29. setenv("TZ", TIMEZONE_POSIX, 1);
  30. tzset();
  31. startConnect();
  32. }
  33. void loop()
  34. {
  35. const uint32_t nowMs = millis();
  36. if (WiFi.status() == WL_CONNECTED) {
  37. if (g_connecting) {
  38. g_connecting = false;
  39. Serial.printf("[net] connected, ip=%s\n", WiFi.localIP().toString().c_str());
  40. syncTimeNow();
  41. }
  42. if (g_synced && nowMs - g_lastSyncMs >= NTP_RESYNC_MS) {
  43. syncTimeNow();
  44. }
  45. return;
  46. }
  47. // Not connected: retry, but never more often than WIFI_RETRY_MS.
  48. const uint32_t since = nowMs - g_lastAttemptMs;
  49. if (g_connecting && since < WIFI_CONNECT_TIMEOUT_MS) {
  50. return;
  51. }
  52. if (since >= WIFI_RETRY_MS || (g_connecting && since >= WIFI_CONNECT_TIMEOUT_MS)) {
  53. if (g_connecting) {
  54. Serial.println("[net] connect attempt timed out");
  55. g_connecting = false;
  56. g_lastAttemptMs = nowMs; // hold off for WIFI_RETRY_MS before retrying
  57. return;
  58. }
  59. startConnect();
  60. }
  61. }
  62. bool isConnected()
  63. {
  64. return WiFi.status() == WL_CONNECTED;
  65. }
  66. bool syncTimeNow()
  67. {
  68. if (!isConnected()) {
  69. return false;
  70. }
  71. configTzTime(TIMEZONE_POSIX, NTP_SERVER_1, NTP_SERVER_2);
  72. // Wait briefly for the first SNTP response. A plausible year means the
  73. // system clock has been set from the network rather than left at the epoch.
  74. struct tm local = {};
  75. const uint32_t deadline = millis() + 10000UL;
  76. bool got = false;
  77. while (millis() < deadline) {
  78. if (getLocalTime(&local, 200) && local.tm_year + 1900 >= 2024) {
  79. got = true;
  80. break;
  81. }
  82. delay(100);
  83. }
  84. if (!got) {
  85. Serial.println("[net] NTP sync failed");
  86. return false;
  87. }
  88. // Persist UTC into the RTC so timekeeping survives the next outage.
  89. const time_t utcNow = time(nullptr);
  90. struct tm utc;
  91. gmtime_r(&utcNow, &utc);
  92. if (!rtc::setTime(utc)) {
  93. Serial.println("[net] NTP ok but RTC write failed");
  94. }
  95. g_synced = true;
  96. g_lastSyncMs = millis();
  97. Serial.printf("[net] time synced: %04d-%02d-%02d %02d:%02d local\n",
  98. local.tm_year + 1900, local.tm_mon + 1, local.tm_mday,
  99. local.tm_hour, local.tm_min);
  100. return true;
  101. }
  102. bool hasSyncedTime()
  103. {
  104. return g_synced;
  105. }
  106. } // namespace network