README

ESP_WiFiManager

arduino-library-badge GitHub release GitHub contributions welcome GitHub issues

Donate to my libraries using BuyMeACoffee



Table of Contents



Important Breaking Change from v1.8.0

For v1.11.0 and up

ESP32 chipID is now correct and unique. The previous releases’ 32-bit wrong chipID is mainly the 24-bit Organizational Unique Identifier (OUI) plus 8 bits from the correct chipID. That’s why ESP_getChipId() function can return duplicated values if the boards are from the same batch.

For example

Chip_ID_64 : 0x98F4AB085288
chipOUI    : 0x98F4AB
chipId     : 0x85288
getEfuseMac: 0x885208ABF498
For v1.9.0 and up

Please have a look at HOWTO Fix Multiple Definitions Linker Error

From v1.9.0, you just use

#include <ESP_WiFiManager.h>               //https://github.com/khoih-prog/ESP_WiFiManager

instead of both

#include <ESP_WiFiManager.h>               //https://github.com/khoih-prog/ESP_WiFiManager

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include <ESP_WiFiManager-Impl.h>          //https://github.com/khoih-prog/ESP_WiFiManager

For complex project having Multiple Definitions Linker Error issue, you can use in many files (Be careful: .hpp, not .h)

#include <ESP_WiFiManager.hpp>             //https://github.com/khoih-prog/ESP_WiFiManager

but only in main(), .ino with setup() to avoid Multiple Definitions Linker Error

#include <ESP_WiFiManager.h>               //https://github.com/khoih-prog/ESP_WiFiManager

For v1.8.0 only

It’s advisable to use v1.9.0+

Please have a look at HOWTO Fix Multiple Definitions Linker Error

From v1.8.0, you must use

#include <ESP_WiFiManager.h>               //https://github.com/khoih-prog/ESP_WiFiManager

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include <ESP_WiFiManager-Impl.h>          //https://github.com/khoih-prog/ESP_WiFiManager

instead of only

#include <ESP_WiFiManager.h>               //https://github.com/khoih-prog/ESP_WiFiManager


Important Note

This ESP_WiFiManager has just been modified to create the new ESPAsync_WiFiManager Library in order to use the better and more efficient ESPAsyncWebServer Library, instead of the (ESP8266)WebServer library.

The new ESPAsync_WiFiManager library is based on and sync’ed with ESP_WiFiManager. Therefore, all the features currently supported by this 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

  • 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 and underlying Async libraries, please compare the more efficient Async_ESP32_FSWebServer example example code against the code of its complicated twin ESP32_FSWebServer.

Thanks to cancodr for requesting an enhancement in Issue #29: Is it possible to use AsyncWebServer.h instead of WebServer.h?, leading to the new ESPAsync_WiFiManager Library.



Why do we need this ESP_WiFiManager library

Features

This is a WiFiManager Library for configuring/auto(re)connecting ESP8266/ESP32 modules to the best or available MultiWiFi APs at runtime. Configuration data to be saved in either LittleFS, SPIFFS or EEPROM. Default Credentials as well as Dynamic custom parameters can be added and modified easily. DoubleResetDetector is used to force Config Portal opening even if the Credentials are still valid.

This library is designed to help you to eliminate hardcoding your Wifi credentials for ESP8266 and ESP32, and updating/reflashing every time you need to change them.

With version v1.3.0 or later, you can use:

  1. LittleFS for ESP32

With version v1.1.0 or later, you can configure:

  1. Multiple WiFi Credentials (SSID, Password) and system will autoconnect to the best and available WiFi SSID.
Currently supported Boards

This ESP_WiFiManager library currently supports these following boards:

  1. ESP8266 and ESP32-based boards using EEPROM, SPIFFS or LittleFS.
  2. ESP32-S2 (ESP32-S2 Saola, AI-Thinker ESP-12K, etc.) using EEPROM, SPIFFS or LittleFS.
  3. ESP32-C3 (ARDUINO_ESP32C3_DEV) using EEPROM, SPIFFS or LittleFS.
  4. ESP32-S3 (ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.) using EEPROM, SPIFFS or LittleFS.

This library is based on, modified, bug-fixed and improved from:

  1. Tzapu WiFiManager
  2. Ken Taylor 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.



Prerequisites

  1. Arduino IDE 1.8.19+ for Arduino. GitHub release
  2. ESP8266 Core 3.0.2+ for ESP8266-based boards. Latest release. To use ESP8266 core 2.7.1+ for LittleFS.
  3. ESP32 Core 2.0.5+ for ESP32-based boards. Latest release
  4. ESP_DoubleResetDetector v1.3.2+ if using DRD feature. To install, check arduino-library-badge. Use v1.1.0+ if using LittleFS for ESP32.
  5. ESP_MultiResetDetector v1.3.2+ if using MRD feature. To install, check arduino-library-badge.
  6. LittleFS_esp32 v1.0.6+ for ESP32-based boards using LittleFS with ESP32 core v1.0.5-. To install, check arduino-library-badge. Notice: This LittleFS_esp32 library has been integrated to Arduino ESP32 core v1.0.6+ and you don’t need to install it if using ESP32 core v1.0.6+

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 for more detailed instructions.

Manual Install

  1. Navigate to 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
  2. Install PlatformIO
  3. Install Latest ESP_WiFiManager library by using Library Manager. Search for ESP_WiFiManager in Platform.io Author’s Libraries
  4. Use included 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


Note for Platform IO using ESP32 LittleFS

Necessary only for esp32 core v1.0.6-

From esp32 core v1.0.6+, LittleFS_esp32 v1.0.6 has been included and this step is not necessary anymore.

In Platform IO, to fix the error when using LittleFS_esp32 v1.0 for ESP32-based boards with ESP32 core v1.0.4- (ESP-IDF v3.2-), uncomment the following line

from

//#define CONFIG_LITTLEFS_FOR_IDF_3_2   /* For old IDF - like in release 1.0.4 */

to

#define CONFIG_LITTLEFS_FOR_IDF_3_2   /* For old IDF - like in release 1.0.4 */

It’s advisable to use the latest LittleFS_esp32 v1.0.5+ to avoid the issue.

Thanks to Roshan to report the issue in Error esp_littlefs.c ‘utime_p’



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.

You can use

#include <ESP_WiFiManager.hpp>               //https://github.com/khoih-prog/ESP_WiFiManager

in many files. But be sure to use the following #include <ESP_WiFiManager.h> in just 1 .h, .cpp or .ino file, which must not be included in any other file, to avoid Multiple Definitions Linker Error

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include <ESP_WiFiManager.h>                //https://github.com/khoih-prog/ESP_WiFiManager

Check ConfigOnDoubleReset_Multi for an example how and where to do so.

Have a look at the discussion in Different behaviour using the src_cpp or src_h lib #80



HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)

Please have a look at ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example to have more detailed description and solution of the issue.

1. ESP32 has 2 ADCs, named ADC1 and ADC2
2. ESP32 ADCs functions
  • ADC1 controls ADC function for pins GPIO32-GPIO39
  • ADC2 controls ADC function for pins GPIO0, 2, 4, 12-15, 25-27
3… ESP32 WiFi uses ADC2 for WiFi functions

Look in file adc_common.c

In ADC2, there’re two locks used for different cases:

  1. lock shared with app and Wi-Fi: ESP32: When Wi-Fi using the ADC2, we assume it will never stop, so app checks the lock and returns immediately if failed. ESP32S2: The controller’s control over the ADC is determined by the arbiter. There is no need to control by lock.

  2. lock shared between tasks: when several tasks sharing the ADC2, we want to guarantee all the requests will be handled. Since conversions are short (about 31us), app returns the lock very soon, we use a spinlock to stand there waiting to do conversions one by one.

adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock.

  • In order to use ADC2 for other functions, we have to acquire complicated firmware locks and very difficult to do
  • So, it’s not advisable to use ADC2 with WiFi/BlueTooth (BT/BLE).
  • Use ADC1, and pins GPIO32-GPIO39
  • If somehow it’s a must to use those pins serviced by ADC2 (GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27), use the fix mentioned at the end of ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example to work with ESP32 WiFi/BlueTooth (BT/BLE).


How It Works

  • The 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)
// 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.


HOWTO Basic configurations

1. Using default for every configurable parameter
  • Include in your sketch
#ifdef ESP32
  #include <esp_wifi.h>
  #include <WiFi.h>
  #include <WiFiClient.h>

  #include <WiFiMulti.h>
  WiFiMulti wifiMulti;

  // LittleFS has higher priority than SPIFFS
  #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
    #define USE_LITTLEFS    true
    #define USE_SPIFFS      false
  #elif defined(ARDUINO_ESP32C3_DEV)
    // For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS
    #define USE_LITTLEFS          false
    #define USE_SPIFFS            true
  #endif

  #if USE_LITTLEFS
    // Use LittleFS
    #include "FS.h"

    // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h
    //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) )  //(ESP_ARDUINO_VERSION_MAJOR >= 2)
    #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
      #warning Using ESP32 Core 1.0.6 or 2.0.0+
      // The library has been merged into esp32 core from release 1.0.6
      #include <LittleFS.h>       // https://github.com/espressif/arduino-esp32/tree/master/libraries/LittleFS
      
      FS* filesystem =      &LittleFS;
      #define FileFS        LittleFS
      #define FS_Name       "LittleFS"
    #else
      #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
      // The library has been merged into esp32 core from release 1.0.6
      #include <LITTLEFS.h>       // https://github.com/lorol/LITTLEFS
      
      FS* filesystem =      &LITTLEFS;
      #define FileFS        LITTLEFS
      #define FS_Name       "LittleFS"
    #endif
    
  #elif USE_SPIFFS
    #include <SPIFFS.h>
    FS* filesystem =      &SPIFFS;
    #define FileFS        SPIFFS
    #define FS_Name       "SPIFFS"
  #else
    // Use FFat
    #include <FFat.h>
    FS* filesystem =      &FFat;
    #define FileFS        FFat
    #define FS_Name       "FFat"
  #endif
  //////

  #define LED_BUILTIN       2
  #define LED_ON            HIGH
  #define LED_OFF           LOW

#else
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
  //needed for library
  #include <DNSServer.h>
  #include <ESP8266WebServer.h>

  #include <ESP8266WiFiMulti.h>
  ESP8266WiFiMulti wifiMulti;

  #define USE_LITTLEFS      true
  
  #if USE_LITTLEFS
    #include <LittleFS.h>
    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

// 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
//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 <ESP_WiFiManager.h>              //https://github.com/khoih-prog/ESP_WiFiManager

// 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;

2. Using many configurable parameters
  • Include in your sketch
#ifdef ESP32
  #include <esp_wifi.h>
  #include <WiFi.h>
  #include <WiFiClient.h>

  #include <WiFiMulti.h>
  WiFiMulti wifiMulti;

  // LittleFS has higher priority than SPIFFS
  #define USE_LITTLEFS    true
  #define USE_SPIFFS      false

  #if USE_LITTLEFS
    // Use LittleFS
    #include "FS.h"

    // Check cores/esp32/esp_arduino_version.h and cores/esp32/core_version.h
    //#if ( ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) )  //(ESP_ARDUINO_VERSION_MAJOR >= 2)
    #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
      #warning Using ESP32 Core 1.0.6 or 2.0.0+
      // The library has been merged into esp32 core from release 1.0.6
      #include <LittleFS.h>
      
      FS* filesystem =      &LittleFS;
      #define FileFS        LittleFS
      #define FS_Name       "LittleFS"
    #else
      #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
      // The library has been merged into esp32 core from release 1.0.6
      #include <LITTLEFS.h>             // https://github.com/lorol/LITTLEFS
      
      FS* filesystem =      &LITTLEFS;
      #define FileFS        LITTLEFS
      #define FS_Name       "LittleFS"
    #endif
    
  #elif USE_SPIFFS
    #include <SPIFFS.h>
    FS* filesystem =      &SPIFFS;
    #define FileFS        SPIFFS
    #define FS_Name       "SPIFFS"
  #else
    // Use FFat
    #include <FFat.h>
    FS* filesystem =      &FFat;
    #define FileFS        FFat
    #define FS_Name       "FFat"
  #endif
  //////

  #define LED_BUILTIN       2
  #define LED_ON            HIGH
  #define LED_OFF           LOW

#else
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
  //needed for library
  #include <DNSServer.h>
  #include <ESP8266WebServer.h>

  #include <ESP8266WiFiMulti.h>
  ESP8266WiFiMulti wifiMulti;

  #define USE_LITTLEFS      true
  
  #if USE_LITTLEFS
    #include <LittleFS.h>
    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

// 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
// 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 <ESP_WiFiManager.h>
#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 )
  // 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 stati

提示:代码过长已自动截断

3. Using STA-mode DHCP, but don’t like to change to static IP or display in Config Portal
// 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
// 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
// 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
// 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
// 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.
// 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.
// 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.
// 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
// 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
// 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
// Set static IP, Gateway, Subnetmask, DNS1 and DNS2
//ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP);
ESP_wifiManager.setSTAStaticIPConfig(WM_STA_IPconfig);

14. Using AUTOCONNECT_NO_INVALIDATE feature
  1. Don’t invalidate WiFi SSID/PW when calling autoConnect() (default)
#define AUTOCONNECT_NO_INVALIDATE     true
  1. To invalidate WiFi SSID/PW when calling autoConnect()
#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.
// Default false for using only whenever necessary to avoid security issue
#define USING_CORS_FEATURE     true
  1. To use CORS feature with specific CORS Header “Your Access-Control-Allow-Origin”. To be modified according to your specific Allowed-Origin.
// Default false for using only whenever necessary to avoid security issue
#define USING_CORS_FEATURE     true

...

#if USING_CORS_FEATURE
  ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin");
#endif
  1. Not use CORS feature (default)
// 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()
void check_WiFi()
{
  if ( (WiFi.status() != WL_CONNECTED) )
  {
    Serial.println("\nWiFi lost. Call connectMultiWiFi in loop");
    connectMultiWiFi();
  }
}

void check_status()
{
  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();
}

17. How to auto getting _timezoneName
  1. Turn on auto NTP configuration by
// 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
  1. The _timezoneName, in the format similar to America/New_York, America/Toronto, Europe/London, etc., can be retrieved by using
String tempTZ = ESP_wifiManager.getTimezoneName();

18. How to get TZ variable to configure Timezone
  1. ESP32 and ESP8266 TZ can be configured, using the similar to EST5EDT,M3.2.0,M11.1.0 (for America/New_York), as follows:
// EST5EDT,M3.2.0,M11.1.0 (for America/New_York)
// EST5EDT is the name of the time zone
// EST is the abbreviation used when DST is off
// 6 hours is the time difference from GMT
// EDT is the abbreviation used when DST is on
// ,M3 is the third month
// .2 is the second occurrence of the day in the month
// .0 is Sunday
// ,M11 is the eleventh month
// .1 is the first occurrence of the day in the month
// .0 is Sunday

#if ESP8266
      configTime(WM_config.TZ, "pool.ntp.org"); 
#else
      //configTzTime(WM_config.TZ, "pool.ntp.org" );
      configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
#endif
  1. To convert from _timezoneName to TZ, use the function getTZ() as follows:
const char * TZ_Result = ESP_wifiManager.getTZ(_timezoneName);

The conversion depends on the stored TZs, which is using some memory, and can cause issue for ESP8266 in certain cases. Therefore, enable just the region you’re interested.

For example, your application is used in America continent, you need just

#define USING_AMERICA       true

Hereafter is the regions’ list

// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen
// if using too much memory
#define USING_AFRICA        false
#define USING_AMERICA       true
#define USING_ANTARCTICA    false
#define USING_ASIA          false
#define USING_ATLANTIC      false
#define USING_AUSTRALIA     false
#define USING_EUROPE        false
#define USING_INDIAN        false
#define USING_PACIFIC       false
#define USING_ETC_GMT       false

19. How to use the TZ variable to configure Timezone
#if ESP8266
      configTime(WM_config.TZ, "pool.ntp.org");
#else
      //configTzTime(WM_config.TZ, "pool.ntp.org" );
      configTzTime(WM_config.TZ, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
#endif

then to print local time

void printLocalTime()
{
#if ESP8266
  static time_t now;
  
  now = time(nullptr);
  
  if ( now > 1451602800 )
  {
    Serial.print("Local Date/Time: ");
    Serial.print(ctime(&now));
  }
#else
  struct tm timeinfo;

  getLocalTime( &timeinfo );

  // Valid only if year > 2000. 
  // You can get from timeinfo : tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec
  if (timeinfo.tm_year > 100 )
  {
    Serial.print("Local Date/Time: ");
    Serial.print( asctime( &timeinfo ) );
  }
#endif
}


HOWTO Open Config Portal

  • When you want to open a config portal, with default DHCP hostname ESP8266-XXXXXX or ESP32-XXXXXX, just add
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

ESP_WiFiManager ESP_wifiManager("Personalized-HostName");

then later call

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:

//set custom ip for portal
//ESP_wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
ESP_wifiManager.setAPStaticIPConfig(WM_AP_IPconfig);

and use fixed / dynamic / random AP channel by:

// 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.



HOWTO Add Dynamic Parameters

These illustrating steps is based on the example ConfigOnSwitchFS

1. Determine the variables to be configured via Config Portal (CP)

The application will:

  • use DHT sensor (either DHT11 or DHT22) and
  • need to connect to ThingSpeak with unique user’s API Key.

The DHT sensor is connected to the ESP boards using SDA/SCL pins which also need to be configurable.

So this is the list of variables to be dynamically configured using CP

1. `thingspeakApiKey`,  type `char array`, max length 17 chars, and just arbitrarily selected default value to be "" or "ThingSpeak-APIKey"
2. `sensorDht22`,       type `bool`, default to be `true` (DHT22)
3. `pinSda`,            type `int`,  default to be `PIN_D2`
4. `pinScl`,            type `int`,  default to be `PIN_D1`

The Label can be any arbitrary string that help you identify the variable, but must be unique in your application

The initial code will be

#define API_KEY_LEN                 17

// Default configuration values
char thingspeakApiKey[API_KEY_LEN]  = "";
bool sensorDht22                    = true;
int pinSda                          = PIN_D2;     // Pin D2 mapped to pin GPIO4 of ESP8266
int pinScl                          = PIN_D1;     // Pin D1 mapped to pin GPIO5 of ESP8266

// Any unique string helping you identify the vars
#define ThingSpeakAPI_Label         "thingspeakApiKey"
#define SensorDht22_Label           "SensorDHT22"
#define PinSDA_Label                "PinSda"
#define PinSCL_Label                "PinScl"

2. Initialize the variables to prepare for Config Portal (CP)

The example ConfigOnSwitchFS will open the CP whenever a SW press is detected in loop(). So the code to add dynamic variables will be there, just after the CP ESP_WiFiManager class initialization to create ESP_wifiManager object.

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 initialization. Once its business is done, there is no need to keep it around
    ESP_WiFiManager ESP_wifiManager("ConfigOnSwitchFS");

    //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. ");
    
    ...
    
    // The addition of dynamic vars will be somewhere here
    
}    

The ESP_WMParameter class constructor will be used to initialize each newly-added parameter object.

2.1 Use the following simple constructor for simple variables such as thingspeakApiKey, pinSda and pinScl :
ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length);
2.2 For example, to create a new ESP_WMParameter object p_thingspeakApiKey for thingspeakApiKey,

The command to use will be

ESP_WMParameter p_thingspeakApiKey(ThingSpeakAPI_Label, "Thingspeak API Key", thingspeakApiKey, API_KEY_LEN);

where

- p_thingspeakApiKey                  : ESP_WMParameter class object reference that stores the new Custom Parameter
- id => ThingSpeakAPI_Label           : var ref to Json associative name and HTML element ID for the new Custom Paramerter you just defined in step 1
- placeholder => "Thingspeak API Key" : HTML input placeholder and/or label element text the user sees in the configuration interface for this Custom Parameter
- defaultValue => thingspeakApiKey    : variable for storing the value of your Custom Parameter in the file system or default value when no data is entered
- length  => API_KEY_LEN              : max allowed length you want for this Custom Parameter to have

For pinSda and pinScl, the command will be similar

// I2C SCL and SDA parameters are integers so we need to convert them to char array but
// no other special considerations
char convertedValue[3];
sprintf(convertedValue, "%d", pinSda);
ESP_WMParameter p_pinSda(PinSDA_Label, "I2C SDA pin", convertedValue, 3);

sprintf(convertedValue, "%d", pinScl);
ESP_WMParameter p_pinScl(PinSCL_Label, "I2C SCL pin", convertedValue, 3);

where

- p_pinSda / p_pinScl                         : ESP_WMParameter class object reference that stores the new Custom Parameter
- id => PinSDA_Label/PinSCL_Label             : var ref to Json associative name and HTML element ID for the new Custom Paramerter you just defined in step 1
- placeholder => "I2C SDA pin"/"I2C SCL pin"  : HTML input placeholder and/or label element text the user sees in the configuration interface for this Custom Parameter
- defaultValue => convertedValue              : variable for storing the value of your Custom Parameter in the file system or default value when no data is entered
- length  => 3                                : max allowed length you want for this Custom Parameter to have

2.3 Use the more complex following constructor for variables such as sensorDht22:
ESP_WMParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom, int labelPlacement);
2.4 For example, to create a new ESP_WMParameter object p_sensorDht22 for sensorDht22,

The command to use will be

ESP_WMParameter p_sensorDht22(SensorDht22_Label, "DHT-22 Sensor", "T", 2, customhtml, WFM_LABEL_AFTER);

where

- p_sensorDht22                       : ESP_WMParameter class object reference that stores the new Custom Parameter
- id => SensorDht22_Label             : var ref to Json associative name and HTML element ID for the new Custom Paramerter you just defined in step 1
- placeholder => "DHT-22 Sensor"      : HTML input placeholder and/or label element text the user sees in the configuration interface for this Custom Parameter
- defaultValue => "T"                 : variable for storing the value of your Custom Parameter in the file system or default value when no data is entered ("T" means `true`)
- length  => 2                        : max allowed length you want for this Custom Parameter to have
- custom => customhtml                : custom HTML code to add element type, e.g. `checkbox`, and `checked` when `sensorDht22 == true`
- labelPlacement => WFM_LABEL_AFTER   : to place label after

and customhtml Code is:

char customhtml[24] = "type=\"checkbox\"";

if (sensorDht22)
{
  strcat(customhtml, " checked");
}

3. Add the variables to Config Portal (CP)

Adding those ESP_WMParameter objects created in Step 2 using the function addParameter() of object ESP_wifiManager

3.1 addParameter() function Prototype:
//adds a custom parameter
bool addParameter(ESP_WMParameter *p);
3.2 Code to add variables to CP

Add parameter objects, previously created in Step 2, such as : p_thingspeakApiKey, p_sensorDht22, p_pinSda and p_pinScl

//add all parameters here

ESP_wifiManager.addParameter(&p_thingspeakApiKey);
ESP_wifiManager.addParameter(&p_sensorDht22);
ESP_wifiManager.addParameter(&p_pinSda);
ESP_wifiManager.addParameter(&p_pinScl);

4. Save the variables configured in Config Portal (CP)

When the CP exits, we have to store the parameters’ values that users input via CP to use later.

For ESP32, that can be EEPROM or SPIFFS. While on ESP8266, LittleFS can be used besides EEPROM or deprecated SPIFFS.

We can write directly to a well-defined structure of our choice, but the current example is using JSON to be portable but much more complicated and not advised for new users.

4.1 Getting variables’ data from CP

After users select Save, the CP ESP_wifiManager object will save the user input data into related ESP_WMParameter objects.

We can now retrieve the data, using getValue() function, for each ESP_WMParameter object. Then we can utilize the data for our purpose, such as thingspeakApiKey to log in, sensorDht22 type to know how to handle the sensor, pinSda and pinSda to know which pins to use to communicate with the DHT sensor.

The code is as follows:

// Getting posted form values and overriding local variables parameters
// Config file is written regardless the connection state
strcpy(thingspeakApiKey, p_thingspeakApiKey.getValue());
sensorDht22 = (strncmp(p_sensorDht22.getValue(), "T", 1) == 0);
pinSda = atoi(p_pinSda.getValue());
pinScl = atoi(p_pinScl.getValue());

We can also save to FS file to use later in next boot.

// Writing JSON config file to flash for next boot
writeConfigFile();

5. Write to FS (SPIFFS, LittleFS, etc.) using JSON format

First, you have to familiarize yourself with ArduinoJson library, its functions, the disruptive differences between ArduinoJson version 5.x.x- and v6.0.0+. The best documentation can be found at The best JSON library for embedded C++.

This documentation will discuss only ArduinoJson v6.x.x+ (ARDUINOJSON_VERSION_MAJOR >= 6)

Then have a look at the code snippet of writeConfigFile() function and the following step-by-step explanations.

bool writeConfigFile()
{
  Serial.println("Saving config file");

#if (ARDUINOJSON_VERSION_MAJOR >= 6)
  DynamicJsonDocument json(1024);
#else
  DynamicJsonBuffer jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
#endif

  // JSONify local configuration parameters
  json[ThingSpeakAPI_Label] = thingspeakApiKey;
  json[SensorDht22_Label] = sensorDht22;
  json[PinSDA_Label] = pinSda;
  json[PinSCL_Label] = pinScl;

  // Open file for writing
  File f = FileFS.open(CONFIG_FILE, "w");

  if (!f)
  {
    Serial.println("Failed to open config file for writing");
    return false;
  }

#if (ARDUINOJSON_VERSION_MAJOR >= 6)
  serializeJsonPretty(json, Serial);
  // Write data to file and close it
  serializeJson(json, f);
#else
  json.prettyPrintTo(Serial);
  // Write data to file and close it
  json.printTo(f);
#endif

  f.close();

  Serial.println("\nConfig file was successfully saved");
  return true;
}
5.1 Create a DynamicJsonDocument Object

We’ll create an object with size 1024 bytes, enough to hold our data:

DynamicJsonDocument json(1024);
5.2 Fill the DynamicJsonDocument Object with data got from Config Portal

Then JSONify all local parameters we’ve just received from CP and wish to store into FS by using the function prototype:

json[Unique_Label] = Value_For_Unique_Label;

as follows:

// JSONify local configuration parameters
json[ThingSpeakAPI_Label] = thingspeakApiKey;
json[SensorDht22_Label]   = sensorDht22;
json[PinSDA_Label]        = pinSda;
json[PinSCL_Label]        = pinScl;
5.3 Open file to write the Jsonified data

This is the CONFIG_FILE file name we already declared at the beginning of the sketch (for ESP32):

#include <SPIFFS.h>
FS* filesystem =      &SPIFFS;
#define FileFS        SPIFFS
    
const char* CONFIG_FILE = "/ConfigSW.json";

Now just open the file for writing, and abort if open-for-writing error:

// Open file for writing
File f = FileFS.open(CONFIG_FILE, "w");

if (!f)
{
  Serial.println("Failed to open config file for writing");
  return false;
}
5.4 Write the Jsonified data to CONFIG_FILE

As simple as this single command to write the whole json object we declared then filled with data in steps 5.1 and 5.2

// Write data to file and close it
serializeJson(json, f);
5.5 Close CONFIG_FILE to flush and save the data

Soooo simple !!! Now everybody can do it.

f.close();

But HOWTO use the saved data in the next startup ??? That’s in next step 6.

6. Read from FS using JSON format

Now, you have familiarized yourself with ArduinoJson library, its functions. We’ll discuss HOWTO read data from the CONFIG_FILE in Jsonified format, then HOWTO parse the to use.

The documentation will discuss only ArduinoJson v6.x.x+ (ARDUINOJSON_VERSION_MAJOR >= 6)

First, have a look at the code snippet of readConfigFile() function.

bool readConfigFile()
{
  // this opens the config file in read-mode
  File f = FileFS.open(CONFIG_FILE, "r");

  if (!f)
  {
    Serial.println("Configuration file not found");
    return false;
  }
  else
  {
    // we could open the file
    size_t size = f.size();
    // Allocate a buffer to store contents of the file.
    std::unique_ptr<char[]> buf(new char[size + 1]);

    // Read and store file contents in buf
    f.readBytes(buf.get(), size);
    // Closing file
    f.close();
    // Using dynamic JSON buffer which is not the recommended memory model, but anyway
    // See https://github.com/bblanchon/ArduinoJson/wiki/Memory%20model

#if (ARDUINOJSON_VERSION_MAJOR >= 6)
    DynamicJsonDocument json(1024);
    auto deserializeError = deserializeJson(json, buf.get());
    if ( deserializeError )
    {
      Serial.println("JSON parseObject() failed");
      return false;
    }
    serializeJson(json, Serial);
#else
    DynamicJsonBuffer jsonBuffer;
    // Parse JSON string
    JsonObject& json = jsonBuffer.parseObject(buf.get());
    // Test if parsing succeeds.
    if (!json.success())
    {
      Serial.println("JSON parseObject() failed");
      return false;
    }
    json.printTo(Serial);
#endif

    // Parse all config file parameters, override
    // local config variables with parsed values
    if (json.containsKey(ThingSpeakAPI_Label))
    {
      strcpy(thingspeakApiKey, json[ThingSpeakAPI_Label]);
    }

    if (json.containsKey(SensorDht22_Label))
    {
      sensorDht22 = json[SensorDht22_Label];
    }

    if (json.containsKey(PinSDA_Label))
    {
      pinSda = json[PinSDA_Label];
    }

    if (json.containsKey(PinSCL_Label))
    {
      pinScl = json[PinSCL_Label];
    }
  }
  Serial.println("\nConfig file was successfully parsed");
  return true;
}

</char></spiffs></esp_wifimanager></esp_wifimanager></littlefs></esp8266wifimulti></esp8266webserver></dnsserver></esp8266wifi></ffat></spiffs></littlefs></littlefs></wifimulti></wificlient></wifi></esp_wifi></esp_wifimanager></littlefs></esp8266wifimulti></esp8266webserver></dnsserver></esp8266wifi></ffat></spiffs></littlefs></littlefs></wifimulti></wificlient></wifi></esp_wifi></esp_wifimanager></esp_wifimanager></esp_wifimanager></esp_wifimanager></esp_wifimanager-impl></esp_wifimanager></esp_wifimanager></esp_wifimanager></esp_wifimanager-impl></esp_wifimanager></esp_wifimanager>

> README 内容过长,已截取前 64 KB。完整内容请前往 GitHub 仓库查看。

评论

暂无评论