# ESP_WiFiManager [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP_WiFiManager.svg?)](https://www.ardu-badge.com/ESP_WiFiManager) [![GitHub release](https://img.shields.io/github/release/khoih-prog/ESP_WiFiManager.svg)](https://github.com/khoih-prog/ESP_WiFiManager/releases) [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/ESP_WiFiManager/blob/master/LICENSE) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) [![GitHub issues](https://img.shields.io/github/issues/khoih-prog/ESP_WiFiManager.svg)](http://github.com/khoih-prog/ESP_WiFiManager/issues) [![star this repo](https://githubbadges.com/star.svg?user=khoih-prog&repo=ESP_WiFiManager&style=default)](https://github.com/khoih-prog/ESP_WiFiManager) --- --- ### Important Note This [**ESP_WiFiManager**](https://github.com/khoih-prog/ESP_WiFiManager) has just been modified to create the new [**ESPAsync_WiFiManager Library**](https://github.com/khoih-prog/ESPAsync_WiFiManager) in order to use the better and more efficient [**ESPAsyncWebServer Library**](https://github.com/me-no-dev/ESPAsyncWebServer), instead of the (ESP8266)WebServer library. The new [**ESPAsync_WiFiManager** library](https://github.com/khoih-prog/ESPAsync_WiFiManager) is based on and sync'ed with [**ESP_WiFiManager**](https://github.com/khoih-prog/ESP_WiFiManager). Therefore, all the features currently supported by this [**ESP_WiFiManager**](https://github.com/khoih-prog/ESP_WiFiManager) will be available to the new library. The code change is to port to the new library is also very negligible, **mostly just changing the Class name from ESP_WiFiManager to ESPAsync_WiFiManager.** #### Why do we need the new Async [ESPAsync_WiFiManager library](https://github.com/khoih-prog/ESPAsync_WiFiManager) - Using asynchronous network means that you can handle **more than one connection at the same time** - **You are called once the request is ready and parsed** - When you send the response, you are **immediately ready** to handle other connections while the server is taking care of sending the response in the background - **Speed is OMG** - **Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse** - Easily extendible to handle **any type of content** - Supports Continue 100 - **Async WebSocket plugin offering different locations without extra servers or ports** - Async EventSource (Server-Sent Events) plugin to send events to the browser - URL Rewrite plugin for conditional and permanent url rewrites - ServeStatic plugin that supports cache, Last-Modified, default index and more - Simple template processing engine to handle templates To appreciate the power of the [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) and underlying Async libraries, please compare the more efficient [Async_ESP32_FSWebServer example](https://github.com/khoih-prog/ESPAsync_WiFiManager/tree/master/examples/Async_ESP32_FSWebServer) example code against the code of its complicated twin [ESP32_FSWebServer](examples/ESP32_FSWebServer). Thanks to [cancodr](https://github.com/cancodr) for requesting an enhancement in [Issue #29: Is it possible to use AsyncWebServer.h instead of WebServer.h?](https://github.com/khoih-prog/ESP_WiFiManager/issues/29), leading to the new [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager). --- --- ### 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). Also have a look at [**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. 2. Add example. ### Releases v1.1.1 1. Add setCORSHeader function to allow **configurable CORS Header**. See [Using CORS feature](https://github.com/khoih-prog/ESP_WiFiManager#15-using-cors-cross-origin-resource-sharing-feature) 2. Fix typo and minor improvement. 3. Shorten MultiWiFi connection time. ### Major Releases v1.1.0 1. Add **MultiWiFi feature to auto(Re)connect to the best WiFi at runtime** 2. Fix bug. 3. Completely enhanced examples to use new MultiWiFi feature. #### Releases v1.0.11 1. Add optional **CORS (Cross-Origin Resource Sharing)** feature. Thanks to [AlesSt](https://github.com/AlesSt). See more in [Issue #27: CORS protection fires up with AJAX](https://github.com/khoih-prog/ESP_WiFiManager/issues/27) and [Cross Origin Resource Sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing). To use, you must explicitly use `#define USING_CORS_FEATURE true` 2. Solve issue softAP with custom IP sometimes not working. Thanks to [AlesSt](https://github.com/AlesSt). See [Issue #26: softAP with custom IP not working](https://github.com/khoih-prog/ESP_WiFiManager/issues/26) and [Wifi.softAPConfig() sometimes set the wrong IP address](https://github.com/espressif/arduino-esp32/issues/985). 3. Temporary fix for issue of not clearing WiFi SSID/PW from flash of ESP32. Thanks to [AlesSt](https://github.com/AlesSt). See more in [Issue #25: API call /r doesnt clear credentials](https://github.com/khoih-prog/ESP_WiFiManager/issues/25) and [WiFi.disconnect(true) problem](https://github.com/espressif/arduino-esp32/issues/400). 4. Fix autoConnect() feature to permit autoConnect() to use STA static IP or DHCP IP. Remove from deprecated function list. 5. Enhance README.md with more instructions and illustrations. #### Releases v1.0.10 1. Don't need to reinput already working SSID in Config Port to update other parameters, such as StaticIP. 2. Disable/Enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. 3. Change HTTP_XYZ constants to WM_HTTP_XYZ to avoid conflicts with future releases of ESP32 and ESP8266 cores. 4. Add feature to change WiFi AP channel (fixed or random) to avoid conflict in AP-overcrowded environments. 5. Enhance Config Portal GUI and get the item out of the bucket list. 6. Enhance README.md with more instructions and illustrations. #### Releases v1.0.9 1. Fix ESP32 STAstaticIP bug. 2. Enable changing from DHCP <-> static IP using Config Portal. 3. Enable NTP configuration from sketch (USE_ESP_WIFIMANAGER_NTP, USE_CLOUDFLARE_NTP). See Issue #21: [CloudFlare link in the default portal](https://github.com/khoih-prog/ESP_WiFiManager/issues/21). 4. Add, enhance examples (fix MDNS for ESP32 examples, add DRD feature). #### Releases v1.0.8 1. Fix setSTAStaticIPConfig issue. See [Static Station IP doesn't work](https://github.com/khoih-prog/ESP_WiFiManager/issues/17) 2. Add LittleFS support for ESP8266 core 2.7.1+ in examples to replace deprecated SPIFFS. 3. Restructure code. #### Releases v1.0.7 1. Use `just-in-time` scanWiFiNetworks() to reduce connection time necessary for battery-operated DeepSleep application. Thanks to [CrispinP](https://github.com/CrispinP) for identifying, requesting and testing. See [Starting WiFIManger is very slow (2000ms)](https://github.com/khoih-prog/ESP_WiFiManager/issues/6) 2. Fix bug relating SPIFFS in examples : - [ConfigOnSwitchFS](examples/ConfigOnSwitchFS) - [ConfigPortalParamsOnSwitch](examples/ConfigPortalParamsOnSwitch) (now support ArduinoJson 6.0.0+ as well as 5.13.5-) - [AutoConnectWithFSParameters](examples/AutoConnectWithFSParameters) See [Having issue to read the SPIFF file](https://github.com/khoih-prog/ESP_WiFiManager/issues/14), Thanks to [OttoKlaasen](https://github.com/OttoKlaasen) to report. 3. Fix [README](README.md). See [Accessing manager after connection](https://github.com/khoih-prog/ESP_WiFiManager/issues/15) #### Releases v1.0.6 1. Add function getConfigPortalPW() 2. Add 4 new complicated examples compatible with ArduinoJson 6.0.0+ :[AutoConnect](examples/AutoConnect), [AutoConnectWithFeedback](examples/AutoConnectWithFeedback), [AutoConnectWithFeedbackLED](examples/AutoConnectWithFeedbackLED) and [AutoConnectWithFSParameters](examples/AutoConnectWithFSParameters) --- --- This library is based on, modified, bug-fixed and improved from: 1. [`Tzapu WiFiManager`](https://github.com/tzapu/WiFiManager) 2. [`Ken Taylor WiFiManager`](https://github.com/kentaylor/WiFiManager) to add support to `ESP32` besides `ESP8266`. This is an `ESP32 / ESP8266` WiFi Connection manager with fallback web ConfigPortal. It's using a web ConfigPortal, served from the `ESP32 / ESP8266`, and operating as an access point. --- --- ## Prerequisite 1. [`Arduino IDE 1.8.13+` for Arduino](https://www.arduino.cc/en/Main/Software) 2. [`ESP8266 Core 2.7.4+`](https://github.com/esp8266/Arduino) for ESP8266-based boards. 3. [`ESP32 Core 1.0.4+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards 4. [`ESP_DoubleResetDetector v1.0.3+`](https://github.com/khoih-prog/ESP_DoubleResetDetector) if using DRD feature. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP_DoubleResetDetector.svg?)](https://www.ardu-badge.com/ESP_DoubleResetDetector). --- ## Installation ### Use Arduino Library Manager The best and easiest way is to use `Arduino Library Manager`. Search for `ESP_WiFiManager`, then select / install the latest version. You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP_WiFiManager.svg?)](https://www.ardu-badge.com/ESP_WiFiManager) for more detailed instructions. ### Manual Install 1. Navigate to [ESP_WiFiManager](https://github.com/khoih-prog/ESP_WiFiManager) page. 2. Download the latest release `ESP_WiFiManager-master.zip`. 3. Extract the zip file to `ESP_WiFiManager-master` directory 4. Copy the whole `ESP_WiFiManager-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. ### VS Code & PlatformIO: 1. Install [VS Code](https://code.visualstudio.com/) 2. Install [PlatformIO](https://platformio.org/platformio-ide) 3. Install **ESP_WiFiManager** library by using [Library Manager](https://docs.platformio.org/en/latest/librarymanager/). Search for ***ESP_WiFiManager*** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) 4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) --- --- ### 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 2 more source directories 1. **scr_h** for new h-only files 2. **src_cpp** for standard h/cpp files 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. - The concept of ConfigOnSwitch is that a new `ESP32 / ESP8266` will start a WiFi ConfigPortal when powered up and save the configuration data in non volatile memory. Thereafter, the ConfigPortal will only be started again if a button is pushed on the `ESP32 / ESP8266` module. - Using any WiFi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point (AP) using configurable SSID and Password (specified in sketch) ```cpp // SSID and PW for Config Portal String ssid = "ESP_" + String(ESP_getChipId(), HEX); const char* password = "your_password"; ``` then connect WebBrowser to configurable ConfigPortal IP address, default is 192.168.4.1 - Choose one of the access points scanned, enter password, click ***Save***. - ESP will restart, then try to connect to the WiFi netwotk using STA-only mode, ***without running the ConfigPortal WebServer and WiFi AP***. See [Accessing manager after connection](https://github.com/khoih-prog/ESP_WiFiManager/issues/15). --- --- ### HOWTO Basic configurations #### 1. Using default for every configurable parameter - Include in your sketch ```cpp #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 ////// #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 #endif // SSID and PW for Config Portal String ssid = "ESP_" + String(ESP_getChipId(), HEX); const char* password = "your_password"; // SSID and PW for your Router String Router_SSID; String Router_Pass; // From v1.1.0 // You only need to format the filesystem once //#define FORMAT_FILESYSTEM true #define FORMAT_FILESYSTEM false #define MIN_AP_PASSWORD_SIZE 8 #define SSID_MAX_LEN 32 //From v1.0.10, WPA2 passwords can be up to 63 characters long. #define PASS_MAX_LEN 64 typedef struct { char wifi_ssid[SSID_MAX_LEN]; char wifi_pw [PASS_MAX_LEN]; } WiFi_Credentials; typedef struct { String wifi_ssid; String wifi_pw; } WiFi_Credentials_String; #define NUM_WIFI_CREDENTIALS 2 typedef struct { WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; } WM_Config; WM_Config WM_config; #define CONFIG_FILENAME F("/wifi_cred.dat") ////// #include //https://github.com/khoih-prog/ESP_WiFiManager ``` --- #### 2. Using many configurable parameters - Include in your sketch ```cpp #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 ////// #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 #endif // SSID and PW for Config Portal String ssid = "ESP_" + String(ESP_getChipId(), HEX); const char* password = "your_password"; // SSID and PW for your Router String Router_SSID; String Router_Pass; // From v1.1.0 // You only need to format the filesystem once //#define FORMAT_FILESYSTEM true #define FORMAT_FILESYSTEM false #define MIN_AP_PASSWORD_SIZE 8 #define SSID_MAX_LEN 32 //From v1.0.10, WPA2 passwords can be up to 63 characters long. #define PASS_MAX_LEN 64 typedef struct { char wifi_ssid[SSID_MAX_LEN]; char wifi_pw [PASS_MAX_LEN]; } WiFi_Credentials; typedef struct { String wifi_ssid; String wifi_pw; } WiFi_Credentials_String; #define NUM_WIFI_CREDENTIALS 2 typedef struct { WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; } WM_Config; WM_Config WM_config; #define CONFIG_FILENAME F("/wifi_cred.dat") ////// // Indicates whether ESP has WiFi credentials saved from previous session bool initialConfig = false; // Use false if you don't like to display Available Pages in Information Page of Config Portal // Comment out or use true to display Available Pages in Information Page of Config Portal // Must be placed before #include #define USE_AVAILABLE_PAGES false // 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. //#define USE_STATIC_IP_CONFIG_IN_CP false // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP false // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) #define USE_CLOUDFLARE_NTP false // New in v1.0.11 #define USING_CORS_FEATURE true ////// // 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 #else // 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); #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); #endif #define USE_CONFIGURABLE_DNS true IPAddress dns1IP = gatewayIP; IPAddress dns2IP = IPAddress(8, 8, 8, 8); #include //https://github.com/khoih-prog/ESP_WiFiManager ``` --- #### 3. Using STA-mode DHCP, but don't like to change to static IP or display in Config Portal ```cpp // 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. #define USE_STATIC_IP_CONFIG_IN_CP false ``` --- #### 4. Using STA-mode DHCP, but permit to change to static IP and display in Config Portal ```cpp // 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. //#define USE_STATIC_IP_CONFIG_IN_CP 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 #else // You can select DHCP or Static IP here #define USE_DHCP_IP true #endif ``` --- #### 5. Using STA-mode StaticIP, and be able to change to DHCP IP and display in Config Portal ```cpp // 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. //#define USE_STATIC_IP_CONFIG_IN_CP 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 #else // You can select DHCP or Static IP here #define USE_DHCP_IP false #endif ``` --- #### 6. Using STA-mode StaticIP and configurable DNS, and be able to change to DHCP IP and display in Config Portal ```cpp // 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. //#define USE_STATIC_IP_CONFIG_IN_CP 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 #else // You can select DHCP or Static IP here #define USE_DHCP_IP false #endif #define USE_CONFIGURABLE_DNS true IPAddress dns1IP = gatewayIP; IPAddress dns2IP = IPAddress(8, 8, 8, 8); ``` --- #### 7. Using STA-mode StaticIP and auto DNS, and be able to change to DHCP IP and display in Config Portal ```cpp // 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. //#define USE_STATIC_IP_CONFIG_IN_CP 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 #else // You can select DHCP or Static IP here #define USE_DHCP_IP false #endif #define USE_CONFIGURABLE_DNS false ``` --- #### 8. Not using NTP to avoid issue with some WebBrowsers, especially in CellPhone or Tablets. ```cpp // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP false ``` --- #### 9. Using NTP feature with CloudFlare. System can hang until you have Internet access for CloudFlare. ```cpp // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP true // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) #define USE_CLOUDFLARE_NTP true ``` --- #### 10. Using NTP feature without CloudFlare to avoid system hang if no Internet access for CloudFlare. ```cpp // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP true // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) #define USE_CLOUDFLARE_NTP false ``` --- #### 11. Using random AP-mode channel to avoid conflict ```cpp // From v1.0.10 only // Set config portal channel, default = 1. Use 0 => random channel from 1-13 ESP_wifiManager.setConfigPortalChannel(0); ////// ``` --- #### 12. Using fixed AP-mode channel, for example channel 3 ```cpp // From v1.0.10 only // Set config portal channel, default = 1. Use 0 => random channel from 1-13 ESP_wifiManager.setConfigPortalChannel(3); ////// ``` --- #### 13. Setting STA-mode static IP ```cpp // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP); ``` --- #### 14. Using AUTOCONNECT_NO_INVALIDATE feature 1. Don't invalidate WiFi SSID/PW when calling autoConnect() (default) ```cpp #define AUTOCONNECT_NO_INVALIDATE true ``` 2. To invalidate WiFi SSID/PW when calling autoConnect() ```cpp #define AUTOCONNECT_NO_INVALIDATE false ``` --- #### 15. Using CORS (Cross-Origin Resource Sharing) feature 1. To use CORS feature with **default** CORS Header "*". Some WebBrowsers won't accept this allowing-all "*" CORS Header. ```cpp // Default false for using only whenever necessary to avoid security issue #define USING_CORS_FEATURE true ``` 2. To use CORS feature with specific CORS Header "Your Access-Control-Allow-Origin". **To be modified** according to your specific Allowed-Origin. ```cpp // Default false for using only whenever necessary to avoid security issue #define USING_CORS_FEATURE true ... // New from v1.1.1 #if USING_CORS_FEATURE ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); #endif ``` 3. Not use CORS feature (default) ```cpp // Default false for using only whenever necessary to avoid security issue #define USING_CORS_FEATURE false ``` --- #### 16. Using MultiWiFi auto(Re)connect feature 1. In loop() ```cpp void check_WiFi(void) { if ( (WiFi.status() != WL_CONNECTED) ) { Serial.println("\nWiFi lost. Call connectMultiWiFi in loop"); connectMultiWiFi(); } } void check_status(void) { static ulong checkwifi_timeout = 0; static ulong current_millis; #define WIFICHECK_INTERVAL 1000L current_millis = millis(); // Check WiFi every WIFICHECK_INTERVAL (1) seconds. if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { check_WiFi(); checkwifi_timeout = current_millis + WIFICHECK_INTERVAL; } } void loop() { // put your main code here, to run repeatedly check_status(); } ``` --- --- ### HOWTO Open Config Portal - When you want to open a config portal, with default DHCP hostname `ESP8266-XXXXXX` or `ESP32-XXXXXX`, just add ```cpp ESP_WiFiManager ESP_wifiManager; ``` If you'd like to have a personalized hostname `(RFC952-conformed,- 24 chars max,- only a..z A..Z 0..9 '-' and no '-' as last char)` add ```cpp ESP_WiFiManager ESP_wifiManager("Personalized-HostName"); ``` then later call ```cpp ESP_wifiManager.startConfigPortal() ``` While in AP mode, connect to it using its `SSID` (ESP_XXXXXX) / `Password` ("your_password"), then open a browser to the AP IP, default `192.168.4.1`, configure wifi then save. The WiFi connection information will be saved in non volatile memory. It will then reboot and autoconnect. You can also change the AP IP by: ```cpp //set custom ip for portal ESP_wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); ``` and use fixed / dynamic / random AP channel by: ```cpp // From v1.0.10 only // Set config portal channel, default = 1. Use 0 => random channel from 1-13 ESP_wifiManager.setConfigPortalChannel(0); ////// ``` Once WiFi network information is saved in the `ESP32 / ESP8266`, it will try to autoconnect to WiFi every time it is started, without requiring any function calls in the sketch. --- --- ### Examples 1. [ConfigOnSwitch](examples/ConfigOnSwitch) 2. [ConfigOnSwitchFS](examples/ConfigOnSwitchFS) 3. [ConfigOnStartup](examples/ConfigOnStartup) 4. [ConfigOnDoubleReset](examples/ConfigOnDoubleReset) (now support ArduinoJson 6.0.0+ as well as 5.13.5-) 5. [ConfigPortalParamsOnSwitch](examples/ConfigPortalParamsOnSwitch) (now support ArduinoJson 6.0.0+ as well as 5.13.5-) 6. [ESP_FSWebServer](examples/ESP_FSWebServer) 7. [ESP_FSWebServer_DRD](examples/ESP_FSWebServer_DRD) 8. [ESP32_FSWebServer](examples/ESP32_FSWebServer) 9. [ESP32_FSWebServer_DRD](examples/ESP32_FSWebServer_DRD) 10. [AutoConnect](examples/AutoConnect) 11. [AutoConnectWithFeedback](examples/AutoConnectWithFeedback) 12. [AutoConnectWithFeedbackLED](examples/AutoConnectWithFeedbackLED) 13. [AutoConnectWithFSParameters](examples/AutoConnectWithFSParameters) 14. [ConfigOnSwitchFS_MQTT_Ptr](examples/ConfigOnSwitchFS_MQTT_Ptr) 15. [ConfigOnDRD_FS_MQTT_Ptr](examples/ConfigOnDRD_FS_MQTT_Ptr). **NEW** --- --- ## So, how it works? In `ConfigPortal Mode`, it starts an access point called `ESP_XXXXXX`. Connect to it using the `configurable password` you can define in the code. For example, `your_password` (see examples): ```cpp // SSID and PW for Config Portal String ssid = "ESP_" + String(ESP_getChipId(), HEX); const char* password = "your_password"; ``` After you connected, please, go to http://192.168.4.1, you'll see this `Main` page:

Select `Information` to enter the Info page where the board info will be shown (long page)

or short page (default)

Select `Configuration` to enter this page where you can select an AP and specify its WiFi Credentials

Enter your credentials, then click ***Save***. The WiFi Credentials will be saved and the board reboots to connect to the selected WiFi AP.

If you're already connected to a listed WiFi AP and don't want to change anything, just select ***Exit Portal*** from the `Main` page to reboot the board and connect to the previously-stored AP. The WiFi Credentials are still intact. --- --- ## Documentation #### Password protect the configuration Access Point You can password protect the ConfigPortal AP. Simply add an SSID as the first parameter and the password as a second parameter to `startConfigPortal`. See the above examples. A short password seems to have unpredictable results so use one that's around 8 characters or more in length. The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal) ```cpp ESP_wifiManager.startConfigPortal( SSID , password ) ``` #### Callbacks ##### Save settings This gets called when custom parameters have been set **AND** a connection has been established. Use it to set a flag, so when all the configuration finishes, you can save the extra parameters somewhere. See [ConfigOnSwitchFS Example](examples/ConfigOnSwitchFS). ```cpp ESP_wifiManager.setSaveConfigCallback(saveConfigCallback); ``` saveConfigCallback declaration and example ```cpp //flag for saving data bool shouldSaveConfig = false; //callback notifying us of the need to save config void saveConfigCallback () { Serial.println("Should save config"); shouldSaveConfig = true; } ``` #### ConfigPortal Timeout If you need to set a timeout so the `ESP32 / ESP8266` doesn't hang waiting to be configured for ever. ```cpp ESP_wifiManager.setConfigPortalTimeout(120); ``` which will wait 2 minutes (120 seconds). When the time passes, the startConfigPortal function will return and continue the sketch, unless you're accessing the Config Portal. In this case, the `startConfigPortal` function will stay until you save config data or exit the Config Portal. #### On Demand ConfigPortal Example usage ```cpp void loop() { // is configuration portal requested? if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW)) { Serial.println("\nConfiguration portal requested."); digitalWrite(PIN_LED, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. //Local intialization. Once its business is done, there is no need to keep it around ESP_WiFiManager ESP_wifiManager("ConfigOnSwitch"); ESP_wifiManager.setMinimumSignalQuality(-1); // From v1.0.10 only // Set config portal channel, default = 1. Use 0 => random channel from 1-13 ESP_wifiManager.setConfigPortalChannel(0); ////// //set custom ip for portal //ESP_wifiManager.setAPStaticIPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255, 255, 255, 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 // New from v1.1.1 #if USING_CORS_FEATURE ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); #endif //Check if there is stored WiFi router/password credentials. //If not found, device will remain in configuration mode until switched off via webserver. Serial.print("Opening configuration portal. "); Router_SSID = ESP_wifiManager.WiFi_SSID(); Router_Pass = ESP_wifiManager.WiFi_Pass(); // From v1.1.0, Don't permit NULL password if ( (Router_SSID != "") && (Router_Pass != "") ) { ESP_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout. Serial.println("Got stored Credentials. Timeout 120s"); } else Serial.println("No stored Credentials. No timeout"); //Starts an access point //and goes into a blocking loop awaiting configuration if (!ESP_wifiManager.startConfigPortal((const char *) ssid.c_str(), password)) { Serial.println("Not connected to WiFi but continuing anyway."); } else { //if you get here you have connected to the WiFi Serial.println("connected...yeey :)"); Serial.print("Local IP: "); Serial.println(WiFi.localIP()); } // Only clear then save data if CP entered and with new valid Credentials // No CP => stored getSSID() = "" if ( String(ESP_wifiManager.getSSID(0)) != "" && String(ESP_wifiManager.getSSID(1)) != "" ) { // 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 strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1); 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); // 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) ) { LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); } } saveConfigData(); } digitalWrite(PIN_LED, LED_OFF); // Turn led off as we are not in configuration mode. } // put your main code here, to run repeatedly check_status(); } ``` See [ConfigOnSwitch](examples/ConfigOnSwitch) example for a more complex version. --- --- #### Custom Parameters Many applications need configuration parameters like `MQTT host and port`, [Blynk](http://www.blynk.cc) or [emoncms](http://emoncms.org) tokens, etc. While it is possible to use `ESP_WiFiManager` to collect additional parameters it is better to read these parameters from a web service once `ESP_WiFiManager` has been used to connect to the internet. To capture other parameters with `ESP_WiFiManager` is a lot more involved than all the other features and requires adding custom HTML to your form. If you want to do it with `ESP_WiFiManager` see the example [ConfigOnSwitchFS](examples/ConfigOnSwitchFS) #### Custom IP Configuration You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state) ##### Custom Access Point IP Configuration This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `startConfigPortal()` ```cpp //set custom ip for portal ESP_wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); ``` ##### Custom Station (client) Static IP Configuration This will use the specified IP configuration instead of using DHCP in station mode. ```cpp ESP_wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0)); ``` #### Custom HTML, CSS, Javascript There are various ways in which you can inject custom HTML, CSS or Javascript into the ConfigPortal. The options are: - inject custom head element You can use this to any html bit to the head of the ConfigPortal. If you add a `"); ``` - inject a custom bit of html in the configuration form ```cpp ESP_WMParameter custom_text("

This is just a text paragraph

"); ESP_wifiManager.addParameter(&custom_text); ``` - inject a custom bit of html in a configuration form element Just add the bit you want added as the last parameter to the custom parameter constructor. ```cpp ESP_WMParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly"); ``` #### Filter Networks You can filter networks based on signal quality and show/hide duplicate networks. - If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %; ```cpp ESP_wifiManager.setMinimumSignalQuality(10); ``` will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%; - You can also remove or show duplicate networks (default is remove). Use this function to show (or hide) all networks. ```cpp ESP_wifiManager.setRemoveDuplicateAPs(false); ``` --- --- ### Example [ConfigOnDRD_FS_MQTT_Ptr](examples/ConfigOnDRD_FS_MQTT_Ptr) ```cpp /**************************************************************************************************************************** This example will open a Config Portal when there is no stored WiFi Credentials or when a DRD is detected. You can reconfigure to use another pin, such as the convenience FLASH / BOOT button @ PIN_D0;. A password is required to connect to the Config Portal so that only who know the password can access the Config Portal. The Credentials, being input via Config Portal, will then be saved into LittleFS / SPIFFS file, and be used to connect to Adafruit MQTT Server at "io.adafruit.com" and publish a Temperature Topic Based on original sketch posted by "Marko"(https://github.com/wackoo-arduino) on https://forum.arduino.cc/index.php?topic=692108 *****************************************************************************************************************************/ #if !( defined(ESP8266) || defined(ESP32) ) #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 // for button #include // for button #include // Now support ArduinoJson 6.0.0+ ( tested with v6.15.2 to v6.16.1 ) #include // get it from https://arduinojson.org/ or install via Arduino library manager //For ESP32, To use ESP32 Dev Module, QIO, Flash 4MB/80MHz, Upload 921600 //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 ////// #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 #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) // For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS) // 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 #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 #endif #define DOUBLERESETDETECTOR_DEBUG true //false #include //https://github.com/khoih-prog/ESP_DoubleResetDetector // Number of seconds after reset during which a // subseqent reset will be considered a double reset. #define DRD_TIMEOUT 10 // RTC Memory Address for the DoubleResetDetector to use #define DRD_ADDRESS 0 DoubleResetDetector* drd = NULL; #include "Adafruit_MQTT.h" //https://github.com/adafruit/Adafruit_MQTT_Library #include "Adafruit_MQTT_Client.h" //https://github.com/adafruit/Adafruit_MQTT_Library const char* CONFIG_FILE = "/ConfigMQTT.json"; // Default configuration values for Adafruit IO MQTT // This actually works #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT "1883" //1883, or 8883 for SSL #define AIO_USERNAME "private" //Adafruit IO #define AIO_KEY "private" // Labels for custom parameters in WiFi manager #define AIO_SERVER_Label "AIO_SERVER_Label" #define AIO_SERVERPORT_Label "AIO_SERVERPORT_Label" #define AIO_USERNAME_Label "AIO_USERNAME_Label" #define AIO_KEY_Label "AIO_KEY_Label" // Just dummy topics. To be updated later when got valid data from FS or Config Portal String MQTT_Pub_Topic = "private/feeds/Temperature"; // Variables to save custom parameters to... // I would like to use these instead of #defines #define custom_AIO_SERVER_LEN 20 #define custom_AIO_PORT_LEN 5 #define custom_AIO_USERNAME_LEN 20 #define custom_AIO_KEY_LEN 40 char custom_AIO_SERVER[custom_AIO_SERVER_LEN]; char custom_AIO_SERVERPORT[custom_AIO_PORT_LEN]; char custom_AIO_USERNAME[custom_AIO_USERNAME_LEN]; char custom_AIO_KEY[custom_AIO_KEY_LEN]; // Function Prototypes void MQTT_connect(); bool readConfigFile(); bool writeConfigFile(); // For Config Portal // SSID and PW for Config Portal String ssid = "ESP_" + String(ESP_getChipId(), HEX); const char* password = "your_password"; // SSID and PW for your Router String Router_SSID; String Router_Pass; // From v1.1.1 // You only need to format the filesystem once //#define FORMAT_FILESYSTEM true #define FORMAT_FILESYSTEM false #define MIN_AP_PASSWORD_SIZE 8 #define SSID_MAX_LEN 32 //From v1.0.10, WPA2 passwords can be up to 63 characters long. #define PASS_MAX_LEN 64 typedef struct { char wifi_ssid[SSID_MAX_LEN]; char wifi_pw [PASS_MAX_LEN]; } WiFi_Credentials; typedef struct { String wifi_ssid; String wifi_pw; } WiFi_Credentials_String; #define NUM_WIFI_CREDENTIALS 2 typedef struct { WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; } WM_Config; WM_Config WM_config; #define CONFIG_FILENAME F("/wifi_cred.dat") ////// // Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected bool initialConfig = false; // Use false if you don't like to display Available Pages in Information Page of Config Portal // Comment out or use true to display Available Pages in Information Page of Config Portal // Must be placed before #include #define USE_AVAILABLE_PAGES false // 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. //#define USE_STATIC_IP_CONFIG_IN_CP false // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP false // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) #define USE_CLOUDFLARE_NTP false // New in v1.0.11 #define USING_CORS_FEATURE true ////// // 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 #else // 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); #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); #endif #define USE_CONFIGURABLE_DNS true IPAddress dns1IP = gatewayIP; IPAddress dns2IP = IPAddress(8, 8, 8, 8); #include //https://github.com/khoih-prog/ESP_WiFiManager #define HTTP_PORT 80 // Create an ESP32 WiFiClient class to connect to the MQTT server WiFiClient *client = NULL; Adafruit_MQTT_Client *mqtt = NULL; Adafruit_MQTT_Publish *Temperature = NULL; // Forward Declaration 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 #else // For ESP8266, this better be 2200 to enable connect the 1st time #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 ); } for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { // 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) ) { 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 #endif int i = 0; status = wifiMulti.run(); delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS); while ( ( i++ < 20 ) && ( status != WL_CONNECTED ) ) { status = wifiMulti.run(); if ( status == WL_CONNECTED ) break; else delay(WIFI_MULTI_CONNECT_WAITING_MS); } if ( status == WL_CONNECTED ) { LOGERROR1(F("WiFi connected after time: "), i); LOGERROR3(F("SSID:"), WiFi.SSID(), F(",RSSI="), WiFi.RSSI()); LOGERROR3(F("Channel:"), WiFi.channel(), F(",IP address:"), WiFi.localIP() ); } else LOGERROR(F("WiFi not connected")); return status; } void toggleLED() { //toggle state digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } void heartBeatPrint(void) { static int num = 1; if (WiFi.status() == WL_CONNECTED) Serial.print(F("W")); // W means connected to WiFi else Serial.print(F("N")); // N means not connected to WiFi if (num == 40) { Serial.println(); num = 1; } else if (num++ % 5 == 0) { Serial.print(F(" ")); } } void publishMQTT(void) { float some_number = 25.0 + (float) ( millis() % 100 ) / 100; // For debug only //Serial.print(F("Published Temp = ")); //Serial.println(some_number); MQTT_connect(); if (Temperature->publish(some_number)) { Serial.print(F("T")); // T means publishing OK } else { Serial.print(F("F")); // F means publishing failure } } void check_WiFi(void) { if ( (WiFi.status() != WL_CONNECTED) ) { Serial.println(F("\nWiFi lost. Call connectMultiWiFi in loop")); connectMultiWiFi(); } } void check_status(void) { static ulong checkstatus_timeout = 0; static ulong LEDstatus_timeout = 0; static ulong checkwifi_timeout = 0; static ulong mqtt_publish_timeout = 0; ulong current_millis = millis(); #define WIFICHECK_INTERVAL 1000L #define LED_INTERVAL 2000L #define HEARTBEAT_INTERVAL 10000L #define PUBLISH_INTERVAL 60000L // Check WiFi every WIFICHECK_INTERVAL (1) seconds. if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { check_WiFi(); checkwifi_timeout = current_millis + WIFICHECK_INTERVAL; } if ((current_millis > LEDstatus_timeout) || (LEDstatus_timeout == 0)) { // Toggle LED at LED_INTERVAL = 2s toggleLED(); LEDstatus_timeout = current_millis + LED_INTERVAL; } // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) { heartBeatPrint(); checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; } // Check every PUBLISH_INTERVAL (60) seconds. if ((current_millis > mqtt_publish_timeout) || (mqtt_publish_timeout == 0)) { if (WiFi.status() == WL_CONNECTED) { publishMQTT(); } mqtt_publish_timeout = current_millis + PUBLISH_INTERVAL; } } void loadConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "r"); LOGERROR(F("LoadWiFiCfgFile ")); if (file) { file.readBytes((char *) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } void saveConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "w"); LOGERROR(F("SaveWiFiCfgFile ")); if (file) { file.write((uint8_t*) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } void deleteOldInstances(void) { // Delete previous instances if (mqtt) { delete mqtt; mqtt = NULL; Serial.println(F("Deleting old MQTT object")); } if (Temperature) { delete Temperature; Temperature = NULL; Serial.println(F("Deleting old Temperature object")); } } void createNewInstances(void) { if (!client) { client = new WiFiClient; Serial.print(F("\nCreating new WiFi client object : ")); Serial.println(client? F("OK") : F("failed")); } // Create new instances from new data if (!mqtt) { // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. mqtt = new Adafruit_MQTT_Client(client, custom_AIO_SERVER, atoi(custom_AIO_SERVERPORT), custom_AIO_USERNAME, custom_AIO_KEY); Serial.print(F("Creating new MQTT object : ")); if (mqtt) { Serial.println(F("OK")); Serial.println(String("AIO_SERVER = ") + custom_AIO_SERVER + ", AIO_SERVERPORT = " + custom_AIO_SERVERPORT); Serial.println(String("AIO_USERNAME = ") + custom_AIO_USERNAME + ", AIO_KEY = " + custom_AIO_KEY); } else Serial.println(F("Failed")); } if (!Temperature) { Serial.print(F("Creating new MQTT_Pub_Topic, Temperature = ")); Serial.println(MQTT_Pub_Topic); Temperature = new Adafruit_MQTT_Publish(mqtt, MQTT_Pub_Topic.c_str()); Serial.print(F("Creating new Temperature object : ")); if (Temperature) { Serial.println(F("OK")); Serial.println(String("Temperature MQTT_Pub_Topic = ") + MQTT_Pub_Topic); } else Serial.println(F("Failed")); } } void wifi_manager() { Serial.println(F("\nConfig Portal requested.")); digitalWrite(LED_BUILTIN, LED_ON); // turn the LED on by making the voltage LOW to tell us we are in configuration mode. //Local intialization. Once its business is done, there is no need to keep it around ESP_WiFiManager ESP_wifiManager("ConfigOnDRD_FS-MQTT");; //Check if there is stored WiFi router/password credentials. //If not found, device will remain in configuration mode until switched off via webserver. Serial.print(F("Opening Configuration Portal. ")); Router_SSID = ESP_wifiManager.WiFi_SSID(); Router_Pass = ESP_wifiManager.WiFi_Pass(); // From v1.1.1, Don't permit NULL password if ( !initialConfig && (Router_SSID != "") && (Router_Pass != "") ) { //If valid AP credential and not DRD, set timeout 120s. ESP_wifiManager.setConfigPortalTimeout(120); Serial.println("Got stored Credentials. Timeout 120s"); } else { ESP_wifiManager.setConfigPortalTimeout(0); Serial.print(F("No timeout : ")); if (initialConfig) { Serial.println(F("DRD or No stored Credentials..")); } else { Serial.println(F("No stored Credentials.")); } } //Local intialization. Once its business is done, there is no need to keep it around // Extra parameters to be configured // After connecting, parameter.getValue() will get you the configured value // Format: