Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Feb 4, 2023. It is now read-only.

ESP32 + LwIP LAN8720, including WT32-S1, ESP32-S2, ESP32-S3 and ESP32-C3, Connection and Credentials Manager using AsyncWebServer, with enhanced GUI and fallback Web ConfigPortal

License

NotificationsYou must be signed in to change notification settings

khoih-prog/AsyncWT32_ETH01_Manager

Repository files navigation

arduino-library-badgeGitHub releaseGitHubcontributions welcomeGitHub issues

Donate to my libraries using BuyMeACoffee



Table of Contents



Why do we need this AsyncAsyncWT32_ETH01_Manager library

Features

This is anESP32 + LwIP LAN8720 Credentials and Connection Manager with fallback Web ConfigPortal. This Library is used for configuring ESP32 Ethernet Static / DHCP and Credentials at runtime. You can specify static DNS servers, personalized HostName and CORS feature.

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

  1. Khoi Hoang's ESPAsync_WiFiManager

to use the better and fasterasynchronousESPAsyncWebServer instead of WebServer_WT32_ETH01

Thanks to thisAsyncWT32_ETH01_Manager library is based on and sync'ed withESPAsync_WiFiManager, all the features currently supported byESPAsync_WiFiManager will be available. Please have a look atESPAsync_WiFiManager for those too-many-to-list features.

Why Async is better

  • Using asynchronous network means that you can handlemore than one connection at the same time
  • You are called once the request is ready and parsed
  • When you send the response, you areimmediately 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 extensible to handleany 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 theESPAsyncWebServer and underlying Async libraries, please compare the more efficientAsync_ESP32_FSWebServer example example with the complicated twinESP32_FSWebServer.

Currently supported Boards

ThisAsyncWT32_ETH01_Manager library currently supports these following boards:

  1. WT32_ETH01 (WT32_S1 + LAN8720) boards usingLwIP LAN8720 Ethernet
  2. (ESP32 + LAN8720) boards usingLwIP LAN8720 Ethernet
WT32_ETH01



Prerequisites

  1. Arduino IDE 1.8.19+ for Arduino.GitHub release
  2. ESP32 Core 2.0.5+ for ESP32-based boards.Latest release
  3. ESPAsyncWebServer v1.2.3+. You have to use the latestforked ESPAsyncWebServer if the PRFix compiler error for ESP32-C3 and mbed TLS v2.7.0+ #970 hasn't been merged.To install manually for Arduino IDE
  4. ESPAsyncDNSServer v1.0.0+ orForked ESPAsyncDNSServer v1.0.0+
  5. AsyncTCP v1.1.1+.To install manually for Arduino IDE
  6. ESP_DoubleResetDetector v1.3.2+ if using DRD feature. To install, checkarduino-library-badge. Use v1.1.0+ if usingLittleFS for ESP32 v1.0.6+.
  7. WebServer_WT32_ETH01 library v1.5.1+ if necessary to use ESP32 boards using LwIP LAN8720 Ethernet. To install, checkarduino-library-badge


Installation

Use Arduino Library Manager

The best and easiest way is to useArduino Library Manager. Search forAsyncWT32_ETH01_Manager, then select / install the latest version. You can also use this linkarduino-library-badge for more detailed instructions.

Manual Install

  1. Navigate toAsyncWT32_ETH01_Manager page.
  2. Download the latest releaseAsyncWT32_ETH01_Manager-main.zip.
  3. Extract the zip file toAsyncWT32_ETH01_Manager-main directory
  4. Copy the wholeAsyncWT32_ETH01_Manager-main folder to Arduino libraries' directory such as~/Arduino/libraries/.

VS Code & PlatformIO:

  1. InstallVS Code
  2. InstallPlatformIO
  3. InstallAsyncWT32_ETH01_Manager library by usingLibrary Manager. Search forAsyncWT32_ETH01_Manager inPlatform.io Author's Libraries
  4. Use includedplatformio.ini file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples atProject Configuration File


Libraries' Patches

1. For ESPAsyncWebServer library

If you don't use theforked ESPAsyncWebServer, to fixESPAsyncWebServer library compile errors, just copy these following files into theESPAsyncWebServer library directory to overwrite the old files:

Check the PRFix compiler error for ESP32-C3 and mbed TLS v2.7.0+ #970



Note for Platform IO using ESP32 LittleFS

Necessary only for esp32 core v1.0.6-

From esp32 corev1.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 usingLittleFS_esp32 v1.0 for ESP32-based boards with ESP32 corev1.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

#defineCONFIG_LITTLEFS_FOR_IDF_3_2/* For old IDF - like in release 1.0.4*/

It's advisable to use the latestLittleFS_esp32 v1.0.6+ to avoid the issue.

Thanks toRoshan to report the issue inError esp_littlefs.c 'utime_p'



HOWTO FixMultiple Definitions Linker Error

The current library implementation, usingxyz-Impl.h instead of standardxyz.cpp, possibly creates certainMultiple Definitions Linker error in certain use cases.

You can use

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

in many files. But be sure to use the following#include <AsyncWT32_ETH01_Manager.h>in just 1.h,.cpp or.ino file, which mustnot be included in any other file, to avoidMultiple Definitions Linker Error

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

CheckAsync_ConfigOnDoubleReset_Multi for an example how and where to do so.

Have a look at the discussion inDifferent 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 atESP_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 pinsGPIO32-GPIO39
  • ADC2 controls ADC function for pinsGPIO0, 2, 4, 12-15, 25-27

3.. ESP32 WiFi uses ADC2 for WiFi functions

Look in fileadc_common.c

InADC2, there're two locks used for different cases:

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

  2. lock shared between tasks:when several tasks sharing theADC2, we want to guaranteeall 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 useADC2 for other functions, we have toacquire complicated firmware locks and very difficult to do
  • So, it's not advisable to useADC2 with WiFi/BlueTooth (BT/BLE).
  • UseADC1, and pins GPIO32-GPIO39
  • If somehow it's a must to use those pins serviced byADC2 (GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27), use thefix mentioned at the end ofESP_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

  • TheAsync_ConfigOnSwitch example shows how it works and should be used as the basis for a sketch that uses this library.
  • The concept ofAsync_ConfigOnSwitch is that a newESP32 will start a 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 theESP32 module.
  • Using any network-enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point (AP) (Dynamic or Static IP specified in sketch)

then connectWebBrowser to configurable ConfigPortal IP address, e.g.192.168.232



HOWTO Basic configurations

1. Using default for every configurable parameter

  • Include in your sketch
#include<esp_wifi.h>// LittleFS has higher priority than SPIFFS#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )  #defineUSE_LITTLEFStrue  #defineUSE_SPIFFSfalse#elif defined(ARDUINO_ESP32C3_DEV)// For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS  #defineUSE_LITTLEFSfalse  #defineUSE_SPIFFStrue#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) )    #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)      #warning Using ESP32 Core 1.0.6 or 2.0.0+    #endif// 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;    #defineFileFS        LittleFS    #defineFS_Name"LittleFS"  #else    #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)      #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library    #endif// The library has been merged into esp32 core from release 1.0.6    #include<LITTLEFS.h>// https://github.com/lorol/LITTLEFS    FS* filesystem =      &LITTLEFS;    #defineFileFS        LITTLEFS    #defineFS_Name"LittleFS"  #endif#elif USE_SPIFFS  #include<SPIFFS.h>  FS* filesystem =      &SPIFFS;  #defineFileFS        SPIFFS  #defineFS_Name"SPIFFS"#else// +Use FFat  #include<FFat.h>  FS* filesystem =      &FFat;  #defineFileFS        FFat  #defineFS_Name"FFat"#endif//////#defineLED_BUILTIN2#defineLED_ON            HIGH#defineLED_OFF           LOW////////////////////////////////////////////////////// You only need to format the filesystem once//#define FORMAT_FILESYSTEM       true#defineFORMAT_FILESYSTEMfalse////////////////////////////////////////////////////#include<AsyncWT32_ETH01_Manager.h>//https://github.com/khoih-prog/AsyncWT32_ETH01_Manager#defineHTTP_PORT80

2. Using many configurable parameters

  • Include in your sketch
#include<esp_wifi.h>// LittleFS has higher priority than SPIFFS#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )  #defineUSE_LITTLEFStrue  #defineUSE_SPIFFSfalse#elif defined(ARDUINO_ESP32C3_DEV)// For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS  #defineUSE_LITTLEFSfalse  #defineUSE_SPIFFStrue#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) )    #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)      #warning Using ESP32 Core 1.0.6 or 2.0.0+    #endif// 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;    #defineFileFS        LittleFS    #defineFS_Name"LittleFS"  #else    #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)      #warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library    #endif// The library has been merged into esp32 core from release 1.0.6    #include<LITTLEFS.h>// https://github.com/lorol/LITTLEFS    FS* filesystem =      &LITTLEFS;    #defineFileFS        LITTLEFS    #defineFS_Name"LittleFS"  #endif#elif USE_SPIFFS  #include<SPIFFS.h>  FS* filesystem =      &SPIFFS;  #defineFileFS        SPIFFS  #defineFS_Name"SPIFFS"#else// +Use FFat  #include<FFat.h>  FS* filesystem =      &FFat;  #defineFileFS        FFat  #defineFS_Name"FFat"#endif//////#defineLED_BUILTIN2#defineLED_ON            HIGH#defineLED_OFF           LOW// These defines must be put before #include <ESP_DoubleResetDetector.h>// 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// These defines must be put before #include <ESP_DoubleResetDetector.h>// 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_LITTLEFS  #defineESP_DRD_USE_LITTLEFStrue  #defineESP_DRD_USE_SPIFFSfalse  #defineESP_DRD_USE_EEPROMfalse#elif USE_SPIFFS  #defineESP_DRD_USE_LITTLEFSfalse  #defineESP_DRD_USE_SPIFFStrue  #defineESP_DRD_USE_EEPROMfalse#else  #defineESP_DRD_USE_LITTLEFSfalse  #defineESP_DRD_USE_SPIFFSfalse  #defineESP_DRD_USE_EEPROMtrue#endif#defineDOUBLERESETDETECTOR_DEBUGtrue//false#include<ESP_DoubleResetDetector.h>//https://github.com/khoih-prog/ESP_DoubleResetDetector// Number of seconds after reset during which a// subsequent reset will be considered a double reset.#defineDRD_TIMEOUT10// RTC Memory Address for the DoubleResetDetector to use#defineDRD_ADDRESS0//DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS);DoubleResetDetector* drd;//////// Onboard LED I/O pin on NodeMCU boardconstint PIN_LED =2;// D4 on NodeMCU and WeMos. GPIO2/ADC12 of ESP32. Controls the onboard LED.// You only need to format the filesystem once//#define FORMAT_FILESYSTEM       true#defineFORMAT_FILESYSTEMfalse// Assuming max 49 chars#defineTZNAME_MAX_LEN50#defineTIMEZONE_MAX_LEN50typedefstruct{char TZ_Name[TZNAME_MAX_LEN];// "America/Toronto"char TZ[TIMEZONE_MAX_LEN];// "EST5EDT,M3.2.0,M11.1.0"uint16_t checksum;} EthConfig;EthConfig         Ethconfig;#defineCONFIG_FILENAMEF("/eth_cred.dat")//////// Indicates whether ESP has credentials saved from previous session, or double reset detectedbool 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 <AsyncWT32_ETH01_Manager.h>#defineUSE_AVAILABLE_PAGEStrue//false// 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)#defineUSE_ESP_ETH_MANAGER_NTPtrue//false// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen// if using too much memory#defineUSING_AFRICAfalse#defineUSING_AMERICAtrue#defineUSING_ANTARCTICAfalse#defineUSING_ASIAfalse#defineUSING_ATLANTICfalse#defineUSING_AUSTRALIAfalse#defineUSING_EUROPEfalse#defineUSING_INDIANfalse#defineUSING_PACIFICfalse#defineUSING_ETC_GMTfalse// 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)#defineUSE_CLOUDFLARE_NTPfalse#defineUSING_CORS_FEATUREtrue////////////////////////////////////////////// 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  #defineUSE_DHCP_IPtrue#else// You can select DHCP or Static IP here//#define USE_DHCP_IP     true  #defineUSE_DHCP_IPfalse#endif#if ( USE_DHCP_IP )// Use DHCP  #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)    #warning Using DHCP IP  #endif  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  #if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)    #warning Using static IP  #endif  IPAddress stationIP   = IPAddress(192,168,2,232);  IPAddress gatewayIP   = IPAddress(192,168,2,1);  IPAddress netMask     = IPAddress(255,255,255,0);#endif////////////////////////////////////////////#defineUSE_CONFIGURABLE_DNStrueIPAddress dns1IP      = gatewayIP;IPAddress dns2IP      = IPAddress(8,8,8,8);#include<AsyncWT32_ETH01_Manager.h>//https://github.com/khoih-prog/AsyncWT32_ETH01_Manager#defineHTTP_PORT80AsyncWebServerwebServer(HTTP_PORT);AsyncDNSServer dnsServer;////////////////////////////////////////////******************************************   // Defined in AsyncWT32_ETH01_Manager.hpp  typedef struct  {    IPAddress _sta_static_ip;    IPAddress _sta_static_gw;    IPAddress _sta_static_sn;    #if USE_CONFIGURABLE_DNS    IPAddress _sta_static_dns1;    IPAddress _sta_static_dns2;    #endif  }  ETH_STA_IPConfig;******************************************/ETH_STA_IPConfig EthSTA_IPconfig;

3. Using STA-mode DHCP, but don't like to change to static IP or display in Config Portal

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

4. Using STA-mode DHCP, but permit to change to static IP and display in Config Portal

// 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  #defineUSE_DHCP_IPtrue#else// You can select DHCP or Static IP here  #defineUSE_DHCP_IPtrue#endif

5. Using STA-mode StaticIP, and be able to change to DHCP IP and display in Config Portal

// 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  #defineUSE_DHCP_IPtrue#else// You can select DHCP or Static IP here  #defineUSE_DHCP_IPfalse#endif

6. Using STA-mode StaticIP and configurable DNS, and be able to change to DHCP IP and display in Config Portal

// 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  #defineUSE_DHCP_IPtrue#else// You can select DHCP or Static IP here  #defineUSE_DHCP_IPfalse#endif#defineUSE_CONFIGURABLE_DNStrueIPAddress 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

// 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  #defineUSE_DHCP_IPtrue#else// You can select DHCP or Static IP here  #defineUSE_DHCP_IPfalse#endif#defineUSE_CONFIGURABLE_DNSfalse

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)#defineUSE_ESP_ETH_MANAGER_NTPfalse

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)#defineUSE_ESP_ETH_MANAGER_NTPtrue// 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)#defineUSE_CLOUDFLARE_NTPtrue

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)#defineUSE_ESP_ETH_MANAGER_NTPtrue// 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)#defineUSE_CLOUDFLARE_NTPfalse

11. Setting STA-mode static IP

//AsyncWT32_ETH01_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP);AsyncWT32_ETH01_manager.setSTAStaticIPConfig(WM_STA_IPconfig);

12. Using CORS (Cross-Origin Resource Sharing) feature

  1. To use CORS feature withdefault CORS Header "". Some WebBrowsers won't accept this allowing-all "" CORS Header.
// Default false for using only whenever necessary to avoid security issue#defineUSING_CORS_FEATUREtrue
  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#defineUSING_CORS_FEATUREtrue...#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#defineUSING_CORS_FEATUREfalse

13. How to auto getting _timezoneName

  1. Turn on autoNTP 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)#defineUSE_ESP_ETH_MANAGER_NTPtrue
  1. The_timezoneName, in the format similar toAmerica/New_York, America/Toronto, Europe/London, etc., can be retrieved by using
String tempTZ = AsyncWT32_ETH01_manager.getTimezoneName();

14. How to get TZ variable to configure Timezone

  1. ESP32TZ can be configured, using the similar toEST5EDT,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//configTzTime(WM_config.TZ, "pool.ntp.org" );configTzTime(WM_config.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");
  1. To convert from_timezoneName toTZ, use the functiongetTZ() as follows:
constchar * TZ_Result = AsyncWT32_ETH01_manager.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

#defineUSING_AMERICAtrue

Hereafter is the regions' list

// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen// if using too much memory#defineUSING_AFRICAfalse#defineUSING_AMERICAtrue#defineUSING_ANTARCTICAfalse#defineUSING_ASIAfalse#defineUSING_ATLANTICfalse#defineUSING_AUSTRALIAfalse#defineUSING_EUROPEfalse#defineUSING_INDIANfalse#defineUSING_PACIFICfalse#defineUSING_ETC_GMTfalse

15. How to use the TZ variable to configure Timezone

//configTzTime(WM_config.TZ, "pool.ntp.org" );configTzTime(WM_config.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");

then to print local time

voidprintLocalTime(){structtm timeinfo;getLocalTime( &timeinfo );  Serial.print("Local Date/Time:");  Serial.print(asctime( &timeinfo ) );}


HOWTO Open Config Portal

  • When you want to open a config portal, with defaultDHCP hostnameESP32-XXXXXX, just add
#include<AsyncWT32_ETH01_Manager.h>//https://github.com/khoih-prog/AsyncWT32_ETH01_Manager#defineHTTP_PORT80AsyncWebServerwebServer(HTTP_PORT);AsyncDNSServer dnsServer;AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer);

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

AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer,"Personalized-HostName");

then later call

AsyncWT32_ETH01_manager.startConfigPortal()

While in Config Portal, connect to it using its AP IP, e.g.192.168.2.232, configure Credentials, then save. The settings will be saved in non volatile memory. It will then reboot and autoconnect.



HOWTO Add Dynamic Parameters

These illustrating steps is based on the exampleAsync_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

#defineAPI_KEY_LEN17// Default configuration valueschar thingspeakApiKey[API_KEY_LEN]  ="";bool sensorDht22                    =true;int pinSda                          = PIN_D2;// Pin D2 mapped to pin GPIO4 of ESP8266int pinScl                          = PIN_D1;// Pin D1 mapped to pin GPIO5 of ESP8266// Any unique string helping you identify the vars#defineThingSpeakAPI_Label"thingspeakApiKey"#defineSensorDht22_Label"SensorDHT22"#definePinSDA_Label"PinSda"#definePinSCL_Label"PinScl"

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

The exampleAsync_ConfigOnSwitchFS will open the CP whenever a SW press is detected inloop(). So the code to adddynamic variables will be there, just after the CPAsyncWT32_ETH01_Manager class initialization to createAsyncWT32_ETH01_Manager object.

