From 3839f7ce5f902a5e25f122934546038f5eb2d75b Mon Sep 17 00:00:00 2001 From: FordPrfkt Date: Wed, 14 Aug 2019 02:05:13 +0200 Subject: [PATCH 1/3] Compatibility with ArduinoJSON v6 Changed implementation to be compatible with v6. --- src/FSWebServerLib.cpp | 146 +++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 77 deletions(-) diff --git a/src/FSWebServerLib.cpp b/src/FSWebServerLib.cpp index cfe4ce7..f76bbd7 100644 --- a/src/FSWebServerLib.cpp +++ b/src/FSWebServerLib.cpp @@ -204,38 +204,37 @@ bool AsyncFSWebServer::load_config() { configFile.readBytes(buf.get(), size); configFile.close(); DEBUGLOG("191 JSON file size: %d bytes\r\n", size); - DynamicJsonBuffer jsonBuffer(1024); - //StaticJsonBuffer<1024> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - - if (!json.success()) { - DEBUGLOG("Failed to parse config file\r\n"); + DynamicJsonDocument jsonDoc(1024); + auto error = deserializeJson(jsonDoc, buf.get()); + if (error) { + DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str()); return false; } + #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); Serial.println(temp); #endif - _config.ssid = json["ssid"].as(); + _config.ssid = jsonDoc["ssid"].as(); - _config.password = json["pass"].as(); + _config.password = jsonDoc["pass"].as(); - _config.ip = IPAddress(json["ip"][0], json["ip"][1], json["ip"][2], json["ip"][3]); - _config.netmask = IPAddress(json["netmask"][0], json["netmask"][1], json["netmask"][2], json["netmask"][3]); - _config.gateway = IPAddress(json["gateway"][0], json["gateway"][1], json["gateway"][2], json["gateway"][3]); - _config.dns = IPAddress(json["dns"][0], json["dns"][1], json["dns"][2], json["dns"][3]); + _config.ip = IPAddress(jsonDoc["ip"][0], jsonDoc["ip"][1], jsonDoc["ip"][2], jsonDoc["ip"][3]); + _config.netmask = IPAddress(jsonDoc["netmask"][0], jsonDoc["netmask"][1], jsonDoc["netmask"][2], jsonDoc["netmask"][3]); + _config.gateway = IPAddress(jsonDoc["gateway"][0], jsonDoc["gateway"][1], jsonDoc["gateway"][2], jsonDoc["gateway"][3]); + _config.dns = IPAddress(jsonDoc["dns"][0], jsonDoc["dns"][1], jsonDoc["dns"][2], jsonDoc["dns"][3]); - _config.dhcp = json["dhcp"].as(); + _config.dhcp = jsonDoc["dhcp"].as(); - _config.ntpServerName = json["ntp"].as(); - _config.updateNTPTimeEvery = json["NTPperiod"].as(); - _config.timezone = json["timeZone"].as(); - _config.daylight = json["daylight"].as(); - _config.deviceName = json["deviceName"].as(); + _config.ntpServerName = jsonDoc["ntp"].as(); + _config.updateNTPTimeEvery = jsonDoc["NTPperiod"].as(); + _config.timezone = jsonDoc["timeZone"].as(); + _config.daylight = jsonDoc["daylight"].as(); + _config.deviceName = jsonDoc["deviceName"].as(); - //config.connectionLed = json["led"]; + //config.connectionLed = jsonDoc["led"]; DEBUGLOG("Data initialized.\r\n"); DEBUGLOG("SSID: %s ", _config.ssid.c_str()); @@ -271,44 +270,43 @@ void AsyncFSWebServer::defaultConfig() { bool AsyncFSWebServer::save_config() { //flag_config = false; DEBUGLOG("Save config\r\n"); - DynamicJsonBuffer jsonBuffer(512); - //StaticJsonBuffer<1024> jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json["ssid"] = _config.ssid; - json["pass"] = _config.password; + DynamicJsonDocument jsonDoc(512); + + jsonDoc["ssid"] = _config.ssid; + jsonDoc["pass"] = _config.password; - JsonArray& jsonip = json.createNestedArray("ip"); + JsonArray jsonip = jsonDoc.createNestedArray("ip"); jsonip.add(_config.ip[0]); jsonip.add(_config.ip[1]); jsonip.add(_config.ip[2]); jsonip.add(_config.ip[3]); - JsonArray& jsonNM = json.createNestedArray("netmask"); + JsonArray jsonNM = jsonDoc.createNestedArray("netmask"); jsonNM.add(_config.netmask[0]); jsonNM.add(_config.netmask[1]); jsonNM.add(_config.netmask[2]); jsonNM.add(_config.netmask[3]); - JsonArray& jsonGateway = json.createNestedArray("gateway"); + JsonArray jsonGateway = jsonDoc.createNestedArray("gateway"); jsonGateway.add(_config.gateway[0]); jsonGateway.add(_config.gateway[1]); jsonGateway.add(_config.gateway[2]); jsonGateway.add(_config.gateway[3]); - JsonArray& jsondns = json.createNestedArray("dns"); + JsonArray jsondns = jsonDoc.createNestedArray("dns"); jsondns.add(_config.dns[0]); jsondns.add(_config.dns[1]); jsondns.add(_config.dns[2]); jsondns.add(_config.dns[3]); - json["dhcp"] = _config.dhcp; - json["ntp"] = _config.ntpServerName; - json["NTPperiod"] = _config.updateNTPTimeEvery; - json["timeZone"] = _config.timezone; - json["daylight"] = _config.daylight; - json["deviceName"] = _config.deviceName; + jsonDoc["dhcp"] = _config.dhcp; + jsonDoc["ntp"] = _config.ntpServerName; + jsonDoc["NTPperiod"] = _config.updateNTPTimeEvery; + jsonDoc["timeZone"] = _config.timezone; + jsonDoc["daylight"] = _config.daylight; + jsonDoc["deviceName"] = _config.deviceName; - //json["led"] = config.connectionLed; + //jsonDoc["led"] = config.connectionLed; //TODO add AP data to html File configFile = _fs->open(CONFIG_FILE, "w"); @@ -320,11 +318,10 @@ bool AsyncFSWebServer::save_config() { #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); Serial.println(temp); #endif - - json.printTo(configFile); + serializeJson(jsonDoc, configFile); configFile.flush(); configFile.close(); return true; @@ -353,21 +350,20 @@ bool AsyncFSWebServer::load_user_config(String name, String &value) { configFile.readBytes(buf.get(), size); configFile.close(); DEBUGLOG("340 JSON file size: %d bytes\r\n", size); - DynamicJsonBuffer jsonBuffer(1024); - //StaticJsonBuffer<1024> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - - if (!json.success()) { - DEBUGLOG("Failed to parse config file\r\n"); + DynamicJsonDocument jsonDoc(1024); + auto error = deserializeJson(jsonDoc, buf.get()); + if (error) { + DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str()); return false; } + #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); Serial.println(temp); #endif - value = json[name].asString(); + value = jsonDoc[name].as(); DEBUGLOG("Data initialized.\r\n"); DEBUGLOG("SSID: %s ", _config.ssid.c_str()); @@ -422,12 +418,11 @@ bool AsyncFSWebServer::save_user_config(String name, String value) { configFile.readBytes(buf.get(), size); configFile.close(); DEBUGLOG("Read JSON file size: %d bytes\r\n", size); - DynamicJsonBuffer jsonBuffer(1024); - //StaticJsonBuffer<1024> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); + DynamicJsonDocument jsonDoc(1024); + auto error = deserializeJson(jsonDoc, buf.get()); - if (!json.success()) { - DEBUGLOG("Failed to parse config file\r\n"); + if (error) { + DEBUGLOG("Failed to parse config file. Error: %s\r\n", error.c_str()); return false; } else @@ -435,7 +430,7 @@ bool AsyncFSWebServer::save_user_config(String name, String value) { DEBUGLOG("Parse User config file\r\n"); } - json[name] = value; + jsonDoc[name] = value; configFile = _fs->open(USER_CONFIG_FILE, "w"); if (!configFile) { @@ -447,11 +442,10 @@ bool AsyncFSWebServer::save_user_config(String name, String value) { #ifndef RELEASE DEBUGLOG("Save user config \r\n"); String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); Serial.println(temp); #endif - - json.printTo(configFile); + serializeJson(jsonDoc, configFile); configFile.flush(); configFile.close(); return true; @@ -518,29 +512,29 @@ bool AsyncFSWebServer::loadHTTPAuth() { configFile.readBytes(buf.get(), size); configFile.close(); DEBUGLOG("JSON secret file size: %d bytes\n", size); - DynamicJsonBuffer jsonBuffer(256); - //StaticJsonBuffer<256> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - - if (!json.success()) { + DynamicJsonDocument jsonDoc(256); + auto error = deserializeJson(jsonDoc, buf.get()); + + if (error) { #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); DBG_OUTPUT_PORT.println(temp); - DBG_OUTPUT_PORT.println("Failed to parse secret file"); + DBG_OUTPUT_PORT.println("Failed to parse secret file. Error: "); + DBG_OUTPUT_PORT.println(error.c_str()); #endif // RELEASE _httpAuth.auth = false; return false; } #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); DBG_OUTPUT_PORT.println(temp); #endif // RELEASE - - _httpAuth.auth = json["auth"]; - _httpAuth.wwwUsername = json["user"].as(); - _httpAuth.wwwPassword = json["pass"].as(); + + _httpAuth.auth = jsonDoc["auth"]; + _httpAuth.wwwUsername = jsonDoc["user"].as(); + _httpAuth.wwwPassword = jsonDoc["pass"].as(); DEBUGLOG(_httpAuth.auth ? "Secret initialized.\r\n" : "Auth disabled.\r\n"); if (_httpAuth.auth) { @@ -1176,12 +1170,11 @@ void AsyncFSWebServer::send_wwwauth_configuration_html(AsyncWebServerRequest *re bool AsyncFSWebServer::saveHTTPAuth() { //flag_config = false; DEBUGLOG("Save secret\r\n"); - DynamicJsonBuffer jsonBuffer(256); - //StaticJsonBuffer<256> jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json["auth"] = _httpAuth.auth; - json["user"] = _httpAuth.wwwUsername; - json["pass"] = _httpAuth.wwwPassword; + DynamicJsonDocument jsonDoc(256); + + jsonDoc["auth"] = _httpAuth.auth; + jsonDoc["user"] = _httpAuth.wwwUsername; + jsonDoc["pass"] = _httpAuth.wwwPassword; //TODO add AP data to html File configFile = _fs->open(SECRET_FILE, "w"); @@ -1193,11 +1186,10 @@ bool AsyncFSWebServer::saveHTTPAuth() { #ifndef RELEASE String temp; - json.prettyPrintTo(temp); + serializeJsonPretty(jsonDoc, temp); Serial.println(temp); #endif // RELEASE - - json.printTo(configFile); + serializeJson(jsonDoc, configFile); configFile.flush(); configFile.close(); return true; From 678918c80774f7375decaf5ab5fd84f49fb82398 Mon Sep 17 00:00:00 2001 From: FordPrfkt Date: Wed, 14 Aug 2019 02:25:54 +0200 Subject: [PATCH 2/3] added .vscode --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 879e44a..5b54826 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Debug/ __vm/ .vs/ *.sln +.vscode/ From 5bbf1e9a9cb48d033a97a2d40ace2a78ec2fb27c Mon Sep 17 00:00:00 2001 From: FordPrfkt Date: Sun, 18 Aug 2019 22:31:30 +0200 Subject: [PATCH 3/3] Added Auto AP Mode after timeout Added code to automatically switch to AP mode if device can not connect to WiFi after an configurable time --- src/FSWebServerLib.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/FSWebServerLib.h | 10 ++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/FSWebServerLib.cpp b/src/FSWebServerLib.cpp index f76bbd7..7bedd25 100644 --- a/src/FSWebServerLib.cpp +++ b/src/FSWebServerLib.cpp @@ -39,6 +39,17 @@ void AsyncFSWebServer::s_secondTick(void* arg) { if (self->_evs.count() > 0) { self->sendTimeData(); } + +//Check connection timeout if enabled +//TODO: as soon as ESP8266Wifi allows setting a timeout on waitForConnectResult use this instead of our own timeout mechanism +#if (AP_ENABLE_TIMEOUT > 0) + if (self->wifiStatus == FS_STAT_CONNECTING) { + if (++self->connectionTimout >= AP_ENABLE_TIMEOUT){ + DBG_OUTPUT_PORT.printf("Connection Timeout, switching to AP Mode.\r\n"); + self->configureWifiAP(); + } + } +#endif //AP_ENABLE_TIMEOUT } void AsyncFSWebServer::sendTimeData() { @@ -87,6 +98,9 @@ void flashLED(int pin, int times, int delayTime) { void AsyncFSWebServer::begin(FS* fs) { _fs = fs; + + connectionTimout = 0; + DBG_OUTPUT_PORT.begin(115200); DBG_OUTPUT_PORT.print("\n\n"); #ifndef RELEASE @@ -560,8 +574,16 @@ void AsyncFSWebServer::handle() { void AsyncFSWebServer::configureWifiAP() { DEBUGLOG(__PRETTY_FUNCTION__); DEBUGLOG("\r\n"); - //WiFi.disconnect(); + + if (WiFi.status() == WL_CONNECTED) { + WiFi.disconnect(); + } + WiFi.mode(WIFI_AP); + + wifiStatus = FS_STAT_APMODE; + connectionTimout = 0; + String APname = _apConfig.APssid + (String)ESP.getChipId(); if (_httpAuth.auth) { WiFi.softAP(APname.c_str(), _httpAuth.wwwPassword.c_str()); @@ -574,6 +596,8 @@ void AsyncFSWebServer::configureWifiAP() { if (CONNECTION_LED >= 0) { flashLED(CONNECTION_LED, 3, 250); } + + DBG_OUTPUT_PORT.printf("AP Mode enabled. SSID: %s IP: %s\r\n", WiFi.softAPSSID().c_str(), WiFi.softAPIP().toString().c_str()); } void AsyncFSWebServer::configureWifi() { @@ -593,10 +617,15 @@ void AsyncFSWebServer::configureWifi() { DEBUGLOG("NO DHCP\r\n"); WiFi.config(_config.ip, _config.gateway, _config.netmask, _config.dns); } + + connectionTimout = 0; + wifiStatus = FS_STAT_CONNECTING; +//Only usw wait waitForConnectResult if the timeout is not enabled to not mess with the timeout +//TODO: as soon as ESP8266Wifi allows setting a timeout on waitForConnectResult use this instead of our own timeout mechanism +#if (AP_ENABLE_TIMEOUT <= 0) WiFi.waitForConnectResult(); - - +#endif //AP_ENABLE_TIMEOUT } void AsyncFSWebServer::ConfigureOTA(String password) { @@ -660,6 +689,9 @@ void AsyncFSWebServer::onWiFiConnectedGotIP(WiFiEventStationModeGotIP data) { if (_config.updateNTPTimeEvery > 0) { // Enable NTP sync updateTimeFromNTP = true; } + + connectionTimout = 0; + wifiStatus = FS_STAT_CONNECTED; } diff --git a/src/FSWebServerLib.h b/src/FSWebServerLib.h index ad7a7d3..dc27963 100644 --- a/src/FSWebServerLib.h +++ b/src/FSWebServerLib.h @@ -34,6 +34,8 @@ #define CONNECTION_LED -1 // Connection LED pin (Built in). -1 to disable #define AP_ENABLE_BUTTON 5 // Button pin to enable AP during startup for configuration. -1 to disable +#define AP_ENABLE_TIMEOUT 90 // (Seconds, max 255) If the device can not connect to WiFi it will switch to AP mode after this time. -1 to disable + // #define HIDE_CONFIG #define CONFIG_FILE "/config.json" #define USER_CONFIG_FILE "/userconfig.json" @@ -71,6 +73,12 @@ typedef struct { String wwwPassword; } strHTTPAuth; +typedef enum { + FS_STAT_CONNECTING, + FS_STAT_CONNECTED, + FS_STAT_APMODE +} enWifiStatus; + class AsyncFSWebServer : public AsyncWebServer { public: AsyncFSWebServer(uint16_t port); @@ -112,6 +120,8 @@ class AsyncFSWebServer : public AsyncWebServer { WiFiEventHandler onStationModeConnectedHandler, onStationModeDisconnectedHandler, onStationModeGotIPHandler; //uint currentWifiStatus; + enWifiStatus wifiStatus; + uint8_t connectionTimout; Ticker _secondTk; bool _secondFlag;