From e7248c4774651f93c386ae8b8ea37311c643453c Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Tue, 4 Jun 2019 21:13:55 +0100 Subject: [PATCH 1/8] leave WiFi disconnected by default implement controlled retry - fixed at 60 seconds --- data/config/wifiSettings.json | 2 +- interface/src/forms/APSettingsForm.js | 2 +- interface/src/forms/WiFiSettingsForm.js | 4 +- src/WiFiSettingsService.cpp | 57 +++++++++++++++++-------- src/WiFiSettingsService.h | 8 +++- src/main.cpp | 4 +- 6 files changed, 53 insertions(+), 24 deletions(-) diff --git a/data/config/wifiSettings.json b/data/config/wifiSettings.json index 4f0b28a..8ff0621 100644 --- a/data/config/wifiSettings.json +++ b/data/config/wifiSettings.json @@ -1,5 +1,5 @@ { - "ssid":"ssid", + "ssid":"", "password":"password", "hostname":"esp8266-react", "static_ip_config":false diff --git a/interface/src/forms/APSettingsForm.js b/interface/src/forms/APSettingsForm.js index 582241d..bdd9191 100644 --- a/interface/src/forms/APSettingsForm.js +++ b/interface/src/forms/APSettingsForm.js @@ -66,7 +66,7 @@ class APSettingsForm extends React.Component { = WIFI_RECONNECTION_DELAY) { + _lastConnectionAttempt = currentMillis; + manageSTA(); + } +} + +void WiFiSettingsService::manageSTA() { + // Abort if already connected, or if we have no SSID + if (WiFi.isConnected() || _ssid.length() == 0) { + return; + } + // Connect or reconnect as required + if ((WiFi.getMode() & WIFI_STA) == 0) { + Serial.println("Connecting to WiFi."); + if (_staticIPConfig) { + // configure for static IP + WiFi.config(_localIP, _gatewayIP, _subnetMask, _dnsIP1, _dnsIP2); + } else { + // configure for DHCP +#if defined(ESP8266) + WiFi.config(INADDR_ANY, INADDR_ANY, INADDR_ANY); + WiFi.hostname(_hostname); +#elif defined(ESP_PLATFORM) + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(_hostname.c_str()); +#endif + } + // attempt to connect to the network + WiFi.begin(_ssid.c_str(), _password.c_str()); + } else { + Serial.println("Retrying WiFi connection."); + WiFi.reconnect(); + } +} diff --git a/src/WiFiSettingsService.h b/src/WiFiSettingsService.h index 1675471..a631258 100644 --- a/src/WiFiSettingsService.h +++ b/src/WiFiSettingsService.h @@ -6,6 +6,7 @@ #define WIFI_SETTINGS_FILE "/config/wifiSettings.json" #define WIFI_SETTINGS_SERVICE_PATH "/rest/wifiSettings" +#define WIFI_RECONNECTION_DELAY 1000 * 60 class WiFiSettingsService : public AdminSettingsService { @@ -15,13 +16,13 @@ class WiFiSettingsService : public AdminSettingsService { ~WiFiSettingsService(); void begin(); + void loop(); protected: void readFromJsonObject(JsonObject& root); void writeToJsonObject(JsonObject& root); void onConfigUpdated(); - void reconfigureWiFiConnection(); private: // connection settings @@ -30,6 +31,9 @@ class WiFiSettingsService : public AdminSettingsService { String _hostname; bool _staticIPConfig; + // for the mangement delay loop + unsigned long _lastConnectionAttempt; + // optional configuration for static IP address IPAddress _localIP; IPAddress _gatewayIP; @@ -39,6 +43,8 @@ class WiFiSettingsService : public AdminSettingsService { void readIP(JsonObject& root, String key, IPAddress& _ip); void writeIP(JsonObject& root, String key, IPAddress& _ip); + void reconfigureWiFiConnection(); + void manageSTA(); }; diff --git a/src/main.cpp b/src/main.cpp index d3256fb..3503240 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,8 +41,9 @@ APStatus apStatus = APStatus(&server, &securitySettingsService); SystemStatus systemStatus = SystemStatus(&server, &securitySettingsService);; void setup() { - // Disable wifi config persistance + // Disable wifi config persistance and auto reconnect WiFi.persistent(false); + WiFi.setAutoReconnect(false); Serial.begin(SERIAL_BAUD_RATE); SPIFFS.begin(); @@ -86,6 +87,7 @@ void setup() { } void loop() { + wifiSettingsService.loop(); apSettingsService.loop(); ntpSettingsService.loop(); otaSettingsService.loop(); From 2eb34e83f806c0f703ab119ffaf141b8590cf15b Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Wed, 5 Jun 2019 00:05:16 +0100 Subject: [PATCH 2/8] Access Point only comes back up if WiFi is properly disconnected on failures. --- src/WiFiSettingsService.cpp | 26 ++++++++++++++++++++------ src/WiFiSettingsService.h | 7 +++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/WiFiSettingsService.cpp b/src/WiFiSettingsService.cpp index 7a2da4e..9fe8f7e 100644 --- a/src/WiFiSettingsService.cpp +++ b/src/WiFiSettingsService.cpp @@ -1,6 +1,12 @@ #include -WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) {} +WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) { +#if defined(ESP8266) + _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); +#elif defined(ESP_PLATFORM) + WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED); +#endif +} WiFiSettingsService::~WiFiSettingsService() {} @@ -56,7 +62,7 @@ void WiFiSettingsService::onConfigUpdated() { } void WiFiSettingsService::reconfigureWiFiConnection() { - // disconnect and de-configure wifi and software access point + // disconnect and de-configure wifi WiFi.disconnect(true); // reset last connection attempt to force loop to reconnect immediately @@ -106,8 +112,16 @@ void WiFiSettingsService::manageSTA() { } // attempt to connect to the network WiFi.begin(_ssid.c_str(), _password.c_str()); - } else { - Serial.println("Retrying WiFi connection."); - WiFi.reconnect(); - } + } } + +#if defined(ESP8266) +void WiFiSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) { + WiFi.disconnect(true); +} +#elif defined(ESP_PLATFORM) +void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { + WiFi.disconnect(true); +} +#endif + diff --git a/src/WiFiSettingsService.h b/src/WiFiSettingsService.h index a631258..e846728 100644 --- a/src/WiFiSettingsService.h +++ b/src/WiFiSettingsService.h @@ -41,6 +41,13 @@ class WiFiSettingsService : public AdminSettingsService { IPAddress _dnsIP1; IPAddress _dnsIP2; +#if defined(ESP8266) + WiFiEventHandler _onStationModeDisconnectedHandler; + void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); +#elif defined(ESP_PLATFORM) + void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); +#endif + void readIP(JsonObject& root, String key, IPAddress& _ip); void writeIP(JsonObject& root, String key, IPAddress& _ip); void reconfigureWiFiConnection(); From 4089b3294110fa917091b4be3fd7e745685bf322 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Wed, 5 Jun 2019 23:56:56 +0100 Subject: [PATCH 3/8] fix issue, using wrong even in esp32 --- src/NTPSettingsService.cpp | 2 +- src/WiFiSettingsService.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NTPSettingsService.cpp b/src/NTPSettingsService.cpp index b09e025..7d8c571 100644 --- a/src/NTPSettingsService.cpp +++ b/src/NTPSettingsService.cpp @@ -6,7 +6,7 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityM _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); _onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1)); #elif defined(ESP_PLATFORM) - WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED); + WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); #endif diff --git a/src/WiFiSettingsService.cpp b/src/WiFiSettingsService.cpp index 9fe8f7e..5483b46 100644 --- a/src/WiFiSettingsService.cpp +++ b/src/WiFiSettingsService.cpp @@ -4,7 +4,7 @@ WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, Securit #if defined(ESP8266) _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); #elif defined(ESP_PLATFORM) - WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED); + WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); #endif } From 142235c355ec60d23bc077946322935614368f09 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 7 Jun 2019 19:47:59 +0100 Subject: [PATCH 4/8] Fix issue with ota service not restarting properly - mdns not being shut down without calling end(). --- src/OTASettingsService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OTASettingsService.cpp b/src/OTASettingsService.cpp index f891448..a74d34f 100644 --- a/src/OTASettingsService.cpp +++ b/src/OTASettingsService.cpp @@ -39,6 +39,7 @@ void OTASettingsService::writeToJsonObject(JsonObject& root) { void OTASettingsService::configureArduinoOTA() { if (_arduinoOTA){ + _arduinoOTA->end(); delete _arduinoOTA; _arduinoOTA = nullptr; } From cf2a20fbd4e32fd9c2929c169b2fd77d905a360e Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 7 Jun 2019 20:08:46 +0100 Subject: [PATCH 5/8] Fix crash on startup when not configured - ESP32 --- src/main.cpp | 85 +++++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3503240..9d90008 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ #endif #include - +#include #include #include #include @@ -41,49 +41,58 @@ APStatus apStatus = APStatus(&server, &securitySettingsService); SystemStatus systemStatus = SystemStatus(&server, &securitySettingsService);; void setup() { - // Disable wifi config persistance and auto reconnect - WiFi.persistent(false); - WiFi.setAutoReconnect(false); + // Disable wifi config persistance and auto reconnect + WiFi.persistent(false); + WiFi.setAutoReconnect(false); + +#if defined(ESP_PLATFORM) + // Init the wifi driver on ESP32 + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t err = esp_wifi_init(&cfg); + if(err){ + log_e("esp_wifi_init %d", err); + } +#endif - Serial.begin(SERIAL_BAUD_RATE); - SPIFFS.begin(); + Serial.begin(SERIAL_BAUD_RATE); + SPIFFS.begin(); + + // Start security settings service first + securitySettingsService.begin(); - // start security settings service first - securitySettingsService.begin(); + // Start services + ntpSettingsService.begin(); + otaSettingsService.begin(); + apSettingsService.begin(); + wifiSettingsService.begin(); - // start services - ntpSettingsService.begin(); - otaSettingsService.begin(); - apSettingsService.begin(); - wifiSettingsService.begin(); + // Serving static resources from /www/ + server.serveStatic("/js/", SPIFFS, "/www/js/"); + server.serveStatic("/css/", SPIFFS, "/www/css/"); + server.serveStatic("/fonts/", SPIFFS, "/www/fonts/"); + server.serveStatic("/app/", SPIFFS, "/www/app/"); + server.serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico"); - // Serving static resources from /www/ - server.serveStatic("/js/", SPIFFS, "/www/js/"); - server.serveStatic("/css/", SPIFFS, "/www/css/"); - server.serveStatic("/fonts/", SPIFFS, "/www/fonts/"); - server.serveStatic("/app/", SPIFFS, "/www/app/"); - server.serveStatic("/favicon.ico", SPIFFS, "/www/favicon.ico"); + // Serving all other get requests with "/www/index.htm" + // OPTIONS get a straight up 200 response + server.onNotFound([](AsyncWebServerRequest *request) { + if (request->method() == HTTP_GET) { + request->send(SPIFFS, "/www/index.html"); + } else if (request->method() == HTTP_OPTIONS) { + request->send(200); + } else { + request->send(404); + } + }); - // Serving all other get requests with "/www/index.htm" - // OPTIONS get a straight up 200 response - server.onNotFound([](AsyncWebServerRequest *request) { - if (request->method() == HTTP_GET) { - request->send(SPIFFS, "/www/index.html"); - } else if (request->method() == HTTP_OPTIONS) { - request->send(200); - } else { - request->send(404); - } - }); + // Disable CORS if required + #if defined(ENABLE_CORS) + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); + #endif - // Disable CORS if required - #if defined(ENABLE_CORS) - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); - #endif - - server.begin(); + server.begin(); } void loop() { From 61f046c1852e404c0cd2282b483b53cb16726109 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 7 Jun 2019 20:14:55 +0100 Subject: [PATCH 6/8] WiFi driver must be managed by arduino, use arduino to init the driver for esp32 core. --- src/main.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9d90008..029092c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,14 +44,15 @@ void setup() { // Disable wifi config persistance and auto reconnect WiFi.persistent(false); WiFi.setAutoReconnect(false); - + #if defined(ESP_PLATFORM) // Init the wifi driver on ESP32 - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - esp_err_t err = esp_wifi_init(&cfg); - if(err){ - log_e("esp_wifi_init %d", err); - } + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t err = esp_wifi_init(&cfg); + if(err){ + log_e("esp_wifi_init %d", err); + } + #endif Serial.begin(SERIAL_BAUD_RATE); From 382299a8284be3a06cc1fb4f38f3eb37a94a7ec1 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 7 Jun 2019 20:14:55 +0100 Subject: [PATCH 7/8] WiFi driver must be managed by arduino, use arduino to init the driver for esp32 core. --- src/main.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9d90008..1aa3266 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,14 +44,11 @@ void setup() { // Disable wifi config persistance and auto reconnect WiFi.persistent(false); WiFi.setAutoReconnect(false); - + #if defined(ESP_PLATFORM) // Init the wifi driver on ESP32 - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - esp_err_t err = esp_wifi_init(&cfg); - if(err){ - log_e("esp_wifi_init %d", err); - } + WiFi.mode(WIFI_MODE_MAX); + WiFi.mode(WIFI_MODE_NULL); #endif Serial.begin(SERIAL_BAUD_RATE); From 2c31b671310780b6a614fb2163216aa167aedc7b Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 7 Jun 2019 20:26:01 +0100 Subject: [PATCH 8/8] latest build --- data/www/index.html | 2 +- data/www/js/0.40b9.js.gz | Bin 0 -> 11159 bytes data/www/js/0.439a.js.gz | Bin 11163 -> 0 bytes 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 data/www/js/0.40b9.js.gz delete mode 100644 data/www/js/0.439a.js.gz diff --git a/data/www/index.html b/data/www/index.html index 7abfc5e..0fef79f 100644 --- a/data/www/index.html +++ b/data/www/index.html @@ -1 +1 @@ -ESP8266 React
\ No newline at end of file +ESP8266 React
\ No newline at end of file diff --git a/data/www/js/0.40b9.js.gz b/data/www/js/0.40b9.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..b821fd58994fce8ab3c39cc5ca1b2ba8877d74ff GIT binary patch literal 11159 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