voidloop(){// is configuration portal requested?if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW))  {    Serial.println("\nConfiguration 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 initialization. Once its business is done, there is no need to keep it around    AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer,"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    }

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

2.1 Use the following simple constructor for simple variables such asthingspeakApiKey,pinSda andpinScl :

ESPAsync_EMParameter(constchar *id,constchar *placeholder,constchar *defaultValue,int length);

2.2 For example, to create a newESPAsync_EMParameter objectp_thingspeakApiKey forthingspeakApiKey,

The command to use will be

ESPAsync_EMParameterp_thingspeakApiKey(ThingSpeakAPI_Label,"Thingspeak API Key", thingspeakApiKey, API_KEY_LEN);

where

- p_thingspeakApiKey                  : ESPAsync_EMParameter 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

ForpinSda andpinScl, 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 considerationschar convertedValue[3];sprintf(convertedValue,"%d", pinSda);ESPAsync_EMParameterp_pinSda(PinSDA_Label,"I2C SDA pin", convertedValue,3);sprintf(convertedValue,"%d", pinScl);ESPAsync_EMParameterp_pinScl(PinSCL_Label,"I2C SCL pin", convertedValue,3);

where

- p_pinSda / p_pinScl                         : ESPAsync_EMParameter 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 assensorDht22:

ESPAsync_EMParameter(constchar *id,constchar *placeholder,constchar *defaultValue,int length,constchar *custom,int labelPlacement);

2.4 For example, to create a newESPAsync_EMParameter objectp_sensorDht22 forsensorDht22,

The command to use will be

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

where

- p_sensorDht22                       : ESPAsync_EMParameter 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 thoseESPAsync_EMParameter objects created in Step 2 using the functionaddParameter() of objectAsyncWT32_ETH01_Manager

3.1 addParameter() function Prototype:

//adds a custom parameterbooladdParameter(ESPAsync_EMParameter *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 andp_pinScl

//add all parameters hereAsyncWT32_ETH01_manager.addParameter(&p_thingspeakApiKey);AsyncWT32_ETH01_manager.addParameter(&p_sensorDht22);AsyncWT32_ETH01_manager.addParameter(&p_pinSda);AsyncWT32_ETH01_manager.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 beEEPROM orSPIFFS. While on ESP8266,LittleFS can be used besidesEEPROM ordeprecated SPIFFS.

We can write directly to awell-defined structure of our choice, but the current example is usingJSON to be portable butmuch more complicated and not advised for new users.

4.1 Getting variables' data from CP

After users selectSave, the CPAsyncWT32_ETH01_Manager object will save the user input data into relatedESPAsync_EMParameter objects.

We can now retrieve the data, usinggetValue() function, for eachESPAsync_EMParameter object. Then we can utilize the data for our purpose, such asthingspeakApiKey to log in,sensorDht22 type to know how to handle the sensor,pinSda andpinSda 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 statestrcpy(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 bootwriteConfigFile();

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

First, you have to familiarize yourself withArduinoJson library, its functions, thedisruptive differences betweenArduinoJson version 5.x.x- andv6.0.0+. The best documentation can be found atThe best JSON library for embedded C++.

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

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

boolwriteConfigFile(){  Serial.println("Saving config file");#if (ARDUINOJSON_VERSION_MAJOR >= 6)  DynamicJsonDocumentjson(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");returnfalse;  }#if (ARDUINOJSON_VERSION_MAJOR >= 6)serializeJsonPretty(json, Serial);// Write data to file and close itserializeJson(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");returntrue;}

5.1 Create a DynamicJsonDocument Object

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

DynamicJsonDocumentjson(1024);

5.2 Fill the DynamicJsonDocument Object with data got from Config Portal

ThenJSONify 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 parametersjson[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 theCONFIG_FILE file name we already declared at the beginning of the sketch (for ESP32):

#include<SPIFFS.h>FS* filesystem =      &SPIFFS;#defineFileFS        SPIFFSconstchar* CONFIG_FILE ="/ConfigSW.json";

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

// Open file for writingFile f = FileFS.open(CONFIG_FILE,"w");if (!f){  Serial.println("Failed to open config file for writing");returnfalse;}

5.4 Write the Jsonified data to CONFIG_FILE

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

// Write data to file and close itserializeJson(json, f);

5.5 Close CONFIG_FILE to flush and save the data

Soooo simple !!! Now everybody can do it.

f.close();

ButHOWTO 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 theCONFIG_FILE in Jsonified format, then HOWTO parse the to use.

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

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

boolreadConfigFile(){// this opens the config file in read-mode  File f = FileFS.open(CONFIG_FILE,"r");if (!f)  {    Serial.println("Configuration file not found");returnfalse;  }else  {// we could open the filesize_t size = f.size();// Allocate a buffer to store contents of the file.    std::unique_ptr<char[]>buf(newchar[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)    DynamicJsonDocumentjson(1024);auto deserializeError =deserializeJson(json, buf.get());if ( deserializeError )    {      Serial.println("JSON parseObject() failed");returnfalse;    }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");returnfalse;    }    json.printTo(Serial);#endif// Parse all config file parameters, override// local config variables with parsed valuesif (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");returntrue;}

and the following step-by-step explanations.

6.1 Open CONFIG_FILE to read

As simple as this

// this opens the config file in read-modeFile f = FileFS.open(CONFIG_FILE,"r");

We'll inform and abort if theCONFIG_FILE can't be opened (file not found, can't be opened, etc.)

if (!f){  Serial.println("Configuration file not found");returnfalse;}

6.2 Open CONFIG_FILE to read

Now we have to determine the file size to create a buffer large enough to store the to-be-read data

// we could open the filesize_t size = f.size();// Allocate a buffer to store contents of the file.std::unique_ptr<char[]>buf(newchar[size +1]);

Remember always add 1 to the buffer length to store the terminating0.

Then just read the file into the buffer, and close the file to be safe

// Read and store file contents in buff.readBytes(buf.get(), size);// Closing filef.close();

6.3 Populate the just-read Jsonified data into the DynamicJsonDocument json object

We again use the sameDynamicJsonDocument json object to store the data we've just read fromCONFIG_FILE.

Why the same complicatedDynamicJsonDocument json object ?? Because in steps 5, we did storeJsonified data using the sameDynamicJsonDocument json object. It's much easier we now use it again to facilitate the parsing ofJsonified data back to the data we can use easily.

We first create the object with enough size

DynamicJsonDocumentjson(1024);

then populate it with data from buffer we read fromCONFIG_FILE in step 6.2, pre-parse and check for error. All is done just by one commanddeserializeJson()

auto deserializeError = deserializeJson(json, buf.get());

Abort if there is any data error in the process of writing, storing, reading back. If OK, just nicely print out to the Debug Terminal

if ( deserializeError ){  Serial.println("JSON parseObject() failed");returnfalse;}serializeJson(json, Serial);

6.4 Parse the Jsonified data from the DynamicJsonDocument json object to store into corresponding parameters

This is as simple as in the step 5.2, but in reverse direction.

To be sure there is good corresponding data, not garbage, for each variable, we have to performsanity checks byverifying theDynamicJsonDocument json object still contains the correct keys we passed to it when we wrote intoCONFIG_FILE.

For example:

if (json.containsKey(ThingSpeakAPI_Label))

Then proceed to get every parameter we know we stored there from last CPSave.

// Parse all config file parameters, override// local config variables with parsed valuesif (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];}

6.5 Then what to do now

Just use those parameters for whatever purpose you designed them for in step 1:

The application will use DHTsensor (either DHT11or 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, how it works?

InConfigPortal Mode, it starts an access point @ the current Static or DHCP IP.

Connect to it by going to, e.g.http://192.168.2.232, you'll see thisMain page:

SelectInformation to enter the Info page where the board info will be shown (long page)

SelectConfiguration to enter this page where you can modify its Credentials

Enter your credentials, then clickSave. The Credentials will be saved and the board continues, or reboots if necessary, to connect to the selected Static IP or DHCP.

If you're already satisfied with the current settings and don't want to change anything, just selectExit Portal from theMain page to continue or reboot the board and connect using the previously-stored Credentials.



Documentation

Password protect the configuration Access Point

You can password protect the ConfigPortal AP. CheckAsync_ESP32_FSWebServer example


Callbacks

Save settings

This gets called when custom parameters have been setAND a connection has been established. Use it to set a flag, so when all the configuration finishes, you can save the extra parameters somewhere.

SeeAsync_ConfigOnSwitchFS Example.

AsyncWT32_ETH01_manager.setSaveConfigCallback(saveConfigCallback);

saveConfigCallback declaration and example

//flag for saving databool shouldSaveConfig =false;//callback notifying us of the need to save configvoidsaveConfigCallback () {  Serial.println("Should save config");  shouldSaveConfig =true;}

ConfigPortal Timeout

If you need to set a timeout so theESP32 doesn't hang waiting to be configured for ever.

AsyncWT32_ETH01_manager.setConfigPortalTimeout(120);

which will wait 2 minutes (120 seconds). When the time passes, thestartConfigPortal() function will return and continue the sketch,unless you're accessing theConfig Portal. In this case, thestartConfigPortal() function will stay until you save config data or exittheConfig Portal.


On Demand ConfigPortal

Example usage

voidloop(){// is configuration portal requested?if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW))  {    Serial.println(F("\nConfiguration 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 initialization. Once its business is done, there is no need to keep it around// Use this to default DHCP hostname to ESP32-XXXXXX//AsyncWT32_ETH01_Manager AsyncWT32_ETH01_manager(&webServer, &dnsServer);// Use this to personalize DHCP hostname (RFC952 conformed)    AsyncWebServerwebServer(HTTP_PORT);#if ( USING_ESP32_S2 || USING_ESP32_C3 )    AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer,NULL,"ConfigOnSwitch");#else    AsyncDNSServer dnsServer;    AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer,"ConfigOnSwitch");#endif#if !USE_DHCP_IP#if USE_CONFIGURABLE_DNS// Set static IP, Gateway, Subnetmask, DNS1 and DNS2    AsyncWT32_ETH01_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP);#else// Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2.    AsyncWT32_ETH01_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask);#endif#endif#if USING_CORS_FEATURE    AsyncWT32_ETH01_manager.setCORSHeader("Your Access-Control-Allow-Origin");#endif//Check if there is stored credentials.//If not found, device will remain in configuration mode until switched off via webserver.    Serial.println(F("Opening configuration portal."));if (loadConfigData())    {      AsyncWT32_ETH01_manager.setConfigPortalTimeout(120);//If no access point name has been previously entered disable timeout.      Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal"));    }else    {// Enter CP only if no stored SSID on flash and file      AsyncWT32_ETH01_manager.setConfigPortalTimeout(0);      Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));      initialConfig =true;    }//Starts an access point//and goes into a blocking loop awaiting configurationif (!AsyncWT32_ETH01_manager.startConfigPortal())      Serial.println(F("Not connected to ETH network but continuing anyway."));else    {      Serial.println(F("ETH network connected...yeey :)"));      Serial.print(F("Local IP:"));      Serial.println(ETH.localIP());    }#if USE_ESP_ETH_MANAGER_NTP    String tempTZ = AsyncWT32_ETH01_manager.getTimezoneName();if (strlen(tempTZ.c_str()) <sizeof(Ethconfig.TZ_Name) -1)strcpy(Ethconfig.TZ_Name, tempTZ.c_str());elsestrncpy(Ethconfig.TZ_Name, tempTZ.c_str(),sizeof(Ethconfig.TZ_Name) -1);constchar * TZ_Result = AsyncWT32_ETH01_manager.getTZ(Ethconfig.TZ_Name);if (strlen(TZ_Result) <sizeof(Ethconfig.TZ) -1)strcpy(Ethconfig.TZ, TZ_Result);elsestrncpy(Ethconfig.TZ, TZ_Result,sizeof(Ethconfig.TZ_Name) -1);if (strlen(Ethconfig.TZ_Name) >0 )    {LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name,F(", TZ ="), Ethconfig.TZ);//configTzTime(Ethconfig.TZ, "pool.ntp.org" );configTzTime(Ethconfig.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");    }else    {LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));    }#endif    AsyncWT32_ETH01_manager.getSTAStaticIPConfig(EthSTA_IPconfig);saveConfigData();#if !USE_DHCP_IP// Reset to use new Static IP, if different from current ETH.localIP()if (ETH.localIP() != EthSTA_IPconfig._sta_static_ip)    {      Serial.print(F("Current IP ="));      Serial.print(ETH.localIP());      Serial.print(F(". Reset to take new IP ="));      Serial.println(EthSTA_IPconfig._sta_static_ip);      ESP.restart();delay(2000);    }#endifdigitalWrite(LED_BUILTIN, LED_OFF);// Turn led off as we are not in configuration mode.  }// put your main code here, to run repeatedlycheck_status();}

SeeAsync_ConfigOnSwitch example for a more complex version.



Custom Parameters

Many applications need configuration parameters likeMQTT host and port,Blynk oremoncms tokens, etc. While it is possible to useAsyncWT32_ETH01_Manager to collect additional parameters, it is better to read these parameters from a web service onceAsyncWT32_ETH01_Manager has been used to connect to the Internet.

To capture other parameters withAsyncWT32_ETH01_Manager is a little bit more complicated than all the other features. This requires adding custom HTML to your form.

If you want to do it withAsyncWT32_ETH01_Manager see the exampleAsync_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 Station (client) Static IP Configuration

This will use the specified IP configuration instead of using DHCP in station mode.

AsyncWT32_ETH01_manager.setSTAStaticIPConfig(IPAddress(192,168,2,232), IPAddress(192,168,2,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<style> element, bare in mind it overwrites the included css, not replaces.

AsyncWT32_ETH01_manager.setCustomHeadElement("<style>html{filter: invert(100%); -webkit-filter: invert(100%);}</style>");
  • inject a custom bit of html in the configuration form
ESPAsync_EMParametercustom_text("<p>This is just a text paragraph</p>");AsyncWT32_ETH01_manager.addParameter(&custom_text);
  • inject a custom bit of html in a configuration form elementJust add the bit you want added as the last parameter to the custom parameter constructor.
ESPAsync_EMParametercustom_mqtt_server("server","mqtt server","iot.eclipse",40," readonly");


Examples

  1. Async_ConfigOnSwitch
  2. Async_ConfigOnSwitchFS
  3. Async_ConfigOnDoubleReset_TZ (now support ArduinoJson 6.0.0+ as well as 5.13.5-)
  4. Async_ConfigOnDoubleReset (now support ArduinoJson 6.0.0+ as well as 5.13.5-)
  5. Async_ConfigPortalParamsOnSwitch (now support ArduinoJson 6.0.0+ as well as 5.13.5-)
  6. Async_ESP32_FSWebServer
  7. Async_ESP32_FSWebServer_DRD


#if !( defined(ESP32) )
#error This code is designed for WT32_ETH01 to run on ESP32 platform! Please check your Tools->Board setting.
#endif
//////////////////////////////////////////////////////////////
// Use from 0 to 4. Higher number, more debugging messages and memory usage.
#define_ESPASYNC_ETH_MGR_LOGLEVEL_4
// To not display stored SSIDs and PWDs on Config Portal, select false. Default is true
// Even the stored Credentials are not display, just leave them all blank to reconnect and reuse the stored Credentials
//#define DISPLAY_STORED_CREDENTIALS_IN_CP false
//////////////////////////////////////////////////////////////
//For ESP32, To use ESP32 Dev Module, QIO, Flash 4MB/80MHz, Upload 921600
//Ported to ESP32
#include<esp_wifi.h>
//////////////////////////////////////////////////////////////
// LittleFS has higher priority than SPIFFS
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) )
#defineUSE_LITTLEFStrue
#defineUSE_SPIFFSfalse
#elif defined(ARDUINO_ESP32C3_DEV)
// For core v1.0.6-, ESP32-C3 only supporting SPIFFS and EEPROM. To use v2.0.0+ for LittleFS
#defineUSE_LITTLEFSfalse
#defineUSE_SPIFFStrue
#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) )
#if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)
#warning Using ESP32 Core 1.0.6 or 2.0.0+
#endif
// 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;
#defineFileFS LittleFS
#defineFS_Name"LittleFS"
#else
#if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)
#warning Using ESP32 Core 1.0.5-. You must install LITTLEFS library
#endif
// The library has been merged into esp32 core from release 1.0.6
#include<LITTLEFS.h>// https://github.com/lorol/LITTLEFS
FS* filesystem = &LITTLEFS;
#defineFileFS LITTLEFS
#defineFS_Name"LittleFS"
#endif
#elif USE_SPIFFS
#include<SPIFFS.h>
FS* filesystem = &SPIFFS;
#defineFileFS SPIFFS
#defineFS_Name"SPIFFS"
#else
// Use FFat
#include<FFat.h>
FS* filesystem = &FFat;
#defineFileFS FFat
#defineFS_Name"FFat"
#endif
//////////////////////////////////////////////////////////////
#defineLED_BUILTIN2
#defineLED_ON HIGH
#defineLED_OFF LOW
#definePIN_D1414// Pin D14 mapped to pin GPIO14/HSPI_SCK/ADC16/TOUCH6/TMS of ESP32
#definePIN_D1515// Pin D15 mapped to pin GPIO15/HSPI_SS/ADC13/TOUCH3/TDO of ESP32
#definePIN_D3535// Pin D35 mapped to pin GPIO35/ADC7 of ESP32
#definePIN_D3636// Pin D36 mapped to pin GPIO36/ADC0/SVP of ESP32
#definePIN_D3939// Pin D39 mapped to pin GPIO39/ADC3/SVN of ESP32
//////////////////////////////////////////////////////////////
constint TRIGGER_PIN = PIN_D14;
/*
Alternative trigger pin. Needs to be connected to a button to use this pin. It must be a momentary connection
not connected permanently to ground. Either trigger pin will work.
*/
constint TRIGGER_PIN2 = PIN_D15;
//////////////////////////////////////////////////////////////
// You only need to format the filesystem once
//#define FORMAT_FILESYSTEM true
#defineFORMAT_FILESYSTEMfalse
//////////////////////////////////////////////////////////////
// Assuming max 49 chars
#defineTZNAME_MAX_LEN50
#defineTIMEZONE_MAX_LEN50
typedefstruct
{
char TZ_Name[TZNAME_MAX_LEN];// "America/Toronto"
char TZ[TIMEZONE_MAX_LEN];// "EST5EDT,M3.2.0,M11.1.0"
uint16_t checksum;
} EthConfig;
EthConfig Ethconfig;
//////////////////////////////////////////////////////////////
#defineCONFIG_FILENAMEF("/eth_cred.dat")
//////////////////////////////////////////////////////////////
// Indicates whether ESP has 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 <AsyncWT32_ETH01_Manager.h>
#defineUSE_AVAILABLE_PAGEStrue
// 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)
#defineUSE_ESP_ETH_MANAGER_NTPtrue
// Just use enough to save memory. On ESP8266, can cause blank ConfigPortal screen
// if using too much memory
#defineUSING_AFRICAfalse
#defineUSING_AMERICAtrue
#defineUSING_ANTARCTICAfalse
#defineUSING_ASIAfalse
#defineUSING_ATLANTICfalse
#defineUSING_AUSTRALIAfalse
#defineUSING_EUROPEfalse
#defineUSING_INDIANfalse
#defineUSING_PACIFICfalse
#defineUSING_ETC_GMTfalse
// 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)
#defineUSE_CLOUDFLARE_NTPfalse
// New in v1.0.11
#defineUSING_CORS_FEATUREtrue
//////////////////////////////////////////////////////////////
// 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
#defineUSE_DHCP_IPtrue
#else
// You can select DHCP or Static IP here
//#define USE_DHCP_IP true
#defineUSE_DHCP_IPfalse
#endif
#if ( USE_DHCP_IP )
// Use DHCP
#if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)
#warning Using DHCP IP
#endif
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
#if (_ESPASYNC_ETH_MGR_LOGLEVEL_ > 3)
#warning Using static IP
#endif
IPAddress stationIP = IPAddress(192,168,2,232);
IPAddress gatewayIP = IPAddress(192,168,2,1);
IPAddress netMask = IPAddress(255,255,255,0);
#endif
//////////////////////////////////////////////////////////////
#defineUSE_CONFIGURABLE_DNStrue
IPAddress dns1IP = gatewayIP;
IPAddress dns2IP = IPAddress(8,8,8,8);
#include<AsyncWT32_ETH01_Manager.h>//https://github.com/khoih-prog/AsyncWT32_ETH01_Manager
#defineHTTP_PORT80
//////////////////////////////////////////////////////////////
/******************************************
// Defined in AsyncWT32_ETH01_Manager.hpp
typedef struct
{
IPAddress _sta_static_ip;
IPAddress _sta_static_gw;
IPAddress _sta_static_sn;
#if USE_CONFIGURABLE_DNS
IPAddress _sta_static_dns1;
IPAddress _sta_static_dns2;
#endif
} ETH_STA_IPConfig;
******************************************/
ETH_STA_IPConfig EthSTA_IPconfig;
//////////////////////////////////////////////////////////////
voidinitSTAIPConfigStruct(ETH_STA_IPConfig &in_EthSTA_IPconfig)
{
in_EthSTA_IPconfig._sta_static_ip = stationIP;
in_EthSTA_IPconfig._sta_static_gw = gatewayIP;
in_EthSTA_IPconfig._sta_static_sn = netMask;
#if USE_CONFIGURABLE_DNS
in_EthSTA_IPconfig._sta_static_dns1 = dns1IP;
in_EthSTA_IPconfig._sta_static_dns2 = dns2IP;
#endif
}
//////////////////////////////////////////////////////////////
voiddisplayIPConfigStruct(ETH_STA_IPConfig in_EthSTA_IPconfig)
{
LOGERROR3(F("stationIP ="), in_EthSTA_IPconfig._sta_static_ip,", gatewayIP =", in_EthSTA_IPconfig._sta_static_gw);
LOGERROR1(F("netMask ="), in_EthSTA_IPconfig._sta_static_sn);
#if USE_CONFIGURABLE_DNS
LOGERROR3(F("dns1IP ="), in_EthSTA_IPconfig._sta_static_dns1,", dns2IP =", in_EthSTA_IPconfig._sta_static_dns2);
#endif
}
//////////////////////////////////////////////////////////////
voidtoggleLED()
{
//toggle state
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
//////////////////////////////////////////////////////////////
#if USE_ESP_ETH_MANAGER_NTP
voidprintLocalTime()
{
structtm 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
//////////////////////////////////////////////////////////////
voidheartBeatPrint()
{
#if USE_ESP_ETH_MANAGER_NTP
printLocalTime();
#else
staticint num =1;
if (WT32_ETH01_isConnected())
Serial.print(F("H"));// H means connected to Ethernet
else
Serial.print(F("F"));// F means not connected to Ethernet
if (num ==80)
{
Serial.println();
num =1;
}
elseif (num++ %10 ==0)
{
Serial.print(F(""));
}
#endif
}
//////////////////////////////////////////////////////////////
voidcheck_status()
{
static ulong checkstatus_timeout =0;
static ulong LEDstatus_timeout =0;
static ulong current_millis;
#if USE_ESP_ETH_MANAGER_NTP
#defineHEARTBEAT_INTERVAL60000L
#else
#defineHEARTBEAT_INTERVAL10000L
#endif
#defineLED_INTERVAL2000L
current_millis =millis();
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;
}
}
//////////////////////////////////////////////////////////////
intcalcChecksum(uint8_t* address,uint16_t sizeToCalc)
{
uint16_t checkSum =0;
for (uint16_t index =0; index < sizeToCalc; index++)
{
checkSum += * ( ( (byte*) address ) + index);
}
return checkSum;
}
//////////////////////////////////////////////////////////////
boolloadConfigData()
{
File file = FileFS.open(CONFIG_FILENAME,"r");
LOGERROR(F("LoadCfgFile"));
memset((void *) &Ethconfig,0,sizeof(Ethconfig));
memset((void *) &EthSTA_IPconfig,0,sizeof(EthSTA_IPconfig));
if (file)
{
file.readBytes((char *) &Ethconfig,sizeof(Ethconfig));
file.readBytes((char *) &EthSTA_IPconfig,sizeof(EthSTA_IPconfig));
file.close();
LOGERROR(F("OK"));
if ( Ethconfig.checksum !=calcChecksum( (uint8_t*) &Ethconfig,sizeof(Ethconfig) -sizeof(Ethconfig.checksum) ) )
{
LOGERROR(F("Ethconfig checksum wrong"));
returnfalse;
}
displayIPConfigStruct(EthSTA_IPconfig);
returntrue;
}
else
{
LOGERROR(F("failed"));
returnfalse;
}
}
//////////////////////////////////////////////////////////////
voidsaveConfigData()
{
File file = FileFS.open(CONFIG_FILENAME,"w");
LOGERROR(F("SaveCfgFile"));
if (file)
{
Ethconfig.checksum =calcChecksum( (uint8_t*) &Ethconfig,sizeof(Ethconfig) -sizeof(Ethconfig.checksum) );
file.write((uint8_t*) &Ethconfig,sizeof(Ethconfig));
displayIPConfigStruct(EthSTA_IPconfig);
file.write((uint8_t*) &EthSTA_IPconfig,sizeof(EthSTA_IPconfig));
file.close();
LOGERROR(F("OK"));
}
else
{
LOGERROR(F("failed"));
}
}
//////////////////////////////////////////////////////////////
voidbeginEthernet()
{
// To be called before ETH.begin()
WT32_ETH01_onEvent();
//bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO,
// eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE);
//ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLK_MODE);
ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER);
}
voidinitEthernet()
{
#if !( USE_DHCP_IP )
displayIPConfigStruct(EthSTA_IPconfig);
// Static IP, leave without this line to get IP via DHCP
//bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0);
//ETH.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP);
ETH.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn,
EthSTA_IPconfig._sta_static_dns1);
#endif
WT32_ETH01_waitForConnect();
}
//////////////////////////////////////////////////////////////
voidsetup()
{
//set led pin as output
pinMode(LED_BUILTIN, OUTPUT);
pinMode(TRIGGER_PIN, INPUT_PULLUP);
pinMode(TRIGGER_PIN2, INPUT_PULLUP);
Serial.begin(115200);
while (!Serial &&millis() <5000);
delay(200);
Serial.print(F("\nStarting Async_ConfigOnSwitch using"));
Serial.print(FS_Name);
Serial.print(F(" on"));
Serial.print(ARDUINO_BOARD);
Serial.print(F(" with"));
Serial.println(SHIELD_TYPE);
Serial.println(ASYNC_WT32_ETH01_MANAGER_VERSION);
Serial.setDebugOutput(false);
if (FORMAT_FILESYSTEM)
FileFS.format();
// Format FileFS if not yet
#ifdef ESP32
if (!FileFS.begin(true))
#else
if (!FileFS.begin())
#endif
{
#ifdef ESP8266
FileFS.format();
#endif
Serial.println(F("SPIFFS/LittleFS failed! Already tried formatting."));
if (!FileFS.begin())
{
// prevents debug info from the library to hide err message.
delay(100);
#if USE_LITTLEFS
Serial.println(F("LittleFS failed!. Please use SPIFFS or EEPROM. Stay forever"));
#else
Serial.println(F("SPIFFS failed!. Please use LittleFS or EEPROM. Stay forever"));
#endif
while (true)
{
delay(1);
}
}
}
unsignedlong startedAt =millis();
beginEthernet();
initSTAIPConfigStruct(EthSTA_IPconfig);
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
// Use this to default DHCP hostname to ESP32-XXXXXX
//AsyncWT32_ETH01_Manager AsyncWT32_ETH01_manager(&webServer, &dnsServer);
// Use this to personalize DHCP hostname (RFC952 conformed)
AsyncWebServerwebServer(HTTP_PORT);
#if ( USING_ESP32_S2 || USING_ESP32_C3 )
AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer,NULL,"AsyncConfigOnSwitch");
#else
AsyncDNSServer dnsServer;
AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer,"AsyncConfigOnSwitch");
#endif
AsyncWT32_ETH01_manager.setDebugOutput(true);
#if !USE_DHCP_IP
// Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask)
AsyncWT32_ETH01_manager.setSTAStaticIPConfig(EthSTA_IPconfig);
#endif
#if USING_CORS_FEATURE
AsyncWT32_ETH01_manager.setCORSHeader("Your Access-Control-Allow-Origin");
#endif
bool configDataLoaded =false;
if (loadConfigData())
{
configDataLoaded =true;
//If no access point name has been previously entered disable timeout.
AsyncWT32_ETH01_manager.setConfigPortalTimeout(120);
Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal"));
#if USE_ESP_ETH_MANAGER_NTP
if (strlen(Ethconfig.TZ_Name) >0 )
{
LOGERROR3(F("Current TZ_Name ="), Ethconfig.TZ_Name,F(", TZ ="), Ethconfig.TZ);
//configTzTime(Ethconfig.TZ, "pool.ntp.org" );
configTzTime(Ethconfig.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");
}
else
{
Serial.println(F("Current Timezone is not set. Enter Config Portal to set."));
}
#endif
}
else
{
// Enter CP only if no stored SSID on flash and file
Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));
initialConfig =true;
}
//////////////////////////////////
// Connect ETH now if using STA
initEthernet();
//////////////////////////////////
if (initialConfig)
{
Serial.print(F("Starting configuration portal @"));
Serial.println(ETH.localIP());
digitalWrite(LED_BUILTIN, LED_ON);// Turn led on as we are in configuration mode.
//sets timeout in seconds until configuration portal gets turned off.
//If not specified device will remain in configuration mode until
//switched off via webserver or device is restarted.
//AsyncWT32_ETH01_manager.setConfigPortalTimeout(600);
// Starts an access point
if (!AsyncWT32_ETH01_manager.startConfigPortal())
Serial.println(F("Not connected to ETH network but continuing anyway."));
else
{
Serial.println(F("ETH network connected...yeey :)"));
}
#if USE_ESP_ETH_MANAGER_NTP
String tempTZ = AsyncWT32_ETH01_manager.getTimezoneName();
if (strlen(tempTZ.c_str()) <sizeof(Ethconfig.TZ_Name) -1)
strcpy(Ethconfig.TZ_Name, tempTZ.c_str());
else
strncpy(Ethconfig.TZ_Name, tempTZ.c_str(),sizeof(Ethconfig.TZ_Name) -1);
constchar * TZ_Result = AsyncWT32_ETH01_manager.getTZ(Ethconfig.TZ_Name);
if (strlen(TZ_Result) <sizeof(Ethconfig.TZ) -1)
strcpy(Ethconfig.TZ, TZ_Result);
else
strncpy(Ethconfig.TZ, TZ_Result,sizeof(Ethconfig.TZ_Name) -1);
if (strlen(Ethconfig.TZ_Name) >0 )
{
LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name,F(", TZ ="), Ethconfig.TZ);
//configTzTime(Ethconfig.TZ, "pool.ntp.org" );
configTzTime(Ethconfig.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");
}
else
{
LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
}
#endif
AsyncWT32_ETH01_manager.getSTAStaticIPConfig(EthSTA_IPconfig);
saveConfigData();
}
digitalWrite(LED_BUILTIN, LED_OFF);// Turn led off as we are not in configuration mode.
startedAt =millis();
Serial.print(F("After waiting"));
Serial.print((float) (millis() - startedAt) /1000);
Serial.print(F(" secs more in setup(), connection result is"));
if (WT32_ETH01_isConnected())
{
Serial.print(F("connected. Local IP:"));
Serial.println(ETH.localIP());
}
}
//////////////////////////////////////////////////////////////
voidloop()
{
// is configuration portal requested?
if ((digitalRead(TRIGGER_PIN) == LOW) || (digitalRead(TRIGGER_PIN2) == LOW))
{
Serial.println(F("\nConfiguration 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
// Use this to default DHCP hostname to ESP32-XXXXXX
//AsyncWT32_ETH01_Manager AsyncWT32_ETH01_manager(&webServer, &dnsServer);
// Use this to personalize DHCP hostname (RFC952 conformed)
AsyncWebServerwebServer(HTTP_PORT);
#if ( USING_ESP32_S2 || USING_ESP32_C3 )
AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer,NULL,"ConfigOnSwitch");
#else
AsyncDNSServer dnsServer;
AsyncWT32_ETH01_ManagerAsyncWT32_ETH01_manager(&webServer, &dnsServer,"ConfigOnSwitch");
#endif
#if !USE_DHCP_IP
#if USE_CONFIGURABLE_DNS
// Set static IP, Gateway, Subnetmask, DNS1 and DNS2
AsyncWT32_ETH01_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP);
#else
// Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2.
AsyncWT32_ETH01_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask);
#endif
#endif
#if USING_CORS_FEATURE
AsyncWT32_ETH01_manager.setCORSHeader("Your Access-Control-Allow-Origin");
#endif
//Check if there is stored credentials.
//If not found, device will remain in configuration mode until switched off via webserver.
Serial.println(F("Opening configuration portal."));
if (loadConfigData())
{
AsyncWT32_ETH01_manager.setConfigPortalTimeout(
120);//If no access point name has been previously entered disable timeout.
Serial.println(F("Got stored Credentials. Timeout 120s for Config Portal"));
}
else
{
// Enter CP only if no stored SSID on flash and file
AsyncWT32_ETH01_manager.setConfigPortalTimeout(0);
Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));
initialConfig =true;
}
//Starts an access point
//and goes into a blocking loop awaiting configuration
if (!AsyncWT32_ETH01_manager.startConfigPortal())
Serial.println(F("Not connected to ETH network but continuing anyway."));
else
{
Serial.println(F("ETH network connected...yeey :)"));
Serial.print(F("Local IP:"));
Serial.println(ETH.localIP());
}
#if USE_ESP_ETH_MANAGER_NTP
String tempTZ = AsyncWT32_ETH01_manager.getTimezoneName();
if (strlen(tempTZ.c_str()) <sizeof(Ethconfig.TZ_Name) -1)
strcpy(Ethconfig.TZ_Name, tempTZ.c_str());
else
strncpy(Ethconfig.TZ_Name, tempTZ.c_str(),sizeof(Ethconfig.TZ_Name) -1);
constchar * TZ_Result = AsyncWT32_ETH01_manager.getTZ(Ethconfig.TZ_Name);
if (strlen(TZ_Result) <sizeof(Ethconfig.TZ) -1)
strcpy(Ethconfig.TZ, TZ_Result);
else
strncpy(Ethconfig.TZ, TZ_Result,sizeof(Ethconfig.TZ_Name) -1);
if (strlen(Ethconfig.TZ_Name) >0 )
{
LOGERROR3(F("Saving current TZ_Name ="), Ethconfig.TZ_Name,F(", TZ ="), Ethconfig.TZ);
//configTzTime(Ethconfig.TZ, "pool.ntp.org" );
configTzTime(Ethconfig.TZ,"time.nist.gov","0.pool.ntp.org","1.pool.ntp.org");
}
else
{
LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
}
#endif
AsyncWT32_ETH01_manager.getSTAStaticIPConfig(EthSTA_IPconfig);
saveConfigData();
#if !USE_DHCP_IP
// Reset to use new Static IP, if different from current ETH.localIP()
if (ETH.localIP() != EthSTA_IPconfig._sta_static_ip)
{
Serial.print(F("Current IP ="));
Serial.print(ETH.localIP());
Serial.print(F(". Reset to take new IP ="));
Serial.println(EthSTA_IPconfig._sta_static_ip);
ESP.restart();
delay(2000);
}
#endif
digitalWrite(LED_BUILTIN, LED_OFF);// Turn led off as we are not in configuration mode.
}
// put your main code here, to run repeatedly
check_status();
}



Debug Terminal Output Samples

1. Async_ConfigOnDoubleReset using LittleFS on ESP32_DEV with ETH_PHY_LAN8720

1.1 DRD => Config Portal

This is terminal debug output when runningAsync_ConfigOnDoubleReset onESP32 + LwIP LAN8720.Config Portal was requested by DRD to input and save Credentials, such as Static IP address.

Starting Async_ConfigOnDoubleReset using LittleFS on ESP32_DEV with ETH_PHY_LAN8720AsyncWT32_ETH01_Manager v1.0.0ESP_DoubleResetDetector v1.3.2ETH StartedETH ConnectedETH MAC: A8:48:FA:08:4B:FF, IPv4: 192.168.2.97FULL_DUPLEX, 100Mbps[EM] RFC925 Hostname = AsyncConfigOnDoubleReset[EM] setSTAStaticIPConfig[EM] Set CORS Header to :  Your Access-Control-Allow-Origin[EM] LoadCfgFile [EM] failed[EM] stationIP = 0.0.0.0 , gatewayIP = 0.0.0.0[EM] netMask = 0.0.0.0[EM] dns1IP = 0.0.0.0 , dns2IP = 0.0.0.0LittleFS Flag read = 0xD0D01234doubleResetDetectedSaving config file...Saving config file OKOpen Config Portal without Timeout: Double Reset DetectedStarting configuration portal @ 192.168.2.97[EM] _configPortalStart millis() = 1937[EM] Config Portal IP address = 192.168.2.97[EM] HTTP server started[EM] startConfigPortal : Enter loop[EM] handleRoot[EM] request host IP = 192.168.2.97[EM] Info[EM] Info page sent[EM] handleRoot[EM] request host IP = 192.168.2.97[EM] Handle ETH[EM] Static IP = 192.168.2.232[EM] Sent config page[EM] ETH save[EM] TZ = America/New_York[EM] New Static IP = 192.168.2.232[EM] New Static Gateway = 192.168.2.1[EM] New Static Netmask = 255.255.255.0[EM] New Static DNS1 = 192.168.2.1[EM] New Static DNS2 = 8.8.8.8[EM] Sent eth save page[EM] stopConfigPortalETH network connected...yeey :)[EM] Saving current TZ_Name = America/New_York , TZ =  EST5EDT,M3.2.0,M11.1.0[EM] getSTAStaticIPConfig[EM] SaveCfgFile [EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8[EM] OKCurrent IP = 192.168.2.97. Reset to take new IP = 192.168.2.232ets Jun  8 2016 00:22:57
1.2. Get new Static IP after reset
Starting Async_ConfigOnDoubleReset using LittleFS on ESP32_DEV with ETH_PHY_LAN8720AsyncWT32_ETH01_Manager v1.0.0ESP_DoubleResetDetector v1.3.2ETH StartedETH ConnectedETH MAC: A8:48:FA:08:4B:FF, IPv4: 192.168.2.97FULL_DUPLEX, 100Mbps[EM] RFC925 Hostname = AsyncConfigOnDoubleReset[EM] setSTAStaticIPConfig[EM] Set CORS Header to :  Your Access-Control-Allow-Origin[EM] LoadCfgFile [EM] OK[EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8Got stored Credentials. Timeout 120s for Config Portal[EM] Current TZ_Name = America/New_York , TZ =  EST5EDT,M3.2.0,M11.1.0[EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8LittleFS Flag read = 0xD0D04321No doubleResetDetectedSaving config file...Saving config file OKAfter waiting 0.00 secs more in setup(), connection result is connected. Local IP: 192.168.2.232[EM] freeing allocated params!Local Date/Time: Thu Dec  8 21:51:18 2022Stop doubleResetDetectingSaving config file...Saving config file OKLocal Date/Time: Thu Dec  8 22:34:53 2022Local Date/Time: Thu Dec  8 22:35:53 2022Local Date/Time: Thu Dec  8 22:36:53 2022Local Date/Time: Thu Dec  8 22:37:53 2022

2. Async_ConfigOnSwichFS using LittleFS on ESP32_DEV with ETH_PHY_LAN8720

This is terminal debug output when runningAsync_ConfigOnSwichFS onESP32 + LwIP LAN8720.Config Portal was requested to input and save Credentials.

Starting Async_ConfigOnSwichFS using LittleFS on ESP32_DEV with ETH_PHY_LAN8720AsyncWT32_ETH01_Manager v1.0.0ESP_DoubleResetDetector v1.3.2ETH StartedETH ConnectedETH MAC: A8:48:FA:08:4B:FF, IPv4: 192.168.2.97FULL_DUPLEX, 100MbpsConfiguration file not foundFailed to read ConfigFile, using default values[EM] RFC925 Hostname = ConfigOnSwitchFS[EM] setSTAStaticIPConfig[EM] Set CORS Header to :  Your Access-Control-Allow-Origin[EM] LoadCfgFile [EM] OK[EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8Got stored Credentials. Timeout 120s for Config Portal[EM] Current TZ_Name = America/New_York , TZ =  EST5EDT,M3.2.0,M11.1.0[EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8ETH ConnectedETH MAC: DE:AD:BE:EF:FE:07, IPv4: 192.168.2.232FULL_DUPLEX, 10MbpsAfter waiting 0.00 secs more in setup(), connection result is connected. Local IP: 192.168.2.232[EM] freeing allocated params!Local Date/Time: Thu Dec  8 16:31:38 2022Configuration portal requested.[EM] RFC925 Hostname = ConfigOnSwitchFSOpening configuration portal. [EM] LoadCfgFile [EM] OK[EM] stationIP = 192.168.2.232 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8Got stored Credentials. Timeout 120s for Config Portal[EM] Adding parameter thingspeakApiKey[EM] Adding parameter SensorDHT22[EM] Adding parameter PinSda[EM] Adding parameter PinScl[EM] setSTAStaticIPConfig for USE_CONFIGURABLE_DNS[EM] Set CORS Header to :  Your Access-Control-Allow-Origin[EM] _configPortalStart millis() = 17427[EM] Config Portal IP address = 192.168.2.232[EM] HTTP server started[EM] startConfigPortal : Enter loop[EM] handleRoot[EM] request host IP = 192.168.2.232[EM] Handle ETH[EM] Static IP = 192.168.2.232[EM] Sent config page[EM] ETH save[EM] TZ = America/New_York[EM] Parameter and value : thingspeakApiKey API_Key[EM] Parameter and value : SensorDHT22 T[EM] Parameter and value : PinSda 21[EM] Parameter and value : PinScl 22[EM] New Static IP = 192.168.2.233[EM] New Static Gateway = 192.168.2.1[EM] New Static Netmask = 255.255.255.0[EM] New Static DNS1 = 192.168.2.1[EM] New Static DNS2 = 8.8.8.8[EM] Sent eth save page[EM] stopConfigPortal[EM] startConfigPortal: exit, _configPortalTimeout = 0 millis() = 67391ETH network connected...yeey :)Local IP: 192.168.2.232[EM] Saving current TZ_Name = America/New_York , TZ =  EST5EDT,M3.2.0,M11.1.0[EM] getSTAStaticIPConfig[EM] SaveCfgFile [EM] stationIP = 192.168.2.233 , gatewayIP = 192.168.2.1[EM] netMask = 255.255.255.0[EM] dns1IP = 192.168.2.1 , dns2IP = 8.8.8.8[EM] OKSaving config file{  "thingspeakApiKey": "API_Key",  "SensorDHT22": true,  "PinSda": 21,  "PinScl": 22}Config file was successfully saved[EM] freeing allocated params!Local Date/Time: Thu Dec  8 22:42:53 2022Local Date/Time: Thu Dec  8 22:43:53 2022Local Date/Time: Thu Dec  8 22:44:53 2022

3. Async_ESP32_FSWebServer_DRD using LittleFS on ESP32_DEV with ETH_PHY_LAN8720

This is terminal debug output when runningAsync_ESP32_FSWebServer_DRD onESP32 + LwIP LAN8720.Config Portal was requested by DRD (also usingLittleFS) to input and save Credentials.

Starting Async_ESP32_FSWebServer_DRDusing LittleFS on ESP32_DEV with ETH_PHY_LAN8720AsyncWT32_ETH01_Manager v1.0.0ESP_DoubleResetDetector v1.3.2FS File: CanadaFlag_1.png, size:40.25KBFS File: CanadaFlag_2.png, size:8.12KBFS File: CanadaFlag_3.jpg, size:10.89KBFS File: drd.dat, size: 4BFS File: edit.htm.gz, size:4.02KBFS File: eth_cred.dat, size: 142BFS File: favicon.ico, size:1.12KBFS File: graphs.js.gz, size:1.92KBFS File: index.htm, size:3.63KBFS File: wifi_cred.dat, size: 142BETH StartedETH ConnectedETH MAC: A8:48:FA:08:4B:FF, IPv4:192.168.2.97FULL_DUPLEX, 100Mbps[EM] RFC925 Hostname = AsyncESP32-FSWebServer[EM] setSTAStaticIPConfig[EM] Set CORS Header to :  Your Access-Control-Allow-Origin[EM] LoadCfgFile [EM] OK[EM] stationIP =192.168.2.232 , gatewayIP =192.168.2.1[EM] netMask =255.255.255.0[EM] dns1IP =192.168.2.1 , dns2IP =8.8.8.8ETH ConnectedETH MAC: DE:AD:BE:EF:FE:07, IPv4:192.168.2.232FULL_DUPLEX, 10MbpsGot stored Credentials. Timeout 120sfor Config PortalLittleFS Flag read =0xD0D04321No doubleResetDetectedSaving config file...Saving config file OKAfter waiting0.00 secs more insetup(), connection result is connected. Local IP: 192.168.2.232HTTP server started @ 192.168.2.232===============================================================Open http://192.168.2.232/edit to see the file browserUsing username = admin and password = admin===============================================================[EM] freeing allocated params!HStop doubleResetDetectingSaving config file...Saving config file OKHHHHH HHHHHHHHHH HHHHHHHHHH HHHHHHHHHH


Debug

Debug is enabled by default on Serial. To disable, add beforestartConfigPortal()

AsyncWT32_ETH01_manager.setDebugOutput(false);

You can also change the debugging level from 0 to 4

// Use from 0 to 4. Higher number, more debugging messages and memory usage.#define_ESPASYNC_ETH_MGR_LOGLEVEL_3

Troubleshooting

If you get compilation errors, more often than not, you may need to install a newer version of theESP32 core for Arduino.

Sometimes, the library will only work if you update theESP32 core to the latest version because I am using some newly added function.

If you connect to the created configuration Access Point but the ConfigPortal does not show up, just open a browser and type in the IP of the web portal, by default192.168.2.232.


Issues

Submit issues to:AsyncWT32_ETH01_Manager issues



Contributions and Thanks

  1. Based on and modified fromTzapu,KenTaylor's version,Alan Steremberg's ESPAsyncWiFiManager andKhoi Hoang's ESPAsync_WiFiManager.
  2. Thanks toHristo Gochkov for greatESPAsyncWebServer Library
me-no-dev
⭐️⭐️ Hristo Gochkov

Tzapu
⭐️ Tzapu

kentaylor
⭐️ Ken Taylor

alanswx
⭐️ Alan Steremberg


Contributing

If you want to contribute to this project:

  • Report bugs and errors
  • Ask for enhancements
  • Create issues and pull requests
  • Tell other people about this library

License and credits

  • The library is licensed underMIT

Copyright

Copyright 2022- Khoi Hoang

About

ESP32 + LwIP LAN8720, including WT32-S1, ESP32-S2, ESP32-S3 and ESP32-C3, Connection and Credentials Manager using AsyncWebServer, with enhanced GUI and fallback Web ConfigPortal

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp