diff --git a/.codespellrc b/.codespellrc
new file mode 100644
index 0000000..00fe362
--- /dev/null
+++ b/.codespellrc
@@ -0,0 +1,7 @@
+# See: https://github.com/codespell-project/codespell#using-a-config-file
+[codespell]
+# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
+ignore-words-list = ,
+check-filenames =
+check-hidden =
+skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..402c164
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,79 @@
+## Contributing to AsyncESP8266_W5500_Manager
+
+### Reporting Bugs
+
+Please report bugs in AsyncESP8266_W5500_Manager if you find them.
+
+However, before reporting a bug please check through the following:
+
+* [Existing Open Issues](https://github.com/khoih-prog/AsyncESP8266_W5500_Manager/issues) - someone might have already encountered this.
+
+If you don't find anything, please [open a new issue](https://github.com/khoih-prog/AsyncESP8266_W5500_Manager/issues/new).
+
+### How to submit a bug report
+
+Please ensure to specify the following:
+
+* Arduino IDE version (e.g. 1.8.19) or Platform.io version
+* Board Core Version (e.g. ESP8266 core v3.0.2)
+* Contextual information (e.g. what you were trying to achieve)
+* Simplest possible steps to reproduce
+* Anything that might be relevant in your opinion, such as:
+ * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
+ * Network configuration
+
+
+Please be educated, civilized and constructive. Disrespective posts against [GitHub Code of Conduct](https://docs.github.com/en/site-policy/github-terms/github-event-code-of-conduct) will be ignored and deleted.
+
+
+### Example
+
+```
+Arduino IDE version: 1.8.19
+ESP8266 Core Version v3.0.2
+ESP8266_NODEMCU
+OS: Ubuntu 20.04 LTS
+Linux xy-Inspiron-3593 5.15.0-56-generic #62~20.04.1-Ubuntu SMP Tue Nov 22 21:24:20 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
+
+Context:
+I encountered a crash while using this library
+Steps to reproduce:
+1. ...
+2. ...
+3. ...
+4. ...
+```
+
+### Additional context
+
+Add any other context about the problem here.
+
+---
+
+### Sending Feature Requests
+
+Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
+
+There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/AsyncESP8266_W5500_Manager/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
+
+---
+
+### Sending Pull Requests
+
+Pull Requests with changes and fixes are also welcome!
+
+Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux)
+
+1. Change directory to the library GitHub
+
+```
+xy@xy-Inspiron-3593:~$ cd Arduino/xy/AsyncESP8266_W5500_Manager_GitHub/
+xy@xy-Inspiron-3593:~/Arduino/xy/AsyncESP8266_W5500_Manager_GitHub$
+```
+
+2. Issue astyle command
+
+```
+xy@xy-Inspiron-3593:~/Arduino/xy/AsyncESP8266_W5500_Manager_GitHub$ bash utils/restyle.sh
+```
+
diff --git a/Images/Configuration_AIO_MQTT.png b/Images/Configuration_AIO_MQTT.png
new file mode 100644
index 0000000..75ad6ca
Binary files /dev/null and b/Images/Configuration_AIO_MQTT.png differ
diff --git a/Images/Configuration_Standard.png b/Images/Configuration_Standard.png
new file mode 100644
index 0000000..701359d
Binary files /dev/null and b/Images/Configuration_Standard.png differ
diff --git a/Images/Info.png b/Images/Info.png
new file mode 100644
index 0000000..f25730a
Binary files /dev/null and b/Images/Info.png differ
diff --git a/Images/Main.png b/Images/Main.png
new file mode 100644
index 0000000..6d570d3
Binary files /dev/null and b/Images/Main.png differ
diff --git a/Images/Saved.png b/Images/Saved.png
new file mode 100644
index 0000000..a4c89cb
Binary files /dev/null and b/Images/Saved.png differ
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000..bc9efbe
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,33 @@
+# AsyncESP8266_W5500_Manager Library
+
+[![arduino-library-badge](https://www.ardu-badge.com/badge/AsyncESP8266_W5500_Manager.svg?)](https://www.ardu-badge.com/AsyncESP8266_W5500_Manager)
+[![GitHub release](https://img.shields.io/github/release/khoih-prog/AsyncESP8266_W5500_Manager.svg)](https://github.com/khoih-prog/AsyncESP8266_W5500_Manager/releases)
+[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/AsyncESP8266_W5500_Manager/blob/main/LICENSE)
+[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing)
+[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/AsyncESP8266_W5500_Manager.svg)](http://github.com/khoih-prog/AsyncESP8266_W5500_Manager/issues)
+
+
+
+
+
+---
+---
+
+## Table of contents
+
+* [Changelog](#changelog)
+ * [Releases v1.0.0](#releases-v100)
+
+
+
+---
+---
+
+## Changelog
+
+#### Releases v1.0.0
+
+1. Initial coding to port [ESPAsync_WiFiManager](https://github.com/khoih-prog/ESPAsync_WiFiManager) to ESP8266 boards using `LwIP W5500 Ethernet`.
+2. Use `allman astyle`
+
+
diff --git a/examples/Async_ConfigOnDoubleReset/Async_ConfigOnDoubleReset.ino b/examples/Async_ConfigOnDoubleReset/Async_ConfigOnDoubleReset.ino
new file mode 100644
index 0000000..43e37eb
--- /dev/null
+++ b/examples/Async_ConfigOnDoubleReset/Async_ConfigOnDoubleReset.ino
@@ -0,0 +1,694 @@
+/****************************************************************************************************************************
+ Async_ConfigOnDoubleReset.ino
+ For Ethernet shields using ESP8266_W5500 (ESP8266 + LwIP W5500)
+
+ WebServer_ESP8266_W5500 is a library for the ESP8266 with Ethernet W5500 to run WebServer
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
+ 4. Khoi Hoang (https://github.com/khoih-prog/ESPAsync_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+/****************************************************************************************************************************
+ This example will open a configuration portal when the reset button is pressed twice.
+ This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
+
+ Settings
+ There are two values to be set in the sketch.
+
+ DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
+ DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
+
+ This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
+ To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
+ *****************************************************************************************************************************/
+
+#if !( defined(ESP8266) )
+ #error This code is intended to run on the (ESP8266 + W5500) 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
+
+//////////////////////////////////////////////////////////////
+// Using GPIO4, GPIO16, or GPIO5
+#define CSPIN 16
+
+//////////////////////////////////////////////////////////
+
+#include
+
+#include //https://github.com/esp8266/Arduino
+//needed for library
+#include
+
+#define USE_LITTLEFS true
+
+#if USE_LITTLEFS
+ #include
+ FS* filesystem = &LittleFS;
+ #define FileFS LittleFS
+ #define FS_Name "LittleFS"
+#else
+ FS* filesystem = &SPIFFS;
+ #define FileFS SPIFFS
+ #define FS_Name "SPIFFS"
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define ESP_getChipId() (ESP.getChipId())
+
+#define LED_ON LOW
+#define LED_OFF HIGH
+
+//////////////////////////////////////////////////////////
+
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP32, You must select one to be true (EEPROM or SPIFFS)
+// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
+// Otherwise, library will use default EEPROM storage
+
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP32, You must select one to be true (EEPROM or SPIFFS)
+// Otherwise, library will use default EEPROM storage
+
+// For DRD
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
+// Otherwise, library will use default EEPROM storage
+#if USE_LITTLEFS
+ #define ESP_DRD_USE_LITTLEFS true
+ #define ESP_DRD_USE_SPIFFS false
+#else
+ #define ESP_DRD_USE_LITTLEFS false
+ #define ESP_DRD_USE_SPIFFS true
+#endif
+
+#define ESP_DRD_USE_EEPROM false
+#define ESP8266_DRD_USE_RTC false
+
+#define DOUBLERESETDETECTOR_DEBUG true //false
+
+#include //https://github.com/khoih-prog/ESP_DoubleResetDetector
+
+// Number of seconds after reset during which a
+// subseqent reset will be considered a double reset.
+#define DRD_TIMEOUT 10
+
+// RTC Memory Address for the DoubleResetDetector to use
+#define DRD_ADDRESS 0
+
+//DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS);
+DoubleResetDetector* drd;
+
+//////////////////////////////////////////////////////////
+
+// Onboard LED I/O pin on NodeMCU board
+const int 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
+#define FORMAT_FILESYSTEM false
+
+//////////////////////////////////////////////////////////
+
+// Assuming max 49 chars
+#define TZNAME_MAX_LEN 50
+#define TIMEZONE_MAX_LEN 50
+
+typedef struct
+{
+ 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;
+
+#define CONFIG_FILENAME F("/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
+#define USE_AVAILABLE_PAGES true //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)
+#define USE_ESP_ETH_MANAGER_NTP false
+
+// 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
+
+// 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
+
+#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
+
+ #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, 186);
+ IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
+ IPAddress netMask = IPAddress(255, 255, 255, 0);
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define USE_CONFIGURABLE_DNS true
+
+IPAddress dns1IP = gatewayIP;
+IPAddress dns2IP = IPAddress(8, 8, 8, 8);
+
+#include //https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+
+#define HTTP_PORT 80
+
+//////////////////////////////////////////////////////////
+
+/******************************************
+ // Defined in AsyncESP8266_W5500_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;
+
+//////////////////////////////////////////////////////////
+
+void initSTAIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////
+
+void displayIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+void printLocalTime()
+{
+ static time_t now;
+
+ now = time(nullptr);
+
+ if ( now > 1451602800 )
+ {
+ Serial.print("Local Date/Time: ");
+ Serial.print(ctime(&now));
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////
+
+void heartBeatPrint()
+{
+#if USE_ESP_ETH_MANAGER_NTP
+ printLocalTime();
+#else
+ static int num = 1;
+
+ if (eth.connected())
+ 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;
+ }
+ else if (num++ % 10 == 0)
+ {
+ Serial.print(F(" "));
+ }
+
+#endif
+}
+
+//////////////////////////////////////////////////////////
+
+void check_status()
+{
+ static ulong checkstatus_timeout = 0;
+
+ static ulong current_millis;
+
+#if USE_ESP_ETH_MANAGER_NTP
+#define HEARTBEAT_INTERVAL 60000L
+#else
+#define HEARTBEAT_INTERVAL 10000L
+#endif
+
+ current_millis = millis();
+
+ // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds.
+ if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0))
+ {
+ heartBeatPrint();
+ checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL;
+ }
+}
+
+//////////////////////////////////////////////////////////
+
+int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
+{
+ uint16_t checkSum = 0;
+
+ for (uint16_t index = 0; index < sizeToCalc; index++)
+ {
+ checkSum += * ( ( (byte*) address ) + index);
+ }
+
+ return checkSum;
+}
+
+//////////////////////////////////////////////////////////
+
+bool loadConfigData()
+{
+ 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"));
+
+ return false;
+ }
+
+ displayIPConfigStruct(EthSTA_IPconfig);
+
+ return true;
+ }
+ else
+ {
+ LOGERROR(F("failed"));
+
+ return false;
+ }
+}
+
+//////////////////////////////////////////////////////////
+
+void saveConfigData()
+{
+ 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"));
+ }
+}
+
+//////////////////////////////////////////////////////////
+
+void initEthernet()
+{
+ SPI.begin();
+ SPI.setClockDivider(SPI_CLOCK_DIV4);
+ SPI.setBitOrder(MSBFIRST);
+ SPI.setDataMode(SPI_MODE0);
+
+ LOGWARN(F("Default SPI pinout:"));
+ LOGWARN1(F("MOSI:"), MOSI);
+ LOGWARN1(F("MISO:"), MISO);
+ LOGWARN1(F("SCK:"), SCK);
+ LOGWARN1(F("CS:"), CSPIN);
+ LOGWARN(F("========================="));
+
+#if !USING_DHCP
+ //eth.config(localIP, gateway, netMask, gateway);
+ eth.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn,
+ EthSTA_IPconfig._sta_static_dns1);
+#endif
+
+ eth.setDefault();
+
+ if (!eth.begin())
+ {
+ Serial.println("No Ethernet hardware ... Stop here");
+
+ while (true)
+ {
+ delay(1000);
+ }
+ }
+ else
+ {
+ Serial.print("Connecting to network : ");
+
+ while (!eth.connected())
+ {
+ Serial.print(".");
+ delay(1000);
+ }
+ }
+
+ Serial.println();
+
+#if USING_DHCP
+ Serial.print("Ethernet DHCP IP address: ");
+#else
+ Serial.print("Ethernet Static IP address: ");
+#endif
+
+ Serial.println(eth.localIP());
+}
+
+//////////////////////////////////////////////////////////
+
+void setup()
+{
+ // put your setup code here, to run once:
+ // initialize the LED digital pin as an output.
+ pinMode(PIN_LED, OUTPUT);
+
+ Serial.begin(115200);
+
+ while (!Serial && millis() < 5000);
+
+ delay(200);
+
+ Serial.print(F("\nStarting Async_ConfigOnDoubleReset using "));
+ Serial.print(FS_Name);
+ Serial.print(F(" on "));
+ Serial.print(ARDUINO_BOARD);
+ Serial.print(F(" with "));
+ Serial.println(SHIELD_TYPE);
+ Serial.println(ASYNC_ESP8266_W5500_MANAGER_VERSION);
+ Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION);
+
+ Serial.setDebugOutput(false);
+
+#if FORMAT_FILESYSTEM
+ Serial.println(F("Forced Formatting."));
+ FileFS.format();
+#endif
+
+ // Format FileFS if not yet
+ if (!FileFS.begin())
+ {
+ FileFS.format();
+
+ 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);
+ }
+ }
+ }
+
+ drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS);
+
+ unsigned long startedAt = millis();
+
+ initSTAIPConfigStruct(EthSTA_IPconfig);
+
+ //Local intialization. Once its business is done, there is no need to keep it around
+ // Use this to default DHCP hostname to ESP8266-XXXXXX
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "AsyncConfigOnDoubleReset");
+
+#if !USE_DHCP_IP
+ // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask)
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(EthSTA_IPconfig);
+#endif
+
+#if USING_CORS_FEATURE
+ AsyncESP8266_W5500_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
+ AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "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 Credentials 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 (drd->detectDoubleReset())
+ {
+ // DRD, disable timeout.
+ AsyncESP8266_W5500_manager.setConfigPortalTimeout(0);
+
+ Serial.println(F("Open Config Portal without Timeout: Double Reset Detected"));
+ initialConfig = true;
+ }
+
+ if (initialConfig)
+ {
+ Serial.print(F("Starting configuration portal @ "));
+ Serial.println(eth.localIP());
+
+ digitalWrite(PIN_LED, LED_ON); // turn the LED on by making the voltage LOW to tell us 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.
+ //AsyncESP8266_W5500_manager.setConfigPortalTimeout(600);
+
+ // Starts an access point
+ if (!AsyncESP8266_W5500_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 = AsyncESP8266_W5500_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);
+
+ const char * TZ_Result = AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "pool.ntp.org");
+ }
+ else
+ {
+ LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
+ }
+
+#endif
+
+ AsyncESP8266_W5500_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.reset();
+ delay(2000);
+ }
+
+#endif
+ }
+
+ digitalWrite(PIN_LED, 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 (eth.connected())
+ {
+ Serial.print(F("connected. Local IP: "));
+ Serial.println(eth.localIP());
+ }
+}
+
+void loop()
+{
+ // Call the double reset detector loop method every so often,
+ // so that it can recognise when the timeout expires.
+ // You can also call drd.stop() when you wish to no longer
+ // consider the next reset as a double reset.
+ drd->loop();
+
+ // put your main code here, to run repeatedly
+ check_status();
+}
diff --git a/examples/Async_ConfigOnDoubleReset_TZ/Async_ConfigOnDoubleReset_TZ.ino b/examples/Async_ConfigOnDoubleReset_TZ/Async_ConfigOnDoubleReset_TZ.ino
new file mode 100644
index 0000000..a6430ea
--- /dev/null
+++ b/examples/Async_ConfigOnDoubleReset_TZ/Async_ConfigOnDoubleReset_TZ.ino
@@ -0,0 +1,696 @@
+/****************************************************************************************************************************
+ Async_ConfigOnDoubleReset_TZ.ino
+ For Ethernet shields using ESP8266_W5500 (ESP8266 + LwIP W5500)
+
+ WebServer_ESP8266_W5500 is a library for the ESP8266 with Ethernet W5500 to run WebServer
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
+ 4. Khoi Hoang (https://github.com/khoih-prog/ESPAsync_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+/****************************************************************************************************************************
+ This example will open a configuration portal when the reset button is pressed twice.
+ This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
+
+ Settings
+ There are two values to be set in the sketch.
+
+ DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
+ DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
+
+ This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
+ To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
+ *****************************************************************************************************************************/
+
+#if !( defined(ESP8266) )
+ #error This code is intended to run on the (ESP8266 + W5500) 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
+
+//////////////////////////////////////////////////////////////
+// Using GPIO4, GPIO16, or GPIO5
+#define CSPIN 16
+
+//////////////////////////////////////////////////////////
+
+#include
+
+#include //https://github.com/esp8266/Arduino
+//needed for library
+#include
+
+#define USE_LITTLEFS true
+
+#if USE_LITTLEFS
+ #include
+ FS* filesystem = &LittleFS;
+ #define FileFS LittleFS
+ #define FS_Name "LittleFS"
+#else
+ FS* filesystem = &SPIFFS;
+ #define FileFS SPIFFS
+ #define FS_Name "SPIFFS"
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define ESP_getChipId() (ESP.getChipId())
+
+#define LED_ON LOW
+#define LED_OFF HIGH
+
+//////////////////////////////////////////////////////////
+
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP32, You must select one to be true (EEPROM or SPIFFS)
+// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
+// Otherwise, library will use default EEPROM storage
+
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP32, You must select one to be true (EEPROM or SPIFFS)
+// Otherwise, library will use default EEPROM storage
+
+// For DRD
+// These defines must be put before #include
+// to select where to store DoubleResetDetector's variable.
+// For ESP8266, You must select one to be true (RTC, EEPROM, SPIFFS or LITTLEFS)
+// Otherwise, library will use default EEPROM storage
+#if USE_LITTLEFS
+ #define ESP_DRD_USE_LITTLEFS true
+ #define ESP_DRD_USE_SPIFFS false
+#else
+ #define ESP_DRD_USE_LITTLEFS false
+ #define ESP_DRD_USE_SPIFFS true
+#endif
+
+#define ESP_DRD_USE_EEPROM false
+#define ESP8266_DRD_USE_RTC false
+
+#define DOUBLERESETDETECTOR_DEBUG true //false
+
+#include //https://github.com/khoih-prog/ESP_DoubleResetDetector
+
+// Number of seconds after reset during which a
+// subseqent reset will be considered a double reset.
+#define DRD_TIMEOUT 10
+
+// RTC Memory Address for the DoubleResetDetector to use
+#define DRD_ADDRESS 0
+
+//DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS);
+DoubleResetDetector* drd;
+
+//////////////////////////////////////////////////////////
+
+// Onboard LED I/O pin on NodeMCU board
+//const int LED_BUILTIN = 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
+#define FORMAT_FILESYSTEM false
+
+//////////////////////////////////////////////////////////
+
+// Assuming max 49 chars
+#define TZNAME_MAX_LEN 50
+#define TIMEZONE_MAX_LEN 50
+
+typedef struct
+{
+ 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;
+
+#define CONFIG_FILENAME F("/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
+#define USE_AVAILABLE_PAGES true //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)
+#define USE_ESP_ETH_MANAGER_NTP true //false
+
+// 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
+
+// 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
+
+#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
+
+ #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, 186);
+ IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
+ IPAddress netMask = IPAddress(255, 255, 255, 0);
+#endif
+
+////////////////////////////////////////////
+
+#define USE_CONFIGURABLE_DNS true
+
+IPAddress dns1IP = gatewayIP;
+IPAddress dns2IP = IPAddress(8, 8, 8, 8);
+
+#include //https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+
+#define HTTP_PORT 80
+
+//////////////////////////////////////////////////////////////
+
+/******************************************
+ // Defined in AsyncESP8266_W5500_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;
+
+//////////////////////////////////////////////////////////////
+
+void initSTAIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+void displayIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+void printLocalTime()
+{
+ static time_t now;
+
+ now = time(nullptr);
+
+ if ( now > 1451602800 )
+ {
+ Serial.print("Local Date/Time: ");
+ Serial.print(ctime(&now));
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////
+
+void heartBeatPrint()
+{
+#if USE_ESP_ETH_MANAGER_NTP
+ printLocalTime();
+#else
+ static int num = 1;
+
+ if (eth.connected())
+ 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;
+ }
+ else if (num++ % 10 == 0)
+ {
+ Serial.print(F(" "));
+ }
+
+#endif
+}
+
+//////////////////////////////////////////////////////////////
+
+void check_status()
+{
+ static ulong checkstatus_timeout = 0;
+
+ static ulong current_millis;
+
+#if USE_ESP_ETH_MANAGER_NTP
+#define HEARTBEAT_INTERVAL 60000L
+#else
+#define HEARTBEAT_INTERVAL 10000L
+#endif
+
+ current_millis = millis();
+
+ // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds.
+ if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0))
+ {
+ heartBeatPrint();
+ checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
+{
+ uint16_t checkSum = 0;
+
+ for (uint16_t index = 0; index < sizeToCalc; index++)
+ {
+ checkSum += * ( ( (byte*) address ) + index);
+ }
+
+ return checkSum;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool loadConfigData()
+{
+ 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"));
+
+ return false;
+ }
+
+ displayIPConfigStruct(EthSTA_IPconfig);
+
+ return true;
+ }
+ else
+ {
+ LOGERROR(F("failed"));
+
+ return false;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void saveConfigData()
+{
+ 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"));
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void initEthernet()
+{
+ SPI.begin();
+ SPI.setClockDivider(SPI_CLOCK_DIV4);
+ SPI.setBitOrder(MSBFIRST);
+ SPI.setDataMode(SPI_MODE0);
+
+ LOGWARN(F("Default SPI pinout:"));
+ LOGWARN1(F("MOSI:"), MOSI);
+ LOGWARN1(F("MISO:"), MISO);
+ LOGWARN1(F("SCK:"), SCK);
+ LOGWARN1(F("CS:"), CSPIN);
+ LOGWARN(F("========================="));
+
+#if !USING_DHCP
+ //eth.config(localIP, gateway, netMask, gateway);
+ eth.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn,
+ EthSTA_IPconfig._sta_static_dns1);
+#endif
+
+ eth.setDefault();
+
+ if (!eth.begin())
+ {
+ Serial.println("No Ethernet hardware ... Stop here");
+
+ while (true)
+ {
+ delay(1000);
+ }
+ }
+ else
+ {
+ Serial.print("Connecting to network : ");
+
+ while (!eth.connected())
+ {
+ Serial.print(".");
+ delay(1000);
+ }
+ }
+
+ Serial.println();
+
+#if USING_DHCP
+ Serial.print("Ethernet DHCP IP address: ");
+#else
+ Serial.print("Ethernet Static IP address: ");
+#endif
+
+ Serial.println(eth.localIP());
+}
+
+//////////////////////////////////////////////////////////////
+
+void setup()
+{
+ // put your setup code here, to run once:
+ // initialize the LED digital pin as an output.
+ pinMode(LED_BUILTIN, OUTPUT);
+
+ Serial.begin(115200);
+
+ while (!Serial && millis() < 5000);
+
+ delay(200);
+
+ Serial.print(F("\nStarting Async_ConfigOnDoubleReset_TZ using "));
+ Serial.print(FS_Name);
+ Serial.print(F(" on "));
+ Serial.print(ARDUINO_BOARD);
+ Serial.print(F(" with "));
+ Serial.println(SHIELD_TYPE);
+ Serial.println(ASYNC_ESP8266_W5500_MANAGER_VERSION);
+ Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION);
+
+ Serial.setDebugOutput(false);
+
+#if FORMAT_FILESYSTEM
+ Serial.println(F("Forced Formatting."));
+ FileFS.format();
+#endif
+
+ // Format FileFS if not yet
+ if (!FileFS.begin())
+ {
+ FileFS.format();
+
+ 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);
+ }
+ }
+ }
+
+ drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS);
+
+ unsigned long startedAt = millis();
+
+ initSTAIPConfigStruct(EthSTA_IPconfig);
+
+ //Local intialization. Once its business is done, there is no need to keep it around
+ // Use this to default DHCP hostname to ESP8266-XXXXXX
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "AsyncConfigOnDoubleReset");
+
+#if !USE_DHCP_IP
+ // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask)
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(EthSTA_IPconfig);
+#endif
+
+#if USING_CORS_FEATURE
+ AsyncESP8266_W5500_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
+ AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "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 Credentials 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 (drd->detectDoubleReset())
+ {
+ // DRD, disable timeout.
+ AsyncESP8266_W5500_manager.setConfigPortalTimeout(0);
+
+ Serial.println(F("Open Config Portal without Timeout: Double Reset Detected"));
+ initialConfig = true;
+ }
+
+ 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.
+ //AsyncESP8266_W5500_manager.setConfigPortalTimeout(600);
+
+ // Starts an access point
+ if (!AsyncESP8266_W5500_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 = AsyncESP8266_W5500_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);
+
+ const char * TZ_Result = AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "pool.ntp.org");
+ }
+ else
+ {
+ LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
+ }
+
+#endif
+
+ AsyncESP8266_W5500_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.reset();
+ delay(2000);
+ }
+
+#endif
+ }
+
+ 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 (eth.connected())
+ {
+ Serial.print(F("connected. Local IP: "));
+ Serial.println(eth.localIP());
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void loop()
+{
+ // Call the double reset detector loop method every so often,
+ // so that it can recognise when the timeout expires.
+ // You can also call drd.stop() when you wish to no longer
+ // consider the next reset as a double reset.
+ drd->loop();
+
+ // put your main code here, to run repeatedly
+ check_status();
+}
diff --git a/examples/Async_ConfigOnSwitch/Async_ConfigOnSwitch.ino b/examples/Async_ConfigOnSwitch/Async_ConfigOnSwitch.ino
new file mode 100644
index 0000000..cdf7885
--- /dev/null
+++ b/examples/Async_ConfigOnSwitch/Async_ConfigOnSwitch.ino
@@ -0,0 +1,797 @@
+/****************************************************************************************************************************
+ Async_ConfigOnSwitch.ino
+ For Ethernet shields using ESP8266_W5500 (ESP8266 + LwIP W5500)
+
+ WebServer_ESP8266_W5500 is a library for the ESP8266 with Ethernet W5500 to run WebServer
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
+ 4. Khoi Hoang (https://github.com/khoih-prog/ESPAsync_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+/****************************************************************************************************************************
+ This example will open a configuration portal when no configuration has been previously entered or when a button is pushed.
+ It is the easiest scenario for configuration but requires a pin and a button on the ESP8266 device.
+ The Flash button is convenient for this on NodeMCU devices.
+
+ Also in this example a password is required to connect to the configuration portal
+ network. This is inconvenient but means that only those who know the password or those
+ already connected to the target network can access the configuration portal and
+ the network credentials will be sent from the browser over an encrypted connection and
+ can not be read by observers.
+ *****************************************************************************************************************************/
+
+#if !( defined(ESP8266) )
+ #error This code is intended to run on the (ESP8266 + W5500) 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
+
+//////////////////////////////////////////////////////////////
+// Using GPIO4, GPIO16, or GPIO5
+#define CSPIN 16
+
+//////////////////////////////////////////////////////////
+
+#include
+
+#include //https://github.com/esp8266/Arduino
+//needed for library
+#include
+
+#define USE_LITTLEFS true
+
+#if USE_LITTLEFS
+ #include
+ FS* filesystem = &LittleFS;
+ #define FileFS LittleFS
+ #define FS_Name "LittleFS"
+#else
+ FS* filesystem = &SPIFFS;
+ #define FileFS SPIFFS
+ #define FS_Name "SPIFFS"
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define ESP_getChipId() (ESP.getChipId())
+
+#define LED_ON LOW
+#define LED_OFF HIGH
+
+//////////////////////////////////////////////////////////
+
+// Onboard LED I/O pin on NodeMCU board
+#define LED_BUILTIN 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266, NodeMCU and WeMoS, control on-board LED
+
+//PIN_D0 can't be used for PWM/I2C
+#define PIN_D0 16 // Pin D0 mapped to pin GPIO16/USER/WAKE of ESP8266. This pin is also used for Onboard-Blue LED. PIN_D0 = 0 => LED ON
+#define PIN_D1 5 // Pin D1 mapped to pin GPIO5 of ESP8266
+#define PIN_D2 4 // Pin D2 mapped to pin GPIO4 of ESP8266
+#define PIN_D3 0 // Pin D3 mapped to pin GPIO0/FLASH of ESP8266
+#define PIN_D4 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266
+#define PIN_D5 14 // Pin D5 mapped to pin GPIO14/HSCLK of ESP8266
+#define PIN_D6 12 // Pin D6 mapped to pin GPIO12/HMISO of ESP8266
+#define PIN_D7 13 // Pin D7 mapped to pin GPIO13/RXD2/HMOSI of ESP8266
+#define PIN_D8 15 // Pin D8 mapped to pin GPIO15/TXD2/HCS of ESP8266
+
+//Don't use pins GPIO6 to GPIO11 as already connected to flash, etc. Use them can crash the program
+//GPIO9(D11/SD2) and GPIO11 can be used only if flash in DIO mode ( not the default QIO mode)
+#define PIN_D11 9 // Pin D11/SD2 mapped to pin GPIO9/SDD2 of ESP8266
+#define PIN_D12 10 // Pin D12/SD3 mapped to pin GPIO10/SDD3 of ESP8266
+#define PIN_SD2 9 // Pin SD2 mapped to pin GPIO9/SDD2 of ESP8266
+#define PIN_SD3 10 // Pin SD3 mapped to pin GPIO10/SDD3 of ESP8266
+
+#define PIN_D9 3 // Pin D9 /RX mapped to pin GPIO3/RXD0 of ESP8266
+#define PIN_D10 1 // Pin D10/TX mapped to pin GPIO1/TXD0 of ESP8266
+#define PIN_RX 3 // Pin RX mapped to pin GPIO3/RXD0 of ESP8266
+#define PIN_TX 1 // Pin RX mapped to pin GPIO1/TXD0 of ESP8266
+
+#define LED_PIN 16 // Pin D0 mapped to pin GPIO16 of ESP8266. This pin is also used for Onboard-Blue LED. PIN_D0 = 0 => LED ON
+
+/* Trigger for inititating config mode is Pin D1 and also flash button on NodeMCU
+ Flash button is convenient to use but if it is pressed it will stuff up the serial port device driver
+ until the computer is rebooted on windows machines.
+*/
+const int TRIGGER_PIN = PIN_D1; // D1 on NodeMCU and WeMos.
+/*
+ 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.
+*/
+const int TRIGGER_PIN2 = PIN_D2; // D2 on NodeMCU and WeMos.
+
+//////////////////////////////////////////////////////////
+
+// You only need to format the filesystem once
+//#define FORMAT_FILESYSTEM true
+#define FORMAT_FILESYSTEM false
+
+//////////////////////////////////////////////////////////
+
+// Assuming max 49 chars
+#define TZNAME_MAX_LEN 50
+#define TIMEZONE_MAX_LEN 50
+
+typedef struct
+{
+ 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;
+
+#define CONFIG_FILENAME F("/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
+#define USE_AVAILABLE_PAGES true //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)
+#define USE_ESP_ETH_MANAGER_NTP true //false
+
+// 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
+
+// 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
+
+#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
+
+ #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, 186);
+ IPAddress gatewayIP = IPAddress(192, 168, 2, 1);
+ IPAddress netMask = IPAddress(255, 255, 255, 0);
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define USE_CONFIGURABLE_DNS true
+
+IPAddress dns1IP = gatewayIP;
+IPAddress dns2IP = IPAddress(8, 8, 8, 8);
+
+#include //https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+
+#define HTTP_PORT 80
+
+//////////////////////////////////////////////////////////////
+
+/******************************************
+ // Defined in AsyncESP8266_W5500_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;
+
+//////////////////////////////////////////////////////////////
+
+void initSTAIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+void displayIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+void toggleLED()
+{
+ //toggle state
+ digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
+}
+
+//////////////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+void printLocalTime()
+{
+ static time_t now;
+
+ now = time(nullptr);
+
+ if ( now > 1451602800 )
+ {
+ Serial.print("Local Date/Time: ");
+ Serial.print(ctime(&now));
+ }
+}
+#endif
+
+void heartBeatPrint()
+{
+#if USE_ESP_ETH_MANAGER_NTP
+ printLocalTime();
+#else
+ static int num = 1;
+
+ if (eth.connected())
+ 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;
+ }
+ else if (num++ % 10 == 0)
+ {
+ Serial.print(F(" "));
+ }
+
+#endif
+}
+
+//////////////////////////////////////////////////////////////
+
+void check_status()
+{
+ static ulong checkstatus_timeout = 0;
+ static ulong LEDstatus_timeout = 0;
+
+ static ulong current_millis;
+
+#if USE_ESP_ETH_MANAGER_NTP
+#define HEARTBEAT_INTERVAL 60000L
+#else
+#define HEARTBEAT_INTERVAL 10000L
+#endif
+
+#define LED_INTERVAL 2000L
+
+ 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;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
+{
+ uint16_t checkSum = 0;
+
+ for (uint16_t index = 0; index < sizeToCalc; index++)
+ {
+ checkSum += * ( ( (byte*) address ) + index);
+ }
+
+ return checkSum;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool loadConfigData()
+{
+ 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"));
+
+ return false;
+ }
+
+ displayIPConfigStruct(EthSTA_IPconfig);
+
+ return true;
+ }
+ else
+ {
+ LOGERROR(F("failed"));
+
+ return false;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void saveConfigData()
+{
+ 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"));
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void initEthernet()
+{
+ SPI.begin();
+ SPI.setClockDivider(SPI_CLOCK_DIV4);
+ SPI.setBitOrder(MSBFIRST);
+ SPI.setDataMode(SPI_MODE0);
+
+ LOGWARN(F("Default SPI pinout:"));
+ LOGWARN1(F("MOSI:"), MOSI);
+ LOGWARN1(F("MISO:"), MISO);
+ LOGWARN1(F("SCK:"), SCK);
+ LOGWARN1(F("CS:"), CSPIN);
+ LOGWARN(F("========================="));
+
+#if !USING_DHCP
+ //eth.config(localIP, gateway, netMask, gateway);
+ eth.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn,
+ EthSTA_IPconfig._sta_static_dns1);
+#endif
+
+ eth.setDefault();
+
+ if (!eth.begin())
+ {
+ Serial.println("No Ethernet hardware ... Stop here");
+
+ while (true)
+ {
+ delay(1000);
+ }
+ }
+ else
+ {
+ Serial.print("Connecting to network : ");
+
+ while (!eth.connected())
+ {
+ Serial.print(".");
+ delay(1000);
+ }
+ }
+
+ Serial.println();
+
+#if USING_DHCP
+ Serial.print("Ethernet DHCP IP address: ");
+#else
+ Serial.print("Ethernet Static IP address: ");
+#endif
+
+ Serial.println(eth.localIP());
+}
+
+//////////////////////////////////////////////////////////////
+
+void setup()
+{
+ //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_ESP8266_W5500_MANAGER_VERSION);
+
+ Serial.setDebugOutput(false);
+
+#if FORMAT_FILESYSTEM
+ Serial.println(F("Forced Formatting."));
+ FileFS.format();
+#endif
+
+ // Format FileFS if not yet
+ if (!FileFS.begin())
+ {
+ FileFS.format();
+
+ 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);
+ }
+ }
+ }
+
+ unsigned long startedAt = millis();
+
+ 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
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+
+#if ( USING_ESP32_S2 || USING_ESP32_C3 )
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, NULL, "AsyncConfigOnSwitch");
+#else
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "AsyncConfigOnSwitch");
+#endif
+
+ AsyncESP8266_W5500_manager.setDebugOutput(true);
+
+#if !USE_DHCP_IP
+ // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask)
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(EthSTA_IPconfig);
+#endif
+
+#if USING_CORS_FEATURE
+ AsyncESP8266_W5500_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
+ AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "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.
+ //AsyncESP8266_W5500_manager.setConfigPortalTimeout(600);
+
+ // Starts an access point
+ if (!AsyncESP8266_W5500_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 = AsyncESP8266_W5500_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);
+
+ const char * TZ_Result = AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "pool.ntp.org");
+ }
+ else
+ {
+ LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
+ }
+
+#endif
+
+ AsyncESP8266_W5500_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 (eth.connected())
+ {
+ Serial.print(F("connected. Local IP: "));
+ Serial.println(eth.localIP());
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void loop()
+{
+ // 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
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+
+#if ( USING_ESP32_S2 || USING_ESP32_C3 )
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, NULL, "ConfigOnSwitch");
+#else
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "ConfigOnSwitch");
+#endif
+
+#if !USE_DHCP_IP
+#if USE_CONFIGURABLE_DNS
+ // Set static IP, Gateway, Subnetmask, DNS1 and DNS2
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP);
+#else
+ // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2.
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask);
+#endif
+#endif
+
+#if USING_CORS_FEATURE
+ AsyncESP8266_W5500_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())
+ {
+ AsyncESP8266_W5500_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
+ AsyncESP8266_W5500_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 (!AsyncESP8266_W5500_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 = AsyncESP8266_W5500_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);
+
+ const char * TZ_Result = AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "pool.ntp.org");
+ }
+ else
+ {
+ LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
+ }
+
+#endif
+
+ AsyncESP8266_W5500_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.reset();
+ 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();
+}
diff --git a/examples/Async_ConfigOnSwitchFS/Async_ConfigOnSwitchFS.ino b/examples/Async_ConfigOnSwitchFS/Async_ConfigOnSwitchFS.ino
new file mode 100644
index 0000000..fdfd4e0
--- /dev/null
+++ b/examples/Async_ConfigOnSwitchFS/Async_ConfigOnSwitchFS.ino
@@ -0,0 +1,1021 @@
+/****************************************************************************************************************************
+ Async_ConfigOnSwitchFS.ino
+ For Ethernet shields using ESP8266_W5500 (ESP8266 + LwIP W5500)
+
+ WebServer_ESP8266_W5500 is a library for the ESP8266 with Ethernet W5500 to run WebServer
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Alan Steremberg (https://github.com/alanswx/ESPAsyncWiFiManager)
+ 4. Khoi Hoang (https://github.com/khoih-prog/ESPAsync_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+/****************************************************************************************************************************
+ This example will open a configuration portal when the reset button is pressed twice.
+ This method works well on Wemos boards which have a single reset button on board. It avoids using a pin for launching the configuration portal.
+
+ Settings
+ There are two values to be set in the sketch.
+
+ DRD_TIMEOUT - Number of seconds to wait for the second reset. Set to 10 in the example.
+ DRD_ADDRESS - The address in ESP8266 RTC RAM to store the flag. This memory must not be used for other purposes in the same sketch. Set to 0 in the example.
+
+ This example, originally relied on the Double Reset Detector library from https://github.com/datacute/DoubleResetDetector
+ To support ESP32, use ESP_DoubleResetDetector library from //https://github.com/khoih-prog/ESP_DoubleResetDetector
+ *****************************************************************************************************************************/
+/****************************************************************************************************************************
+ This example will open a configuration portal when no configuration has been previously entered or when a button is pushed.
+ It is the easiest scenario for configuration but requires a pin and a button on the ESP8266 device.
+ The Flash button is convenient for this on NodeMCU devices.
+
+ Also in this example a password is required to connect to the configuration portal
+ network. This is inconvenient but means that only those who know the password or those
+ already connected to the target network can access the configuration portal and
+ the network credentials will be sent from the browser over an encrypted connection and
+ can not be read by observers.
+ *****************************************************************************************************************************/
+
+#if !( defined(ESP8266) )
+ #error This code is intended to run on the (ESP8266 + W5500) 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
+
+//////////////////////////////////////////////////////////////
+// Using GPIO4, GPIO16, or GPIO5
+#define CSPIN 16
+
+//////////////////////////////////////////////////////////
+
+#include
+
+// Now support ArduinoJson 6.0.0+ ( tested with v6.14.1 )
+#include // get it from https://arduinojson.org/ or install via Arduino library manager
+
+#include //https://github.com/esp8266/Arduino
+//needed for library
+#include
+
+#define USE_LITTLEFS true
+
+#if USE_LITTLEFS
+ #include
+ FS* filesystem = &LittleFS;
+ #define FileFS LittleFS
+ #define FS_Name "LittleFS"
+#else
+ FS* filesystem = &SPIFFS;
+ #define FileFS SPIFFS
+ #define FS_Name "SPIFFS"
+#endif
+
+//////////////////////////////////////////////////////////
+
+#define ESP_getChipId() (ESP.getChipId())
+
+#define LED_ON LOW
+#define LED_OFF HIGH
+
+//////////////////////////////////////////////////////////
+
+// Onboard LED I/O pin on NodeMCU board
+#define LED_BUILTIN 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266, NodeMCU and WeMoS, control on-board LED
+
+//PIN_D0 can't be used for PWM/I2C
+#define PIN_D0 16 // Pin D0 mapped to pin GPIO16/USER/WAKE of ESP8266. This pin is also used for Onboard-Blue LED. PIN_D0 = 0 => LED ON
+#define PIN_D1 5 // Pin D1 mapped to pin GPIO5 of ESP8266
+#define PIN_D2 4 // Pin D2 mapped to pin GPIO4 of ESP8266
+#define PIN_D3 0 // Pin D3 mapped to pin GPIO0/FLASH of ESP8266
+#define PIN_D4 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266
+#define PIN_D5 14 // Pin D5 mapped to pin GPIO14/HSCLK of ESP8266
+#define PIN_D6 12 // Pin D6 mapped to pin GPIO12/HMISO of ESP8266
+#define PIN_D7 13 // Pin D7 mapped to pin GPIO13/RXD2/HMOSI of ESP8266
+#define PIN_D8 15 // Pin D8 mapped to pin GPIO15/TXD2/HCS of ESP8266
+
+//Don't use pins GPIO6 to GPIO11 as already connected to flash, etc. Use them can crash the program
+//GPIO9(D11/SD2) and GPIO11 can be used only if flash in DIO mode ( not the default QIO mode)
+#define PIN_D11 9 // Pin D11/SD2 mapped to pin GPIO9/SDD2 of ESP8266
+#define PIN_D12 10 // Pin D12/SD3 mapped to pin GPIO10/SDD3 of ESP8266
+#define PIN_SD2 9 // Pin SD2 mapped to pin GPIO9/SDD2 of ESP8266
+#define PIN_SD3 10 // Pin SD3 mapped to pin GPIO10/SDD3 of ESP8266
+
+#define PIN_D9 3 // Pin D9 /RX mapped to pin GPIO3/RXD0 of ESP8266
+#define PIN_D10 1 // Pin D10/TX mapped to pin GPIO1/TXD0 of ESP8266
+#define PIN_RX 3 // Pin RX mapped to pin GPIO3/RXD0 of ESP8266
+#define PIN_TX 1 // Pin RX mapped to pin GPIO1/TXD0 of ESP8266
+
+//////////////////////////////////////////////////////////////
+
+/* Trigger for inititating config mode is Pin D1 and also flash button on NodeMCU
+ Flash button is convenient to use but if it is pressed it will stuff up the serial port device driver
+ until the computer is rebooted on windows machines.
+*/
+const int TRIGGER_PIN = PIN_D1; // D1 on NodeMCU and WeMos.
+/*
+ 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.
+*/
+const int TRIGGER_PIN2 = PIN_D2; // D2 on NodeMCU and WeMos.
+
+int pinSda = PIN_D2; // Pin D2 mapped to pin GPIO4 of ESP8266
+int pinScl = PIN_D1; // Pin D1 mapped to pin GPIO5 of ESP8266
+
+//////////////////////////////////////////////////////////////
+
+const char* JSON_CONFIG_FILE = "/ConfigSW.json";
+
+//////////////////////////////////////////////////////////////
+
+// Variables
+
+// Default configuration values
+char thingspeakApiKey[17] = "";
+bool sensorDht22 = true;
+
+#define ThingSpeakAPI_Label "thingspeakApiKey"
+#define SensorDht22_Label "SensorDHT22"
+#define PinSDA_Label "PinSda"
+#define PinSCL_Label "PinScl"
+
+//////////////////////////////////////////////////////////////
+
+// Function Prototypes
+
+bool readConfigFile();
+bool writeConfigFile();
+
+//////////////////////////////////////////////////////////////
+
+// You only need to format the filesystem once
+//#define FORMAT_FILESYSTEM true
+#define FORMAT_FILESYSTEM false
+
+//////////////////////////////////////////////////////////////
+
+// Assuming max 49 chars
+#define TZNAME_MAX_LEN 50
+#define TIMEZONE_MAX_LEN 50
+
+typedef struct
+{
+ 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;
+
+#define CONFIG_FILENAME F("/eth_cred.dat")
+
+//////////////////////////////////////////////////////////////
+
+// Indicates whether ESP has credentials saved from previous session
+bool initialConfig = false;
+
+// Use false if you don't like to display Available Pages in Information Page of Config Portal
+// Comment out or use true to display Available Pages in Information Page of Config Portal
+// Must be placed before #include
+#define USE_AVAILABLE_PAGES true
+
+// 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_ETH_MANAGER_NTP true
+
+// 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
+
+// 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
+
+ #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
+
+//////////////////////////////////////////////////////////////
+
+#define USE_CONFIGURABLE_DNS true
+
+IPAddress dns1IP = gatewayIP;
+IPAddress dns2IP = IPAddress(8, 8, 8, 8);
+
+#include //https://github.com/khoih-prog/AsyncESP8266_W5500_Manager
+
+#define HTTP_PORT 80
+
+//////////////////////////////////////////////////////////////
+
+/******************************************
+ // Defined in AsyncESP8266_W5500_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;
+
+//////////////////////////////////////////////////////////////
+
+void initSTAIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+void displayIPConfigStruct(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
+}
+
+//////////////////////////////////////////////////////////////
+
+void toggleLED()
+{
+ //toggle state
+ digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
+}
+
+//////////////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+void printLocalTime()
+{
+ static time_t now;
+
+ now = time(nullptr);
+
+ if ( now > 1451602800 )
+ {
+ Serial.print("Local Date/Time: ");
+ Serial.print(ctime(&now));
+ }
+}
+#endif
+
+void heartBeatPrint()
+{
+#if USE_ESP_ETH_MANAGER_NTP
+ printLocalTime();
+#else
+ static int num = 1;
+
+ if (eth.connected())
+ 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;
+ }
+ else if (num++ % 10 == 0)
+ {
+ Serial.print(F(" "));
+ }
+
+#endif
+}
+
+//////////////////////////////////////////////////////////////
+
+void check_status()
+{
+ static ulong checkstatus_timeout = 0;
+ static ulong LEDstatus_timeout = 0;
+
+ static ulong current_millis;
+
+#if USE_ESP_ETH_MANAGER_NTP
+#define HEARTBEAT_INTERVAL 60000L
+#else
+#define HEARTBEAT_INTERVAL 10000L
+#endif
+
+#define LED_INTERVAL 2000L
+
+ 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;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+int calcChecksum(uint8_t* address, uint16_t sizeToCalc)
+{
+ uint16_t checkSum = 0;
+
+ for (uint16_t index = 0; index < sizeToCalc; index++)
+ {
+ checkSum += * ( ( (byte*) address ) + index);
+ }
+
+ return checkSum;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool loadConfigData()
+{
+ 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"));
+
+ return false;
+ }
+
+ displayIPConfigStruct(EthSTA_IPconfig);
+
+ return true;
+ }
+ else
+ {
+ LOGERROR(F("failed"));
+
+ return false;
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void saveConfigData()
+{
+ 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"));
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+bool readConfigFile()
+{
+ // this opens the config file in read-mode
+ File f = FileFS.open(JSON_CONFIG_FILE, "r");
+
+ if (!f)
+ {
+ Serial.println(F("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 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(F("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(F("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(F("\nConfig file was successfully parsed"));
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool writeConfigFile()
+{
+ Serial.println(F("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(JSON_CONFIG_FILE, "w");
+
+ if (!f)
+ {
+ Serial.println(F("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(F("\nConfig file was successfully saved"));
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////
+
+void initEthernet()
+{
+ SPI.begin();
+ SPI.setClockDivider(SPI_CLOCK_DIV4);
+ SPI.setBitOrder(MSBFIRST);
+ SPI.setDataMode(SPI_MODE0);
+
+ LOGWARN(F("Default SPI pinout:"));
+ LOGWARN1(F("MOSI:"), MOSI);
+ LOGWARN1(F("MISO:"), MISO);
+ LOGWARN1(F("SCK:"), SCK);
+ LOGWARN1(F("CS:"), CSPIN);
+ LOGWARN(F("========================="));
+
+#if !USING_DHCP
+ //eth.config(localIP, gateway, netMask, gateway);
+ eth.config(EthSTA_IPconfig._sta_static_ip, EthSTA_IPconfig._sta_static_gw, EthSTA_IPconfig._sta_static_sn,
+ EthSTA_IPconfig._sta_static_dns1);
+#endif
+
+ eth.setDefault();
+
+ if (!eth.begin())
+ {
+ Serial.println("No Ethernet hardware ... Stop here");
+
+ while (true)
+ {
+ delay(1000);
+ }
+ }
+ else
+ {
+ Serial.print("Connecting to network : ");
+
+ while (!eth.connected())
+ {
+ Serial.print(".");
+ delay(1000);
+ }
+ }
+
+ Serial.println();
+
+#if USING_DHCP
+ Serial.print("Ethernet DHCP IP address: ");
+#else
+ Serial.print("Ethernet Static IP address: ");
+#endif
+
+ Serial.println(eth.localIP());
+}
+
+//////////////////////////////////////////////////////////////
+
+void setup()
+{
+ //set led pin as output
+ pinMode(LED_BUILTIN, OUTPUT);
+
+ // Put your setup code here, to run once
+ Serial.begin(115200);
+
+ while (!Serial && millis() < 5000);
+
+ delay(200);
+
+ Serial.print(F("\nStarting Async_ConfigOnSwichFS using "));
+ Serial.print(FS_Name);
+ Serial.print(F(" on "));
+ Serial.print(ARDUINO_BOARD);
+ Serial.print(F(" with "));
+ Serial.println(SHIELD_TYPE);
+ Serial.println(ASYNC_ESP8266_W5500_MANAGER_VERSION);
+
+ // Initialize the LED digital pin as an output.
+ // Initialize trigger pins
+ pinMode(TRIGGER_PIN, INPUT_PULLUP);
+ pinMode(TRIGGER_PIN2, INPUT_PULLUP);
+
+#if FORMAT_FILESYSTEM
+ Serial.println(F("Forced Formatting."));
+ FileFS.format();
+#endif
+
+ // Format FileFS if not yet
+ if (!FileFS.begin())
+ {
+ FileFS.format();
+
+ 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);
+ }
+ }
+ }
+
+ initSTAIPConfigStruct(EthSTA_IPconfig);
+
+ if (!readConfigFile())
+ {
+ Serial.println(F("Failed to read ConfigFile, using default values"));
+ }
+
+ unsigned long startedAt = millis();
+
+ //Local intialization. Once its business is done, there is no need to keep it around
+ // Use this to default DHCP hostname to ESP32-XXXXXX
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+
+#if ( USING_ESP32_S2 || USING_ESP32_C3 )
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, NULL, "ConfigOnSwitchFS");
+#else
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "ConfigOnSwitchFS");
+#endif
+
+ AsyncESP8266_W5500_manager.setDebugOutput(true);
+
+#if !USE_DHCP_IP
+ // Set (static IP, Gateway, Subnetmask, DNS1 and DNS2) or (IP, Gateway, Subnetmask)
+ AsyncESP8266_W5500_manager.setSTAStaticIPConfig(EthSTA_IPconfig);
+#endif
+
+#if USING_CORS_FEATURE
+ AsyncESP8266_W5500_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
+ AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "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 Credentials 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.
+ //AsyncESP8266_W5500_manager.setConfigPortalTimeout(600);
+
+ // Starts an access point
+ if (!AsyncESP8266_W5500_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 = AsyncESP8266_W5500_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);
+
+ const char * TZ_Result = AsyncESP8266_W5500_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);
+
+ configTime(Ethconfig.TZ, "pool.ntp.org");
+ }
+ else
+ {
+ LOGERROR(F("Current Timezone Name is not set. Enter Config Portal to set."));
+ }
+
+#endif
+
+ AsyncESP8266_W5500_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 (eth.connected())
+ {
+ Serial.print(F("connected. Local IP: "));
+ Serial.println(eth.localIP());
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void loop()
+{
+ // 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
+ //AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer);
+ // Use this to personalize DHCP hostname (RFC952 conformed)
+ AsyncWebServer webServer(HTTP_PORT);
+ AsyncDNSServer dnsServer;
+
+ AsyncESP8266_W5500_Manager AsyncESP8266_W5500_manager(&webServer, &dnsServer, "ConfigOnSwitchFS");
+
+ //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())
+ {
+ AsyncESP8266_W5500_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
+ Serial.println(F("Open Config Portal without Timeout: No stored Credentials."));
+ initialConfig = true;
+ }
+
+ // Extra parameters to be configured
+ // After connecting, parameter.getValue() will get you the configured value
+ // Format: