/**************************************************************************************************************************** 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"