From b7e83f2fa66df1db5c7401254a66b57bab9e9ab3 Mon Sep 17 00:00:00 2001 From: Andreas Mandel Date: Fri, 5 Jan 2024 16:57:04 +0100 Subject: [PATCH] Allow multiple WiFi configurations for different networks (#343) * Use wifi multi to connect to different networks - use multi wifi - enhance config structure - about page updated - trusted networks (private) get direct http access - delay for ntp to get proper time - UI for config --- README.md | 2 +- docs/software/firmware/obs_cfg.md | 17 +- src/config.cpp | 53 ++++++ src/config.h | 14 ++ src/configServer.cpp | 291 ++++++++++++++++++++++-------- src/utils/timeutils.cpp | 19 +- src/utils/timeutils.h | 2 +- 7 files changed, 312 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index a6228ec1..9ade3e10 100755 --- a/README.md +++ b/README.md @@ -158,4 +158,4 @@ You can find the OpenBikeSensor documentation under: ## Supporters -[JetBrains supports the development with one license for their IDEs.](https://jb.gg/OpenSource) \ No newline at end of file +[JetBrains supports the development with one license for their IDEs.](https://jb.gg/OpenSource) diff --git a/docs/software/firmware/obs_cfg.md b/docs/software/firmware/obs_cfg.md index cc48119c..eff7970e 100644 --- a/docs/software/firmware/obs_cfg.md +++ b/docs/software/firmware/obs_cfg.md @@ -72,10 +72,21 @@ relevant put the order of the array content. "privacyConfig": 10, // Active preset - always 0 as of today "selectedPreset": 0, - // Password of your Wi-Fi where the OBS should log into in server mode + // Deprecated: Password of your Wi-Fi where the OBS should log into in server mode "wifiPassword": "swordfish", - // SSID of your Wi-Fi where the OBS should log into in server mode - "wifiSsid": "obs-cloud" + // Deprecated: SSID of your Wi-Fi where the OBS should log into in server mode + "wifiSsid": "obs-cloud", + // Array with multiple Wi-Fi networks to be used in client mode + "wifiNetworks": [ + { + // Password of your Wi-Fi where the OBS should log into in client mode + "wifiPassword": "swordfish", + // SSID of your Wi-Fi where the OBS should log into in client mode + "wifiSsid": "obs-cloud", + // if true obs will allow unprotected access in this network + "wifiPrivate": true + } + ] } ] } diff --git a/src/config.cpp b/src/config.cpp index 4a94dfb0..be970c05 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -41,6 +41,8 @@ const String ObsConfig::PROPERTY_BLUETOOTH = String("bluetooth"); const String ObsConfig::PROPERTY_OFFSET = String("offset"); const String ObsConfig::PROPERTY_WIFI_SSID = String("wifiSsid"); const String ObsConfig::PROPERTY_WIFI_PASSWORD = String("wifiPassword"); +const String ObsConfig::PROPERTY_WIFI_NETWORKS = String("wifiNetworks"); +const String ObsConfig::PROPERTY_WIFI_PRIVATE = String("wifiPrivate"); const String ObsConfig::PROPERTY_PORTAL_URL = String("portalUrl"); const String ObsConfig::PROPERTY_PORTAL_TOKEN = String("portalToken"); const String ObsConfig::PROPERTY_DISPLAY_CONFIG = String("displayConfig"); @@ -482,3 +484,54 @@ bool ObsConfig::removeConfig() { && !SPIFFS.exists(CONFIG_OLD_FILENAME) && !SPIFFS.exists(CONFIG_FILENAME); } + +WifiConfig ObsConfig::getWifiConfig(int wifiId) const { + WifiConfig result; + auto data = getProfileConst(selectedProfile)[PROPERTY_WIFI_NETWORKS][wifiId]; + + // legacy data single wifi + if (wifiId == 0 && data.isNull()) { + result.ssid = getProperty(PROPERTY_WIFI_SSID); + result.password = getProperty(PROPERTY_WIFI_PASSWORD); + result.trusted = false; + return result; + } + result.ssid = data[PROPERTY_WIFI_SSID].as(); + result.password = data[PROPERTY_WIFI_PASSWORD].as(); + result.trusted = data[PROPERTY_WIFI_PRIVATE].as(); + return result; +} + +int ObsConfig::getNumberOfWifiConfigs() const { + uint result = getProfileConst(selectedProfile)[PROPERTY_WIFI_NETWORKS].size(); + + log_i("getNumberOfWifiConfigs: %d", result); + log_i("PROPERTY_WIFI_SSID: %s", getProperty(PROPERTY_WIFI_SSID)); + log_i("getProperty(PROPERTY_WIFI_SSID): %s", getProperty(PROPERTY_WIFI_SSID).c_str()); + + if (result == 0 && getProperty(PROPERTY_WIFI_SSID).length() > 0) { + result = 1; + } + return (int) result; +} + +bool ObsConfig::removeWifiConfig(int wifiId) { + getProfile(selectedProfile)[PROPERTY_WIFI_NETWORKS].remove(wifiId); + return true; +} + +bool ObsConfig::addWifiConfig(const WifiConfig &wifiConfig) { + auto data = getProfile(selectedProfile)[PROPERTY_WIFI_NETWORKS].createNestedObject(); + data[PROPERTY_WIFI_SSID] = wifiConfig.ssid; + data[PROPERTY_WIFI_PASSWORD] = wifiConfig.password; + data[PROPERTY_WIFI_PRIVATE] = wifiConfig.trusted; + return true; +} + +bool ObsConfig::setWifiConfig(int wifiId, const WifiConfig &wifiConfig) { + auto data = getProfile(selectedProfile)[PROPERTY_WIFI_NETWORKS][wifiId]; + data[PROPERTY_WIFI_SSID] = wifiConfig.ssid; + data[PROPERTY_WIFI_PASSWORD] = wifiConfig.password; + data[PROPERTY_WIFI_PRIVATE] = wifiConfig.trusted; + return true; +} diff --git a/src/config.h b/src/config.h index da970b9c..d6d00ba8 100644 --- a/src/config.h +++ b/src/config.h @@ -55,6 +55,12 @@ enum PrivacyOptions { OverridePrivacy = 0x08 //8 }; +struct WifiConfig { + String ssid = ""; + String password = ""; + bool trusted = false; +}; + struct PrivacyArea { double latitude; double longitude; @@ -75,6 +81,7 @@ struct Config { int privacyConfig; int confirmationTimeWindow; std::vector privacyAreas; + std::vector wifiConfigs; }; enum DevOptions { @@ -109,6 +116,11 @@ class ObsConfig { bool removePrivacyArea(int profile, int paId); PrivacyArea getPrivacyArea(int profile, int paId) const; int getNumberOfPrivacyAreas(int profile) const; + WifiConfig getWifiConfig(int wifiId) const; + int getNumberOfWifiConfigs() const; + bool removeWifiConfig(int wifiId); + bool addWifiConfig(WifiConfig const &wifiConfig); + bool setWifiConfig(int wifiId, WifiConfig const &wifiConfig); int getNumberOfProfiles() const; int addProfile(); @@ -130,6 +142,8 @@ class ObsConfig { static const String PROPERTY_SIM_RA; static const String PROPERTY_WIFI_SSID; static const String PROPERTY_WIFI_PASSWORD; + static const String PROPERTY_WIFI_NETWORKS; + static const String PROPERTY_WIFI_PRIVATE; static const String PROPERTY_PORTAL_TOKEN; static const String PROPERTY_PORTAL_URL; static const String PROPERTY_DISPLAY_CONFIG; diff --git a/src/configServer.cpp b/src/configServer.cpp index 2c982048..5a4c118c 100644 --- a/src/configServer.cpp +++ b/src/configServer.cpp @@ -39,6 +39,9 @@ #include "utils/https.h" #include "utils/timeutils.h" #include "obsimprov.h" +#include +#include +#include using namespace httpsserver; @@ -56,8 +59,9 @@ static HTTPServer * insecureServer; static SSLCert * serverSslCert; static String OBS_ID; static String OBS_ID_SHORT; -static DNSServer *dnsServer; +static DNSServer *dnsServer = nullptr; static ObsImprov *obsImprov = nullptr; +static WiFiMulti wifiMulti; // TODO // - Fix CSS Style for mobile && desktop @@ -230,16 +234,10 @@ static const char* const rebootIndex = // Wifi // ######################################### -static const char* const wifiSettingsIndex = - "" - "

Settings

" - "SSID" - "" - "Password" - "" - ""; +static const char* const wifiSettingsIndexPostfix = + "" +; + static const char* const backupIndex = "

This backups and restores the device configuration incl. the Basic Config, Privacy Zones and Wifi Settings.

" @@ -446,6 +444,7 @@ static void handleBackup(HTTPRequest * req, HTTPResponse * res); static void handleBackupDownload(HTTPRequest * req, HTTPResponse * res); static void handleBackupRestore(HTTPRequest * req, HTTPResponse * res); static void handleWifi(HTTPRequest * req, HTTPResponse * res); +static void handleWifiDeleteAction(HTTPRequest * req, HTTPResponse * res); static void handleWifiSave(HTTPRequest * req, HTTPResponse * res); static void handleConfig(HTTPRequest * req, HTTPResponse * res); static void handleConfigSave(HTTPRequest * req, HTTPResponse * res); @@ -478,6 +477,7 @@ static void handleHttpAction(HTTPRequest *req, HTTPResponse *res); static void accessFilter(HTTPRequest * req, HTTPResponse * res, std::function next); bool configServerWasConnectedViaHttpFlag = false; +bool wifiNetworkIsTrusted = false; static void tryWiFiConnect(); static uint16_t countFilesInRoot(); @@ -535,6 +535,7 @@ void registerPages(HTTPServer * httpServer) { httpServer->registerNode(new ResourceNode("/settings/restore", HTTP_POST, handleBackupRestore)); httpServer->registerNode(new ResourceNode("/settings/wifi", HTTP_GET, handleWifi)); httpServer->registerNode(new ResourceNode("/settings/wifi/action", HTTP_POST, handleWifiSave)); + httpServer->registerNode(new ResourceNode("/settings/wifi/delete", HTTP_POST, handleWifiDeleteAction)); httpServer->registerNode(new ResourceNode("/settings/general", HTTP_GET, handleConfig)); httpServer->registerNode(new ResourceNode("/settings/general/action", HTTP_POST, handleConfigSave)); httpServer->registerNode(new ResourceNode("/updateFlash", HTTP_GET, handleFlashUpdate)); @@ -562,10 +563,13 @@ void registerPages(HTTPServer * httpServer) { void beginPages() { registerPages(server); - - insecureServer->registerNode(new ResourceNode("/cert", HTTP_GET, handleDownloadCert)); - insecureServer->registerNode(new ResourceNode("/http", HTTP_POST, handleHttpAction)); - insecureServer->setDefaultNode(new ResourceNode("", HTTP_GET, handleHttpsRedirect)); + if (wifiNetworkIsTrusted) { + registerPages(insecureServer); + } else { + insecureServer->registerNode(new ResourceNode("/cert", HTTP_GET, handleDownloadCert)); + insecureServer->registerNode(new ResourceNode("/http", HTTP_POST, handleHttpAction)); + insecureServer->setDefaultNode(new ResourceNode("", HTTP_GET, handleHttpsRedirect)); + } insecureServer->setDefaultHeader("Server", std::string("OBS/") + OBSVersion); } @@ -672,7 +676,9 @@ bool CreateWifiSoftAP() { IPAddress apIP(172, 20, 0, 1); IPAddress netMsk(255, 255, 255, 0); + WiFi.softAPsetHostname("obs"); WiFi.softAPConfig(apIP, apIP, netMsk); + WiFi.softAPsetHostname("obs"); if (softAccOK) { dnsServer = new DNSServer(); // with "*" we get a lot of requests from all sort of apps, @@ -687,18 +693,34 @@ bool CreateWifiSoftAP() { } /* Actions to be taken when we get internet. */ -static void wifiConectedActions() { +static void wifiConnectedActions() { log_i("Connected to %s, IP: %s", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); if (dnsServer) { // was used to announce AP ip dnsServer->start(53, "obs.local", WiFi.localIP()); } updateDisplay(obsDisplay); - MDNS.begin("obs"); - TimeUtils::setClockByNtp(WiFi.gatewayIP().toString().c_str()); + if (MDNS.begin("obs")) { + log_i("MDNS responder started"); + } else { + log_e("Error setting up MDNS responder!"); + } + if (WiFiClass::status() == WL_CONNECTED) { + TimeUtils::setClockByNtpAndWait(WiFi.gatewayIP().toString().c_str()); + } if (SD.begin() && WiFiClass::status() == WL_CONNECTED) { AlpData::update(obsDisplay); } + + String ssid = WiFi.SSID(); + int configs = theObsConfig->getNumberOfWifiConfigs(); + for (int i = 0; i < configs; i++) { + auto wifiConfig = theObsConfig->getWifiConfig(i); + if (ssid == wifiConfig.ssid) { + wifiNetworkIsTrusted = wifiConfig.trusted; + break; + } + } } /* callback function called if wifi data is received via improv */ @@ -716,7 +738,7 @@ bool initWifi(const std::string & ssid, const std::string & password) { bool connected = WiFiClass::status() == WL_CONNECTED; if (connected) { theObsConfig->saveConfig(); - wifiConectedActions(); + wifiConnectedActions(); } else { CreateWifiSoftAP(); obsDisplay->showTextOnGrid(0, 4, "Connect failed."); @@ -783,53 +805,44 @@ void startServer(ObsConfig *obsConfig) { touchConfigServerHttp(); // side effect do not allow track upload via button MDNS.begin("obs"); } else { - wifiConectedActions(); + wifiConnectedActions(); } createHttpServer(); createImprovServer(); } -static void tryWiFiConnect() { - if (!WiFiGenericClass::mode(WIFI_MODE_STA)) { - log_e("Failed to enable WiFi station mode."); +static void setWifiMultiAps() { + if (theObsConfig->getNumberOfWifiConfigs() == 0) { + log_w("No wifi SID set - will not try to connect."); + return; } - if (!WiFi.setHostname("obs")) { + for (int i = 0; i < theObsConfig->getNumberOfWifiConfigs(); i++) { + WifiConfig wifiConfig = theObsConfig->getWifiConfig(i); + log_i("Adding wifi SID %s", wifiConfig.ssid.c_str()); + wifiMulti.addAP(wifiConfig.ssid.c_str(), wifiConfig.password.c_str()); + } +} + +static void tryWiFiConnect() { + if (WiFiClass::setHostname("obs")) { log_e("Failed to set hostname to 'obs'."); } - if (theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_SSID).isEmpty()) { + if (theObsConfig->getNumberOfWifiConfigs() == 0) { log_w("No wifi SID set - will not try to connect."); return; } + setWifiMultiAps(); - const auto startTime = millis(); - const uint16_t timeout = 10000; - // Connect to WiFi network - while ((WiFiClass::status() != WL_CONNECTED) && (( millis() - startTime) <= timeout)) { - log_i("Trying to connect to %s", - theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_SSID)); - wl_status_t status = WiFi.begin( - theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_SSID), - theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_PASSWORD)); - log_d("WiFi status after begin is %d", status); - status = static_cast(WiFi.waitForConnectResult()); - while(status != WL_CONNECTED && (( millis() - startTime) <= timeout)) { - log_d("WiFi status after wait is %d", status); - if (status >= WL_CONNECT_FAILED) { - log_i("WiFi resetting connection for retry. (status 0x%02x))", status); - WiFi.disconnect(true, true); - break; - } else if (status == WL_NO_SSID_AVAIL) { - log_i("WiFi SSID not found - delay (status 0x%02x))", status); - delay(250);// WiFi.scanNetworks(false); - } - delay(250); - status = static_cast(WiFi.waitForConnectResult()); - } + log_w("Connection to wifi."); + if (wifiMulti.run(10000) == WL_CONNECTED) { + log_i("Connected to wifi SID: %s strength %ddBm ip: %s.", + WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str()); + } else { + log_w("Failed to connect to wifi."); } } - static void handleIndex(HTTPRequest *, HTTPResponse * res) { // ############################################################### // ### Index ### @@ -872,6 +885,43 @@ static String appVersion(const esp_partition_t *partition) { } } +static String wifiSatusAsString() { + switch (WiFiClass::status()) { + case WL_NO_SHIELD: + return "No WiFi shield"; + case WL_IDLE_STATUS: + return "Idle"; + case WL_NO_SSID_AVAIL: + return "No SSID available"; + case WL_SCAN_COMPLETED: + return "Scan completed"; + case WL_CONNECTED: + return "Connected"; + case WL_CONNECT_FAILED: + return "Connection failed"; + case WL_CONNECTION_LOST: + return "Connection lost"; + case WL_DISCONNECTED: + return "Disconnected"; + default: + return "Unknown"; + } +} + +static String wifiModeAsString() { +switch (WiFiClass::getMode()) { + case WIFI_OFF: + return "Off"; + case WIFI_STA: + return "Station"; + case WIFI_AP: + return "Access Point"; + case WIFI_AP_STA: + return "Access Point and Station"; + default: + return "Unknown"; + } +} static void handleAbout(HTTPRequest *req, HTTPResponse * res) { res->setHeader("Content-Type", "text/html"); @@ -890,6 +940,9 @@ static void handleAbout(HTTPRequest *req, HTTPResponse * res) { res->print(keyValue("Chip id", chipId)); res->print(keyValue("FlashApp Version", Firmware::getFlashAppVersion())); res->print(keyValue("IDF Version", esp_get_idf_version())); + res->print(keyValue("Arduino Version", ESP_ARDUINO_VERSION_MAJOR + String(".") + + ESP_ARDUINO_VERSION_MINOR + String(".") + + ESP_ARDUINO_VERSION_PATCH)); res->print(keyValue("App size", ObsUtils::toScaledByteString(ESP.getSketchSize()))); res->print(keyValue("App space", ObsUtils::toScaledByteString(ESP.getFreeSketchSpace()))); @@ -1007,11 +1060,29 @@ static void handleAbout(HTTPRequest *req, HTTPResponse * res) { page += keyValue("Display i2c timeout", Wire.getTimeOut(), "ms"); page += "

WiFi

"; - page += keyValue("Local IP", WiFi.localIP().toString()); - page += keyValue("AP IP", WiFi.softAPIP().toString()); - page += keyValue("Gateway IP", WiFi.gatewayIP().toString()); - page += keyValue("Hostname", WiFi.getHostname()); - page += keyValue("SSID", WiFi.SSID()); + page += keyValue("Mode", wifiModeAsString()); + if (WiFiGenericClass::getMode() == WIFI_MODE_AP || WiFiGenericClass::getMode() == WIFI_MODE_APSTA) { + page += keyValue("AP SSID", WiFi.softAPSSID()); + page += keyValue("AP Hostname", WiFi.softAPgetHostname()); + page += keyValue("AP IP", WiFi.softAPIP().toString()); + page += keyValue("AP MAC", WiFi.softAPmacAddress()); + page += keyValue("AP BSSID", WiFi.softAPmacAddress()); + page += keyValue("AP Clients", WiFi.softAPgetStationNum()); + } else { + page += keyValue("SSID", WiFi.SSID()); + page += keyValue("Hostname", WiFiClass::getHostname()); + page += keyValue("Local IP", WiFi.localIP().toString()); + page += keyValue("Gateway IP", WiFi.gatewayIP().toString()); + page += keyValue("Subnet Mask", WiFi.subnetMask().toString()); + page += keyValue("MAC", WiFi.macAddress()); + page += keyValue("RSSI", WiFi.RSSI(), "dBm"); + page += keyValue("DNS", WiFi.dnsIP().toString()); + page += keyValue("Status", wifiSatusAsString()); + page += keyValue("AutoConnect", WiFi.getAutoConnect() == 0 ? "Disabled" : "Enabled"); + page += keyValue("AutoReconnect", WiFi.getAutoReconnect() == 0 ? "Disabled" : "Enabled"); + page += keyValue("BSSID", WiFi.BSSIDstr()); + } + page += keyValue("Channel", WiFi.channel()); page += "

HTTP

"; page += keyValue("User Agent", req->getHeader("user-agent").c_str()); @@ -1098,31 +1169,105 @@ static void handleBackupRestore(HTTPRequest * req, HTTPResponse * res) { static void handleWifi(HTTPRequest *, HTTPResponse * res) { - String html = createPage(wifiSettingsIndex); - html = replaceDefault(html, "WiFi", "/settings/wifi/action"); - - // Form data - html = replaceHtml(html, "{ssid}", theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_SSID)); - if (theObsConfig->getProperty(ObsConfig::PROPERTY_WIFI_SSID).length() > 0) { - html = replaceHtml(html, "{password}", "******"); - } else { - html = replaceHtml(html, "{password}", ""); + String page; + page = "
Please note that the WiFi password is stored as plain Text on the OBS" + " and can be read by anyone with access to the device. "; + for (int idx = 0; idx < theObsConfig->getNumberOfWifiConfigs(); ++idx) { + auto wifi = theObsConfig->getWifiConfig(idx); + page += "

WiFi #" + String(idx + 1) + "

"; + const String &index = String(idx); + page += "SSID"; + page += "Password"; + page += "Private"; + page += ""; } + + page += "

New WiFi

"; + page += "SSID"; + page += "Password"; + page += "Private"; + page += "Select private only for trusted, none public networks, others on the same net will be able to " + "control your device. Allows direct, unencrypted access to the device."; + + String html = createPage(page, wifiSettingsIndexPostfix); + html = replaceDefault(html, "WiFi Settings", "/settings/wifi/action"); + + log_i("Page %s", page.c_str()); + sendHtml(res, html); } -static void handleWifiSave(HTTPRequest * req, HTTPResponse * res) { +static void handleWifiDeleteAction(HTTPRequest *req, HTTPResponse *res) { + String erase = getParameter(req, "erase"); + if (erase != "") { + theObsConfig->removeWifiConfig(atoi(erase.c_str())); + theObsConfig->saveConfig(); + } + sendRedirect(res, "/settings/wifi"); +} + +static bool updateWifi(const std::vector> ¶ms) { + bool modified = false; + for (int pos = 0; pos < theObsConfig->getNumberOfWifiConfigs(); ++pos) { + String idx = String(pos); + String ssid = getParameter(params, "ssid" + idx); + String password = getParameter(params, "pass" + idx); + bool trusted = getParameter(params, "private" + idx) == "on"; + + auto oldWifi = theObsConfig->getWifiConfig(pos); + if (password == "******") { + password = oldWifi.password; + } + if ((ssid != oldWifi.ssid) || (password != oldWifi.password) || (trusted != oldWifi.trusted)) { + log_i("Update wifi %d!", pos); + WifiConfig newWifiConfig; + newWifiConfig.password = password; + newWifiConfig.ssid = ssid; + newWifiConfig.trusted = trusted; + theObsConfig->setWifiConfig(pos, newWifiConfig); + modified = true; + } + } + return modified; +} + + +static bool addWifi(const std::vector> ¶ms) { + bool modified = false; + + String ssid = getParameter(params, "newSSID"); + String password = getParameter(params, "newPassword"); + bool trusted = getParameter(params, "newPrivate") == "on"; + + if ((ssid != "") && (password != "")) { + log_i("New wifi!"); + WifiConfig newWifiConfig; + newWifiConfig.password = password; + newWifiConfig.ssid = ssid; + newWifiConfig.trusted = trusted; + theObsConfig->addWifiConfig(newWifiConfig); + modified = true; + } + return modified; +} + +static void handleWifiSave(HTTPRequest *req, HTTPResponse *res) { const auto params = extractParameters(req); - const auto ssid = getParameter(params, "ssid"); - if (ssid) { - theObsConfig->setProperty(0, ObsConfig::PROPERTY_WIFI_SSID, ssid); + bool modified = false; + + modified = updateWifi(params); + if (addWifi(params)) { + modified = true; } - const auto password = getParameter(params, "pass"); - if (password != "******") { - theObsConfig->setProperty(0, ObsConfig::PROPERTY_WIFI_PASSWORD, password); + if (modified) { + theObsConfig->saveConfig(); + sendRedirect(res, "/settings/wifi"); + } else { + sendRedirect(res, "/"); } - theObsConfig->saveConfig(); - sendRedirect(res, "/settings/wifi"); } static void handleConfigSave(HTTPRequest * req, HTTPResponse * res) { diff --git a/src/utils/timeutils.cpp b/src/utils/timeutils.cpp index f61284af..3119ed6d 100644 --- a/src/utils/timeutils.cpp +++ b/src/utils/timeutils.cpp @@ -161,17 +161,20 @@ void TimeUtils::setClockByGps(uint32_t iTow, int32_t fTow, int16_t week, int8_t timeZone = TIMEZONE_GPS; } -void TimeUtils::setClockByNtpAndWait(const char* ntpServer) { +void TimeUtils::setClockByNtpAndWait(const char* ntpServer, uint32_t timeoutMs) { setClockByNtp(ntpServer); - log_i("Waiting for NTP time sync: "); - while (!systemTimeIsSet()) { - delay(500); - log_i("."); - yield(); + log_i("Waiting %dms for NTP time sync. ", timeoutMs); + const uint32_t startMs = millis(); + const uint32_t endMs = startMs + timeoutMs; + while (!systemTimeIsSet() && (millis() < endMs)) { + delay(100); + } + if (systemTimeIsSet()) { + log_i("System time is set after %ums via NTP to %s.", millis() - startMs, dateTimeToString().c_str()); + } else { + log_e("System time could not be set via NTP after %ums starting with %s.", millis() - startMs, dateTimeToString().c_str()); } - timeZone = TIMEZONE_UTC; - log_i("NTP time set got %s.", dateTimeToString(time(nullptr)).c_str()); } bool TimeUtils::systemTimeIsSet() { diff --git a/src/utils/timeutils.h b/src/utils/timeutils.h index 2836f3bf..161e0824 100644 --- a/src/utils/timeutils.h +++ b/src/utils/timeutils.h @@ -33,7 +33,7 @@ class TimeUtils { static String timeToString(time_t theTime =0); static String dateTimeToHttpHeaderString(time_t theTime); static void setClockByNtp(const char *ntpServer = nullptr); - static void setClockByNtpAndWait(const char *ntpServer = nullptr); + static void setClockByNtpAndWait(const char *ntpServer = nullptr, uint32_t timeout = 3 * 60 * 1000); static void setClockByGps(uint32_t iTow, int32_t fTow, int16_t week, int8_t leapS = 0); static bool systemTimeIsSet(); static int16_t getLeapSecondsGps(time_t gps);