From 06cc68e47201e4c821d09bc1ecf6986940e41dca Mon Sep 17 00:00:00 2001 From: Khoi Hoang <57012152+khoih-prog@users.noreply.github.com> Date: Thu, 15 Oct 2020 00:58:46 -0400 Subject: [PATCH] v1.2.0 ### Releases v1.2.0 1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. See [`Change Implementation to seperate *.h and *.cpp file instead of *.h and *-Impl.h`](https://github.com/khoih-prog/ESP_WiFiManager/issues/38) and [`Support building in PlatformIO PR`](https://github.com/khoih-prog/ESP_WiFiManager/pull/20). SSee [**HOWTO Fix `Multiple Definitions` Linker Error**](https://github.com/khoih-prog/ESP_WiFiManager#HOWTO-Fix-Multiple-Definitions-Linker-Error) 2. Fix bug [/close does not close the config portal](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/16). --- README.md | 33 +- examples/AutoConnect/AutoConnect.ino | 3 + .../AutoConnectWithFSParameters.ino | 3 + .../AutoConnectWithFeedback.ino | 3 + .../AutoConnectWithFeedbackLED.ino | 3 + .../ConfigOnDRD_FS_MQTT_Ptr.ino | 3 +- .../ConfigOnDoubleReset.ino | 293 +-- examples/ConfigOnStartup/ConfigOnStartup.ino | 3 + examples/ConfigOnSwitch/ConfigOnSwitch.ino | 3 + .../ConfigOnSwitchFS/ConfigOnSwitchFS.ino | 3 + .../ConfigOnSwitchFS_MQTT_Ptr.ino | 3 +- .../ConfigPortalParamsOnSwitch.ino | 3 + .../ESP32_FSWebServer/ESP32_FSWebServer.ino | 3 + .../ESP32_FSWebServer_DRD.ino | 3 + examples/ESP_FSWebServer/ESP_FSWebServer.ino | 3 + .../ESP_FSWebServer_DRD.ino | 3 + library.json | 2 +- library.properties | 2 +- src/ESP_WiFiManager-Impl.h | 39 +- src/ESP_WiFiManager.h | 57 +- src/ESP_WiFiManager_Debug.h | 37 +- src_cpp/ESP_WiFiManager.cpp | 2022 ++++++++++++++++ src_cpp/ESP_WiFiManager.h | 543 +++++ src_cpp/ESP_WiFiManager_Debug.h | 83 + src_h/ESP_WiFiManager-Impl.h | 2029 +++++++++++++++++ src_h/ESP_WiFiManager.h | 546 +++++ src_h/ESP_WiFiManager_Debug.h | 87 + 27 files changed, 5601 insertions(+), 214 deletions(-) create mode 100644 src_cpp/ESP_WiFiManager.cpp create mode 100644 src_cpp/ESP_WiFiManager.h create mode 100644 src_cpp/ESP_WiFiManager_Debug.h create mode 100644 src_h/ESP_WiFiManager-Impl.h create mode 100644 src_h/ESP_WiFiManager.h create mode 100644 src_h/ESP_WiFiManager_Debug.h diff --git a/README.md b/README.md index fe72179..0231399 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,11 @@ Thanks to [cancodr](https://github.com/cancodr) for requesting an enhancement in --- --- +### Releases v1.2.0 + +1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. See [`Change Implementation to seperate *.h and *.cpp file instead of *.h and *-Impl.h`](https://github.com/khoih-prog/ESP_WiFiManager/issues/38) and [`Support building in PlatformIO PR`](https://github.com/khoih-prog/ESP_WiFiManager/pull/20). SSee [**HOWTO Fix `Multiple Definitions` Linker Error**](https://github.com/khoih-prog/ESP_WiFiManager#HOWTO-Fix-Multiple-Definitions-Linker-Error) +2. Fix bug [/close does not close the config portal](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/16). + ### Releases v1.1.2 1. Fix bug in examples. @@ -147,6 +152,25 @@ The best and easiest way is to use `Arduino Library Manager`. Search for `ESP_Wi --- --- +### HOWTO Fix `Multiple Definitions` Linker Error + +The current library implementation, using xyz-Impl.h instead of standard xyz.cpp, possibly creates certain `Multiple Definitions` Linker error in certain use cases. Although it's simple to just modify several lines of code, either in the library or in the application, the library is adding a separate source directory, named src_cpp, besides the standard src directory. + +To use the old standard cpp way, locate this library' directory, then just + +1. **Delete the all the files in src directory.** +2. **Copy all the files in src_cpp directory into src.** +3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch. + +To re-use the new h-only way, just + +1. **Delete the all the files in src directory.** +2. **Copy the files in src_h directory into src.** +3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch. + +--- +--- + ## How It Works - The [ConfigOnSwitch](examples/ConfigOnSwitch) example shows how it works and should be used as the basis for a sketch that uses this library. @@ -2321,6 +2345,11 @@ Submit issues to: [ESP_WiFiManager issues](https://github.com/khoih-prog/ESP_WiF --- --- +### Releases v1.2.0 + +1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. See [`Change Implementation to seperate *.h and *.cpp file instead of *.h and *-Impl.h`](https://github.com/khoih-prog/ESP_WiFiManager/issues/38) and [`Support building in PlatformIO PR`](https://github.com/khoih-prog/ESP_WiFiManager/pull/20) +2. Fix bug [/close does not close the config portal](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/16). + ### Releases v1.1.2 1. Fix bug in examples. @@ -2432,7 +2461,7 @@ See [KenTaylor's version](https://github.com/kentaylor/WiFiManager) for previous - [Issue #25: API call /r doesnt clear credentials](https://github.com/khoih-prog/ESP_WiFiManager/issues/25), [Issue #26: softAP with custom IP not working](https://github.com/khoih-prog/ESP_WiFiManager/issues/26) and [Issue #27: CORS protection fires up with AJAX](https://github.com/khoih-prog/ESP_WiFiManager/issues/27) leading to [ESP_WiFiManager v1.0.11](https://github.com/khoih-prog/ESP_WiFiManager/releases/tag/v1.0.11). 7. Thanks to [Marko](https://github.com/wackoo-arduino) for agreeing to contribute the sample code dealing with MQTT which the [ConfigOnSwitchFS_MQTT_Ptr](examples/ConfigOnSwitchFS_MQTT_Ptr) is based on. See [Custom MQTT parameters using Wifi Manager](https://forum.arduino.cc/index.php?topic=692108.75). 8. Thanks to [05prateek](https://github.com/05prateek) for reporting [Stationmode Static IP changes to dhcp when esp8266 is restarted](https://github.com/khoih-prog/ESP_WiFiManager/issues/28) bug which is fixed in v1.0.11 by enhance autoConnect() function. - +9. Thanks to [Egor](https://github.com/eg321) and [HenrikW](https://github.com/Invento3D) to make [`Support building in PlatformIO PR`](https://github.com/khoih-prog/ESP_WiFiManager/pull/20) and post issue [`Change Implementation to seperate *.h and *.cpp file instead of *.h and *-Impl.h`](https://github.com/khoih-prog/ESP_WiFiManager/issues/38) to address the `multiple definition` linker error in certain cases, leading to v1.2.0 @@ -2448,6 +2477,8 @@ See [KenTaylor's version](https://github.com/kentaylor/WiFiManager) for previous + +
AlesSt
⭐️ AlesSt

wackoo-arduino
Marko

05prateek
05prateek

eg321
Egor

Invento3D
HenrikW

diff --git a/examples/AutoConnect/AutoConnect.ino b/examples/AutoConnect/AutoConnect.ino index 488d36a..daebf23 100644 --- a/examples/AutoConnect/AutoConnect.ino +++ b/examples/AutoConnect/AutoConnect.ino @@ -10,6 +10,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -28,6 +30,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. diff --git a/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino b/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino index 90211b5..846fe50 100644 --- a/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino +++ b/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino @@ -10,6 +10,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -28,6 +30,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. diff --git a/examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino b/examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino index 7f1fe40..4fed641 100644 --- a/examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino +++ b/examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino @@ -10,6 +10,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -28,6 +30,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. diff --git a/examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino b/examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino index 392b00a..8b36d60 100644 --- a/examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino +++ b/examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino @@ -10,6 +10,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -28,6 +30,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. diff --git a/examples/ConfigOnDRD_FS_MQTT_Ptr/ConfigOnDRD_FS_MQTT_Ptr.ino b/examples/ConfigOnDRD_FS_MQTT_Ptr/ConfigOnDRD_FS_MQTT_Ptr.ino index 288dd41..17af5a3 100644 --- a/examples/ConfigOnDRD_FS_MQTT_Ptr/ConfigOnDRD_FS_MQTT_Ptr.ino +++ b/examples/ConfigOnDRD_FS_MQTT_Ptr/ConfigOnDRD_FS_MQTT_Ptr.ino @@ -13,7 +13,7 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license - Version: 1.1.2 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -33,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a Config Portal when there is no stored WiFi Credentials or when a DRD is detected. diff --git a/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino b/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino index 1ef74cd..954cea4 100644 --- a/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino +++ b/examples/ConfigOnDoubleReset/ConfigOnDoubleReset.ino @@ -1,18 +1,20 @@ /**************************************************************************************************************************** ConfigOnDoubleReset.ino For ESP8266 / ESP32 boards - + ESP_WiFiManager is a library for the ESP8266/ESP32 platform (https://github.com/esp8266/Arduino) to enable easy configuration and reconfiguration of WiFi credentials using a Captive Portal. Inspired by: http://www.esp8266.com/viewtopic.php?f=29&t=2520 https://github.com/chriscook8/esp-arduino-apboot https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ - + Modified from Tzapu https://github.com/tzapu/WiFiManager and from Ken Taylor https://github.com/kentaylor - + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -31,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal when the reset button is pressed twice. @@ -56,74 +59,74 @@ To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) - #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. +#error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting. #endif // Use from 0 to 4. Higher number, more debugging messages and memory usage. #define _WIFIMGR_LOGLEVEL_ 3 #include - + //Ported to ESP32 #ifdef ESP32 - #include - #include - #include - - // From v1.1.0 - #include - WiFiMulti wifiMulti; - - #define USE_SPIFFS true - - #if USE_SPIFFS - #include - FS* filesystem = &SPIFFS; - #define FileFS SPIFFS - #define FS_Name "SPIFFS" - #else - // Use FFat - #include - FS* filesystem = &FFat; - #define FileFS FFat - #define FS_Name "FFat" - #endif - ////// +#include +#include +#include + +// From v1.1.0 +#include +WiFiMulti wifiMulti; - #define ESP_getChipId() ((uint32_t)ESP.getEfuseMac()) +#define USE_SPIFFS true - #define LED_BUILTIN 2 - #define LED_ON HIGH - #define LED_OFF LOW +#if USE_SPIFFS +#include +FS* filesystem = &SPIFFS; +#define FileFS SPIFFS +#define FS_Name "SPIFFS" +#else +// Use FFat +#include +FS* filesystem = &FFat; +#define FileFS FFat +#define FS_Name "FFat" +#endif +////// + +#define ESP_getChipId() ((uint32_t)ESP.getEfuseMac()) + +#define LED_BUILTIN 2 +#define LED_ON HIGH +#define LED_OFF LOW #else #include //https://github.com/esp8266/Arduino - //needed for library - #include - #include - - // From v1.1.0 - #include - ESP8266WiFiMulti wifiMulti; - - #define USE_LITTLEFS true - - #if USE_LITTLEFS - #include - FS* filesystem = &LittleFS; - #define FileFS LittleFS - #define FS_Name "LittleFS" - #else - FS* filesystem = &SPIFFS; - #define FileFS SPIFFS - #define FS_Name "SPIFFS" - #endif - ////// - - #define ESP_getChipId() (ESP.getChipId()) - - #define LED_ON LOW - #define LED_OFF HIGH +//needed for library +#include +#include + +// From v1.1.0 +#include +ESP8266WiFiMulti wifiMulti; + +#define USE_LITTLEFS true + +#if USE_LITTLEFS +#include +FS* filesystem = &LittleFS; +#define FileFS LittleFS +#define FS_Name "LittleFS" +#else +FS* filesystem = &SPIFFS; +#define FileFS SPIFFS +#define FS_Name "SPIFFS" +#endif +////// + +#define ESP_getChipId() (ESP.getChipId()) + +#define LED_ON LOW +#define LED_OFF HIGH #endif // These defines must be put before #include @@ -133,35 +136,35 @@ // Otherwise, library will use default EEPROM storage #ifdef ESP32 - // These defines must be put before #include - // to select where to store DoubleResetDetector's variable. - // For ESP32, You must select one to be true (EEPROM or SPIFFS) - // Otherwise, library will use default EEPROM storage - #if USE_SPIFFS - #define ESP_DRD_USE_SPIFFS true - #define ESP_DRD_USE_EEPROM false - #else - #define ESP_DRD_USE_SPIFFS false - #define ESP_DRD_USE_EEPROM true - #endif - +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP32, You must select one to be true (EEPROM or SPIFFS) +// Otherwise, library will use default EEPROM storage +#if USE_SPIFFS +#define ESP_DRD_USE_SPIFFS true +#define ESP_DRD_USE_EEPROM false +#else +#define ESP_DRD_USE_SPIFFS false +#define ESP_DRD_USE_EEPROM true +#endif + #else //ESP8266 - - // For DRD - // These defines must be put before #include - // to select where to store DoubleResetDetector's variable. - // For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS) - // Otherwise, library will use default EEPROM storage - #if USE_LITTLEFS - #define ESP_DRD_USE_LITTLEFS true - #define ESP_DRD_USE_SPIFFS false - #else - #define ESP_DRD_USE_LITTLEFS false - #define ESP_DRD_USE_SPIFFS true - #endif - - #define ESP_DRD_USE_EEPROM false - #define ESP8266_DRD_USE_RTC false + +// For DRD +// These defines must be put before #include +// to select where to store DoubleResetDetector's variable. +// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS) +// Otherwise, library will use default EEPROM storage +#if USE_LITTLEFS +#define ESP_DRD_USE_LITTLEFS true +#define ESP_DRD_USE_SPIFFS false +#else +#define ESP_DRD_USE_LITTLEFS false +#define ESP_DRD_USE_SPIFFS true +#endif + +#define ESP_DRD_USE_EEPROM false +#define ESP8266_DRD_USE_RTC false #endif #define DOUBLERESETDETECTOR_DEBUG true //false @@ -251,34 +254,34 @@ bool initialConfig = false; // Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network #if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) - // Force DHCP to be true - #if defined(USE_DHCP_IP) - #undef USE_DHCP_IP - #endif - #define USE_DHCP_IP true +// Force DHCP to be true +#if defined(USE_DHCP_IP) +#undef USE_DHCP_IP +#endif +#define USE_DHCP_IP true #else - // You can select DHCP or Static IP here - //#define USE_DHCP_IP true - #define USE_DHCP_IP false +// You can select DHCP or Static IP here +//#define USE_DHCP_IP true +#define USE_DHCP_IP false #endif #if ( USE_DHCP_IP || ( defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP ) ) - // Use DHCP - #warning Using DHCP IP - IPAddress stationIP = IPAddress(0, 0, 0, 0); - IPAddress gatewayIP = IPAddress(192, 168, 2, 1); - IPAddress netMask = IPAddress(255, 255, 255, 0); +// Use DHCP +#warning Using DHCP IP +IPAddress stationIP = IPAddress(0, 0, 0, 0); +IPAddress gatewayIP = IPAddress(192, 168, 2, 1); +IPAddress netMask = IPAddress(255, 255, 255, 0); #else - // Use static IP - #warning Using static IP - #ifdef ESP32 - IPAddress stationIP = IPAddress(192, 168, 2, 232); - #else - IPAddress stationIP = IPAddress(192, 168, 2, 186); - #endif - - IPAddress gatewayIP = IPAddress(192, 168, 2, 1); - IPAddress netMask = IPAddress(255, 255, 255, 0); +// Use static IP +#warning Using static IP +#ifdef ESP32 +IPAddress stationIP = IPAddress(192, 168, 2, 232); +#else +IPAddress stationIP = IPAddress(192, 168, 2, 186); +#endif + +IPAddress gatewayIP = IPAddress(192, 168, 2, 1); +IPAddress netMask = IPAddress(255, 255, 255, 0); #endif #define USE_CONFIGURABLE_DNS true @@ -318,7 +321,7 @@ void check_WiFi(void) Serial.println("\nWiFi lost. Call connectMultiWiFi in loop"); connectMultiWiFi(); } -} +} void check_status(void) { @@ -331,7 +334,7 @@ void check_status(void) #define HEARTBEAT_INTERVAL 10000L current_millis = millis(); - + // Check WiFi every WIFICHECK_INTERVAL (1) seconds. if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { @@ -363,7 +366,7 @@ void loadConfigData(void) LOGERROR(F("failed")); } } - + void saveConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "w"); @@ -385,18 +388,18 @@ uint8_t connectMultiWiFi(void) { #if ESP32 // For ESP32, this better be 0 to shorten the connect time - #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 0 +#define WIFI_MULTI_1ST_CONNECT_WAITING_MS 0 #else // For ESP8266, this better be 2200 to enable connect the 1st time - #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 2200L +#define WIFI_MULTI_1ST_CONNECT_WAITING_MS 2200L #endif #define WIFI_MULTI_CONNECT_WAITING_MS 100L - + uint8_t status; LOGERROR(F("ConnectMultiWiFi with :")); - + if ( (Router_SSID != "") && (Router_Pass != "") ) { LOGERROR3(F("* Flash-stored Router_SSID = "), Router_SSID, F(", Router_Pass = "), Router_Pass ); @@ -410,19 +413,19 @@ uint8_t connectMultiWiFi(void) LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); } } - + LOGERROR(F("Connecting MultiWifi...")); WiFi.mode(WIFI_STA); -#if !USE_DHCP_IP - #if USE_CONFIGURABLE_DNS - // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 - WiFi.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); - #else - // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. - WiFi.config(stationIP, gatewayIP, netMask); - #endif +#if !USE_DHCP_IP +#if USE_CONFIGURABLE_DNS + // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 + WiFi.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); +#else + // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. + WiFi.config(stationIP, gatewayIP, netMask); +#endif #endif int i = 0; @@ -465,7 +468,7 @@ void setup() Serial.setDebugOutput(false); - if (FORMAT_FILESYSTEM) + if (FORMAT_FILESYSTEM) FileFS.format(); // Format FileFS if not yet @@ -473,11 +476,11 @@ void setup() if (!FileFS.begin(true)) #else if (!FileFS.begin()) -#endif +#endif { Serial.print(FS_Name); Serial.println(F(" failed! AutoFormatting.")); - + #ifdef ESP8266 FileFS.format(); #endif @@ -503,19 +506,19 @@ void setup() ESP_wifiManager.setConfigPortalChannel(0); ////// -#if !USE_DHCP_IP - #if USE_CONFIGURABLE_DNS - // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 - ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP); - #else - // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. - ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask); - #endif -#endif +#if !USE_DHCP_IP +#if USE_CONFIGURABLE_DNS + // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 + ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP); +#else + // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. + ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask); +#endif +#endif // New from v1.1.1 #if USING_CORS_FEATURE - ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); + ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); #endif // We can't use WiFi.SSID() in ESP32 as it's only valid after connected. @@ -535,7 +538,7 @@ void setup() { LOGERROR3(F("* Add SSID = "), Router_SSID, F(", PW = "), Router_Pass); wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str()); - + ESP_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout. Serial.println("Got stored Credentials. Timeout 120s for Config Portal"); } @@ -549,7 +552,7 @@ void setup() { // DRD, disable timeout. ESP_wifiManager.setConfigPortalTimeout(0); - + Serial.println("Open Config Portal without Timeout: Double Reset Detected"); initialConfig = true; } @@ -574,12 +577,12 @@ void setup() // Stored for later usage, from v1.1.0, but clear first memset(&WM_config, 0, sizeof(WM_config)); - + for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { String tempSSID = ESP_wifiManager.getSSID(i); String tempPW = ESP_wifiManager.getPW(i); - + if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str()); else @@ -588,7 +591,7 @@ void setup() if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str()); else - strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1); + strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1); // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) @@ -620,10 +623,10 @@ void setup() } } - if ( WiFi.status() != WL_CONNECTED ) + if ( WiFi.status() != WL_CONNECTED ) { Serial.println("ConnectMultiWiFi in setup"); - + connectMultiWiFi(); } } diff --git a/examples/ConfigOnStartup/ConfigOnStartup.ino b/examples/ConfigOnStartup/ConfigOnStartup.ino index 78d2caa..31546b7 100644 --- a/examples/ConfigOnStartup/ConfigOnStartup.ino +++ b/examples/ConfigOnStartup/ConfigOnStartup.ino @@ -13,6 +13,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -31,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal for 60 seconds when first powered up if the boards has stored WiFi Credentials. diff --git a/examples/ConfigOnSwitch/ConfigOnSwitch.ino b/examples/ConfigOnSwitch/ConfigOnSwitch.ino index 3e46517..2682151 100644 --- a/examples/ConfigOnSwitch/ConfigOnSwitch.ino +++ b/examples/ConfigOnSwitch/ConfigOnSwitch.ino @@ -13,6 +13,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -31,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal when no WiFi configuration has been previously entered or when a button is pushed. diff --git a/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino b/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino index 8d02a7f..4ff7382 100644 --- a/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino +++ b/examples/ConfigOnSwitchFS/ConfigOnSwitchFS.ino @@ -13,6 +13,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -31,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal when the reset button is pressed twice. diff --git a/examples/ConfigOnSwitchFS_MQTT_Ptr/ConfigOnSwitchFS_MQTT_Ptr.ino b/examples/ConfigOnSwitchFS_MQTT_Ptr/ConfigOnSwitchFS_MQTT_Ptr.ino index c393048..6fff514 100644 --- a/examples/ConfigOnSwitchFS_MQTT_Ptr/ConfigOnSwitchFS_MQTT_Ptr.ino +++ b/examples/ConfigOnSwitchFS_MQTT_Ptr/ConfigOnSwitchFS_MQTT_Ptr.ino @@ -13,7 +13,7 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license - Version: 1.1.2 + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -33,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal when no WiFi configuration has been previously entered or when a button is pushed. diff --git a/examples/ConfigPortalParamsOnSwitch/ConfigPortalParamsOnSwitch.ino b/examples/ConfigPortalParamsOnSwitch/ConfigPortalParamsOnSwitch.ino index b279f83..e88ea82 100644 --- a/examples/ConfigPortalParamsOnSwitch/ConfigPortalParamsOnSwitch.ino +++ b/examples/ConfigPortalParamsOnSwitch/ConfigPortalParamsOnSwitch.ino @@ -13,6 +13,8 @@ Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -31,6 +33,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /**************************************************************************************************************************** This example will open a configuration portal when a predetermined button is pressed diff --git a/examples/ESP32_FSWebServer/ESP32_FSWebServer.ino b/examples/ESP32_FSWebServer/ESP32_FSWebServer.ino index c0b90e1..3991ca8 100644 --- a/examples/ESP32_FSWebServer/ESP32_FSWebServer.ino +++ b/examples/ESP32_FSWebServer/ESP32_FSWebServer.ino @@ -27,6 +27,8 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -45,6 +47,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /***************************************************************************************************************************** How To Use: diff --git a/examples/ESP32_FSWebServer_DRD/ESP32_FSWebServer_DRD.ino b/examples/ESP32_FSWebServer_DRD/ESP32_FSWebServer_DRD.ino index bc27281..0572651 100644 --- a/examples/ESP32_FSWebServer_DRD/ESP32_FSWebServer_DRD.ino +++ b/examples/ESP32_FSWebServer_DRD/ESP32_FSWebServer_DRD.ino @@ -27,6 +27,8 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -45,6 +47,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /***************************************************************************************************************************** How To Use: diff --git a/examples/ESP_FSWebServer/ESP_FSWebServer.ino b/examples/ESP_FSWebServer/ESP_FSWebServer.ino index 8c408db..16404d9 100644 --- a/examples/ESP_FSWebServer/ESP_FSWebServer.ino +++ b/examples/ESP_FSWebServer/ESP_FSWebServer.ino @@ -27,6 +27,8 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -45,6 +47,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /***************************************************************************************************************************** How To Use: diff --git a/examples/ESP_FSWebServer_DRD/ESP_FSWebServer_DRD.ino b/examples/ESP_FSWebServer_DRD/ESP_FSWebServer_DRD.ino index 2198689..2379f66 100644 --- a/examples/ESP_FSWebServer_DRD/ESP_FSWebServer_DRD.ino +++ b/examples/ESP_FSWebServer_DRD/ESP_FSWebServer_DRD.ino @@ -27,6 +27,8 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding @@ -45,6 +47,7 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /***************************************************************************************************************************** How To Use: diff --git a/library.json b/library.json index f8c3c8f..bf1d0af 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP_WifiManager", - "version": "1.1.2", + "version": "1.2.0", "keywords": "wifi, WiFiManager, esp8266, esp32", "description": "ESP32, ESP8266 MultiWiFi Connection Manager with enhanced GUI and fallback web ConfigPortal. This Library is used for configuring ESP32, ESP8266 modules MultiWiFi Credentials at runtime. You can also specify static DNS servers, personalized HostName, fixed or random AP channel. Now with MultiWiFi auto(Re)connect feature and configurable CORS Header.", "authors": diff --git a/library.properties b/library.properties index 0048e3c..f44a23c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP_WiFiManager -version=1.1.2 +version=1.2.0 author=Khoi Hoang maintainer=Khoi Hoang license=MIT diff --git a/src/ESP_WiFiManager-Impl.h b/src/ESP_WiFiManager-Impl.h index a2bb130..fd4d363 100644 --- a/src/ESP_WiFiManager-Impl.h +++ b/src/ESP_WiFiManager-Impl.h @@ -1,21 +1,21 @@ /**************************************************************************************************************************** - ESP_WiFiManager-Impl.h - For ESP8266 / ESP32 boards + ESP_WiFiManager-Impl.h + For ESP8266 / ESP32 boards - ESP_WiFiManager is a library for the ESP8266/Arduino platform - (https://github.com/esp8266/Arduino) to enable easy - configuration and reconfiguration of WiFi credentials using a Captive Portal - inspired by: - http://www.esp8266.com/viewtopic.php?f=29&t=2520 - https://github.com/chriscook8/esp-arduino-apboot - https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ - Modified from Tzapu https://github.com/tzapu/WiFiManager - and from Ken Taylor https://github.com/kentaylor + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor - Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager - Licensed under MIT license - Version: 1.1.2 + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -35,10 +35,13 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ -#ifndef ESP_WiFiManager_Impl_h -#define ESP_WiFiManager_Impl_h +#pragma once + +//#ifndef ESP_WiFiManager_Impl_h +//#define ESP_WiFiManager_Impl_h ////////////////////////////////////////// @@ -1456,7 +1459,7 @@ void ESP_WiFiManager::handleServerClose() //page += F("Push button on device to restart configuration server!"); page += FPSTR(WM_HTTP_END); server->send(200, "text/html", page); - //stopConfigPortal = true; //signal ready to shutdown config portal //KH crash if use this ??? + stopConfigPortal = true; //signal ready to shutdown config portal LOGDEBUG(F("Sent server close page")); @@ -2023,4 +2026,4 @@ String ESP_WiFiManager::getStoredWiFiPass() #endif -#endif //ESP_WiFiManager_Impl_h +//#endif //ESP_WiFiManager_Impl_h diff --git a/src/ESP_WiFiManager.h b/src/ESP_WiFiManager.h index c1f7b7b..1f76314 100644 --- a/src/ESP_WiFiManager.h +++ b/src/ESP_WiFiManager.h @@ -1,21 +1,21 @@ /**************************************************************************************************************************** - ESP_WiFiManager.h - For ESP8266 / ESP32 boards + ESP_WiFiManager.h + For ESP8266 / ESP32 boards - ESP_WiFiManager is a library for the ESP8266/Arduino platform - (https://github.com/esp8266/Arduino) to enable easy - configuration and reconfiguration of WiFi credentials using a Captive Portal - inspired by: - http://www.esp8266.com/viewtopic.php?f=29&t=2520 - https://github.com/chriscook8/esp-arduino-apboot - https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ - Modified from Tzapu https://github.com/tzapu/WiFiManager - and from Ken Taylor https://github.com/kentaylor + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor - Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager - Licensed under MIT license - Version: 1.1.2 + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -35,10 +35,10 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ -#ifndef ESP_WiFiManager_h -#define ESP_WiFiManager_h +#pragma once #include "ESP_WiFiManager_Debug.h" @@ -348,13 +348,14 @@ class ESP_WiFiManager // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" #if USING_CORS_FEATURE - void setCORSHeader(const char * CORSHeaders = "*") - { - _CORS_Header = String(CORSHeaders); + void setCORSHeader(const char* CORSHeaders) + { + _CORS_Header = CORSHeaders; + LOGWARN1(F("Set CORS Header to : "), _CORS_Header); } - String getCORSHeader(void) + const char* getCORSHeader(void) { return _CORS_Header; } @@ -465,19 +466,19 @@ class ESP_WiFiManager IPAddress _sta_static_dns2; #endif - int _paramsCount = 0; - int _minimumQuality = -1; - boolean _removeDuplicateAPs = true; + int _paramsCount = 0; + int _minimumQuality = -1; + boolean _removeDuplicateAPs = true; boolean _shouldBreakAfterConfig = false; - boolean _tryWPS = false; + boolean _tryWPS = false; - const char* _customHeadElement = ""; + const char* _customHeadElement = ""; - int status = WL_IDLE_STATUS; + int status = WL_IDLE_STATUS; // New from v1.1.0, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" #if USING_CORS_FEATURE - String _CORS_Header = FPSTR(WM_HTTP_CORS_ALLOW_ALL); + const char* _CORS_Header = WM_HTTP_CORS_ALLOW_ALL; //"*"; #endif ////// @@ -541,7 +542,5 @@ class ESP_WiFiManager } }; - #include "ESP_WiFiManager-Impl.h" -#endif diff --git a/src/ESP_WiFiManager_Debug.h b/src/ESP_WiFiManager_Debug.h index c093b1e..7d77669 100644 --- a/src/ESP_WiFiManager_Debug.h +++ b/src/ESP_WiFiManager_Debug.h @@ -1,21 +1,21 @@ /**************************************************************************************************************************** - ESP_WiFiManager_Debug.h - For ESP8266 / ESP32 boards + ESP_WiFiManager_Debug.h + For ESP8266 / ESP32 boards - ESP_WiFiManager is a library for the ESP8266/Arduino platform - (https://github.com/esp8266/Arduino) to enable easy - configuration and reconfiguration of WiFi credentials using a Captive Portal - inspired by: - http://www.esp8266.com/viewtopic.php?f=29&t=2520 - https://github.com/chriscook8/esp-arduino-apboot - https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ - Modified from Tzapu https://github.com/tzapu/WiFiManager - and from Ken Taylor https://github.com/kentaylor + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor - Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager - Licensed under MIT license - Version: 1.1.2 + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- @@ -35,10 +35,13 @@ 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ -#ifndef ESP_WiFiManager_Debug_H -#define ESP_WiFiManager_Debug_H +#pragma once + +//#ifndef ESP_WiFiManager_Debug_H +//#define ESP_WiFiManager_Debug_H #ifdef WIFIMGR_DEBUG_PORT #define DBG_PORT WIFIMGR_DEBUG_PORT @@ -81,4 +84,4 @@ #define LOGDEBUG2(x,y,z) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } #define LOGDEBUG3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } -#endif //ESP_WiFiManager_Debug_H +//#endif //ESP_WiFiManager_Debug_H diff --git a/src_cpp/ESP_WiFiManager.cpp b/src_cpp/ESP_WiFiManager.cpp new file mode 100644 index 0000000..d45f858 --- /dev/null +++ b/src_cpp/ESP_WiFiManager.cpp @@ -0,0 +1,2022 @@ +/**************************************************************************************************************************** + ESP_WiFiManager.cpp + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ + +#include "ESP_WiFiManager_Debug.h" +#include "ESP_WiFiManager.h" + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *custom) +{ + _id = NULL; + _placeholder = NULL; + _length = 0; + _value = NULL; + _labelPlacement = WFM_LABEL_BEFORE; + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length) +{ + init(id, placeholder, defaultValue, length, "", WFM_LABEL_BEFORE); +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) +{ + init(id, placeholder, defaultValue, length, custom, WFM_LABEL_BEFORE); +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) +{ + init(id, placeholder, defaultValue, length, custom, labelPlacement); +} + +////////////////////////////////////////// + +void ESP_WMParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) +{ + _id = id; + _placeholder = placeholder; + _length = length; + _labelPlacement = labelPlacement; + + _value = new char[_length + 1]; + + if (_value != NULL) + { + memset(_value, 0, _length + 1); + + if (defaultValue != NULL) + { + strncpy(_value, defaultValue, _length); + } + } + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP_WMParameter::~ESP_WMParameter() +{ + if (_value != NULL) + { + delete[] _value; + } +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getValue() +{ + return _value; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getID() +{ + return _id; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getPlaceholder() +{ + return _placeholder; +} + +////////////////////////////////////////// + +int ESP_WMParameter::getValueLength() +{ + return _length; +} + +////////////////////////////////////////// + +int ESP_WMParameter::getLabelPlacement() +{ + return _labelPlacement; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getCustomHTML() +{ + return _customHTML; +} + +////////////////////////////////////////// + +/** + [getParameters description] + @access public +*/ +ESP_WMParameter** ESP_WiFiManager::getParameters() +{ + return _params; +} + +/** + [getParametersCount description] + @access public +*/ +int ESP_WiFiManager::getParametersCount() +{ + return _paramsCount; +} + +////////////////////////////////////////// + +char* ESP_WiFiManager::getRFC952_hostname(const char* iHostname) +{ + memset(RFC952_hostname, 0, sizeof(RFC952_hostname)); + + size_t len = (RFC952_HOSTNAME_MAXLEN < strlen(iHostname)) ? RFC952_HOSTNAME_MAXLEN : strlen(iHostname); + + size_t j = 0; + + for (size_t i = 0; i < len - 1; i++) + { + if (isalnum(iHostname[i]) || iHostname[i] == '-') + { + RFC952_hostname[j] = iHostname[i]; + j++; + } + } + + // no '-' as last char + if (isalnum(iHostname[len - 1]) || (iHostname[len - 1] != '-')) + RFC952_hostname[j] = iHostname[len - 1]; + + return RFC952_hostname; +} + +////////////////////////////////////////// + +ESP_WiFiManager::ESP_WiFiManager(const char *iHostname) +{ +#if USE_DYNAMIC_PARAMS + _max_params = WIFI_MANAGER_MAX_PARAMS; + _params = (ESP_WMParameter**)malloc(_max_params * sizeof(ESP_WMParameter*)); +#endif + + //WiFi not yet started here, must call WiFi.mode(WIFI_STA) and modify function WiFiGenericClass::mode(wifi_mode_t m) !!! + + WiFi.mode(WIFI_STA); + + if (iHostname[0] == 0) + { +#ifdef ESP8266 + String _hostname = "ESP8266-" + String(ESP.getChipId(), HEX); +#else //ESP32 + String _hostname = "ESP32-" + String((uint32_t)ESP.getEfuseMac(), HEX); +#endif + _hostname.toUpperCase(); + + getRFC952_hostname(_hostname.c_str()); + + } + else + { + // Prepare and store the hostname only not NULL + getRFC952_hostname(iHostname); + } + + LOGWARN1(F("RFC925 Hostname ="), RFC952_hostname); + + setHostname(); + + networkIndices = NULL; +} + +////////////////////////////////////////// + +ESP_WiFiManager::~ESP_WiFiManager() +{ +#if USE_DYNAMIC_PARAMS + if (_params != NULL) + { + LOGINFO(F("freeing allocated params!")); + + free(_params); + } +#endif + + if (networkIndices) + { + free(networkIndices); //indices array no longer required so free memory + } +} + +////////////////////////////////////////// + +#if USE_DYNAMIC_PARAMS +bool ESP_WiFiManager::addParameter(ESP_WMParameter *p) +#else +void ESP_WiFiManager::addParameter(ESP_WMParameter *p) +#endif +{ +#if USE_DYNAMIC_PARAMS + + if (_paramsCount == _max_params) + { + // rezise the params array + _max_params += WIFI_MANAGER_MAX_PARAMS; + + LOGINFO1(F("Increasing _max_params to:"), _max_params); + + ESP_WMParameter** new_params = (ESP_WMParameter**)realloc(_params, _max_params * sizeof(ESP_WMParameter*)); + + if (new_params != NULL) + { + _params = new_params; + } + else + { + LOGINFO(F("ERROR: failed to realloc params, size not increased!")); + + return false; + } + } + + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + + return true; + +#else + + // Danger here. Better to use Tzapu way here + if (_paramsCount < (WIFI_MANAGER_MAX_PARAMS)) + { + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + } + else + { + LOGINFO("Can't add parameter. Full"); + } + +#endif +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setupConfigPortal() +{ + stopConfigPortal = false; //Signal not to close config portal + + /*This library assumes autoconnect is set to 1. It usually is + but just in case check the setting and turn on autoconnect if it is off. + Some useful discussion at https://github.com/esp8266/Arduino/issues/1615*/ + if (WiFi.getAutoConnect() == 0) + WiFi.setAutoConnect(1); + + dnsServer.reset(new DNSServer()); + +#ifdef ESP8266 + server.reset(new ESP8266WebServer(80)); +#else //ESP32 + server.reset(new WebServer(80)); +#endif + + /* Setup the DNS server redirecting all the domains to the apIP */ + if (dnsServer) + { + dnsServer->setErrorReplyCode(DNSReplyCode::NoError); + dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); + } + + _configPortalStart = millis(); + + LOGWARN1(F("Configuring AP SSID ="), _apName); + + if (_apPassword != NULL) + { + if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) + { + // fail passphrase to short or long! + LOGERROR(F("Invalid AccessPoint password. Ignoring")); + + _apPassword = NULL; + } + LOGWARN1(F("AP PWD ="), _apPassword); + } + + + // KH, new from v1.0.10 to enable dynamic/random channel + static int channel; + + // Use random channel if _WiFiAPChannel == 0 + if (_WiFiAPChannel == 0) + channel = (_configPortalStart % MAX_WIFI_CHANNEL) + 1; + else + channel = _WiFiAPChannel; + + if (_apPassword != NULL) + { + LOGWARN1(F("AP Channel ="), channel); + + //WiFi.softAP(_apName, _apPassword);//password option + WiFi.softAP(_apName, _apPassword, channel); + } + else + { + // Can't use channel here + WiFi.softAP(_apName); + } + ////// + + // From v1.0.11 + // Contributed by AlesSt (https://github.com/AlesSt) to solve issue softAP with custom IP sometimes not working + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/26 and https://github.com/espressif/arduino-esp32/issues/985 + // delay 100ms to wait for SYSTEM_EVENT_AP_START + delay(100); + ////// + + //optional soft ip config + if (_ap_static_ip) + { + LOGWARN3(F("Custom AP IP/GW/Subnet = "), _ap_static_ip, _ap_static_gw, _ap_static_sn); + + WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); + } + + delay(500); // Without delay I've seen the IP address blank + + LOGWARN1(F("AP IP address ="), WiFi.softAPIP()); + + /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ + server->on("/", std::bind(&ESP_WiFiManager::handleRoot, this)); + server->on("/wifi", std::bind(&ESP_WiFiManager::handleWifi, this)); + server->on("/wifisave", std::bind(&ESP_WiFiManager::handleWifiSave, this)); + server->on("/close", std::bind(&ESP_WiFiManager::handleServerClose, this)); + server->on("/i", std::bind(&ESP_WiFiManager::handleInfo, this)); + server->on("/r", std::bind(&ESP_WiFiManager::handleReset, this)); + server->on("/state", std::bind(&ESP_WiFiManager::handleState, this)); + server->on("/scan", std::bind(&ESP_WiFiManager::handleScan, this)); + server->onNotFound(std::bind(&ESP_WiFiManager::handleNotFound, this)); + server->begin(); // Web server start + + LOGWARN(F("HTTP server started")); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::autoConnect() +{ +#ifdef ESP8266 + String ssid = "ESP_" + String(ESP.getChipId()); +#else //ESP32 + String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); +#endif + + return autoConnect(ssid.c_str(), NULL); +} + +/* This is not very useful as there has been an assumption that device has to be + told to connect but Wifi already does it's best to connect in background. Calling this + method will block until WiFi connects. Sketch can avoid + blocking call then use (WiFi.status()==WL_CONNECTED) test to see if connected yet. + See some discussion at https://github.com/tzapu/WiFiManager/issues/68 +*/ + +// New in v1.0.11 +// To permit autoConnect() to use STA static IP or DHCP IP. +#ifndef AUTOCONNECT_NO_INVALIDATE + #define AUTOCONNECT_NO_INVALIDATE true +#endif + +////////////////////////////////////////// + +boolean ESP_WiFiManager::autoConnect(char const *apName, char const *apPassword) +{ +#if AUTOCONNECT_NO_INVALIDATE + LOGINFO(F("\nAutoConnect using previously saved SSID/PW, but keep previous settings")); + // Connect to previously saved SSID/PW, but keep previous settings + connectWifi(); +#else + LOGINFO(F("\nAutoConnect using previously saved SSID/PW, but invalidate previous settings")); + // Connect to previously saved SSID/PW, but invalidate previous settings + connectWifi(WiFi_SSID(), WiFi_Pass()); +#endif + + unsigned long startedAt = millis(); + + while (millis() - startedAt < 10000) + { + //delay(100); + delay(200); + + if (WiFi.status() == WL_CONNECTED) + { + float waited = (millis() - startedAt); + + LOGWARN1(F("Connected after waiting (s) :"), waited / 1000); + LOGWARN1(F("Local ip ="), WiFi.localIP()); + + return true; + } + } + + return startConfigPortal(apName, apPassword); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::startConfigPortal() +{ +#ifdef ESP8266 + String ssid = "ESP_" + String(ESP.getChipId()); +#else //ESP32 + String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); +#endif + ssid.toUpperCase(); + + return startConfigPortal(ssid.c_str(), NULL); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::startConfigPortal(char const *apName, char const *apPassword) +{ + //setup AP + int connRes = WiFi.waitForConnectResult(); + + LOGINFO("WiFi.waitForConnectResult Done"); + + if (connRes == WL_CONNECTED) + { + LOGINFO("SET AP_STA"); + + WiFi.mode(WIFI_AP_STA); //Dual mode works fine if it is connected to WiFi + } + else + { + LOGINFO("SET AP"); + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + // When ESP8266 station is trying to find a target AP, it will scan on every channel, + // that means ESP8266 station is changing its channel to scan. This makes the channel of ESP8266 softAP keep changing too.. + // So the connection may break. From http://bbs.espressif.com/viewtopic.php?t=671#p2531 + } + + _apName = apName; + _apPassword = apPassword; + + //notify we entered AP mode + if (_apcallback != NULL) + { + LOGINFO("_apcallback"); + + _apcallback(this); + } + + connect = false; + + setupConfigPortal(); + + bool TimedOut = true; + + LOGINFO("ESP_WiFiManager::startConfigPortal : Enter loop"); + + while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) + { + //DNS + dnsServer->processNextRequest(); + //HTTP + server->handleClient(); + + if (connect) + { + TimedOut = false; + delay(2000); + + LOGERROR(F("Connecting to new AP")); + +#if 0 + + // New Mod from v1.1.0 + int wifiConnected = reconnectWifi(); + + if ( wifiConnected == WL_CONNECTED ) + { + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + + break; + } + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + ////// + +#else + + // using user-provided _ssid, _pass in place of system-stored ssid and pass + if (connectWifi(_ssid, _pass) != WL_CONNECTED) + { + LOGERROR(F("Failed to connect")); + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + } + else + { + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + break; + } + +#endif + + if (_shouldBreakAfterConfig) + { + //flag set to exit after config after trying to connect + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + + break; + } + } + + if (stopConfigPortal) + { + LOGERROR("Stop ConfigPortal"); //KH + + stopConfigPortal = false; + break; + } + + yield(); + } + + WiFi.mode(WIFI_STA); + + if (TimedOut) + { + setHostname(); + + // New v1.0.8 to fix static IP when CP not entered or timed-out + setWifiStaticIP(); + + WiFi.begin(); + int connRes = waitForConnectResult(); + + LOGERROR1("Timed out connection result:", getStatus(connRes)); + } + + server->stop(); + server.reset(); + dnsServer->stop(); + dnsServer.reset(); + + return WiFi.status() == WL_CONNECTED; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setWifiStaticIP(void) +{ +#if USE_CONFIGURABLE_DNS + if (_sta_static_ip) + { + LOGWARN(F("Custom STA IP/GW/Subnet")); + + //***** Added section for DNS config option ***** + if (_sta_static_dns1 && _sta_static_dns2) + { + LOGWARN(F("DNS1 and DNS2 set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns1, _sta_static_dns2); + } + else if (_sta_static_dns1) + { + LOGWARN(F("Only DNS1 set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns1); + } + else + { + LOGWARN(F("No DNS server set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); + } + //***** End added section for DNS config option ***** + + LOGINFO1(F("setWifiStaticIP IP ="), WiFi.localIP()); + } + else + { + LOGWARN(F("Can't use Custom STA IP/GW/Subnet")); + } +#else + // check if we've got static_ip settings, if we do, use those. + if (_sta_static_ip) + { + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); + + LOGWARN1(F("Custom STA IP/GW/Subnet : "), WiFi.localIP()); + } +#endif +} + +////////////////////////////////////////// + +// New from v1.1.0 +int ESP_WiFiManager::reconnectWifi(void) +{ + int connectResult; + + // using user-provided _ssid, _pass in place of system-stored ssid and pass + if ( ( connectResult = connectWifi(_ssid, _pass) ) != WL_CONNECTED) + { + LOGERROR1(F("Failed to connect to"), _ssid); + + if ( ( connectResult = connectWifi(_ssid1, _pass1) ) != WL_CONNECTED) + { + LOGERROR1(F("Failed to connect to"), _ssid1); + + } + else + LOGERROR1(F("Connected to"), _ssid1); + } + else + LOGERROR1(F("Connected to"), _ssid); + + return connectResult; +} + +////////////////////////////////////////// + +int ESP_WiFiManager::connectWifi(String ssid, String pass) +{ + //KH, from v1.0.10. + // Add option if didn't input/update SSID/PW => Use the previous saved Credentials. + // But update the Static/DHCP options if changed. + if ( (ssid != "") || ( (ssid == "") && (WiFi_SSID() != "") ) ) + { + //fix for auto connect racing issue. Move up from v1.1.0 to avoid resetSettings() + if (WiFi.status() == WL_CONNECTED) + { + LOGWARN(F("Already connected. Bailing out.")); + return WL_CONNECTED; + } + + if (ssid != "") + resetSettings(); + +#ifdef ESP8266 + setWifiStaticIP(); +#endif + + WiFi.mode(WIFI_AP_STA); //It will start in station mode if it was previously in AP mode. + + setHostname(); + + // KH, Fix ESP32 staticIP after exiting CP, from v1.0.9 +#ifdef ESP32 + setWifiStaticIP(); +#endif + + if (ssid != "") + { + // Start Wifi with new values. + LOGWARN(F("Connect to new WiFi using new IP parameters")); + + WiFi.begin(ssid.c_str(), pass.c_str()); + } + else + { + // Start Wifi with old values. + LOGWARN(F("Connect to previous WiFi using new IP parameters")); + + WiFi.begin(); + } + } + else if (WiFi_SSID() == "") + { + LOGWARN(F("No saved credentials")); + } + + int connRes = waitForConnectResult(); + LOGWARN1("Connection result: ", getStatus(connRes)); + + //not connected, WPS enabled, no pass - first attempt + if (_tryWPS && connRes != WL_CONNECTED && pass == "") + { + startWPS(); + //should be connected at the end of WPS + connRes = waitForConnectResult(); + } + + return connRes; +} + +////////////////////////////////////////// + +uint8_t ESP_WiFiManager::waitForConnectResult() +{ + if (_connectTimeout == 0) + { + unsigned long startedAt = millis(); + + // In ESP8266, WiFi.waitForConnectResult() @return wl_status_t (0-255) or -1 on timeout !!! + // In ESP32, WiFi.waitForConnectResult() @return wl_status_t (0-255) + // So, using int for connRes to be safe + //int connRes = WiFi.waitForConnectResult(); + WiFi.waitForConnectResult(); + + float waited = (millis() - startedAt); + + LOGWARN1(F("Connected after waiting (s) :"), waited / 1000); + LOGWARN1(F("Local ip ="), WiFi.localIP()); + + // Fix bug from v1.1.0+, connRes is sometimes not correct. + //return connRes; + return WiFi.status(); + } + else + { + LOGERROR(F("Waiting WiFi connection with time out")); + unsigned long start = millis(); + boolean keepConnecting = true; + uint8_t status; + + while (keepConnecting) + { + status = WiFi.status(); + if (millis() > start + _connectTimeout) + { + keepConnecting = false; + LOGERROR(F("Connection timed out")); + } + + if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) + { + keepConnecting = false; + } + delay(100); + } + return status; + } +} + +////////////////////////////////////////// + +void ESP_WiFiManager::startWPS() +{ +#ifdef ESP8266 + LOGINFO("START WPS"); + WiFi.beginWPSConfig(); + LOGINFO("END WPS"); +#else //ESP32 + // TODO + LOGINFO("ESP32 WPS TODO"); +#endif +} + +////////////////////////////////////////// + +//Convenient for debugging but wasteful of program space. +//Remove if short of space +const char* ESP_WiFiManager::getStatus(int status) +{ + switch (status) + { + case WL_IDLE_STATUS: + return "WL_IDLE_STATUS"; + case WL_NO_SSID_AVAIL: + return "WL_NO_SSID_AVAIL"; + case WL_CONNECTED: + return "WL_CONNECTED"; + case WL_CONNECT_FAILED: + return "WL_CONNECT_FAILED"; + case WL_DISCONNECTED: + return "WL_DISCONNECTED"; + default: + return "UNKNOWN"; + } +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getConfigPortalSSID() +{ + return _apName; +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getConfigPortalPW() +{ + return _apPassword; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::resetSettings() +{ + LOGINFO(F("Previous settings invalidated")); + +#ifdef ESP8266 + WiFi.disconnect(true); +#else + WiFi.disconnect(true, true); + // New in v1.0.11 + // Temporary fix for issue of not clearing WiFi SSID/PW from flash of ESP32 + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/25 and https://github.com/espressif/arduino-esp32/issues/400 + WiFi.begin("0","0"); + ////// +#endif + + delay(200); + return; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setTimeout(unsigned long seconds) +{ + setConfigPortalTimeout(seconds); +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setConfigPortalTimeout(unsigned long seconds) +{ + _configPortalTimeout = seconds * 1000; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setConnectTimeout(unsigned long seconds) +{ + _connectTimeout = seconds * 1000; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setDebugOutput(boolean debug) +{ + _debug = debug; +} + +////////////////////////////////////////// + +// KH, new from v1.0.10 to enable dynamic/random channel +int ESP_WiFiManager::setConfigPortalChannel(int channel) +{ + // If channel < MIN_WIFI_CHANNEL - 1 or channel > MAX_WIFI_CHANNEL => channel = 1 + // If channel == 0 => will use random channel from MIN_WIFI_CHANNEL to MAX_WIFI_CHANNEL + // If (MIN_WIFI_CHANNEL <= channel <= MAX_WIFI_CHANNEL) => use it + if ( (channel < MIN_WIFI_CHANNEL - 1) || (channel > MAX_WIFI_CHANNEL) ) + _WiFiAPChannel = 1; + else if ( (channel >= MIN_WIFI_CHANNEL - 1) && (channel <= MAX_WIFI_CHANNEL) ) + _WiFiAPChannel = channel; + + return _WiFiAPChannel; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) +{ + LOGINFO(F("setAPStaticIPConfig")); + _ap_static_ip = ip; + _ap_static_gw = gw; + _ap_static_sn = sn; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) +{ + LOGINFO(F("setSTAStaticIPConfig")); + _sta_static_ip = ip; + _sta_static_gw = gw; + _sta_static_sn = sn; +} + +////////////////////////////////////////// + +#if USE_CONFIGURABLE_DNS +void ESP_WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn, IPAddress dns_address_1, IPAddress dns_address_2) +{ + LOGINFO(F("setSTAStaticIPConfig for USE_CONFIGURABLE_DNS")); + _sta_static_ip = ip; + _sta_static_gw = gw; + _sta_static_sn = sn; + _sta_static_dns1 = dns_address_1; //***** Added argument ***** + _sta_static_dns2 = dns_address_2; //***** Added argument ***** +} +#endif + +////////////////////////////////////////// + +void ESP_WiFiManager::setMinimumSignalQuality(int quality) +{ + _minimumQuality = quality; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setBreakAfterConfig(boolean shouldBreak) +{ + _shouldBreakAfterConfig = shouldBreak; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::reportStatus(String &page) +{ + page += FPSTR(WM_HTTP_SCRIPT_NTP_MSG); + + if (WiFi_SSID() != "") + { + page += F("Configured to connect to access point "); + page += WiFi_SSID(); + + if (WiFi.status() == WL_CONNECTED) + { + page += F(" and currently connected on IP "); + page += WiFi.localIP().toString(); + page += F(""); + } + else + { + page += F(" but not currently connected to network."); + } + } + else + { + page += F("No network currently configured."); + } +} + +////////////////////////////////////////// + +/** Handle root or redirect to captive portal */ +void ESP_WiFiManager::handleRoot() +{ + LOGDEBUG(F("Handle root")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + if (captivePortal()) + { + // If caprive portal redirect instead of displaying the error page. + return; + } + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Options"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += "

"; + page += _apName; + + if (WiFi_SSID() != "") + { + if (WiFi.status() == WL_CONNECTED) + { + page += " on "; + page += WiFi_SSID(); + } + else + { + page += " on "; + page += WiFi_SSID(); + page += ""; + } + } + + page += "

"; + page += FPSTR(WM_HTTP_PORTAL_OPTIONS); + page += F("
"); + reportStatus(page); + page += F("
"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + +} + +////////////////////////////////////////// + +/** Wifi config page handler */ +void ESP_WiFiManager::handleWifi() +{ + LOGDEBUG(F("Handle WiFi")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Config ESP"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("

Configuration

"); + + // KH, New, v1.0.6+ + numberOfNetworks = scanWifiNetworks(&networkIndices); + + //Print list of WiFi networks that were found in earlier scan + if (numberOfNetworks == 0) + { + page += F("WiFi scan found no networks. Restart configuration portal to scan again."); + } + else + { + // From v1.0.10 + page += FPSTR(WM_FLDSET_START); + ////// + + //display networks in page + for (int i = 0; i < numberOfNetworks; i++) + { + if (networkIndices[i] == -1) + continue; // skip dups and those that are below the required quality + + LOGDEBUG1(F("Index ="), i); + LOGDEBUG1(F("SSID ="), WiFi.SSID(networkIndices[i])); + LOGDEBUG1(F("RSSI ="), WiFi.RSSI(networkIndices[i])); + + int quality = getRSSIasQuality(WiFi.RSSI(networkIndices[i])); + + String item = FPSTR(WM_HTTP_ITEM); + String rssiQ; + rssiQ += quality; + item.replace("{v}", WiFi.SSID(networkIndices[i])); + item.replace("{r}", rssiQ); + +#ifdef ESP8266 + if (WiFi.encryptionType(networkIndices[i]) != ENC_TYPE_NONE) +#else //ESP32 + if (WiFi.encryptionType(networkIndices[i]) != WIFI_AUTH_OPEN) +#endif + { + item.replace("{i}", "l"); + } + else + { + item.replace("{i}", ""); + } + + //LOGDEBUG(item); + page += item; + delay(0); + } + + // From v1.0.10 + page += FPSTR(WM_FLDSET_END); + ////// + + page += "
"; + } + + page += FPSTR(WM_HTTP_FORM_START); + char parLength[2]; + + // add the extra parameters to the form + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + // From v1.0.10 + if (i == 1) + { + page += FPSTR(WM_FLDSET_START); + } + ////// + + String pitem; + switch (_params[i]->getLabelPlacement()) + { + case WFM_LABEL_BEFORE: + pitem = FPSTR(WM_HTTP_FORM_LABEL_BEFORE); + break; + case WFM_LABEL_AFTER: + pitem = FPSTR(WM_HTTP_FORM_LABEL_AFTER); + break; + default: + // WFM_NO_LABEL + pitem = FPSTR(WM_HTTP_FORM_PARAM); + break; + } + + if (_params[i]->getID() != NULL) + { + pitem.replace("{i}", _params[i]->getID()); + pitem.replace("{n}", _params[i]->getID()); + pitem.replace("{p}", _params[i]->getPlaceholder()); + snprintf(parLength, 2, "%d", _params[i]->getValueLength()); + pitem.replace("{l}", parLength); + pitem.replace("{v}", _params[i]->getValue()); + pitem.replace("{c}", _params[i]->getCustomHTML()); + } + else + { + pitem = _params[i]->getCustomHTML(); + } + + page += pitem; + } + + // From v1.0.10 + if (_paramsCount > 0) + { + page += FPSTR(WM_FLDSET_END); + } + ////// + + if (_params[0] != NULL) + { + page += "
"; + } + + LOGDEBUG1(F("Static IP ="), _sta_static_ip.toString()); + + // KH, Comment out in v1.0.9 to permit changing from DHCP to static IP, or vice versa + // and add staticIP label in CP + + // From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. + // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa + // You have to explicitly specify false to disable the feature. + +#if !USE_STATIC_IP_CONFIG_IN_CP + if (_sta_static_ip) +#endif + { + // From v1.0.10 + page += FPSTR(WM_FLDSET_START); + ////// + + String item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "ip"); + item.replace("{n}", "ip"); + item.replace("{p}", "Static IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_ip.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "gw"); + item.replace("{n}", "gw"); + item.replace("{p}", "Gateway IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_gw.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "sn"); + item.replace("{n}", "sn"); + item.replace("{p}", "Subnet"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_sn.toString()); + + #if USE_CONFIGURABLE_DNS + //***** Added for DNS address options ***** + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "dns1"); + item.replace("{n}", "dns1"); + item.replace("{p}", "DNS1 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_dns1.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "dns2"); + item.replace("{n}", "dns2"); + item.replace("{p}", "DNS2 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_dns2.toString()); + //***** End added for DNS address options ***** + #endif + + page += item; + + // From v1.0.10 + page += FPSTR(WM_FLDSET_END); + ////// + + page += "
"; + } + + page += FPSTR(WM_HTTP_FORM_END); + + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent config page")); +} + +////////////////////////////////////////// + +/** Handle the WLAN save form and redirect to WLAN config page again */ +void ESP_WiFiManager::handleWifiSave() +{ + LOGDEBUG(F("WiFi save")); + + //SAVE/connect here + _ssid = server->arg("s").c_str(); + _pass = server->arg("p").c_str(); + + // New from v1.1.0 + _ssid1 = server->arg("s1").c_str(); + _pass1 = server->arg("p1").c_str(); + ////// + + //parameters + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + //read parameter + String value = server->arg(_params[i]->getID()).c_str(); + //store it in array + value.toCharArray(_params[i]->_value, _params[i]->_length); + + LOGDEBUG2(F("Parameter and value :"), _params[i]->getID(), value); + } + + if (server->arg("ip") != "") + { + String ip = server->arg("ip"); + optionalIPFromString(&_sta_static_ip, ip.c_str()); + + LOGDEBUG1(F("New Static IP ="), _sta_static_ip.toString()); + } + + if (server->arg("gw") != "") + { + String gw = server->arg("gw"); + optionalIPFromString(&_sta_static_gw, gw.c_str()); + + LOGDEBUG1(F("New Static Gateway ="), _sta_static_gw.toString()); + } + + if (server->arg("sn") != "") + { + String sn = server->arg("sn"); + optionalIPFromString(&_sta_static_sn, sn.c_str()); + + LOGDEBUG1(F("New Static Netmask ="), _sta_static_sn.toString()); + } + +#if USE_CONFIGURABLE_DNS + //***** Added for DNS Options ***** + if (server->arg("dns1") != "") + { + String dns1 = server->arg("dns1"); + optionalIPFromString(&_sta_static_dns1, dns1.c_str()); + + LOGDEBUG1(F("New Static DNS1 ="), _sta_static_dns1.toString()); + } + + if (server->arg("dns2") != "") + { + String dns2 = server->arg("dns2"); + optionalIPFromString(&_sta_static_dns2, dns2.c_str()); + + LOGDEBUG1(F("New Static DNS2 ="), _sta_static_dns2.toString()); + } + //***** End added for DNS Options ***** +#endif + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Credentials Saved"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += FPSTR(WM_HTTP_SAVED); + page.replace("{v}", _apName); + page.replace("{x}", _ssid); + + // KH, update from v1.1.0 + page.replace("{x1}", _ssid1); + ////// + + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent wifi save page")); + + connect = true; //signal ready to connect/reset + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +/** Handle shut down the server page */ +void ESP_WiFiManager::handleServerClose() +{ + LOGDEBUG(F("Server Close")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Close Server"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("
"); + page += F("My network is "); + page += WiFi_SSID(); + page += F("
"); + page += F("IP address is "); + page += WiFi.localIP().toString(); + page += F("

"); + page += F("Portal closed...

"); + //page += F("Push button on device to restart configuration server!"); + page += FPSTR(WM_HTTP_END); + server->send(200, "text/html", page); + stopConfigPortal = true; //signal ready to shutdown config portal + + LOGDEBUG(F("Sent server close page")); + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +/** Handle the info page */ +void ESP_WiFiManager::handleInfo() +{ + LOGDEBUG(F("Info")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Info"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("

WiFi Information

"); + reportStatus(page); + page += F("

Device Data

"); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + page += F("
NameValue
Chip ID"); + +#ifdef ESP8266 + page += String(ESP.getChipId(), HEX); //ESP.getChipId(); +#else //ESP32 + page += String((uint32_t)ESP.getEfuseMac(), HEX); //ESP.getChipId(); +#endif + + page += F("
Flash Chip ID"); + +#ifdef ESP8266 + page += String(ESP.getFlashChipId(), HEX); //ESP.getFlashChipId(); +#else //ESP32 + // TODO + page += F("TODO"); +#endif + + page += F("
IDE Flash Size"); + page += ESP.getFlashChipSize(); + page += F(" bytes
Real Flash Size"); + +#ifdef ESP8266 + page += ESP.getFlashChipRealSize(); +#else //ESP32 + // TODO + page += F("TODO"); +#endif + + page += F(" bytes
Access Point IP"); + page += WiFi.softAPIP().toString(); + page += F("
Access Point MAC"); + page += WiFi.softAPmacAddress(); + page += F("
SSID"); + page += WiFi_SSID(); + page += F("
Station IP"); + page += WiFi.localIP().toString(); + page += F("
Station MAC"); + page += WiFi.macAddress(); + page += F("
"); + + page += FPSTR(WM_HTTP_AVAILABLE_PAGES); + + page += F("

More information about ESP_WiFiManager at"); + page += F("

https://github.com/khoih-prog/ESP_WiFiManager"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent info page")); +} + +////////////////////////////////////////// + +/** Handle the state page */ +void ESP_WiFiManager::handleState() +{ + LOGDEBUG(F("State - json")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = F("{\"Soft_AP_IP\":\""); + + page += WiFi.softAPIP().toString(); + page += F("\",\"Soft_AP_MAC\":\""); + page += WiFi.softAPmacAddress(); + page += F("\",\"Station_IP\":\""); + page += WiFi.localIP().toString(); + page += F("\",\"Station_MAC\":\""); + page += WiFi.macAddress(); + page += F("\","); + + if (WiFi.psk() != "") + { + page += F("\"Password\":true,"); + } + else + { + page += F("\"Password\":false,"); + } + + page += F("\"SSID\":\""); + page += WiFi_SSID(); + page += F("\"}"); + server->send(200, "application/json", page); + + LOGDEBUG(F("Sent state page in json format")); +} + +////////////////////////////////////////// + +/** Handle the scan page */ +void ESP_WiFiManager::handleScan() +{ + LOGDEBUG(F("Scan")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + LOGDEBUG(F("State-Json")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + int n; + int *indices; + + //Space for indices array allocated on heap in scanWifiNetworks + //and should be freed when indices no longer required. + + n = scanWifiNetworks(&indices); + LOGDEBUG(F("In handleScan, scanWifiNetworks done")); + String page = F("{\"Access_Points\":["); + + //display networks in page + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip duplicates and those that are below the required quality + + if (i != 0) + page += F(", "); + + LOGDEBUG1(F("Index ="), i); + LOGDEBUG1(F("SSID ="), WiFi.SSID(indices[i])); + LOGDEBUG1(F("RSSI ="), WiFi.RSSI(indices[i])); + + int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); + String item = FPSTR(JSON_ITEM); + String rssiQ; + + rssiQ += quality; + item.replace("{v}", WiFi.SSID(indices[i])); + item.replace("{r}", rssiQ); + +#ifdef ESP8266 + if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) +#else //ESP32 + if (WiFi.encryptionType(indices[i]) != WIFI_AUTH_OPEN) +#endif + { + item.replace("{i}", "true"); + } + else + { + item.replace("{i}", "false"); + } + //LOGDEBUG(item); + page += item; + delay(0); + } + + if (indices) + { + free(indices); //indices array no longer required so free memory + } + + page += F("]}"); + + server->send(200, "application/json", page); + + LOGDEBUG(F("Sent WiFiScan Data in Json format")); +} + +////////////////////////////////////////// + +/** Handle the reset page */ +void ESP_WiFiManager::handleReset() +{ + LOGDEBUG(F("Reset")); + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "WiFi Information"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("Resetting"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent reset page")); + delay(5000); + + // New in v1.0.11 + // Temporary fix for issue of not clearing WiFi SSID/PW from flash of ESP32 + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/25 and https://github.com/espressif/arduino-esp32/issues/400 + resetSettings(); + //WiFi.disconnect(true); // Wipe out WiFi credentials. + ////// + +#ifdef ESP8266 + ESP.reset(); +#else //ESP32 + ESP.restart(); +#endif + + delay(2000); +} + +////////////////////////////////////////// + +void ESP_WiFiManager::handleNotFound() +{ + if (captivePortal()) + { + // If caprive portal redirect instead of displaying the error page. + return; + } + + String message = "File Not Found\n\n"; + + message += "URI: "; + message += server->uri(); + message += "\nMethod: "; + message += (server->method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server->args(); + message += "\n"; + + for (uint8_t i = 0; i < server->args(); i++) + { + message += " " + server->argName(i) + ": " + server->arg(i) + "\n"; + } + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + server->send(404, "text/plain", message); +} + +////////////////////////////////////////// + +/** + HTTPD redirector + Redirect to captive portal if we got a request for another domain. + Return true in that case so the page handler do not try to handle the request again. +*/ +boolean ESP_WiFiManager::captivePortal() +{ + if (!isIp(server->hostHeader())) + { + LOGDEBUG(F("Request redirected to captive portal")); + + server->sendHeader(F("Location"), (String)F("http://") + toStringIp(server->client().localIP()), true); + server->send(302, FPSTR(WM_HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. + server->client().stop(); // Stop is needed because we sent no content length + + return true; + } + return false; +} + +////////////////////////////////////////// + +//start up config portal callback +void ESP_WiFiManager::setAPCallback(void(*func)(ESP_WiFiManager* myWiFiManager)) +{ + _apcallback = func; +} + +////////////////////////////////////////// + +//start up save config callback +void ESP_WiFiManager::setSaveConfigCallback(void(*func)(void)) +{ + _savecallback = func; +} + +////////////////////////////////////////// + +//sets a custom element to add to head, like a new style tag +void ESP_WiFiManager::setCustomHeadElement(const char* element) { + _customHeadElement = element; +} + +//if this is true, remove duplicated Access Points - defaut true +void ESP_WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) +{ + _removeDuplicateAPs = removeDuplicates; +} + +////////////////////////////////////////// + +//Scan for WiFiNetworks in range and sort by signal strength +//space for indices array allocated on the heap and should be freed when no longer required +int ESP_WiFiManager::scanWifiNetworks(int **indicesptr) +{ + LOGDEBUG(F("Scanning Network")); + + int n = WiFi.scanNetworks(); + + LOGDEBUG1(F("scanWifiNetworks: Done, Scanned Networks n ="), n); + + //KH, Terrible bug here. WiFi.scanNetworks() returns n < 0 => malloc( negative == very big ) => crash!!! + //In .../esp32/libraries/WiFi/src/WiFiType.h + //#define WIFI_SCAN_RUNNING (-1) + //#define WIFI_SCAN_FAILED (-2) + //if (n == 0) + if (n <= 0) + { + LOGDEBUG(F("No network found")); + return (0); + } + else + { + // Allocate space off the heap for indices array. + // This space should be freed when no longer required. + int* indices = (int *)malloc(n * sizeof(int)); + + if (indices == NULL) + { + LOGDEBUG(F("ERROR: Out of memory")); + *indicesptr = NULL; + return (0); + } + + *indicesptr = indices; + + //sort networks + for (int i = 0; i < n; i++) + { + indices[i] = i; + } + + LOGDEBUG(F("Sorting")); + + // RSSI SORT + // old sort + for (int i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) + { + std::swap(indices[i], indices[j]); + } + } + } + + LOGDEBUG(F("Removing Dup")); + + // remove duplicates ( must be RSSI sorted ) + if (_removeDuplicateAPs) + { + String cssid; + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; + + cssid = WiFi.SSID(indices[i]); + for (int j = i + 1; j < n; j++) + { + if (cssid == WiFi.SSID(indices[j])) + { + LOGDEBUG1("DUP AP:", WiFi.SSID(indices[j])); + indices[j] = -1; // set dup aps to index -1 + } + } + } + } + + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip dups + + int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); + + if (!(_minimumQuality == -1 || _minimumQuality < quality)) + { + indices[i] = -1; + LOGDEBUG(F("Skipping low quality")); + } + } + +#if (DEBUG_WIFIMGR > 2) + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip dups + else + Serial.println(WiFi.SSID(indices[i])); + } +#endif + + return (n); + } +} + +////////////////////////////////////////// + +int ESP_WiFiManager::getRSSIasQuality(int RSSI) +{ + int quality = 0; + + if (RSSI <= -100) + { + quality = 0; + } + else if (RSSI >= -50) + { + quality = 100; + } + else + { + quality = 2 * (RSSI + 100); + } + + return quality; +} + +////////////////////////////////////////// + +/** Is this an IP? */ +boolean ESP_WiFiManager::isIp(String str) +{ + for (int i = 0; i < str.length(); i++) + { + int c = str.charAt(i); + + if (c != '.' && (c < '0' || c > '9')) + { + return false; + } + } + return true; +} + +////////////////////////////////////////// + +/** IP to String? */ +String ESP_WiFiManager::toStringIp(IPAddress ip) +{ + String res = ""; + for (int i = 0; i < 3; i++) + { + res += String((ip >> (8 * i)) & 0xFF) + "."; + } + + res += String(((ip >> 8 * 3)) & 0xFF); + + return res; +} + +////////////////////////////////////////// + +#ifdef ESP32 +// We can't use WiFi.SSID() in ESP32 as it's only valid after connected. +// SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot +// Have to create a new function to store in EEPROM/SPIFFS for this purpose + +String ESP_WiFiManager::getStoredWiFiSSID() +{ + if (WiFi.getMode() == WIFI_MODE_NULL) + { + return String(); + } + + wifi_ap_record_t info; + + if (!esp_wifi_sta_get_ap_info(&info)) + { + return String(reinterpret_cast(info.ssid)); + } + else + { + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + return String(reinterpret_cast(conf.sta.ssid)); + } + + return String(); +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getStoredWiFiPass() +{ + if (WiFi.getMode() == WIFI_MODE_NULL) + { + return String(); + } + + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + + return String(reinterpret_cast(conf.sta.password)); +} +#endif diff --git a/src_cpp/ESP_WiFiManager.h b/src_cpp/ESP_WiFiManager.h new file mode 100644 index 0000000..6dac8b1 --- /dev/null +++ b/src_cpp/ESP_WiFiManager.h @@ -0,0 +1,543 @@ +/**************************************************************************************************************************** + ESP_WiFiManager.h + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. + *****************************************************************************************************************************/ + +#pragma once + +#include "ESP_WiFiManager_Debug.h" + +//KH, for ESP32 +#ifdef ESP8266 + #include + #include +#else //ESP32 + #include + #include +#endif + +#include +#include +#undef min +#undef max +#include + +//KH, for ESP32 +#ifdef ESP8266 + extern "C" + { + #include "user_interface.h" + } + + #define ESP_getChipId() (ESP.getChipId()) +#else //ESP32 + #include + #define ESP_getChipId() ((uint32_t)ESP.getEfuseMac()) +#endif + +#define WFM_LABEL_BEFORE 1 +#define WFM_LABEL_AFTER 2 +#define WFM_NO_LABEL 0 + +/** Handle CORS in pages */ +// Default false for using only whenever necessary to avoid security issue when using CORS (Cross-Origin Resource Sharing) +#ifndef USING_CORS_FEATURE + // Contributed by AlesSt (https://github.com/AlesSt) to solve AJAX CORS protection problem of API redirects on client side + // See more in https://github.com/khoih-prog/ESP_WiFiManager/issues/27 and https://en.wikipedia.org/wiki/Cross-origin_resource_sharing + #define USING_CORS_FEATURE false +#endif + +//KH +//Mofidy HTTP_HEAD to WM_HTTP_HEAD_START to avoid conflict in Arduino esp8266 core 2.6.0+ +const char WM_HTTP_200[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; +const char WM_HTTP_HEAD_START[] PROGMEM = "{v}"; + +// KH, update from v1.0.10 +const char WM_HTTP_STYLE[] PROGMEM = ""; +////// + +// KH, update from v1.1.0 +const char WM_HTTP_SCRIPT[] PROGMEM = ""; +////// + +// From v1.0.9 to permit disable or configure NTP from sketch +#ifndef USE_ESP_WIFIMANAGER_NTP + // From v1.0.6 to enable NTP config + #define USE_ESP_WIFIMANAGER_NTP true +#endif + +#if USE_ESP_WIFIMANAGER_NTP + +const char WM_HTTP_SCRIPT_NTP_MSG[] PROGMEM = "

Your timezone is :

"; + +// From v1.0.9 to permit disable or configure NTP from sketch +#ifndef USE_CLOUDFLARE_NTP + #define USE_CLOUDFLARE_NTP false +#endif + +#if USE_CLOUDFLARE_NTP +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#else +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#endif + +#else +const char WM_HTTP_SCRIPT_NTP_MSG[] PROGMEM = ""; +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#endif + +// KH, update from v1.0.10 +const char WM_HTTP_HEAD_END[] PROGMEM = "
"; + +const char WM_FLDSET_START[] PROGMEM = "
"; +const char WM_FLDSET_END[] PROGMEM = "
"; +////// + +const char WM_HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; +const char WM_HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; +const char JSON_ITEM[] PROGMEM = "{\"SSID\":\"{v}\", \"Encryption\":{i}, \"Quality\":\"{r}\"}"; + +// KH, update from v1.1.0 +const char WM_HTTP_FORM_START[] PROGMEM = "
"; +////// + +// KH, add from v1.0.10 +const char WM_HTTP_FORM_LABEL_BEFORE[] PROGMEM = "
"; +const char WM_HTTP_FORM_LABEL_AFTER[] PROGMEM = "
"; +////// + +const char WM_HTTP_FORM_LABEL[] PROGMEM = ""; +const char WM_HTTP_FORM_PARAM[] PROGMEM = ""; + +const char WM_HTTP_FORM_END[] PROGMEM = "
"; + +// KH, update from v1.1.0 +const char WM_HTTP_SAVED[] PROGMEM = "
Credentials Saved
Try connecting ESP to the {x}/{x1} network. Wait around 10 seconds then check if it's OK.

The {v} AP will run on the same WiFi channel of the {x}/{x1} AP. You may have to manually reconnect to the {v} AP.

"; +////// + +const char WM_HTTP_END[] PROGMEM = "
"; + +//KH, from v1.1.0 +const char WM_HTTP_HEAD_CL[] PROGMEM = "Content-Length"; +const char WM_HTTP_HEAD_CT[] PROGMEM = "text/html"; +const char WM_HTTP_HEAD_CT2[] PROGMEM = "text/plain"; + +//KH Add repeatedly used const +const char WM_HTTP_CACHE_CONTROL[] PROGMEM = "Cache-Control"; +const char WM_HTTP_NO_STORE[] PROGMEM = "no-cache, no-store, must-revalidate"; +const char WM_HTTP_PRAGMA[] PROGMEM = "Pragma"; +const char WM_HTTP_NO_CACHE[] PROGMEM = "no-cache"; +const char WM_HTTP_EXPIRES[] PROGMEM = "Expires"; +const char WM_HTTP_CORS[] PROGMEM = "Access-Control-Allow-Origin"; +const char WM_HTTP_CORS_ALLOW_ALL[] PROGMEM = "*"; + +#if USE_AVAILABLE_PAGES +const char WM_HTTP_AVAILABLE_PAGES[] PROGMEM = "

Available Pages

PageFunction
/Menu page.
/wifiShow WiFi scan results and enter WiFi configuration.
/wifisaveSave WiFi configuration information and configure device. Needs variables supplied.
/closeClose the configuration server and configuration WiFi network.
/iThis page.
/rDelete WiFi configuration and reboot. ESP device will not reconnect to a network until new WiFi configuration data is entered.
/stateCurrent device state in JSON format. Interface for programmatic WiFi configuration.
/scanRun a WiFi scan and return results in JSON format. Interface for programmatic WiFi configuration.
"; +#else +const char WM_HTTP_AVAILABLE_PAGES[] PROGMEM = ""; +#endif + +//KH +#define WIFI_MANAGER_MAX_PARAMS 20 + +// Thanks to @Amorphous for the feature and code, from v1.0.5 +// (https://community.blynk.cc/t/esp-wifimanager-for-esp32-and-esp8266/42257/13) +// Form v1.0.10, enable to configure from sketch +#ifndef USE_CONFIGURABLE_DNS + #define USE_CONFIGURABLE_DNS true +#endif + + +class ESP_WMParameter +{ + public: + ESP_WMParameter(const char *custom); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement); + + ~ESP_WMParameter(); + + const char *getID(); + const char *getValue(); + const char *getPlaceholder(); + int getValueLength(); + int getLabelPlacement(); + const char *getCustomHTML(); + private: + const char *_id; + const char *_placeholder; + char *_value; + int _length; + int _labelPlacement; + const char *_customHTML; + + void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement); + + friend class ESP_WiFiManager; +}; + +#define USE_DYNAMIC_PARAMS true +#define DEFAULT_PORTAL_TIMEOUT 60000L + +// From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You have to explicitly specify false to disable the feature. +#ifndef USE_STATIC_IP_CONFIG_IN_CP + #define USE_STATIC_IP_CONFIG_IN_CP true +#endif + +class ESP_WiFiManager +{ + public: + + ESP_WiFiManager(const char *iHostname = ""); + + ~ESP_WiFiManager(); + + // Update feature from v1.0.11. Can use with STA staticIP now + boolean autoConnect(); + boolean autoConnect(char const *apName, char const *apPassword = NULL); + ////// + + //if you want to start the config portal + boolean startConfigPortal(); + boolean startConfigPortal(char const *apName, char const *apPassword = NULL); + + // get the AP name of the config portal, so it can be used in the callback + String getConfigPortalSSID(); + // get the AP password of the config portal, so it can be used in the callback + String getConfigPortalPW(); + + void resetSettings(); + + //sets timeout before webserver loop ends and exits even if there has been no setup. + //usefully for devices that failed to connect at some point and got stuck in a webserver loop + //in seconds setConfigPortalTimeout is a new name for setTimeout + void setConfigPortalTimeout(unsigned long seconds); + void setTimeout(unsigned long seconds); + + //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects + void setConnectTimeout(unsigned long seconds); + + + void setDebugOutput(boolean debug); + //defaults to not showing anything under 8% signal quality if called + void setMinimumSignalQuality(int quality = 8); + + // KH, new from v1.0.10 to enable dynamic/random channel + int setConfigPortalChannel(int channel = 1); + ////// + + //sets a custom ip /gateway /subnet configuration + void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); + //sets config for a static IP + void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); + +#if USE_CONFIGURABLE_DNS + void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn, + IPAddress dns_address_1, IPAddress dns_address_2); +#endif + + //called when AP mode and config portal is started + void setAPCallback(void(*func)(ESP_WiFiManager*)); + //called when settings have been changed and connection was successful + void setSaveConfigCallback(void(*func)(void)); + +#if USE_DYNAMIC_PARAMS + //adds a custom parameter + bool addParameter(ESP_WMParameter *p); +#else + //adds a custom parameter + void addParameter(ESP_WMParameter *p); +#endif + + //if this is set, it will exit after config, even if connection is unsucessful. + void setBreakAfterConfig(boolean shouldBreak); + //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) + //TODO + //if this is set, customise style + void setCustomHeadElement(const char* element); + //if this is true, remove duplicated Access Points - defaut true + void setRemoveDuplicateAPs(boolean removeDuplicates); + //Scan for WiFiNetworks in range and sort by signal strength + //space for indices array allocated on the heap and should be freed when no longer required + int scanWifiNetworks(int **indicesptr); + + // return SSID of router in STA mode got from config portal. NULL if no user's input //KH + String getSSID(void) + { + return _ssid; + } + + // return password of router in STA mode got from config portal. NULL if no user's input //KH + String getPW(void) + { + return _pass; + } + + // New from v1.1.0 + // return SSID of router in STA mode got from config portal. NULL if no user's input //KH + String getSSID1(void) + { + return _ssid1; + } + + // return password of router in STA mode got from config portal. NULL if no user's input //KH + String getPW1(void) + { + return _pass1; + } + + #define MAX_WIFI_CREDENTIALS 2 + + String getSSID(uint8_t index) + { + if (index == 0) + return _ssid; + else if (index == 1) + return _ssid1; + else + return String(""); + } + + String getPW(uint8_t index) + { + if (index == 0) + return _pass; + else if (index == 1) + return _pass1; + else + return String(""); + } + ////// + + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + void setCORSHeader(const char* CORSHeaders) + { + _CORS_Header = CORSHeaders; + + LOGWARN1(F("Set CORS Header to : "), _CORS_Header); + } + + const char* getCORSHeader(void) + { + return _CORS_Header; + } +#endif + + //returns the list of Parameters + ESP_WMParameter** getParameters(); + // returns the Parameters Count + int getParametersCount(); + + const char* getStatus(int status); + +#ifdef ESP32 + String getStoredWiFiSSID(); + String getStoredWiFiPass(); +#endif + + String WiFi_SSID(void) + { +#ifdef ESP8266 + return WiFi.SSID(); +#else + return getStoredWiFiSSID(); +#endif + } + + String WiFi_Pass(void) + { +#ifdef ESP8266 + return WiFi.psk(); +#else + return getStoredWiFiPass(); +#endif + } + + void setHostname(void) + { + if (RFC952_hostname[0] != 0) + { +#ifdef ESP8266 + WiFi.hostname(RFC952_hostname); +#else //ESP32 + // See https://github.com/espressif/arduino-esp32/issues/2537 + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(RFC952_hostname); +#endif + } + } + + private: + std::unique_ptr dnsServer; + + //KH, for ESP32 +#ifdef ESP8266 + std::unique_ptr server; +#else //ESP32 + std::unique_ptr server; +#endif + +#define RFC952_HOSTNAME_MAXLEN 24 + char RFC952_hostname[RFC952_HOSTNAME_MAXLEN + 1]; + + char* getRFC952_hostname(const char* iHostname); + + void setupConfigPortal(); + void startWPS(); + //const char* getStatus(int status); + + const char* _apName = "no-net"; + const char* _apPassword = NULL; + + String _ssid = ""; + String _pass = ""; + + // New from v1.1.0 + String _ssid1 = ""; + String _pass1 = ""; + ////// + + // From v1.0.6 with timezone info + String _timezoneName = ""; + + unsigned long _configPortalTimeout = 0; + + unsigned long _connectTimeout = 0; + unsigned long _configPortalStart = 0; + + int numberOfNetworks; + int *networkIndices; + + // KH, new from v1.0.10 to enable dynamic/random channel + // default to channel 1 + #define MIN_WIFI_CHANNEL 1 + #define MAX_WIFI_CHANNEL 11 // Channel 12,13 is flaky, because of bad number 13 ;-) + + int _WiFiAPChannel = 1; + ////// + + IPAddress _ap_static_ip; + IPAddress _ap_static_gw; + IPAddress _ap_static_sn; + IPAddress _sta_static_ip = IPAddress(0, 0, 0, 0); + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + +#if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; +#endif + + int _paramsCount = 0; + int _minimumQuality = -1; + boolean _removeDuplicateAPs = true; + boolean _shouldBreakAfterConfig = false; + boolean _tryWPS = false; + + const char* _customHeadElement = ""; + + int status = WL_IDLE_STATUS; + + // New from v1.1.0, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + const char* _CORS_Header = WM_HTTP_CORS_ALLOW_ALL; //"*"; +#endif + ////// + + // New v1.0.8 + void setWifiStaticIP(void); + + // New v1.1.0 + int reconnectWifi(void); + ////// + + // New v1.0.11 + int connectWifi(String ssid = "", String pass = ""); + ////// + + uint8_t waitForConnectResult(); + + void handleRoot(); + void handleWifi(); + void handleWifiSave(); + void handleServerClose(); + void handleInfo(); + void handleState(); + void handleScan(); + void handleReset(); + void handleNotFound(); + boolean captivePortal(); + void reportStatus(String &page); + + // DNS server + const byte DNS_PORT = 53; + + //helpers + int getRSSIasQuality(int RSSI); + boolean isIp(String str); + String toStringIp(IPAddress ip); + + boolean connect; + boolean stopConfigPortal = false; + boolean _debug = false; //true; + + void(*_apcallback)(ESP_WiFiManager*) = NULL; + void(*_savecallback)(void) = NULL; + +#if USE_DYNAMIC_PARAMS + int _max_params; + ESP_WMParameter** _params; +#else + ESP_WMParameter* _params[WIFI_MANAGER_MAX_PARAMS]; +#endif + + template + void DEBUG_WM(Generic text); + + template + auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s)) { + return obj->fromString(s); + } + auto optionalIPFromString(...) -> bool { + LOGINFO("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); + return false; + } +}; diff --git a/src_cpp/ESP_WiFiManager_Debug.h b/src_cpp/ESP_WiFiManager_Debug.h new file mode 100644 index 0000000..9338daa --- /dev/null +++ b/src_cpp/ESP_WiFiManager_Debug.h @@ -0,0 +1,83 @@ +/**************************************************************************************************************************** + ESP_WiFiManager_Debug.h + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. + *****************************************************************************************************************************/ + +#pragma once + +#ifdef WIFIMGR_DEBUG_PORT + #define DBG_PORT WIFIMGR_DEBUG_PORT +#else + #define DBG_PORT Serial +#endif + +// Change _WIFIMGR_LOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _WIFIMGR_LOGLEVEL_ + #define _WIFIMGR_LOGLEVEL_ 0 +#endif + +#define LOGERROR(x) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGERROR0(x) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print(x); } +#define LOGERROR1(x,y) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGERROR2(x,y,z) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGERROR3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGWARN(x) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGWARN0(x) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print(x); } +#define LOGWARN1(x,y) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGWARN2(x,y,z) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGWARN3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGINFO(x) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGINFO0(x) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print(x); } +#define LOGINFO1(x,y) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGINFO2(x,y,z) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGINFO3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGDEBUG(x) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGDEBUG0(x) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print(x); } +#define LOGDEBUG1(x,y) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGDEBUG2(x,y,z) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGDEBUG3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + diff --git a/src_h/ESP_WiFiManager-Impl.h b/src_h/ESP_WiFiManager-Impl.h new file mode 100644 index 0000000..fd4d363 --- /dev/null +++ b/src_h/ESP_WiFiManager-Impl.h @@ -0,0 +1,2029 @@ +/**************************************************************************************************************************** + ESP_WiFiManager-Impl.h + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. + *****************************************************************************************************************************/ + +#pragma once + +//#ifndef ESP_WiFiManager_Impl_h +//#define ESP_WiFiManager_Impl_h + + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *custom) +{ + _id = NULL; + _placeholder = NULL; + _length = 0; + _value = NULL; + _labelPlacement = WFM_LABEL_BEFORE; + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length) +{ + init(id, placeholder, defaultValue, length, "", WFM_LABEL_BEFORE); +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom) +{ + init(id, placeholder, defaultValue, length, custom, WFM_LABEL_BEFORE); +} + +////////////////////////////////////////// + +ESP_WMParameter::ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) +{ + init(id, placeholder, defaultValue, length, custom, labelPlacement); +} + +////////////////////////////////////////// + +void ESP_WMParameter::init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement) +{ + _id = id; + _placeholder = placeholder; + _length = length; + _labelPlacement = labelPlacement; + + _value = new char[_length + 1]; + + if (_value != NULL) + { + memset(_value, 0, _length + 1); + + if (defaultValue != NULL) + { + strncpy(_value, defaultValue, _length); + } + } + + _customHTML = custom; +} + +////////////////////////////////////////// + +ESP_WMParameter::~ESP_WMParameter() +{ + if (_value != NULL) + { + delete[] _value; + } +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getValue() +{ + return _value; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getID() +{ + return _id; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getPlaceholder() +{ + return _placeholder; +} + +////////////////////////////////////////// + +int ESP_WMParameter::getValueLength() +{ + return _length; +} + +////////////////////////////////////////// + +int ESP_WMParameter::getLabelPlacement() +{ + return _labelPlacement; +} + +////////////////////////////////////////// + +const char* ESP_WMParameter::getCustomHTML() +{ + return _customHTML; +} + +////////////////////////////////////////// + +/** + [getParameters description] + @access public +*/ +ESP_WMParameter** ESP_WiFiManager::getParameters() +{ + return _params; +} + +/** + [getParametersCount description] + @access public +*/ +int ESP_WiFiManager::getParametersCount() +{ + return _paramsCount; +} + +////////////////////////////////////////// + +char* ESP_WiFiManager::getRFC952_hostname(const char* iHostname) +{ + memset(RFC952_hostname, 0, sizeof(RFC952_hostname)); + + size_t len = (RFC952_HOSTNAME_MAXLEN < strlen(iHostname)) ? RFC952_HOSTNAME_MAXLEN : strlen(iHostname); + + size_t j = 0; + + for (size_t i = 0; i < len - 1; i++) + { + if (isalnum(iHostname[i]) || iHostname[i] == '-') + { + RFC952_hostname[j] = iHostname[i]; + j++; + } + } + + // no '-' as last char + if (isalnum(iHostname[len - 1]) || (iHostname[len - 1] != '-')) + RFC952_hostname[j] = iHostname[len - 1]; + + return RFC952_hostname; +} + +////////////////////////////////////////// + +ESP_WiFiManager::ESP_WiFiManager(const char *iHostname) +{ +#if USE_DYNAMIC_PARAMS + _max_params = WIFI_MANAGER_MAX_PARAMS; + _params = (ESP_WMParameter**)malloc(_max_params * sizeof(ESP_WMParameter*)); +#endif + + //WiFi not yet started here, must call WiFi.mode(WIFI_STA) and modify function WiFiGenericClass::mode(wifi_mode_t m) !!! + + WiFi.mode(WIFI_STA); + + if (iHostname[0] == 0) + { +#ifdef ESP8266 + String _hostname = "ESP8266-" + String(ESP.getChipId(), HEX); +#else //ESP32 + String _hostname = "ESP32-" + String((uint32_t)ESP.getEfuseMac(), HEX); +#endif + _hostname.toUpperCase(); + + getRFC952_hostname(_hostname.c_str()); + + } + else + { + // Prepare and store the hostname only not NULL + getRFC952_hostname(iHostname); + } + + LOGWARN1(F("RFC925 Hostname ="), RFC952_hostname); + + setHostname(); + + networkIndices = NULL; +} + +////////////////////////////////////////// + +ESP_WiFiManager::~ESP_WiFiManager() +{ +#if USE_DYNAMIC_PARAMS + if (_params != NULL) + { + LOGINFO(F("freeing allocated params!")); + + free(_params); + } +#endif + + if (networkIndices) + { + free(networkIndices); //indices array no longer required so free memory + } +} + +////////////////////////////////////////// + +#if USE_DYNAMIC_PARAMS +bool ESP_WiFiManager::addParameter(ESP_WMParameter *p) +#else +void ESP_WiFiManager::addParameter(ESP_WMParameter *p) +#endif +{ +#if USE_DYNAMIC_PARAMS + + if (_paramsCount == _max_params) + { + // rezise the params array + _max_params += WIFI_MANAGER_MAX_PARAMS; + + LOGINFO1(F("Increasing _max_params to:"), _max_params); + + ESP_WMParameter** new_params = (ESP_WMParameter**)realloc(_params, _max_params * sizeof(ESP_WMParameter*)); + + if (new_params != NULL) + { + _params = new_params; + } + else + { + LOGINFO(F("ERROR: failed to realloc params, size not increased!")); + + return false; + } + } + + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + + return true; + +#else + + // Danger here. Better to use Tzapu way here + if (_paramsCount < (WIFI_MANAGER_MAX_PARAMS)) + { + _params[_paramsCount] = p; + _paramsCount++; + + LOGINFO1(F("Adding parameter"), p->getID()); + } + else + { + LOGINFO("Can't add parameter. Full"); + } + +#endif +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setupConfigPortal() +{ + stopConfigPortal = false; //Signal not to close config portal + + /*This library assumes autoconnect is set to 1. It usually is + but just in case check the setting and turn on autoconnect if it is off. + Some useful discussion at https://github.com/esp8266/Arduino/issues/1615*/ + if (WiFi.getAutoConnect() == 0) + WiFi.setAutoConnect(1); + + dnsServer.reset(new DNSServer()); + +#ifdef ESP8266 + server.reset(new ESP8266WebServer(80)); +#else //ESP32 + server.reset(new WebServer(80)); +#endif + + /* Setup the DNS server redirecting all the domains to the apIP */ + if (dnsServer) + { + dnsServer->setErrorReplyCode(DNSReplyCode::NoError); + dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); + } + + _configPortalStart = millis(); + + LOGWARN1(F("Configuring AP SSID ="), _apName); + + if (_apPassword != NULL) + { + if (strlen(_apPassword) < 8 || strlen(_apPassword) > 63) + { + // fail passphrase to short or long! + LOGERROR(F("Invalid AccessPoint password. Ignoring")); + + _apPassword = NULL; + } + LOGWARN1(F("AP PWD ="), _apPassword); + } + + + // KH, new from v1.0.10 to enable dynamic/random channel + static int channel; + + // Use random channel if _WiFiAPChannel == 0 + if (_WiFiAPChannel == 0) + channel = (_configPortalStart % MAX_WIFI_CHANNEL) + 1; + else + channel = _WiFiAPChannel; + + if (_apPassword != NULL) + { + LOGWARN1(F("AP Channel ="), channel); + + //WiFi.softAP(_apName, _apPassword);//password option + WiFi.softAP(_apName, _apPassword, channel); + } + else + { + // Can't use channel here + WiFi.softAP(_apName); + } + ////// + + // From v1.0.11 + // Contributed by AlesSt (https://github.com/AlesSt) to solve issue softAP with custom IP sometimes not working + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/26 and https://github.com/espressif/arduino-esp32/issues/985 + // delay 100ms to wait for SYSTEM_EVENT_AP_START + delay(100); + ////// + + //optional soft ip config + if (_ap_static_ip) + { + LOGWARN3(F("Custom AP IP/GW/Subnet = "), _ap_static_ip, _ap_static_gw, _ap_static_sn); + + WiFi.softAPConfig(_ap_static_ip, _ap_static_gw, _ap_static_sn); + } + + delay(500); // Without delay I've seen the IP address blank + + LOGWARN1(F("AP IP address ="), WiFi.softAPIP()); + + /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ + server->on("/", std::bind(&ESP_WiFiManager::handleRoot, this)); + server->on("/wifi", std::bind(&ESP_WiFiManager::handleWifi, this)); + server->on("/wifisave", std::bind(&ESP_WiFiManager::handleWifiSave, this)); + server->on("/close", std::bind(&ESP_WiFiManager::handleServerClose, this)); + server->on("/i", std::bind(&ESP_WiFiManager::handleInfo, this)); + server->on("/r", std::bind(&ESP_WiFiManager::handleReset, this)); + server->on("/state", std::bind(&ESP_WiFiManager::handleState, this)); + server->on("/scan", std::bind(&ESP_WiFiManager::handleScan, this)); + server->onNotFound(std::bind(&ESP_WiFiManager::handleNotFound, this)); + server->begin(); // Web server start + + LOGWARN(F("HTTP server started")); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::autoConnect() +{ +#ifdef ESP8266 + String ssid = "ESP_" + String(ESP.getChipId()); +#else //ESP32 + String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); +#endif + + return autoConnect(ssid.c_str(), NULL); +} + +/* This is not very useful as there has been an assumption that device has to be + told to connect but Wifi already does it's best to connect in background. Calling this + method will block until WiFi connects. Sketch can avoid + blocking call then use (WiFi.status()==WL_CONNECTED) test to see if connected yet. + See some discussion at https://github.com/tzapu/WiFiManager/issues/68 +*/ + +// New in v1.0.11 +// To permit autoConnect() to use STA static IP or DHCP IP. +#ifndef AUTOCONNECT_NO_INVALIDATE + #define AUTOCONNECT_NO_INVALIDATE true +#endif + +////////////////////////////////////////// + +boolean ESP_WiFiManager::autoConnect(char const *apName, char const *apPassword) +{ +#if AUTOCONNECT_NO_INVALIDATE + LOGINFO(F("\nAutoConnect using previously saved SSID/PW, but keep previous settings")); + // Connect to previously saved SSID/PW, but keep previous settings + connectWifi(); +#else + LOGINFO(F("\nAutoConnect using previously saved SSID/PW, but invalidate previous settings")); + // Connect to previously saved SSID/PW, but invalidate previous settings + connectWifi(WiFi_SSID(), WiFi_Pass()); +#endif + + unsigned long startedAt = millis(); + + while (millis() - startedAt < 10000) + { + //delay(100); + delay(200); + + if (WiFi.status() == WL_CONNECTED) + { + float waited = (millis() - startedAt); + + LOGWARN1(F("Connected after waiting (s) :"), waited / 1000); + LOGWARN1(F("Local ip ="), WiFi.localIP()); + + return true; + } + } + + return startConfigPortal(apName, apPassword); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::startConfigPortal() +{ +#ifdef ESP8266 + String ssid = "ESP_" + String(ESP.getChipId()); +#else //ESP32 + String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac()); +#endif + ssid.toUpperCase(); + + return startConfigPortal(ssid.c_str(), NULL); +} + +////////////////////////////////////////// + +boolean ESP_WiFiManager::startConfigPortal(char const *apName, char const *apPassword) +{ + //setup AP + int connRes = WiFi.waitForConnectResult(); + + LOGINFO("WiFi.waitForConnectResult Done"); + + if (connRes == WL_CONNECTED) + { + LOGINFO("SET AP_STA"); + + WiFi.mode(WIFI_AP_STA); //Dual mode works fine if it is connected to WiFi + } + else + { + LOGINFO("SET AP"); + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + // When ESP8266 station is trying to find a target AP, it will scan on every channel, + // that means ESP8266 station is changing its channel to scan. This makes the channel of ESP8266 softAP keep changing too.. + // So the connection may break. From http://bbs.espressif.com/viewtopic.php?t=671#p2531 + } + + _apName = apName; + _apPassword = apPassword; + + //notify we entered AP mode + if (_apcallback != NULL) + { + LOGINFO("_apcallback"); + + _apcallback(this); + } + + connect = false; + + setupConfigPortal(); + + bool TimedOut = true; + + LOGINFO("ESP_WiFiManager::startConfigPortal : Enter loop"); + + while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) + { + //DNS + dnsServer->processNextRequest(); + //HTTP + server->handleClient(); + + if (connect) + { + TimedOut = false; + delay(2000); + + LOGERROR(F("Connecting to new AP")); + +#if 0 + + // New Mod from v1.1.0 + int wifiConnected = reconnectWifi(); + + if ( wifiConnected == WL_CONNECTED ) + { + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + + break; + } + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + ////// + +#else + + // using user-provided _ssid, _pass in place of system-stored ssid and pass + if (connectWifi(_ssid, _pass) != WL_CONNECTED) + { + LOGERROR(F("Failed to connect")); + + WiFi.mode(WIFI_AP); // Dual mode becomes flaky if not connected to a WiFi network. + } + else + { + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + break; + } + +#endif + + if (_shouldBreakAfterConfig) + { + //flag set to exit after config after trying to connect + //notify that configuration has changed and any optional parameters should be saved + if (_savecallback != NULL) + { + //todo: check if any custom parameters actually exist, and check if they really changed maybe + _savecallback(); + } + + break; + } + } + + if (stopConfigPortal) + { + LOGERROR("Stop ConfigPortal"); //KH + + stopConfigPortal = false; + break; + } + + yield(); + } + + WiFi.mode(WIFI_STA); + + if (TimedOut) + { + setHostname(); + + // New v1.0.8 to fix static IP when CP not entered or timed-out + setWifiStaticIP(); + + WiFi.begin(); + int connRes = waitForConnectResult(); + + LOGERROR1("Timed out connection result:", getStatus(connRes)); + } + + server->stop(); + server.reset(); + dnsServer->stop(); + dnsServer.reset(); + + return WiFi.status() == WL_CONNECTED; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setWifiStaticIP(void) +{ +#if USE_CONFIGURABLE_DNS + if (_sta_static_ip) + { + LOGWARN(F("Custom STA IP/GW/Subnet")); + + //***** Added section for DNS config option ***** + if (_sta_static_dns1 && _sta_static_dns2) + { + LOGWARN(F("DNS1 and DNS2 set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns1, _sta_static_dns2); + } + else if (_sta_static_dns1) + { + LOGWARN(F("Only DNS1 set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn, _sta_static_dns1); + } + else + { + LOGWARN(F("No DNS server set")); + + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); + } + //***** End added section for DNS config option ***** + + LOGINFO1(F("setWifiStaticIP IP ="), WiFi.localIP()); + } + else + { + LOGWARN(F("Can't use Custom STA IP/GW/Subnet")); + } +#else + // check if we've got static_ip settings, if we do, use those. + if (_sta_static_ip) + { + WiFi.config(_sta_static_ip, _sta_static_gw, _sta_static_sn); + + LOGWARN1(F("Custom STA IP/GW/Subnet : "), WiFi.localIP()); + } +#endif +} + +////////////////////////////////////////// + +// New from v1.1.0 +int ESP_WiFiManager::reconnectWifi(void) +{ + int connectResult; + + // using user-provided _ssid, _pass in place of system-stored ssid and pass + if ( ( connectResult = connectWifi(_ssid, _pass) ) != WL_CONNECTED) + { + LOGERROR1(F("Failed to connect to"), _ssid); + + if ( ( connectResult = connectWifi(_ssid1, _pass1) ) != WL_CONNECTED) + { + LOGERROR1(F("Failed to connect to"), _ssid1); + + } + else + LOGERROR1(F("Connected to"), _ssid1); + } + else + LOGERROR1(F("Connected to"), _ssid); + + return connectResult; +} + +////////////////////////////////////////// + +int ESP_WiFiManager::connectWifi(String ssid, String pass) +{ + //KH, from v1.0.10. + // Add option if didn't input/update SSID/PW => Use the previous saved Credentials. + // But update the Static/DHCP options if changed. + if ( (ssid != "") || ( (ssid == "") && (WiFi_SSID() != "") ) ) + { + //fix for auto connect racing issue. Move up from v1.1.0 to avoid resetSettings() + if (WiFi.status() == WL_CONNECTED) + { + LOGWARN(F("Already connected. Bailing out.")); + return WL_CONNECTED; + } + + if (ssid != "") + resetSettings(); + +#ifdef ESP8266 + setWifiStaticIP(); +#endif + + WiFi.mode(WIFI_AP_STA); //It will start in station mode if it was previously in AP mode. + + setHostname(); + + // KH, Fix ESP32 staticIP after exiting CP, from v1.0.9 +#ifdef ESP32 + setWifiStaticIP(); +#endif + + if (ssid != "") + { + // Start Wifi with new values. + LOGWARN(F("Connect to new WiFi using new IP parameters")); + + WiFi.begin(ssid.c_str(), pass.c_str()); + } + else + { + // Start Wifi with old values. + LOGWARN(F("Connect to previous WiFi using new IP parameters")); + + WiFi.begin(); + } + } + else if (WiFi_SSID() == "") + { + LOGWARN(F("No saved credentials")); + } + + int connRes = waitForConnectResult(); + LOGWARN1("Connection result: ", getStatus(connRes)); + + //not connected, WPS enabled, no pass - first attempt + if (_tryWPS && connRes != WL_CONNECTED && pass == "") + { + startWPS(); + //should be connected at the end of WPS + connRes = waitForConnectResult(); + } + + return connRes; +} + +////////////////////////////////////////// + +uint8_t ESP_WiFiManager::waitForConnectResult() +{ + if (_connectTimeout == 0) + { + unsigned long startedAt = millis(); + + // In ESP8266, WiFi.waitForConnectResult() @return wl_status_t (0-255) or -1 on timeout !!! + // In ESP32, WiFi.waitForConnectResult() @return wl_status_t (0-255) + // So, using int for connRes to be safe + //int connRes = WiFi.waitForConnectResult(); + WiFi.waitForConnectResult(); + + float waited = (millis() - startedAt); + + LOGWARN1(F("Connected after waiting (s) :"), waited / 1000); + LOGWARN1(F("Local ip ="), WiFi.localIP()); + + // Fix bug from v1.1.0+, connRes is sometimes not correct. + //return connRes; + return WiFi.status(); + } + else + { + LOGERROR(F("Waiting WiFi connection with time out")); + unsigned long start = millis(); + boolean keepConnecting = true; + uint8_t status; + + while (keepConnecting) + { + status = WiFi.status(); + if (millis() > start + _connectTimeout) + { + keepConnecting = false; + LOGERROR(F("Connection timed out")); + } + + if (status == WL_CONNECTED || status == WL_CONNECT_FAILED) + { + keepConnecting = false; + } + delay(100); + } + return status; + } +} + +////////////////////////////////////////// + +void ESP_WiFiManager::startWPS() +{ +#ifdef ESP8266 + LOGINFO("START WPS"); + WiFi.beginWPSConfig(); + LOGINFO("END WPS"); +#else //ESP32 + // TODO + LOGINFO("ESP32 WPS TODO"); +#endif +} + +////////////////////////////////////////// + +//Convenient for debugging but wasteful of program space. +//Remove if short of space +const char* ESP_WiFiManager::getStatus(int status) +{ + switch (status) + { + case WL_IDLE_STATUS: + return "WL_IDLE_STATUS"; + case WL_NO_SSID_AVAIL: + return "WL_NO_SSID_AVAIL"; + case WL_CONNECTED: + return "WL_CONNECTED"; + case WL_CONNECT_FAILED: + return "WL_CONNECT_FAILED"; + case WL_DISCONNECTED: + return "WL_DISCONNECTED"; + default: + return "UNKNOWN"; + } +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getConfigPortalSSID() +{ + return _apName; +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getConfigPortalPW() +{ + return _apPassword; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::resetSettings() +{ + LOGINFO(F("Previous settings invalidated")); + +#ifdef ESP8266 + WiFi.disconnect(true); +#else + WiFi.disconnect(true, true); + // New in v1.0.11 + // Temporary fix for issue of not clearing WiFi SSID/PW from flash of ESP32 + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/25 and https://github.com/espressif/arduino-esp32/issues/400 + WiFi.begin("0","0"); + ////// +#endif + + delay(200); + return; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setTimeout(unsigned long seconds) +{ + setConfigPortalTimeout(seconds); +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setConfigPortalTimeout(unsigned long seconds) +{ + _configPortalTimeout = seconds * 1000; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setConnectTimeout(unsigned long seconds) +{ + _connectTimeout = seconds * 1000; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setDebugOutput(boolean debug) +{ + _debug = debug; +} + +////////////////////////////////////////// + +// KH, new from v1.0.10 to enable dynamic/random channel +int ESP_WiFiManager::setConfigPortalChannel(int channel) +{ + // If channel < MIN_WIFI_CHANNEL - 1 or channel > MAX_WIFI_CHANNEL => channel = 1 + // If channel == 0 => will use random channel from MIN_WIFI_CHANNEL to MAX_WIFI_CHANNEL + // If (MIN_WIFI_CHANNEL <= channel <= MAX_WIFI_CHANNEL) => use it + if ( (channel < MIN_WIFI_CHANNEL - 1) || (channel > MAX_WIFI_CHANNEL) ) + _WiFiAPChannel = 1; + else if ( (channel >= MIN_WIFI_CHANNEL - 1) && (channel <= MAX_WIFI_CHANNEL) ) + _WiFiAPChannel = channel; + + return _WiFiAPChannel; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) +{ + LOGINFO(F("setAPStaticIPConfig")); + _ap_static_ip = ip; + _ap_static_gw = gw; + _ap_static_sn = sn; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn) +{ + LOGINFO(F("setSTAStaticIPConfig")); + _sta_static_ip = ip; + _sta_static_gw = gw; + _sta_static_sn = sn; +} + +////////////////////////////////////////// + +#if USE_CONFIGURABLE_DNS +void ESP_WiFiManager::setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn, IPAddress dns_address_1, IPAddress dns_address_2) +{ + LOGINFO(F("setSTAStaticIPConfig for USE_CONFIGURABLE_DNS")); + _sta_static_ip = ip; + _sta_static_gw = gw; + _sta_static_sn = sn; + _sta_static_dns1 = dns_address_1; //***** Added argument ***** + _sta_static_dns2 = dns_address_2; //***** Added argument ***** +} +#endif + +////////////////////////////////////////// + +void ESP_WiFiManager::setMinimumSignalQuality(int quality) +{ + _minimumQuality = quality; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::setBreakAfterConfig(boolean shouldBreak) +{ + _shouldBreakAfterConfig = shouldBreak; +} + +////////////////////////////////////////// + +void ESP_WiFiManager::reportStatus(String &page) +{ + page += FPSTR(WM_HTTP_SCRIPT_NTP_MSG); + + if (WiFi_SSID() != "") + { + page += F("Configured to connect to access point "); + page += WiFi_SSID(); + + if (WiFi.status() == WL_CONNECTED) + { + page += F(" and currently connected on IP "); + page += WiFi.localIP().toString(); + page += F(""); + } + else + { + page += F(" but not currently connected to network."); + } + } + else + { + page += F("No network currently configured."); + } +} + +////////////////////////////////////////// + +/** Handle root or redirect to captive portal */ +void ESP_WiFiManager::handleRoot() +{ + LOGDEBUG(F("Handle root")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + if (captivePortal()) + { + // If caprive portal redirect instead of displaying the error page. + return; + } + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Options"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += "

"; + page += _apName; + + if (WiFi_SSID() != "") + { + if (WiFi.status() == WL_CONNECTED) + { + page += " on "; + page += WiFi_SSID(); + } + else + { + page += " on "; + page += WiFi_SSID(); + page += ""; + } + } + + page += "

"; + page += FPSTR(WM_HTTP_PORTAL_OPTIONS); + page += F("
"); + reportStatus(page); + page += F("
"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + +} + +////////////////////////////////////////// + +/** Wifi config page handler */ +void ESP_WiFiManager::handleWifi() +{ + LOGDEBUG(F("Handle WiFi")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Config ESP"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("

Configuration

"); + + // KH, New, v1.0.6+ + numberOfNetworks = scanWifiNetworks(&networkIndices); + + //Print list of WiFi networks that were found in earlier scan + if (numberOfNetworks == 0) + { + page += F("WiFi scan found no networks. Restart configuration portal to scan again."); + } + else + { + // From v1.0.10 + page += FPSTR(WM_FLDSET_START); + ////// + + //display networks in page + for (int i = 0; i < numberOfNetworks; i++) + { + if (networkIndices[i] == -1) + continue; // skip dups and those that are below the required quality + + LOGDEBUG1(F("Index ="), i); + LOGDEBUG1(F("SSID ="), WiFi.SSID(networkIndices[i])); + LOGDEBUG1(F("RSSI ="), WiFi.RSSI(networkIndices[i])); + + int quality = getRSSIasQuality(WiFi.RSSI(networkIndices[i])); + + String item = FPSTR(WM_HTTP_ITEM); + String rssiQ; + rssiQ += quality; + item.replace("{v}", WiFi.SSID(networkIndices[i])); + item.replace("{r}", rssiQ); + +#ifdef ESP8266 + if (WiFi.encryptionType(networkIndices[i]) != ENC_TYPE_NONE) +#else //ESP32 + if (WiFi.encryptionType(networkIndices[i]) != WIFI_AUTH_OPEN) +#endif + { + item.replace("{i}", "l"); + } + else + { + item.replace("{i}", ""); + } + + //LOGDEBUG(item); + page += item; + delay(0); + } + + // From v1.0.10 + page += FPSTR(WM_FLDSET_END); + ////// + + page += "
"; + } + + page += FPSTR(WM_HTTP_FORM_START); + char parLength[2]; + + // add the extra parameters to the form + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + // From v1.0.10 + if (i == 1) + { + page += FPSTR(WM_FLDSET_START); + } + ////// + + String pitem; + switch (_params[i]->getLabelPlacement()) + { + case WFM_LABEL_BEFORE: + pitem = FPSTR(WM_HTTP_FORM_LABEL_BEFORE); + break; + case WFM_LABEL_AFTER: + pitem = FPSTR(WM_HTTP_FORM_LABEL_AFTER); + break; + default: + // WFM_NO_LABEL + pitem = FPSTR(WM_HTTP_FORM_PARAM); + break; + } + + if (_params[i]->getID() != NULL) + { + pitem.replace("{i}", _params[i]->getID()); + pitem.replace("{n}", _params[i]->getID()); + pitem.replace("{p}", _params[i]->getPlaceholder()); + snprintf(parLength, 2, "%d", _params[i]->getValueLength()); + pitem.replace("{l}", parLength); + pitem.replace("{v}", _params[i]->getValue()); + pitem.replace("{c}", _params[i]->getCustomHTML()); + } + else + { + pitem = _params[i]->getCustomHTML(); + } + + page += pitem; + } + + // From v1.0.10 + if (_paramsCount > 0) + { + page += FPSTR(WM_FLDSET_END); + } + ////// + + if (_params[0] != NULL) + { + page += "
"; + } + + LOGDEBUG1(F("Static IP ="), _sta_static_ip.toString()); + + // KH, Comment out in v1.0.9 to permit changing from DHCP to static IP, or vice versa + // and add staticIP label in CP + + // From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. + // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa + // You have to explicitly specify false to disable the feature. + +#if !USE_STATIC_IP_CONFIG_IN_CP + if (_sta_static_ip) +#endif + { + // From v1.0.10 + page += FPSTR(WM_FLDSET_START); + ////// + + String item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "ip"); + item.replace("{n}", "ip"); + item.replace("{p}", "Static IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_ip.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "gw"); + item.replace("{n}", "gw"); + item.replace("{p}", "Gateway IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_gw.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "sn"); + item.replace("{n}", "sn"); + item.replace("{p}", "Subnet"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_sn.toString()); + + #if USE_CONFIGURABLE_DNS + //***** Added for DNS address options ***** + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "dns1"); + item.replace("{n}", "dns1"); + item.replace("{p}", "DNS1 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_dns1.toString()); + + page += item; + + item = FPSTR(WM_HTTP_FORM_LABEL); + item += FPSTR(WM_HTTP_FORM_PARAM); + item.replace("{i}", "dns2"); + item.replace("{n}", "dns2"); + item.replace("{p}", "DNS2 IP"); + item.replace("{l}", "15"); + item.replace("{v}", _sta_static_dns2.toString()); + //***** End added for DNS address options ***** + #endif + + page += item; + + // From v1.0.10 + page += FPSTR(WM_FLDSET_END); + ////// + + page += "
"; + } + + page += FPSTR(WM_HTTP_FORM_END); + + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent config page")); +} + +////////////////////////////////////////// + +/** Handle the WLAN save form and redirect to WLAN config page again */ +void ESP_WiFiManager::handleWifiSave() +{ + LOGDEBUG(F("WiFi save")); + + //SAVE/connect here + _ssid = server->arg("s").c_str(); + _pass = server->arg("p").c_str(); + + // New from v1.1.0 + _ssid1 = server->arg("s1").c_str(); + _pass1 = server->arg("p1").c_str(); + ////// + + //parameters + for (int i = 0; i < _paramsCount; i++) + { + if (_params[i] == NULL) + { + break; + } + + //read parameter + String value = server->arg(_params[i]->getID()).c_str(); + //store it in array + value.toCharArray(_params[i]->_value, _params[i]->_length); + + LOGDEBUG2(F("Parameter and value :"), _params[i]->getID(), value); + } + + if (server->arg("ip") != "") + { + String ip = server->arg("ip"); + optionalIPFromString(&_sta_static_ip, ip.c_str()); + + LOGDEBUG1(F("New Static IP ="), _sta_static_ip.toString()); + } + + if (server->arg("gw") != "") + { + String gw = server->arg("gw"); + optionalIPFromString(&_sta_static_gw, gw.c_str()); + + LOGDEBUG1(F("New Static Gateway ="), _sta_static_gw.toString()); + } + + if (server->arg("sn") != "") + { + String sn = server->arg("sn"); + optionalIPFromString(&_sta_static_sn, sn.c_str()); + + LOGDEBUG1(F("New Static Netmask ="), _sta_static_sn.toString()); + } + +#if USE_CONFIGURABLE_DNS + //***** Added for DNS Options ***** + if (server->arg("dns1") != "") + { + String dns1 = server->arg("dns1"); + optionalIPFromString(&_sta_static_dns1, dns1.c_str()); + + LOGDEBUG1(F("New Static DNS1 ="), _sta_static_dns1.toString()); + } + + if (server->arg("dns2") != "") + { + String dns2 = server->arg("dns2"); + optionalIPFromString(&_sta_static_dns2, dns2.c_str()); + + LOGDEBUG1(F("New Static DNS2 ="), _sta_static_dns2.toString()); + } + //***** End added for DNS Options ***** +#endif + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Credentials Saved"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += FPSTR(WM_HTTP_SAVED); + page.replace("{v}", _apName); + page.replace("{x}", _ssid); + + // KH, update from v1.1.0 + page.replace("{x1}", _ssid1); + ////// + + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent wifi save page")); + + connect = true; //signal ready to connect/reset + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +/** Handle shut down the server page */ +void ESP_WiFiManager::handleServerClose() +{ + LOGDEBUG(F("Server Close")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Close Server"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("
"); + page += F("My network is "); + page += WiFi_SSID(); + page += F("
"); + page += F("IP address is "); + page += WiFi.localIP().toString(); + page += F("

"); + page += F("Portal closed...

"); + //page += F("Push button on device to restart configuration server!"); + page += FPSTR(WM_HTTP_END); + server->send(200, "text/html", page); + stopConfigPortal = true; //signal ready to shutdown config portal + + LOGDEBUG(F("Sent server close page")); + + // Restore when Press Save WiFi + _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT; +} + +////////////////////////////////////////// + +/** Handle the info page */ +void ESP_WiFiManager::handleInfo() +{ + LOGDEBUG(F("Info")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "Info"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("

WiFi Information

"); + reportStatus(page); + page += F("

Device Data

"); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + + page += F(""); + + page += F(""); + + page += F(""); + page += F("
NameValue
Chip ID"); + +#ifdef ESP8266 + page += String(ESP.getChipId(), HEX); //ESP.getChipId(); +#else //ESP32 + page += String((uint32_t)ESP.getEfuseMac(), HEX); //ESP.getChipId(); +#endif + + page += F("
Flash Chip ID"); + +#ifdef ESP8266 + page += String(ESP.getFlashChipId(), HEX); //ESP.getFlashChipId(); +#else //ESP32 + // TODO + page += F("TODO"); +#endif + + page += F("
IDE Flash Size"); + page += ESP.getFlashChipSize(); + page += F(" bytes
Real Flash Size"); + +#ifdef ESP8266 + page += ESP.getFlashChipRealSize(); +#else //ESP32 + // TODO + page += F("TODO"); +#endif + + page += F(" bytes
Access Point IP"); + page += WiFi.softAPIP().toString(); + page += F("
Access Point MAC"); + page += WiFi.softAPmacAddress(); + page += F("
SSID"); + page += WiFi_SSID(); + page += F("
Station IP"); + page += WiFi.localIP().toString(); + page += F("
Station MAC"); + page += WiFi.macAddress(); + page += F("
"); + + page += FPSTR(WM_HTTP_AVAILABLE_PAGES); + + page += F("

More information about ESP_WiFiManager at"); + page += F("

https://github.com/khoih-prog/ESP_WiFiManager"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent info page")); +} + +////////////////////////////////////////// + +/** Handle the state page */ +void ESP_WiFiManager::handleState() +{ + LOGDEBUG(F("State - json")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + String page = F("{\"Soft_AP_IP\":\""); + + page += WiFi.softAPIP().toString(); + page += F("\",\"Soft_AP_MAC\":\""); + page += WiFi.softAPmacAddress(); + page += F("\",\"Station_IP\":\""); + page += WiFi.localIP().toString(); + page += F("\",\"Station_MAC\":\""); + page += WiFi.macAddress(); + page += F("\","); + + if (WiFi.psk() != "") + { + page += F("\"Password\":true,"); + } + else + { + page += F("\"Password\":false,"); + } + + page += F("\"SSID\":\""); + page += WiFi_SSID(); + page += F("\"}"); + server->send(200, "application/json", page); + + LOGDEBUG(F("Sent state page in json format")); +} + +////////////////////////////////////////// + +/** Handle the scan page */ +void ESP_WiFiManager::handleScan() +{ + LOGDEBUG(F("Scan")); + + // Disable _configPortalTimeout when someone accessing Portal to give some time to config + _configPortalTimeout = 0; //KH + + LOGDEBUG(F("State-Json")); + + server->sendHeader(FPSTR(WM_HTTP_CACHE_CONTROL), FPSTR(WM_HTTP_NO_STORE)); + +#if USING_CORS_FEATURE + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" + server->sendHeader(FPSTR(WM_HTTP_CORS), _CORS_Header); +#endif + + server->sendHeader(FPSTR(WM_HTTP_PRAGMA), FPSTR(WM_HTTP_NO_CACHE)); + server->sendHeader(FPSTR(WM_HTTP_EXPIRES), "-1"); + + int n; + int *indices; + + //Space for indices array allocated on heap in scanWifiNetworks + //and should be freed when indices no longer required. + + n = scanWifiNetworks(&indices); + LOGDEBUG(F("In handleScan, scanWifiNetworks done")); + String page = F("{\"Access_Points\":["); + + //display networks in page + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip duplicates and those that are below the required quality + + if (i != 0) + page += F(", "); + + LOGDEBUG1(F("Index ="), i); + LOGDEBUG1(F("SSID ="), WiFi.SSID(indices[i])); + LOGDEBUG1(F("RSSI ="), WiFi.RSSI(indices[i])); + + int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); + String item = FPSTR(JSON_ITEM); + String rssiQ; + + rssiQ += quality; + item.replace("{v}", WiFi.SSID(indices[i])); + item.replace("{r}", rssiQ); + +#ifdef ESP8266 + if (WiFi.encryptionType(indices[i]) != ENC_TYPE_NONE) +#else //ESP32 + if (WiFi.encryptionType(indices[i]) != WIFI_AUTH_OPEN) +#endif + { + item.replace("{i}", "true"); + } + else + { + item.replace("{i}", "false"); + } + //LOGDEBUG(item); + page += item; + delay(0); + } + + if (indices) + { + free(indices); //indices array no longer required so free memory + } + + page += F("]}"); + + server->send(200, "application/json", page); + + LOGDEBUG(F("Sent WiFiScan Data in Json format")); +} + +////////////////////////////////////////// + +/** Handle the reset page */ +void ESP_WiFiManager::handleReset() +{ + LOGDEBUG(F("Reset")); + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + String page = FPSTR(WM_HTTP_HEAD_START); + + page.replace("{v}", "WiFi Information"); + page += FPSTR(WM_HTTP_SCRIPT); + page += FPSTR(WM_HTTP_SCRIPT_NTP); + page += FPSTR(WM_HTTP_STYLE); + page += _customHeadElement; + page += FPSTR(WM_HTTP_HEAD_END); + page += F("Resetting"); + page += FPSTR(WM_HTTP_END); + + server->send(200, "text/html", page); + + LOGDEBUG(F("Sent reset page")); + delay(5000); + + // New in v1.0.11 + // Temporary fix for issue of not clearing WiFi SSID/PW from flash of ESP32 + // See https://github.com/khoih-prog/ESP_WiFiManager/issues/25 and https://github.com/espressif/arduino-esp32/issues/400 + resetSettings(); + //WiFi.disconnect(true); // Wipe out WiFi credentials. + ////// + +#ifdef ESP8266 + ESP.reset(); +#else //ESP32 + ESP.restart(); +#endif + + delay(2000); +} + +////////////////////////////////////////// + +void ESP_WiFiManager::handleNotFound() +{ + if (captivePortal()) + { + // If caprive portal redirect instead of displaying the error page. + return; + } + + String message = "File Not Found\n\n"; + + message += "URI: "; + message += server->uri(); + message += "\nMethod: "; + message += (server->method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server->args(); + message += "\n"; + + for (uint8_t i = 0; i < server->args(); i++) + { + message += " " + server->argName(i) + ": " + server->arg(i) + "\n"; + } + + server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server->sendHeader("Pragma", "no-cache"); + server->sendHeader("Expires", "-1"); + + server->send(404, "text/plain", message); +} + +////////////////////////////////////////// + +/** + HTTPD redirector + Redirect to captive portal if we got a request for another domain. + Return true in that case so the page handler do not try to handle the request again. +*/ +boolean ESP_WiFiManager::captivePortal() +{ + if (!isIp(server->hostHeader())) + { + LOGDEBUG(F("Request redirected to captive portal")); + + server->sendHeader(F("Location"), (String)F("http://") + toStringIp(server->client().localIP()), true); + server->send(302, FPSTR(WM_HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. + server->client().stop(); // Stop is needed because we sent no content length + + return true; + } + return false; +} + +////////////////////////////////////////// + +//start up config portal callback +void ESP_WiFiManager::setAPCallback(void(*func)(ESP_WiFiManager* myWiFiManager)) +{ + _apcallback = func; +} + +////////////////////////////////////////// + +//start up save config callback +void ESP_WiFiManager::setSaveConfigCallback(void(*func)(void)) +{ + _savecallback = func; +} + +////////////////////////////////////////// + +//sets a custom element to add to head, like a new style tag +void ESP_WiFiManager::setCustomHeadElement(const char* element) { + _customHeadElement = element; +} + +//if this is true, remove duplicated Access Points - defaut true +void ESP_WiFiManager::setRemoveDuplicateAPs(boolean removeDuplicates) +{ + _removeDuplicateAPs = removeDuplicates; +} + +////////////////////////////////////////// + +//Scan for WiFiNetworks in range and sort by signal strength +//space for indices array allocated on the heap and should be freed when no longer required +int ESP_WiFiManager::scanWifiNetworks(int **indicesptr) +{ + LOGDEBUG(F("Scanning Network")); + + int n = WiFi.scanNetworks(); + + LOGDEBUG1(F("scanWifiNetworks: Done, Scanned Networks n ="), n); + + //KH, Terrible bug here. WiFi.scanNetworks() returns n < 0 => malloc( negative == very big ) => crash!!! + //In .../esp32/libraries/WiFi/src/WiFiType.h + //#define WIFI_SCAN_RUNNING (-1) + //#define WIFI_SCAN_FAILED (-2) + //if (n == 0) + if (n <= 0) + { + LOGDEBUG(F("No network found")); + return (0); + } + else + { + // Allocate space off the heap for indices array. + // This space should be freed when no longer required. + int* indices = (int *)malloc(n * sizeof(int)); + + if (indices == NULL) + { + LOGDEBUG(F("ERROR: Out of memory")); + *indicesptr = NULL; + return (0); + } + + *indicesptr = indices; + + //sort networks + for (int i = 0; i < n; i++) + { + indices[i] = i; + } + + LOGDEBUG(F("Sorting")); + + // RSSI SORT + // old sort + for (int i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) + { + std::swap(indices[i], indices[j]); + } + } + } + + LOGDEBUG(F("Removing Dup")); + + // remove duplicates ( must be RSSI sorted ) + if (_removeDuplicateAPs) + { + String cssid; + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; + + cssid = WiFi.SSID(indices[i]); + for (int j = i + 1; j < n; j++) + { + if (cssid == WiFi.SSID(indices[j])) + { + LOGDEBUG1("DUP AP:", WiFi.SSID(indices[j])); + indices[j] = -1; // set dup aps to index -1 + } + } + } + } + + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip dups + + int quality = getRSSIasQuality(WiFi.RSSI(indices[i])); + + if (!(_minimumQuality == -1 || _minimumQuality < quality)) + { + indices[i] = -1; + LOGDEBUG(F("Skipping low quality")); + } + } + +#if (DEBUG_WIFIMGR > 2) + for (int i = 0; i < n; i++) + { + if (indices[i] == -1) + continue; // skip dups + else + Serial.println(WiFi.SSID(indices[i])); + } +#endif + + return (n); + } +} + +////////////////////////////////////////// + +int ESP_WiFiManager::getRSSIasQuality(int RSSI) +{ + int quality = 0; + + if (RSSI <= -100) + { + quality = 0; + } + else if (RSSI >= -50) + { + quality = 100; + } + else + { + quality = 2 * (RSSI + 100); + } + + return quality; +} + +////////////////////////////////////////// + +/** Is this an IP? */ +boolean ESP_WiFiManager::isIp(String str) +{ + for (int i = 0; i < str.length(); i++) + { + int c = str.charAt(i); + + if (c != '.' && (c < '0' || c > '9')) + { + return false; + } + } + return true; +} + +////////////////////////////////////////// + +/** IP to String? */ +String ESP_WiFiManager::toStringIp(IPAddress ip) +{ + String res = ""; + for (int i = 0; i < 3; i++) + { + res += String((ip >> (8 * i)) & 0xFF) + "."; + } + + res += String(((ip >> 8 * 3)) & 0xFF); + + return res; +} + +////////////////////////////////////////// + +#ifdef ESP32 +// We can't use WiFi.SSID() in ESP32 as it's only valid after connected. +// SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot +// Have to create a new function to store in EEPROM/SPIFFS for this purpose + +String ESP_WiFiManager::getStoredWiFiSSID() +{ + if (WiFi.getMode() == WIFI_MODE_NULL) + { + return String(); + } + + wifi_ap_record_t info; + + if (!esp_wifi_sta_get_ap_info(&info)) + { + return String(reinterpret_cast(info.ssid)); + } + else + { + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + return String(reinterpret_cast(conf.sta.ssid)); + } + + return String(); +} + +////////////////////////////////////////// + +String ESP_WiFiManager::getStoredWiFiPass() +{ + if (WiFi.getMode() == WIFI_MODE_NULL) + { + return String(); + } + + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + + return String(reinterpret_cast(conf.sta.password)); +} +#endif + + +//#endif //ESP_WiFiManager_Impl_h diff --git a/src_h/ESP_WiFiManager.h b/src_h/ESP_WiFiManager.h new file mode 100644 index 0000000..1f76314 --- /dev/null +++ b/src_h/ESP_WiFiManager.h @@ -0,0 +1,546 @@ +/**************************************************************************************************************************** + ESP_WiFiManager.h + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. + *****************************************************************************************************************************/ + +#pragma once + +#include "ESP_WiFiManager_Debug.h" + +//KH, for ESP32 +#ifdef ESP8266 + #include + #include +#else //ESP32 + #include + #include +#endif + +#include +#include +#undef min +#undef max +#include + +//KH, for ESP32 +#ifdef ESP8266 + extern "C" + { + #include "user_interface.h" + } + + #define ESP_getChipId() (ESP.getChipId()) +#else //ESP32 + #include + #define ESP_getChipId() ((uint32_t)ESP.getEfuseMac()) +#endif + +#define WFM_LABEL_BEFORE 1 +#define WFM_LABEL_AFTER 2 +#define WFM_NO_LABEL 0 + +/** Handle CORS in pages */ +// Default false for using only whenever necessary to avoid security issue when using CORS (Cross-Origin Resource Sharing) +#ifndef USING_CORS_FEATURE + // Contributed by AlesSt (https://github.com/AlesSt) to solve AJAX CORS protection problem of API redirects on client side + // See more in https://github.com/khoih-prog/ESP_WiFiManager/issues/27 and https://en.wikipedia.org/wiki/Cross-origin_resource_sharing + #define USING_CORS_FEATURE false +#endif + +//KH +//Mofidy HTTP_HEAD to WM_HTTP_HEAD_START to avoid conflict in Arduino esp8266 core 2.6.0+ +const char WM_HTTP_200[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; +const char WM_HTTP_HEAD_START[] PROGMEM = "{v}"; + +// KH, update from v1.0.10 +const char WM_HTTP_STYLE[] PROGMEM = ""; +////// + +// KH, update from v1.1.0 +const char WM_HTTP_SCRIPT[] PROGMEM = ""; +////// + +// From v1.0.9 to permit disable or configure NTP from sketch +#ifndef USE_ESP_WIFIMANAGER_NTP + // From v1.0.6 to enable NTP config + #define USE_ESP_WIFIMANAGER_NTP true +#endif + +#if USE_ESP_WIFIMANAGER_NTP + +const char WM_HTTP_SCRIPT_NTP_MSG[] PROGMEM = "

Your timezone is :

"; + +// From v1.0.9 to permit disable or configure NTP from sketch +#ifndef USE_CLOUDFLARE_NTP + #define USE_CLOUDFLARE_NTP false +#endif + +#if USE_CLOUDFLARE_NTP +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#else +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#endif + +#else +const char WM_HTTP_SCRIPT_NTP_MSG[] PROGMEM = ""; +const char WM_HTTP_SCRIPT_NTP[] PROGMEM = ""; +#endif + +// KH, update from v1.0.10 +const char WM_HTTP_HEAD_END[] PROGMEM = "
"; + +const char WM_FLDSET_START[] PROGMEM = "
"; +const char WM_FLDSET_END[] PROGMEM = "
"; +////// + +const char WM_HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; +const char WM_HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; +const char JSON_ITEM[] PROGMEM = "{\"SSID\":\"{v}\", \"Encryption\":{i}, \"Quality\":\"{r}\"}"; + +// KH, update from v1.1.0 +const char WM_HTTP_FORM_START[] PROGMEM = "
"; +////// + +// KH, add from v1.0.10 +const char WM_HTTP_FORM_LABEL_BEFORE[] PROGMEM = "
"; +const char WM_HTTP_FORM_LABEL_AFTER[] PROGMEM = "
"; +////// + +const char WM_HTTP_FORM_LABEL[] PROGMEM = ""; +const char WM_HTTP_FORM_PARAM[] PROGMEM = ""; + +const char WM_HTTP_FORM_END[] PROGMEM = "
"; + +// KH, update from v1.1.0 +const char WM_HTTP_SAVED[] PROGMEM = "
Credentials Saved
Try connecting ESP to the {x}/{x1} network. Wait around 10 seconds then check if it's OK.

The {v} AP will run on the same WiFi channel of the {x}/{x1} AP. You may have to manually reconnect to the {v} AP.

"; +////// + +const char WM_HTTP_END[] PROGMEM = "
"; + +//KH, from v1.1.0 +const char WM_HTTP_HEAD_CL[] PROGMEM = "Content-Length"; +const char WM_HTTP_HEAD_CT[] PROGMEM = "text/html"; +const char WM_HTTP_HEAD_CT2[] PROGMEM = "text/plain"; + +//KH Add repeatedly used const +const char WM_HTTP_CACHE_CONTROL[] PROGMEM = "Cache-Control"; +const char WM_HTTP_NO_STORE[] PROGMEM = "no-cache, no-store, must-revalidate"; +const char WM_HTTP_PRAGMA[] PROGMEM = "Pragma"; +const char WM_HTTP_NO_CACHE[] PROGMEM = "no-cache"; +const char WM_HTTP_EXPIRES[] PROGMEM = "Expires"; +const char WM_HTTP_CORS[] PROGMEM = "Access-Control-Allow-Origin"; +const char WM_HTTP_CORS_ALLOW_ALL[] PROGMEM = "*"; + +#if USE_AVAILABLE_PAGES +const char WM_HTTP_AVAILABLE_PAGES[] PROGMEM = "

Available Pages

PageFunction
/Menu page.
/wifiShow WiFi scan results and enter WiFi configuration.
/wifisaveSave WiFi configuration information and configure device. Needs variables supplied.
/closeClose the configuration server and configuration WiFi network.
/iThis page.
/rDelete WiFi configuration and reboot. ESP device will not reconnect to a network until new WiFi configuration data is entered.
/stateCurrent device state in JSON format. Interface for programmatic WiFi configuration.
/scanRun a WiFi scan and return results in JSON format. Interface for programmatic WiFi configuration.
"; +#else +const char WM_HTTP_AVAILABLE_PAGES[] PROGMEM = ""; +#endif + +//KH +#define WIFI_MANAGER_MAX_PARAMS 20 + +// Thanks to @Amorphous for the feature and code, from v1.0.5 +// (https://community.blynk.cc/t/esp-wifimanager-for-esp32-and-esp8266/42257/13) +// Form v1.0.10, enable to configure from sketch +#ifndef USE_CONFIGURABLE_DNS + #define USE_CONFIGURABLE_DNS true +#endif + + +class ESP_WMParameter +{ + public: + ESP_WMParameter(const char *custom); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); + ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement); + + ~ESP_WMParameter(); + + const char *getID(); + const char *getValue(); + const char *getPlaceholder(); + int getValueLength(); + int getLabelPlacement(); + const char *getCustomHTML(); + private: + const char *_id; + const char *_placeholder; + char *_value; + int _length; + int _labelPlacement; + const char *_customHTML; + + void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement); + + friend class ESP_WiFiManager; +}; + +#define USE_DYNAMIC_PARAMS true +#define DEFAULT_PORTAL_TIMEOUT 60000L + +// From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. +// You have to explicitly specify false to disable the feature. +#ifndef USE_STATIC_IP_CONFIG_IN_CP + #define USE_STATIC_IP_CONFIG_IN_CP true +#endif + +class ESP_WiFiManager +{ + public: + + ESP_WiFiManager(const char *iHostname = ""); + + ~ESP_WiFiManager(); + + // Update feature from v1.0.11. Can use with STA staticIP now + boolean autoConnect(); + boolean autoConnect(char const *apName, char const *apPassword = NULL); + ////// + + //if you want to start the config portal + boolean startConfigPortal(); + boolean startConfigPortal(char const *apName, char const *apPassword = NULL); + + // get the AP name of the config portal, so it can be used in the callback + String getConfigPortalSSID(); + // get the AP password of the config portal, so it can be used in the callback + String getConfigPortalPW(); + + void resetSettings(); + + //sets timeout before webserver loop ends and exits even if there has been no setup. + //usefully for devices that failed to connect at some point and got stuck in a webserver loop + //in seconds setConfigPortalTimeout is a new name for setTimeout + void setConfigPortalTimeout(unsigned long seconds); + void setTimeout(unsigned long seconds); + + //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects + void setConnectTimeout(unsigned long seconds); + + + void setDebugOutput(boolean debug); + //defaults to not showing anything under 8% signal quality if called + void setMinimumSignalQuality(int quality = 8); + + // KH, new from v1.0.10 to enable dynamic/random channel + int setConfigPortalChannel(int channel = 1); + ////// + + //sets a custom ip /gateway /subnet configuration + void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); + //sets config for a static IP + void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); + +#if USE_CONFIGURABLE_DNS + void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn, + IPAddress dns_address_1, IPAddress dns_address_2); +#endif + + //called when AP mode and config portal is started + void setAPCallback(void(*func)(ESP_WiFiManager*)); + //called when settings have been changed and connection was successful + void setSaveConfigCallback(void(*func)(void)); + +#if USE_DYNAMIC_PARAMS + //adds a custom parameter + bool addParameter(ESP_WMParameter *p); +#else + //adds a custom parameter + void addParameter(ESP_WMParameter *p); +#endif + + //if this is set, it will exit after config, even if connection is unsucessful. + void setBreakAfterConfig(boolean shouldBreak); + //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) + //TODO + //if this is set, customise style + void setCustomHeadElement(const char* element); + //if this is true, remove duplicated Access Points - defaut true + void setRemoveDuplicateAPs(boolean removeDuplicates); + //Scan for WiFiNetworks in range and sort by signal strength + //space for indices array allocated on the heap and should be freed when no longer required + int scanWifiNetworks(int **indicesptr); + + // return SSID of router in STA mode got from config portal. NULL if no user's input //KH + String getSSID(void) + { + return _ssid; + } + + // return password of router in STA mode got from config portal. NULL if no user's input //KH + String getPW(void) + { + return _pass; + } + + // New from v1.1.0 + // return SSID of router in STA mode got from config portal. NULL if no user's input //KH + String getSSID1(void) + { + return _ssid1; + } + + // return password of router in STA mode got from config portal. NULL if no user's input //KH + String getPW1(void) + { + return _pass1; + } + + #define MAX_WIFI_CREDENTIALS 2 + + String getSSID(uint8_t index) + { + if (index == 0) + return _ssid; + else if (index == 1) + return _ssid1; + else + return String(""); + } + + String getPW(uint8_t index) + { + if (index == 0) + return _pass; + else if (index == 1) + return _pass1; + else + return String(""); + } + ////// + + // New from v1.1.1, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + void setCORSHeader(const char* CORSHeaders) + { + _CORS_Header = CORSHeaders; + + LOGWARN1(F("Set CORS Header to : "), _CORS_Header); + } + + const char* getCORSHeader(void) + { + return _CORS_Header; + } +#endif + + //returns the list of Parameters + ESP_WMParameter** getParameters(); + // returns the Parameters Count + int getParametersCount(); + + const char* getStatus(int status); + +#ifdef ESP32 + String getStoredWiFiSSID(); + String getStoredWiFiPass(); +#endif + + String WiFi_SSID(void) + { +#ifdef ESP8266 + return WiFi.SSID(); +#else + return getStoredWiFiSSID(); +#endif + } + + String WiFi_Pass(void) + { +#ifdef ESP8266 + return WiFi.psk(); +#else + return getStoredWiFiPass(); +#endif + } + + void setHostname(void) + { + if (RFC952_hostname[0] != 0) + { +#ifdef ESP8266 + WiFi.hostname(RFC952_hostname); +#else //ESP32 + // See https://github.com/espressif/arduino-esp32/issues/2537 + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(RFC952_hostname); +#endif + } + } + + private: + std::unique_ptr dnsServer; + + //KH, for ESP32 +#ifdef ESP8266 + std::unique_ptr server; +#else //ESP32 + std::unique_ptr server; +#endif + +#define RFC952_HOSTNAME_MAXLEN 24 + char RFC952_hostname[RFC952_HOSTNAME_MAXLEN + 1]; + + char* getRFC952_hostname(const char* iHostname); + + void setupConfigPortal(); + void startWPS(); + //const char* getStatus(int status); + + const char* _apName = "no-net"; + const char* _apPassword = NULL; + + String _ssid = ""; + String _pass = ""; + + // New from v1.1.0 + String _ssid1 = ""; + String _pass1 = ""; + ////// + + // From v1.0.6 with timezone info + String _timezoneName = ""; + + unsigned long _configPortalTimeout = 0; + + unsigned long _connectTimeout = 0; + unsigned long _configPortalStart = 0; + + int numberOfNetworks; + int *networkIndices; + + // KH, new from v1.0.10 to enable dynamic/random channel + // default to channel 1 + #define MIN_WIFI_CHANNEL 1 + #define MAX_WIFI_CHANNEL 11 // Channel 12,13 is flaky, because of bad number 13 ;-) + + int _WiFiAPChannel = 1; + ////// + + IPAddress _ap_static_ip; + IPAddress _ap_static_gw; + IPAddress _ap_static_sn; + IPAddress _sta_static_ip = IPAddress(0, 0, 0, 0); + IPAddress _sta_static_gw; + IPAddress _sta_static_sn; + +#if USE_CONFIGURABLE_DNS + IPAddress _sta_static_dns1; + IPAddress _sta_static_dns2; +#endif + + int _paramsCount = 0; + int _minimumQuality = -1; + boolean _removeDuplicateAPs = true; + boolean _shouldBreakAfterConfig = false; + boolean _tryWPS = false; + + const char* _customHeadElement = ""; + + int status = WL_IDLE_STATUS; + + // New from v1.1.0, for configure CORS Header, default to WM_HTTP_CORS_ALLOW_ALL = "*" +#if USING_CORS_FEATURE + const char* _CORS_Header = WM_HTTP_CORS_ALLOW_ALL; //"*"; +#endif + ////// + + // New v1.0.8 + void setWifiStaticIP(void); + + // New v1.1.0 + int reconnectWifi(void); + ////// + + // New v1.0.11 + int connectWifi(String ssid = "", String pass = ""); + ////// + + uint8_t waitForConnectResult(); + + void handleRoot(); + void handleWifi(); + void handleWifiSave(); + void handleServerClose(); + void handleInfo(); + void handleState(); + void handleScan(); + void handleReset(); + void handleNotFound(); + boolean captivePortal(); + void reportStatus(String &page); + + // DNS server + const byte DNS_PORT = 53; + + //helpers + int getRSSIasQuality(int RSSI); + boolean isIp(String str); + String toStringIp(IPAddress ip); + + boolean connect; + boolean stopConfigPortal = false; + boolean _debug = false; //true; + + void(*_apcallback)(ESP_WiFiManager*) = NULL; + void(*_savecallback)(void) = NULL; + +#if USE_DYNAMIC_PARAMS + int _max_params; + ESP_WMParameter** _params; +#else + ESP_WMParameter* _params[WIFI_MANAGER_MAX_PARAMS]; +#endif + + template + void DEBUG_WM(Generic text); + + template + auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s)) { + return obj->fromString(s); + } + auto optionalIPFromString(...) -> bool { + LOGINFO("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); + return false; + } +}; + +#include "ESP_WiFiManager-Impl.h" + diff --git a/src_h/ESP_WiFiManager_Debug.h b/src_h/ESP_WiFiManager_Debug.h new file mode 100644 index 0000000..7d77669 --- /dev/null +++ b/src_h/ESP_WiFiManager_Debug.h @@ -0,0 +1,87 @@ +/**************************************************************************************************************************** + ESP_WiFiManager_Debug.h + For ESP8266 / ESP32 boards + + ESP_WiFiManager is a library for the ESP8266/Arduino platform + (https://github.com/esp8266/Arduino) to enable easy + configuration and reconfiguration of WiFi credentials using a Captive Portal + inspired by: + http://www.esp8266.com/viewtopic.php?f=29&t=2520 + https://github.com/chriscook8/esp-arduino-apboot + https://github.com/esp8266/Arduino/blob/master/libraries/DNSServer/examples/CaptivePortalAdvanced/ + + Modified from Tzapu https://github.com/tzapu/WiFiManager + and from Ken Taylor https://github.com/kentaylor + + Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager + Licensed under MIT license + Version: 1.2.0 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 07/10/2019 Initial coding + 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 + 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. + 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples + 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. + 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc + 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) + 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md + 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ + 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. + Add, enhance examples (fix MDNS for ESP32) + 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. + 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. + 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime + 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. + 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. + 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. + *****************************************************************************************************************************/ + +#pragma once + +//#ifndef ESP_WiFiManager_Debug_H +//#define ESP_WiFiManager_Debug_H + +#ifdef WIFIMGR_DEBUG_PORT + #define DBG_PORT WIFIMGR_DEBUG_PORT +#else + #define DBG_PORT Serial +#endif + +// Change _WIFIMGR_LOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _WIFIMGR_LOGLEVEL_ + #define _WIFIMGR_LOGLEVEL_ 0 +#endif + +#define LOGERROR(x) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGERROR0(x) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print(x); } +#define LOGERROR1(x,y) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGERROR2(x,y,z) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGERROR3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>0) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGWARN(x) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGWARN0(x) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print(x); } +#define LOGWARN1(x,y) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGWARN2(x,y,z) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGWARN3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>1) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGINFO(x) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGINFO0(x) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print(x); } +#define LOGINFO1(x,y) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGINFO2(x,y,z) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGINFO3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>2) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +#define LOGDEBUG(x) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.println(x); } +#define LOGDEBUG0(x) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print(x); } +#define LOGDEBUG1(x,y) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.println(y); } +#define LOGDEBUG2(x,y,z) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.println(z); } +#define LOGDEBUG3(x,y,z,w) if(_WIFIMGR_LOGLEVEL_>3) { DBG_PORT.print("[WM] "); DBG_PORT.print(x); DBG_PORT.print(" "); DBG_PORT.print(y); DBG_PORT.print(" "); DBG_PORT.print(z); DBG_PORT.print(" "); DBG_PORT.println(w); } + +//#endif //ESP_WiFiManager_Debug_H