From c1473c449a4a4bce61377c1606bc9287368c6e16 Mon Sep 17 00:00:00 2001 From: khoih-prog <57012152+khoih-prog@users.noreply.github.com> Date: Mon, 28 Oct 2019 13:19:13 -0400 Subject: [PATCH] Add files via upload --- README.md | 56 +++- examples/ESP32WM_Config/ESP32WM_Config.ino | 123 +++++++++ .../ESP8266WM_Config/ESP8266WM_Config.ino | 129 +++++++++ src/BlynkSimpleEsp32_SSL_WM.h | 224 ++++++++++++---- src/BlynkSimpleEsp32_WM.h | 226 ++++++++++++---- src/BlynkSimpleEsp8266_SSL_WM.h | 249 +++++++++++++----- src/BlynkSimpleEsp8266_WM.h | 225 ++++++++++++---- 7 files changed, 1022 insertions(+), 210 deletions(-) create mode 100644 examples/ESP32WM_Config/ESP32WM_Config.ino create mode 100644 examples/ESP8266WM_Config/ESP8266WM_Config.ino diff --git a/README.md b/README.md index 38fa6ca..79f49d1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,17 @@ to use SPIFFS or ``` #define USE_SPIFFS false ``` -to use EEPROM ( 168 bytes from address 0-167) to save your configuration data. +to use EEPROM ( 172 bytes from address EEPROM_START ) to save your configuration data. +EEPROM_SIZE can be specified from 256 to 4096 bytes. See examples ESP32WM_Config and ESP8266WM_Config. + + +``` +// Force some params in Blynk, only valid for library version 1.0.1 and later +#define TIMEOUT_RECONNECT_WIFI 10000L +#define RESET_IF_CONFIG_TIMEOUT true +#define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 5 + +``` Then replace @@ -52,13 +62,49 @@ Anyway, this is better for projects using Blynk just for graphical user interfac * ESP8266 core for Arduino https://github.com/esp8266/Arduino#installing-with-boards-manager * Blynk library https://www.arduino.cc/en/guide/libraries#toc3 +## TO DO + +1. Same features for other boards with WiFi. + +## DONE + +1. Permit EEPROM size and location configurable to avoid conflict with others. +2. More flexible to configure reconnection timeout. +3. For fresh config data, don't need to wait for connecting timeout before entering config portal. + ## Hello World Please take a look at examples, as well. ``` -#define BLYNK_PRINT Serial -#define USE_SPIFFS true - -#include +#define BLYNK_PRINT Serial + +// Not use #define USE_SPIFFS => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS false => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS true => using SPIFFS for configuration data in WiFiManager +// Be sure to define USE_SPIFFS before #include + +//#define USE_SPIFFS true +#define USE_SPIFFS false + +#if (!USE_SPIFFS) + // EEPROM_SIZE must be <= 4096 and >= CONFIG_DATA_SIZE (currently 172 bytes) + #define EEPROM_SIZE (4 * 1024) + // EEPROM_START + CONFIG_DATA_SIZE must be <= EEPROM_SIZE + #define EEPROM_START 1024 +#endif + +// Force some params in Blynk, only valid for library version 1.0.1 and later +#define TIMEOUT_RECONNECT_WIFI 10000L +#define RESET_IF_CONFIG_TIMEOUT true +#define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 5 +// Those above #define's must be placed before #include + +#define USE_SSL true + +#if USE_SSL + #include +#else + #include +#endif void setup() { diff --git a/examples/ESP32WM_Config/ESP32WM_Config.ino b/examples/ESP32WM_Config/ESP32WM_Config.ino new file mode 100644 index 0000000..2aefe20 --- /dev/null +++ b/examples/ESP32WM_Config/ESP32WM_Config.ino @@ -0,0 +1,123 @@ +#define BLYNK_PRINT Serial + +// Not use #define USE_SPIFFS => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS false => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS true => using SPIFFS for configuration data in WiFiManager +// Be sure to define USE_SPIFFS before #include + +//#define USE_SPIFFS true +#define USE_SPIFFS false + +#if (!USE_SPIFFS) + // EEPROM_SIZE must be <= 4096 and >= CONFIG_DATA_SIZE (currently 172 bytes) + #define EEPROM_SIZE (4 * 1024) + // EEPROM_START + CONFIG_DATA_SIZE must be <= EEPROM_SIZE + #define EEPROM_START 2048 +#endif + +// Force some params in Blynk, only valid for library version 1.0.1 and later +#define TIMEOUT_RECONNECT_WIFI 10000L +#define RESET_IF_CONFIG_TIMEOUT true +#define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 5 +// Those above #define's must be placed before #include + +#define USE_SSL false + +#if USE_SSL + #include +#else + #include +#endif + +#include +#include + +#define PIN_D22 22 // Pin D22 mapped to pin GPIO22/SCL of ESP32 + +#define DHT_PIN PIN_D22 // pin DATA @ D22 / GPIO22 +#define DHT_TYPE DHT11 + +DHT dht(DHT_PIN, DHT_TYPE); +BlynkTimer timer; +Ticker led_ticker; + +void readAndSendData() +{ + float temperature = dht.readTemperature(); + float humidity = dht.readHumidity(); + + if (!isnan(temperature) && !isnan(humidity)) + { + Blynk.virtualWrite(V17, String(temperature, 1)); + Blynk.virtualWrite(V18, String(humidity, 1)); + } + else + { + Blynk.virtualWrite(V17, "NAN"); + Blynk.virtualWrite(V18, "NAN"); + } + + // Blynk Timer uses millis() and is still working even if WiFi/Blynk not connected + Serial.println("R"); +} + +void set_led(byte status) +{ + digitalWrite(LED_BUILTIN, status); +} + +void check_status() +{ + static unsigned long checkstatus_timeout = 0; + +#define STATUS_CHECK_INTERVAL 15000L + + // Send status report every STATUS_REPORT_INTERVAL (10) seconds: we don't need to send updates frequently if there is no status change. + if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + // report status to Blynk + if (Blynk.connected()) + { + set_led(LOW); + led_ticker.once_ms(111, set_led, (byte) HIGH); + + Serial.println("B"); + } + else + { + Serial.println("F"); + } + + checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL; + } +} + +void setup() +{ + // Debug console + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + + Serial.println("\nStarting ..."); + + dht.begin(); + Blynk.begin(); + timer.setInterval(60 * 1000, readAndSendData); + + if (Blynk.connected()) + { + #if USE_SPIFFS + Serial.println("\nBlynk ESP32 using SPIFFS connected. Board Name : " + Blynk.getBoardName()); + #else + Serial.println("\nBlynk ESP32 using EEPROM connected. Board Name : " + Blynk.getBoardName()); + Serial.printf("EEPROM size = %d bytes, EEPROM start address = %d / 0x%X\n", EEPROM_SIZE, EEPROM_START, EEPROM_START); + #endif + } +} + +void loop() +{ + Blynk.run(); + timer.run(); + check_status(); +} diff --git a/examples/ESP8266WM_Config/ESP8266WM_Config.ino b/examples/ESP8266WM_Config/ESP8266WM_Config.ino new file mode 100644 index 0000000..52f14e9 --- /dev/null +++ b/examples/ESP8266WM_Config/ESP8266WM_Config.ino @@ -0,0 +1,129 @@ +#define BLYNK_PRINT Serial + +// Not use #define USE_SPIFFS => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS false => using EEPROM for configuration data in WiFiManager +// #define USE_SPIFFS true => using SPIFFS for configuration data in WiFiManager +// Be sure to define USE_SPIFFS before #include + +//#define USE_SPIFFS true +#define USE_SPIFFS false + +#if (!USE_SPIFFS) + // EEPROM_SIZE must be <= 4096 and >= CONFIG_DATA_SIZE (currently 172 bytes) + #define EEPROM_SIZE (4 * 1024) + // EEPROM_START + CONFIG_DATA_SIZE must be <= EEPROM_SIZE + #define EEPROM_START 1024 +#endif + +// Force some params in Blynk, only valid for library version 1.0.1 and later +#define TIMEOUT_RECONNECT_WIFI 10000L +#define RESET_IF_CONFIG_TIMEOUT true +#define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 5 +// Those above #define's must be placed before #include + +#define USE_SSL true + +#if USE_SSL + #include +#else + #include +#endif + +#include +#include + +#define PIN_LED 2 // Pin D4 mapped to pin GPIO2/TXD1 of ESP8266, NodeMCU and WeMoS, control on-board LED +#define PIN_D2 4 // Pin D2 mapped to pin GPIO4 of ESP8266 + +#define DHT_PIN PIN_D2 +#define DHT_TYPE DHT11 + +DHT dht(DHT_PIN, DHT_TYPE); +BlynkTimer timer; +Ticker led_ticker; + +void readAndSendData() +{ + float temperature = dht.readTemperature(); + float humidity = dht.readHumidity(); + + if (Blynk.connected()) + { + if (!isnan(temperature) && !isnan(humidity)) + { + Blynk.virtualWrite(V17, String(temperature, 1)); + Blynk.virtualWrite(V18, String(humidity, 1)); + } + else + { + Blynk.virtualWrite(V17, "NAN"); + Blynk.virtualWrite(V18, "NAN"); + } + } + + // Blynk Timer uses millis() and is still working even if WiFi/Blynk not connected + Serial.println("R"); +} + +void set_led(byte status) +{ + digitalWrite(PIN_LED, status); +} + +void check_status() +{ + static unsigned long checkstatus_timeout = 0; + +#define STATUS_CHECK_INTERVAL 15000L + + // Send status report every STATUS_REPORT_INTERVAL (10) seconds: we don't need to send updates frequently if there is no status change. + if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0)) + { + // report status to Blynk + if (Blynk.connected()) + { + set_led(LOW); + led_ticker.once_ms(111, set_led, (byte) HIGH); + + Serial.println("B"); + } + else + { + Serial.println("F"); + } + + checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL; + } +} + +void setup() +{ + // Debug console + Serial.begin(115200); + pinMode(PIN_LED, OUTPUT); + + Serial.println("\nStarting ..."); + + dht.begin(); + Blynk.begin(); + timer.setInterval(60 * 1000, readAndSendData); + + if (Blynk.connected()) + { + #if USE_SPIFFS + Serial.println("\nBlynk ESP8288 using SPIFFS connected. Board Name : " + Blynk.getBoardName()); + #else + { + Serial.println("\nBlynk ESP8288 using EEPROM connected. Board Name : " + Blynk.getBoardName()); + Serial.printf("EEPROM size = %d bytes, EEPROM start address = %d / 0x%X\n", EEPROM_SIZE, EEPROM_START, EEPROM_START); + } + #endif + } +} + +void loop() +{ + Blynk.run(); + timer.run(); + check_status(); +} diff --git a/src/BlynkSimpleEsp32_SSL_WM.h b/src/BlynkSimpleEsp32_SSL_WM.h index acc1d66..e463840 100644 --- a/src/BlynkSimpleEsp32_SSL_WM.h +++ b/src/BlynkSimpleEsp32_SSL_WM.h @@ -1,11 +1,10 @@ /** * Blynk_WM is a library for the ESP8266/ESP32 Arduino platform (https://github.com/esp8266/Arduino) to enable easy * configuration/reconfiguration and autoconnect/autoreconnect of WiFi/Blynk - * inspired by: - * https://github.com/Barbayar/EasyBlynk8266 * Forked from Blynk library v0.6.1 https://github.com/blynkkk/blynk-library/releases * Built by Khoi Hoang https://github.com/khoih-prog/Blynk_WM * Licensed under MIT license + * Version: 1.0.1 * Original Blynk Library author: * @file BlynkSimpleEsp32_SSL.h * @author Volodymyr Shymanskyy @@ -97,7 +96,7 @@ struct Configuration char blynk_server [32]; int blynk_port; char blynk_token [36]; - char board_name [16]; + char board_name [24]; }; String root_html_template = " \ @@ -255,57 +254,122 @@ class BlynkWifi { #define TIMEOUT_CONNECT_WIFI 30000 - getConfigData(); - - Base::begin(BlynkESP32_WM_config.blynk_token); - this->conn.begin(BlynkESP32_WM_config.blynk_server, BlynkESP32_WM_config.blynk_port); - - if (connectToWifi(TIMEOUT_CONNECT_WIFI)) + if (getConfigData()) { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); - - int i = 0; - while ( (i++ < 10) && !this->connect() ) - { - } + hadConfigData = true; + + Base::begin(BlynkESP32_WM_config.blynk_token); + this->conn.begin(BlynkESP32_WM_config.blynk_server, BlynkESP32_WM_config.blynk_port); - if (this->connected()) + if (connectToWifi(TIMEOUT_CONNECT_WIFI)) { - BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); - } + BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); + + int i = 0; + while ( (i++ < 10) && !this->connect() ) + { + } + + if (this->connected()) + { + BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); + } + else + { + BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); + // failed to connect to Blynk server, will start configuration mode + // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON + digitalWrite(LED_BUILTIN, HIGH); + startConfigurationMode(); + } + } else { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); - // failed to connect to Blynk server, will start configuration mode - // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON - digitalWrite(LED_BUILTIN, HIGH); - startConfigurationMode(); + BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + // failed to connect to Blynk server, will start configuration mode + // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON + digitalWrite(LED_BUILTIN, HIGH); + startConfigurationMode(); } - } - else + } + else { - BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + BLYNK_LOG1(BLYNK_F("begin: No stored config data. Will forever stay in config mode until getting data")); // failed to connect to Blynk server, will start configuration mode - // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON - digitalWrite(LED_BUILTIN, HIGH); - startConfigurationMode(); - } + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + hadConfigData = false; + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); + } } + +#ifndef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L +#else + // Force range of user-defined TIMEOUT_RECONNECT_WIFI between 10-60s + #if (TIMEOUT_RECONNECT_WIFI < 10000L) + #warning TIMEOUT_RECONNECT_WIFI too low. Reseting to 10000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L + #elif (TIMEOUT_RECONNECT_WIFI > 60000L) + #warning TIMEOUT_RECONNECT_WIFI too high. Reseting to 60000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 60000L + #endif +#endif + +#ifndef RESET_IF_CONFIG_TIMEOUT + #define RESET_IF_CONFIG_TIMEOUT true +#endif + +#ifndef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 10 +#else + // Force range of user-defined TIMES_BEFORE_RESET between 2-100 + #if (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET < 2) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too low. Reseting to 2 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 2 + #elif (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET > 100) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too high. Reseting to 100 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 100 + #endif +#endif void run() { - #define TIMEOUT_RECONNECT_WIFI 10000 + static int retryTimes = 0; // Lost connection in running. Give chance to reconfig. if ( WiFi.status() != WL_CONNECTED || !this->connected() ) { - if (configuration_mode) + // If configTimeout but user hasn't connected to configWeb => try to reconnect WiFi / Blynk. + // But if user has connected to configWeb, stay there until done, then reset hardware + if ( configuration_mode && ( configTimeout == 0 || millis() < configTimeout ) ) { + retryTimes = 0; server.handleClient(); return; } else { + #if RESET_IF_CONFIG_TIMEOUT + // If we're here but still in configuration_mode, permit running TIMES_BEFORE_RESET times before reset hardware + // to permit user another chance to config. + if ( configuration_mode && (configTimeout != 0) ) + { + if (++retryTimes <= CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET) + { + BLYNK_LOG2(BLYNK_F("run: WiFi lost but config Timeout. Try connecting WiFi and Blynk. RetryTimes : "), retryTimes); + } + else + { + ESP.restart(); + } + } + #endif + // Not in config mode, try reconnecting before force to config mode if ( WiFi.status() != WL_CONNECTED ) { @@ -356,6 +420,11 @@ class BlynkWifi WebServer server; boolean configuration_mode = false; struct Configuration BlynkESP32_WM_config; + + unsigned long configTimeout; + bool hadConfigData; + +#define BOARD_TYPE "SSL_ESP32" #if USE_SPIFFS @@ -420,14 +489,13 @@ class BlynkWifi } } - void getConfigData() - { - #define BOARD_TYPE "SSL_ESP32" - + // Return false if init new EEPROM or SPIFFS. No more need trying to connect. Go directly to config mode + bool getConfigData() + { if (!SPIFFS.begin()) { BLYNK_LOG1(BLYNK_F("SPIFFS failed!. Please use EEPROM.")); - return; + return false; } if ( SPIFFS.exists(CONFIG_FILENAME) || SPIFFS.exists(CONFIG_FILENAME_BACKUP) ) @@ -451,7 +519,9 @@ class BlynkWifi strcpy(BlynkESP32_WM_config.blynk_token, no_config); strcpy(BlynkESP32_WM_config.board_name, no_config); - saveConfigData(); + saveConfigData(); + + return false; } else @@ -462,18 +532,43 @@ class BlynkWifi BLYNK_F(", Token = "), BlynkESP32_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), BlynkESP32_WM_config.board_name); } + + return true; } #else - void getConfigData() - { - #define EEPROM_SIZE 512 - #define BOARD_TYPE "SSL_ESP32" - +#define CONFIG_DATA_SIZE 172 + +#ifndef EEPROM_SIZE + #define EEPROM_SIZE 512 +#else + #if (EEPROM_SIZE > 4096) + #warning EEPROM_SIZE must be <= 4096. Reset to 4096 + #undef EEPROM_SIZE + #define EEPROM_SIZE 4096 + #endif + #if (EEPROM_SIZE < CONFIG_DATA_SIZE) + #warning EEPROM_SIZE must be > CONFIG_DATA_SIZE. Reset to 512 + #undef EEPROM_SIZE + #define EEPROM_SIZE 512 + #endif +#endif + +#ifndef EEPROM_START + #define EEPROM_START 0 +#else + #if (EEPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE) + #error EPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE. Please adjust. + #endif +#endif + + // Return false if init new EEPROM or SPIFFS. No more need trying to connect. Go directly to config mode + bool getConfigData() + { EEPROM.begin(EEPROM_SIZE); - EEPROM.get(0, BlynkESP32_WM_config); + EEPROM.get(EEPROM_START, BlynkESP32_WM_config); if (strncmp(BlynkESP32_WM_config.header, BOARD_TYPE, strlen(BOARD_TYPE)) != 0) { @@ -490,8 +585,10 @@ class BlynkWifi strcpy(BlynkESP32_WM_config.blynk_token, no_config); strcpy(BlynkESP32_WM_config.board_name, no_config); - EEPROM.put(0, BlynkESP32_WM_config); + EEPROM.put(EEPROM_START, BlynkESP32_WM_config); EEPROM.commit(); + + return false; } else @@ -502,11 +599,13 @@ class BlynkWifi BLYNK_F(", Token = "), BlynkESP32_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), BlynkESP32_WM_config.board_name); } + + return true; } void saveConfigData() { - EEPROM.put(0, BlynkESP32_WM_config); + EEPROM.put(EEPROM_START, BlynkESP32_WM_config); EEPROM.commit(); } @@ -560,6 +659,11 @@ class BlynkWifi if (key == "" && value == "") { String result = root_html_template; + + BLYNK_LOG1(BLYNK_F("handleRequest: replacing result")); + + // Reset configTimeout to stay here until finished. + configTimeout = 0; result.replace("[[wifi_ssid]]", BlynkESP32_WM_config.wifi_ssid); result.replace("[[wifi_passphrase]]", BlynkESP32_WM_config.wifi_passphrase); @@ -573,17 +677,27 @@ class BlynkWifi return; } + if (number_items_Updated == 0) + { + memset(&BlynkESP32_WM_config, 0, sizeof(BlynkESP32_WM_config)); + strcpy(BlynkESP32_WM_config.header, BOARD_TYPE); + } + if (key == "wifi_ssid") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.wifi_ssid) -1) strcpy(BlynkESP32_WM_config.wifi_ssid, value.c_str()); + else + strncpy(BlynkESP32_WM_config.wifi_ssid, value.c_str(), sizeof(BlynkESP32_WM_config.wifi_ssid) -1); } else if (key == "wifi_passphrase") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.wifi_passphrase) -1) strcpy(BlynkESP32_WM_config.wifi_passphrase, value.c_str()); + else + strncpy(BlynkESP32_WM_config.wifi_passphrase, value.c_str(), sizeof(BlynkESP32_WM_config.wifi_passphrase) -1); } else if (key == "blynk_server") @@ -591,6 +705,8 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.blynk_server) -1) strcpy(BlynkESP32_WM_config.blynk_server, value.c_str()); + else + strncpy(BlynkESP32_WM_config.blynk_server, value.c_str(), sizeof(BlynkESP32_WM_config.blynk_server) -1); } else if (key == "blynk_port") { @@ -602,14 +718,18 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.blynk_token) -1) strcpy(BlynkESP32_WM_config.blynk_token, value.c_str()); + else + strncpy(BlynkESP32_WM_config.blynk_token, value.c_str(), sizeof(BlynkESP32_WM_config.blynk_token) -1); } else if (key == "board_name") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.board_name) -1) strcpy(BlynkESP32_WM_config.board_name, value.c_str()); + else + strncpy(BlynkESP32_WM_config.board_name, value.c_str(), sizeof(BlynkESP32_WM_config.board_name) -1); } - + server.send(200, "text/html", "OK"); if (number_items_Updated == NUM_CONFIGURABLE_ITEMS) @@ -622,13 +742,15 @@ class BlynkWifi // Delay then reset the ESP8266 after save data delay(1000); - ESP.restart(); + ESP.restart(); } } void startConfigurationMode() { + #define CONFIG_TIMEOUT 60000L + String chipID = String(ESP_getChipId(), HEX); chipID.toUpperCase(); @@ -650,6 +772,12 @@ class BlynkWifi server.on("/", [this](){ handleRequest(); }); server.begin(); + + // If there is no saved config Data, stay in config mode forever until having config Data. + if (hadConfigData) + configTimeout = millis() + CONFIG_TIMEOUT; + else + configTimeout = 0; configuration_mode = true; } diff --git a/src/BlynkSimpleEsp32_WM.h b/src/BlynkSimpleEsp32_WM.h index 2f68113..4be5064 100644 --- a/src/BlynkSimpleEsp32_WM.h +++ b/src/BlynkSimpleEsp32_WM.h @@ -1,11 +1,10 @@ /** * Blynk_WM is a library for the ESP8266/ESP32 Arduino platform (https://github.com/esp8266/Arduino) to enable easy * configuration/reconfiguration and autoconnect/autoreconnect of WiFi/Blynk - * inspired by: - * https://github.com/Barbayar/EasyBlynk8266 * Forked from Blynk library v0.6.1 https://github.com/blynkkk/blynk-library/releases * Built by Khoi Hoang https://github.com/khoih-prog/Blynk_WM * Licensed under MIT license + * Version: 1.0.1 * Original Blynk Library author: * @file BlynkSimpleEsp32.h * @author Volodymyr Shymanskyy @@ -53,7 +52,7 @@ struct Configuration char blynk_server [32]; int blynk_port; char blynk_token [36]; - char board_name [16]; + char board_name [24]; }; String root_html_template = " \ @@ -204,57 +203,122 @@ class BlynkWifi { #define TIMEOUT_CONNECT_WIFI 30000 - getConfigData(); + if (getConfigData()) + { + hadConfigData = true; - Base::begin(BlynkESP32_WM_config.blynk_token); - this->conn.begin(BlynkESP32_WM_config.blynk_server, BlynkESP32_WM_config.blynk_port); + Base::begin(BlynkESP32_WM_config.blynk_token); + this->conn.begin(BlynkESP32_WM_config.blynk_server, BlynkESP32_WM_config.blynk_port); - if (connectToWifi(TIMEOUT_CONNECT_WIFI)) - { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); - - int i = 0; - while ( (i++ < 10) && !this->connect() ) - { - } - - if (this->connected()) + if (connectToWifi(TIMEOUT_CONNECT_WIFI)) { - BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); - } + BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); + + int i = 0; + while ( (i++ < 10) && !this->connect() ) + { + } + + if (this->connected()) + { + BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); + } + else + { + BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); + // failed to connect to Blynk server, will start configuration mode + // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON + digitalWrite(LED_BUILTIN, HIGH); + startConfigurationMode(); + } + } else { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); - // failed to connect to Blynk server, will start configuration mode - // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON - digitalWrite(LED_BUILTIN, HIGH); - startConfigurationMode(); + BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + // failed to connect to Blynk server, will start configuration mode + // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON + digitalWrite(LED_BUILTIN, HIGH); + startConfigurationMode(); } - } - else + } + else { - BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + BLYNK_LOG1(BLYNK_F("begin: No stored config data. Will forever stay in config mode until getting data")); // failed to connect to Blynk server, will start configuration mode - // Turn the LED_BUILTIN ON in configuration mode. ESP32 LED_BUILDIN is correct polarity, HIGH to turn ON - digitalWrite(LED_BUILTIN, HIGH); - startConfigurationMode(); - } + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + hadConfigData = false; + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); + } } + +#ifndef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L +#else + // Force range of user-defined TIMEOUT_RECONNECT_WIFI between 10-60s + #if (TIMEOUT_RECONNECT_WIFI < 10000L) + #warning TIMEOUT_RECONNECT_WIFI too low. Reseting to 10000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L + #elif (TIMEOUT_RECONNECT_WIFI > 60000L) + #warning TIMEOUT_RECONNECT_WIFI too high. Reseting to 60000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 60000L + #endif +#endif + +#ifndef RESET_IF_CONFIG_TIMEOUT + #define RESET_IF_CONFIG_TIMEOUT true +#endif + +#ifndef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 10 +#else + // Force range of user-defined TIMES_BEFORE_RESET between 2-100 + #if (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET < 2) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too low. Reseting to 2 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 2 + #elif (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET > 100) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too high. Reseting to 100 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 100 + #endif +#endif void run() { - #define TIMEOUT_RECONNECT_WIFI 10000 + static int retryTimes = 0; // Lost connection in running. Give chance to reconfig. if ( WiFi.status() != WL_CONNECTED || !connected() ) { - if (configuration_mode) + // If configTimeout but user hasn't connected to configWeb => try to reconnect WiFi / Blynk. + // But if user has connected to configWeb, stay there until done, then reset hardware + if ( configuration_mode && ( configTimeout == 0 || millis() < configTimeout ) ) { + retryTimes = 0; server.handleClient(); return; } else { + #if RESET_IF_CONFIG_TIMEOUT + // If we're here but still in configuration_mode, permit running TIMES_BEFORE_RESET times before reset hardware + // to permit user another chance to config. + if ( configuration_mode && (configTimeout != 0) ) + { + if (++retryTimes <= CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET) + { + BLYNK_LOG2(BLYNK_F("run: WiFi lost but config Timeout. Try connecting WiFi and Blynk. RetryTimes : "), retryTimes); + } + else + { + ESP.restart(); + } + } + #endif + // Not in config mode, try reconnecting before force to config mode if ( WiFi.status() != WL_CONNECTED ) { @@ -304,9 +368,14 @@ class BlynkWifi private: WebServer server; - boolean configuration_mode = false; + bool configuration_mode = false; struct Configuration BlynkESP32_WM_config; + unsigned long configTimeout; + bool hadConfigData; + +#define BOARD_TYPE "ESP32" + #if USE_SPIFFS #define CONFIG_FILENAME BLYNK_F("/wm_config.dat") @@ -370,14 +439,13 @@ class BlynkWifi } } - void getConfigData() - { - #define BOARD_TYPE "ESP32" - + // Return false if init new EEPROM or SPIFFS. No more need trying to connect. Go directly to config mode + bool getConfigData() + { if (!SPIFFS.begin()) { BLYNK_LOG1(BLYNK_F("SPIFFS failed!. Please use EEPROM.")); - return; + return false; } if ( SPIFFS.exists(CONFIG_FILENAME) || SPIFFS.exists(CONFIG_FILENAME_BACKUP) ) @@ -401,7 +469,9 @@ class BlynkWifi strcpy(BlynkESP32_WM_config.blynk_token, no_config); strcpy(BlynkESP32_WM_config.board_name, no_config); - saveConfigData(); + saveConfigData(); + + return false; } else @@ -412,25 +482,50 @@ class BlynkWifi BLYNK_F(", Token = "), BlynkESP32_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), BlynkESP32_WM_config.board_name); } + + return true; } -#else +#else - void getConfigData() - { - #define EEPROM_SIZE 512 - #define BOARD_TYPE "ESP32" - +#define CONFIG_DATA_SIZE 172 + +#ifndef EEPROM_SIZE + #define EEPROM_SIZE 512 +#else + #if (EEPROM_SIZE > 4096) + #warning EEPROM_SIZE must be <= 4096. Reset to 4096 + #undef EEPROM_SIZE + #define EEPROM_SIZE 4096 + #endif + #if (EEPROM_SIZE < CONFIG_DATA_SIZE) + #warning EEPROM_SIZE must be > CONFIG_DATA_SIZE. Reset to 512 + #undef EEPROM_SIZE + #define EEPROM_SIZE 512 + #endif +#endif + +#ifndef EEPROM_START + #define EEPROM_START 0 +#else + #if (EEPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE) + #error EPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE. Please adjust. + #endif +#endif + + // Return false if init new EEPROM or SPIFFS. No more need trying to connect. Go directly to config mode + bool getConfigData() + { EEPROM.begin(EEPROM_SIZE); - EEPROM.get(0, BlynkESP32_WM_config); + EEPROM.get(EEPROM_START, BlynkESP32_WM_config); if (strncmp(BlynkESP32_WM_config.header, BOARD_TYPE, strlen(BOARD_TYPE)) != 0) { memset(&BlynkESP32_WM_config, 0, sizeof(BlynkESP32_WM_config)); char no_config[] = "nothing"; - BLYNK_LOG2(BLYNK_F("Init new EEPROM, size = "), EEPROM.length()); + BLYNK_LOG2(BLYNK_F("Init new EEPROM, size = "), EEPROM_SIZE /*EEPROM.length()*/); // doesn't have any configuration strcpy(BlynkESP32_WM_config.header, BOARD_TYPE); strcpy(BlynkESP32_WM_config.wifi_ssid, no_config); @@ -440,8 +535,10 @@ class BlynkWifi strcpy(BlynkESP32_WM_config.blynk_token, no_config); strcpy(BlynkESP32_WM_config.board_name, no_config); - EEPROM.put(0, BlynkESP32_WM_config); + EEPROM.put(EEPROM_START, BlynkESP32_WM_config); EEPROM.commit(); + + return false; } else @@ -452,11 +549,13 @@ class BlynkWifi BLYNK_F(", Token = "), BlynkESP32_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), BlynkESP32_WM_config.board_name); } + + return true; } void saveConfigData() { - EEPROM.put(0, BlynkESP32_WM_config); + EEPROM.put(EEPROM_START, BlynkESP32_WM_config); EEPROM.commit(); } @@ -510,6 +609,11 @@ class BlynkWifi if (key == "" && value == "") { String result = root_html_template; + + BLYNK_LOG1(BLYNK_F("handleRequest: replacing result")); + + // Reset configTimeout to stay here until finished. + configTimeout = 0; result.replace("[[wifi_ssid]]", BlynkESP32_WM_config.wifi_ssid); result.replace("[[wifi_passphrase]]", BlynkESP32_WM_config.wifi_passphrase); @@ -523,17 +627,27 @@ class BlynkWifi return; } + if (number_items_Updated == 0) + { + memset(&BlynkESP32_WM_config, 0, sizeof(BlynkESP32_WM_config)); + strcpy(BlynkESP32_WM_config.header, BOARD_TYPE); + } + if (key == "wifi_ssid") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.wifi_ssid) -1) strcpy(BlynkESP32_WM_config.wifi_ssid, value.c_str()); + else + strncpy(BlynkESP32_WM_config.wifi_ssid, value.c_str(), sizeof(BlynkESP32_WM_config.wifi_ssid) -1); } else if (key == "wifi_passphrase") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.wifi_passphrase) -1) strcpy(BlynkESP32_WM_config.wifi_passphrase, value.c_str()); + else + strncpy(BlynkESP32_WM_config.wifi_passphrase, value.c_str(), sizeof(BlynkESP32_WM_config.wifi_passphrase) -1); } else if (key == "blynk_server") @@ -541,6 +655,8 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.blynk_server) -1) strcpy(BlynkESP32_WM_config.blynk_server, value.c_str()); + else + strncpy(BlynkESP32_WM_config.blynk_server, value.c_str(), sizeof(BlynkESP32_WM_config.blynk_server) -1); } else if (key == "blynk_port") { @@ -552,12 +668,16 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.blynk_token) -1) strcpy(BlynkESP32_WM_config.blynk_token, value.c_str()); + else + strncpy(BlynkESP32_WM_config.blynk_token, value.c_str(), sizeof(BlynkESP32_WM_config.blynk_token) -1); } else if (key == "board_name") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(BlynkESP32_WM_config.board_name) -1) strcpy(BlynkESP32_WM_config.board_name, value.c_str()); + else + strncpy(BlynkESP32_WM_config.board_name, value.c_str(), sizeof(BlynkESP32_WM_config.board_name) -1); } server.send(200, "text/html", "OK"); @@ -579,6 +699,8 @@ class BlynkWifi void startConfigurationMode() { + #define CONFIG_TIMEOUT 60000L + String chipID = String(ESP_getChipId(), HEX); chipID.toUpperCase(); @@ -600,6 +722,12 @@ class BlynkWifi server.on("/", [this](){ handleRequest(); }); server.begin(); + + // If there is no saved config Data, stay in config mode forever until having config Data. + if (hadConfigData) + configTimeout = millis() + CONFIG_TIMEOUT; + else + configTimeout = 0; configuration_mode = true; } diff --git a/src/BlynkSimpleEsp8266_SSL_WM.h b/src/BlynkSimpleEsp8266_SSL_WM.h index 0b1d0cc..20cc5c0 100644 --- a/src/BlynkSimpleEsp8266_SSL_WM.h +++ b/src/BlynkSimpleEsp8266_SSL_WM.h @@ -1,11 +1,10 @@ /** * Blynk_WM is a library for the ESP8266/ESP32 Arduino platform (https://github.com/esp8266/Arduino) to enable easy * configuration/reconfiguration and autoconnect/autoreconnect of WiFi/Blynk - * inspired by: - * https://github.com/Barbayar/EasyBlynk8266 * Forked from Blynk library v0.6.1 https://github.com/blynkkk/blynk-library/releases * Built by Khoi Hoang https://github.com/khoih-prog/Blynk_WM * Licensed under MIT license + * Version: 1.0.1 * Original Blynk Library author: * @file BlynkSimpleEsp8266_SSL.h * @author Volodymyr Shymanskyy @@ -142,7 +141,7 @@ struct Configuration char blynk_server [32]; int blynk_port; char blynk_token [36]; - char board_name [16]; + char board_name [24]; }; String root_html_template = " \ @@ -310,67 +309,132 @@ class BlynkWifi { #define TIMEOUT_CONNECT_WIFI 30000 - getConfigData(); - - Base::begin(Blynk8266_WM_config.blynk_token); - this->conn.begin(Blynk8266_WM_config.blynk_server, Blynk8266_WM_config.blynk_port); - - if (fingerprint) - { - this->conn.setFingerprint(fingerprint); - } - else + if (getConfigData()) { - this->conn.setCACert_P(BLYNK_DEFAULT_CERT_DER, sizeof(BLYNK_DEFAULT_CERT_DER)); - } + hadConfigData = true; - if (connectToWifi(TIMEOUT_CONNECT_WIFI)) - { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); + Base::begin(Blynk8266_WM_config.blynk_token); + this->conn.begin(Blynk8266_WM_config.blynk_server, Blynk8266_WM_config.blynk_port); - int i = 0; - while ( (i++ < 10) && !this->connect() ) + if (fingerprint) { - } - - if (this->connected()) + this->conn.setFingerprint(fingerprint); + } + else { - BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); - } + this->conn.setCACert_P(BLYNK_DEFAULT_CERT_DER, sizeof(BLYNK_DEFAULT_CERT_DER)); + } + + if (connectToWifi(TIMEOUT_CONNECT_WIFI)) + { + BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); + + int i = 0; + while ( (i++ < 10) && !this->connect() ) + { + } + + if (this->connected()) + { + BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); + } + else + { + BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); + // failed to connect to Blynk server, will start configuration mode + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); + } + } else { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); - // failed to connect to Blynk server, will start configuration mode - // turn the LED_BUILTIN ON to tell us we are in configuration mode. - digitalWrite(LED_BUILTIN, LOW); - startConfigurationMode(); + BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + // failed to connect to Blynk server, will start configuration mode + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); } - } - else + } + else { - BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + BLYNK_LOG1(BLYNK_F("begin: No stored config data. Will forever stay in config mode until getting data")); // failed to connect to Blynk server, will start configuration mode // turn the LED_BUILTIN ON to tell us we are in configuration mode. + hadConfigData = false; digitalWrite(LED_BUILTIN, LOW); - startConfigurationMode(); - } + startConfigurationMode(); + } } + +#ifndef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L +#else + // Force range of user-defined TIMEOUT_RECONNECT_WIFI between 10-60s + #if (TIMEOUT_RECONNECT_WIFI < 10000L) + #warning TIMEOUT_RECONNECT_WIFI too low. Reseting to 10000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L + #elif (TIMEOUT_RECONNECT_WIFI > 60000L) + #warning TIMEOUT_RECONNECT_WIFI too high. Reseting to 60000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 60000L + #endif +#endif + +#ifndef RESET_IF_CONFIG_TIMEOUT + #define RESET_IF_CONFIG_TIMEOUT true +#endif + +#ifndef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 10 +#else + // Force range of user-defined TIMES_BEFORE_RESET between 2-100 + #if (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET < 2) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too low. Reseting to 2 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 2 + #elif (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET > 100) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too high. Reseting to 100 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 100 + #endif +#endif void run() - { - #define TIMEOUT_RECONNECT_WIFI 10000 + { + static int retryTimes = 0; // Lost connection in running. Give chance to reconfig. if ( WiFi.status() != WL_CONNECTED || !this->connected() ) { - if (configuration_mode) + // If configTimeout but user hasn't connected to configWeb => try to reconnect WiFi / Blynk. + // But if user has connected to configWeb, stay there until done, then reset hardware + if ( configuration_mode && ( configTimeout == 0 || millis() < configTimeout ) ) { + retryTimes = 0; server.handleClient(); return; } else { - // Not in config mode, try reconnecting before force to config mode + #if RESET_IF_CONFIG_TIMEOUT + // If we're here but still in configuration_mode, permit running TIMES_BEFORE_RESET times before reset hardware + // to permit user another chance to config. + if ( configuration_mode && (configTimeout != 0) ) + { + if (++retryTimes <= CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET) + { + BLYNK_LOG2(BLYNK_F("run: WiFi lost but config Timeout. Try connecting WiFi and Blynk. RetryTimes : "), retryTimes); + } + else + { + ESP.reset(); + } + } + #endif + + // Not in config mode, try reconnecting before forcing to config mode if ( WiFi.status() != WL_CONNECTED ) { BLYNK_LOG1(BLYNK_F("run: WiFi lost. Try reconnecting WiFi and Blynk")); @@ -378,19 +442,19 @@ class BlynkWifi { BLYNK_LOG1(BLYNK_F("run: WiFi reconnected. Trying connect to Blynk")); - if (this->connect()) - { - BLYNK_LOG1(BLYNK_F("run: WiFi and Blynk reconnected")); - } + if (this->connect()) + { + BLYNK_LOG1(BLYNK_F("run: WiFi and Blynk reconnected")); + } } } else { BLYNK_LOG1(BLYNK_F("run: Blynk lost. Try connecting Blynk")); - if (this->connect()) - { - BLYNK_LOG1(BLYNK_F("run: Blynk reconnected")); - } + if (this->connect()) + { + BLYNK_LOG1(BLYNK_F("run: Blynk reconnected")); + } } //BLYNK_LOG1(BLYNK_F("run: Lost connection => configMode")); @@ -402,7 +466,7 @@ class BlynkWifi configuration_mode = false; BLYNK_LOG1(BLYNK_F("run: got WiFi/Blynk back, great")); // turn the LED_BUILTIN OFF to tell us we exit configuration mode. - digitalWrite(LED_BUILTIN, HIGH); + digitalWrite(LED_BUILTIN, HIGH); } if (this->connected()) @@ -418,8 +482,11 @@ class BlynkWifi private: ESP8266WebServer server; - boolean configuration_mode = false; + bool configuration_mode = false; struct Configuration Blynk8266_WM_config; + + unsigned long configTimeout; + bool hadConfigData; #if USE_SPIFFS @@ -484,14 +551,14 @@ class BlynkWifi } } - void getConfigData() + bool getConfigData() { #define BOARD_TYPE "SSL_ESP8266" if (!SPIFFS.begin()) { BLYNK_LOG1(BLYNK_F("SPIFFS failed!. Please use EEPROM.")); - return; + return false; } if ( SPIFFS.exists(CONFIG_FILENAME) || SPIFFS.exists(CONFIG_FILENAME_BACKUP) ) @@ -515,7 +582,9 @@ class BlynkWifi strcpy(Blynk8266_WM_config.blynk_token, no_config); strcpy(Blynk8266_WM_config.board_name, no_config); - saveConfigData(); + saveConfigData(); + + return false; } else @@ -526,18 +595,44 @@ class BlynkWifi BLYNK_F(", Token = "), Blynk8266_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), Blynk8266_WM_config.board_name); } + + return true; } -#else +#else + +#define CONFIG_DATA_SIZE 172 + +#ifndef EEPROM_SIZE + #define EEPROM_SIZE 512 +#else + #if (EEPROM_SIZE > 4096) + #warning EEPROM_SIZE must be <= 4096. Reset to 4096 + #undef EEPROM_SIZE + #define EEPROM_SIZE 4096 + #endif + #if (EEPROM_SIZE < CONFIG_DATA_SIZE) + #warning EEPROM_SIZE must be > CONFIG_DATA_SIZE. Reset to 512 + #undef EEPROM_SIZE + #define EEPROM_SIZE 512 + #endif +#endif + +#ifndef EEPROM_START + #define EEPROM_START 0 +#else + #if (EEPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE) + #error EPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE. Please adjust. + #endif +#endif - void getConfigData() + bool getConfigData() { - #define EEPROM_SIZE 512 #define BOARD_TYPE "SSL_ESP8266" EEPROM.begin(EEPROM_SIZE); - EEPROM.get(0, Blynk8266_WM_config); + EEPROM.get(EEPROM_START, Blynk8266_WM_config); if (strncmp(Blynk8266_WM_config.header, BOARD_TYPE, strlen(BOARD_TYPE)) != 0) { @@ -554,8 +649,10 @@ class BlynkWifi strcpy(Blynk8266_WM_config.blynk_token, no_config); strcpy(Blynk8266_WM_config.board_name, no_config); - EEPROM.put(0, Blynk8266_WM_config); + EEPROM.put(EEPROM_START, Blynk8266_WM_config); EEPROM.commit(); + + return false; } else @@ -566,11 +663,13 @@ class BlynkWifi BLYNK_F(", Token = "), Blynk8266_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), Blynk8266_WM_config.board_name); } + + return true; } void saveConfigData() { - EEPROM.put(0, Blynk8266_WM_config); + EEPROM.put(EEPROM_START, Blynk8266_WM_config); EEPROM.commit(); } @@ -624,6 +723,11 @@ class BlynkWifi if (key == "" && value == "") { String result = root_html_template; + + BLYNK_LOG1(BLYNK_F("handleRequest: replacing result")); + + // Reset configTimeout to stay here until finished. + configTimeout = 0; result.replace("[[wifi_ssid]]", Blynk8266_WM_config.wifi_ssid); result.replace("[[wifi_passphrase]]", Blynk8266_WM_config.wifi_passphrase); @@ -636,18 +740,28 @@ class BlynkWifi return; } + + if (number_items_Updated == 0) + { + memset(&Blynk8266_WM_config, 0, sizeof(Blynk8266_WM_config)); + strcpy(Blynk8266_WM_config.header, BOARD_TYPE); + } if (key == "wifi_ssid") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.wifi_ssid) -1) strcpy(Blynk8266_WM_config.wifi_ssid, value.c_str()); + else + strncpy(Blynk8266_WM_config.wifi_ssid, value.c_str(), sizeof(Blynk8266_WM_config.wifi_ssid) -1); } else if (key == "wifi_passphrase") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.wifi_passphrase) -1) strcpy(Blynk8266_WM_config.wifi_passphrase, value.c_str()); + else + strncpy(Blynk8266_WM_config.wifi_passphrase, value.c_str(), sizeof(Blynk8266_WM_config.wifi_passphrase) -1); } else if (key == "blynk_server") @@ -655,6 +769,8 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.blynk_server) -1) strcpy(Blynk8266_WM_config.blynk_server, value.c_str()); + else + strncpy(Blynk8266_WM_config.blynk_server, value.c_str(), sizeof(Blynk8266_WM_config.blynk_server) -1); } else if (key == "blynk_port") { @@ -666,12 +782,17 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.blynk_token) -1) strcpy(Blynk8266_WM_config.blynk_token, value.c_str()); + else + strncpy(Blynk8266_WM_config.blynk_token, value.c_str(), sizeof(Blynk8266_WM_config.blynk_token) -1); + } else if (key == "board_name") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.board_name) -1) strcpy(Blynk8266_WM_config.board_name, value.c_str()); + else + strncpy(Blynk8266_WM_config.board_name, value.c_str(), sizeof(Blynk8266_WM_config.board_name) -1); } server.send(200, "text/html", "OK"); @@ -692,7 +813,9 @@ class BlynkWifi } void startConfigurationMode() - { + { + #define CONFIG_TIMEOUT 60000L + String chipID = String(ESP.getChipId(), HEX); chipID.toUpperCase(); @@ -714,10 +837,16 @@ class BlynkWifi server.on("/", [this](){ handleRequest(); }); server.begin(); + + // If there is no saved config Data, stay in config mode forever until having config Data. + if (hadConfigData) + configTimeout = millis() + CONFIG_TIMEOUT; + else + configTimeout = 0; configuration_mode = true; } -}; + }; static WiFiClientSecure _blynkWifiClient; static BlynkArduinoClientSecure _blynkTransport(_blynkWifiClient); diff --git a/src/BlynkSimpleEsp8266_WM.h b/src/BlynkSimpleEsp8266_WM.h index 62e0aa2..3d26acb 100644 --- a/src/BlynkSimpleEsp8266_WM.h +++ b/src/BlynkSimpleEsp8266_WM.h @@ -1,11 +1,10 @@ /** * Blynk_WM is a library for the ESP8266/ESP32 Arduino platform (https://github.com/esp8266/Arduino) to enable easy * configuration/reconfiguration and autoconnect/autoreconnect of WiFi/Blynk - * inspired by: - * https://github.com/Barbayar/EasyBlynk8266 * Forked from Blynk library v0.6.1 https://github.com/blynkkk/blynk-library/releases * Built by Khoi Hoang https://github.com/khoih-prog/Blynk_WM * Licensed under MIT license + * Version: 1.0.1 * Original Blynk Library author: * @file BlynkSimpleEsp8266.h * @author Volodymyr Shymanskyy @@ -39,9 +38,9 @@ //default to use EEPROM, otherwise, use SPIFFS #if USE_SPIFFS -#include + #include #else -#include + #include #endif @@ -55,7 +54,7 @@ struct Configuration char blynk_server [32]; int blynk_port; char blynk_token [36]; - char board_name [16]; + char board_name [24]; }; String root_html_template = " \ @@ -214,58 +213,123 @@ class BlynkWifi { #define TIMEOUT_CONNECT_WIFI 30000 - getConfigData(); - - Base::begin(Blynk8266_WM_config.blynk_token); - this->conn.begin(Blynk8266_WM_config.blynk_server, Blynk8266_WM_config.blynk_port); - - if (connectToWifi(TIMEOUT_CONNECT_WIFI)) + if (getConfigData()) { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); - - int i = 0; - while ( (i++ < 10) && !this->connect() ) - { - } + hadConfigData = true; - if (connected()) + Base::begin(Blynk8266_WM_config.blynk_token); + this->conn.begin(Blynk8266_WM_config.blynk_server, Blynk8266_WM_config.blynk_port); + + if (connectToWifi(TIMEOUT_CONNECT_WIFI)) { - BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); - } + BLYNK_LOG1(BLYNK_F("begin: WiFi connected. Try connecting to Blynk")); + + int i = 0; + while ( (i++ < 10) && !this->connect() ) + { + } + + if (connected()) + { + BLYNK_LOG1(BLYNK_F("begin: WiFi and Blynk connected")); + } + else + { + BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); + // failed to connect to Blynk server, will start configuration mode + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); + } + } else { - BLYNK_LOG1(BLYNK_F("begin: WiFi connected but Bynk not connected")); - // failed to connect to Blynk server, will start configuration mode - // turn the LED_BUILTIN ON to tell us we are in configuration mode. - digitalWrite(LED_BUILTIN, LOW); - startConfigurationMode(); + BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + // failed to connect to Blynk server, will start configuration mode + // turn the LED_BUILTIN ON to tell us we are in configuration mode. + digitalWrite(LED_BUILTIN, LOW); + startConfigurationMode(); } - } - else + } + else { - BLYNK_LOG1(BLYNK_F("begin: Fail to connect WiFi and Blynk")); + BLYNK_LOG1(BLYNK_F("begin: No stored config data. Will forever stay in config mode until getting data")); // failed to connect to Blynk server, will start configuration mode // turn the LED_BUILTIN ON to tell us we are in configuration mode. + hadConfigData = false; digitalWrite(LED_BUILTIN, LOW); - startConfigurationMode(); - } + startConfigurationMode(); + } } - + +#ifndef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L +#else + // Force range of user-defined TIMEOUT_RECONNECT_WIFI between 10-60s + #if (TIMEOUT_RECONNECT_WIFI < 10000L) + #warning TIMEOUT_RECONNECT_WIFI too low. Reseting to 10000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 10000L + #elif (TIMEOUT_RECONNECT_WIFI > 60000L) + #warning TIMEOUT_RECONNECT_WIFI too high. Reseting to 60000 + #undef TIMEOUT_RECONNECT_WIFI + #define TIMEOUT_RECONNECT_WIFI 60000L + #endif +#endif + +#ifndef RESET_IF_CONFIG_TIMEOUT + #define RESET_IF_CONFIG_TIMEOUT true +#endif + +#ifndef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 10 +#else + // Force range of user-defined TIMES_BEFORE_RESET between 2-100 + #if (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET < 2) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too low. Reseting to 2 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 2 + #elif (CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET > 100) + #warning CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET too high. Reseting to 100 + #undef CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET + #define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 100 + #endif +#endif + void run() - { - #define TIMEOUT_RECONNECT_WIFI 10000 + { + static int retryTimes = 0; // Lost connection in running. Give chance to reconfig. if ( WiFi.status() != WL_CONNECTED || !connected() ) { - if (configuration_mode) + // If configTimeout but user hasn't connected to configWeb => try to reconnect WiFi / Blynk. + // But if user has connected to configWeb, stay there until done, then reset hardware + if ( configuration_mode && ( configTimeout == 0 || millis() < configTimeout ) ) { + retryTimes = 0; server.handleClient(); return; } else { - // Not in config mode, try reconnecting before force to config mode + #if RESET_IF_CONFIG_TIMEOUT + // If we're here but still in configuration_mode, permit running TIMES_BEFORE_RESET times before reset hardware + // to permit user another chance to config. + if ( configuration_mode && (configTimeout != 0) ) + { + if (++retryTimes <= CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET) + { + BLYNK_LOG2(BLYNK_F("run: WiFi lost but config Timeout. Try connecting WiFi and Blynk. RetryTimes : "), retryTimes); + } + else + { + ESP.reset(); + } + } + #endif + + // Not in config mode, try reconnecting before forcing to config mode if ( WiFi.status() != WL_CONNECTED ) { BLYNK_LOG1(BLYNK_F("run: WiFi lost. Try reconnecting WiFi and Blynk")); @@ -313,9 +377,12 @@ class BlynkWifi private: ESP8266WebServer server; - boolean configuration_mode = false; + bool configuration_mode = false; struct Configuration Blynk8266_WM_config; + unsigned long configTimeout; + bool hadConfigData; + #if USE_SPIFFS #define CONFIG_FILENAME BLYNK_F("/wm_config.dat") @@ -379,14 +446,15 @@ class BlynkWifi } } - void getConfigData() + // Return false if init new EEPROM or SPIFFS. No more need trying to connect. Go directly to config mode + bool getConfigData() { #define BOARD_TYPE "ESP8266" if (!SPIFFS.begin()) { BLYNK_LOG1(BLYNK_F("SPIFFS failed!. Please use EEPROM.")); - return; + return false; } if ( SPIFFS.exists(CONFIG_FILENAME) || SPIFFS.exists(CONFIG_FILENAME_BACKUP) ) @@ -410,7 +478,9 @@ class BlynkWifi strcpy(Blynk8266_WM_config.blynk_token, no_config); strcpy(Blynk8266_WM_config.board_name, no_config); - saveConfigData(); + saveConfigData(); + + return false; } else @@ -421,18 +491,44 @@ class BlynkWifi BLYNK_F(", Token = "), Blynk8266_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), Blynk8266_WM_config.board_name); } + + return true; } -#else +#else - void getConfigData() +#define CONFIG_DATA_SIZE 172 + +#ifndef EEPROM_SIZE + #define EEPROM_SIZE 512 +#else + #if (EEPROM_SIZE > 4096) + #warning EEPROM_SIZE must be <= 4096. Reset to 4096 + #undef EEPROM_SIZE + #define EEPROM_SIZE 4096 + #endif + #if (EEPROM_SIZE < CONFIG_DATA_SIZE) + #warning EEPROM_SIZE must be > CONFIG_DATA_SIZE. Reset to 512 + #undef EEPROM_SIZE + #define EEPROM_SIZE 512 + #endif +#endif + +#ifndef EEPROM_START + #define EEPROM_START 0 +#else + #if (EEPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE) + #error EPROM_START + CONFIG_DATA_SIZE > EEPROM_SIZE. Please adjust. + #endif +#endif + + bool getConfigData() { - #define EEPROM_SIZE 512 #define BOARD_TYPE "ESP8266" EEPROM.begin(EEPROM_SIZE); - EEPROM.get(0, Blynk8266_WM_config); + EEPROM.get(EEPROM_START, Blynk8266_WM_config); if (strncmp(Blynk8266_WM_config.header, BOARD_TYPE, strlen(BOARD_TYPE)) != 0) { @@ -449,8 +545,10 @@ class BlynkWifi strcpy(Blynk8266_WM_config.blynk_token, no_config); strcpy(Blynk8266_WM_config.board_name, no_config); - EEPROM.put(0, Blynk8266_WM_config); + EEPROM.put(EEPROM_START, Blynk8266_WM_config); EEPROM.commit(); + + return false; } else @@ -461,11 +559,13 @@ class BlynkWifi BLYNK_F(", Token = "), Blynk8266_WM_config.blynk_token); BLYNK_LOG2(BLYNK_F("Board Name = "), Blynk8266_WM_config.board_name); } + + return true; } void saveConfigData() { - EEPROM.put(0, Blynk8266_WM_config); + EEPROM.put(EEPROM_START, Blynk8266_WM_config); EEPROM.commit(); } @@ -519,6 +619,11 @@ class BlynkWifi if (key == "" && value == "") { String result = root_html_template; + + BLYNK_LOG1(BLYNK_F("handleRequest: replacing result")); + + // Reset configTimeout to stay here until finished. + configTimeout = 0; result.replace("[[wifi_ssid]]", Blynk8266_WM_config.wifi_ssid); result.replace("[[wifi_passphrase]]", Blynk8266_WM_config.wifi_passphrase); @@ -532,17 +637,27 @@ class BlynkWifi return; } + if (number_items_Updated == 0) + { + memset(&Blynk8266_WM_config, 0, sizeof(Blynk8266_WM_config)); + strcpy(Blynk8266_WM_config.header, BOARD_TYPE); + } + if (key == "wifi_ssid") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.wifi_ssid) -1) strcpy(Blynk8266_WM_config.wifi_ssid, value.c_str()); + else + strncpy(Blynk8266_WM_config.wifi_ssid, value.c_str(), sizeof(Blynk8266_WM_config.wifi_ssid) -1); } else if (key == "wifi_passphrase") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.wifi_passphrase) -1) strcpy(Blynk8266_WM_config.wifi_passphrase, value.c_str()); + else + strncpy(Blynk8266_WM_config.wifi_passphrase, value.c_str(), sizeof(Blynk8266_WM_config.wifi_passphrase) -1); } else if (key == "blynk_server") @@ -550,6 +665,8 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.blynk_server) -1) strcpy(Blynk8266_WM_config.blynk_server, value.c_str()); + else + strncpy(Blynk8266_WM_config.blynk_server, value.c_str(), sizeof(Blynk8266_WM_config.blynk_server) -1); } else if (key == "blynk_port") { @@ -561,12 +678,17 @@ class BlynkWifi number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.blynk_token) -1) strcpy(Blynk8266_WM_config.blynk_token, value.c_str()); + else + strncpy(Blynk8266_WM_config.blynk_token, value.c_str(), sizeof(Blynk8266_WM_config.blynk_token) -1); + } else if (key == "board_name") { number_items_Updated++; if (strlen(value.c_str()) < sizeof(Blynk8266_WM_config.board_name) -1) strcpy(Blynk8266_WM_config.board_name, value.c_str()); + else + strncpy(Blynk8266_WM_config.board_name, value.c_str(), sizeof(Blynk8266_WM_config.board_name) -1); } server.send(200, "text/html", "OK"); @@ -587,7 +709,9 @@ class BlynkWifi } void startConfigurationMode() - { + { + #define CONFIG_TIMEOUT 60000L + String chipID = String(ESP.getChipId(), HEX); chipID.toUpperCase(); @@ -609,11 +733,16 @@ class BlynkWifi server.on("/", [this](){ handleRequest(); }); server.begin(); + + // If there is no saved config Data, stay in config mode forever until having config Data. + if (hadConfigData) + configTimeout = millis() + CONFIG_TIMEOUT; + else + configTimeout = 0; configuration_mode = true; } - -}; + }; static WiFiClient _blynkWifiClient; static BlynkArduinoClient _blynkTransport(_blynkWifiClient);