From dfa64b296080920257c6cf847994f6437432da52 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 9 May 2020 19:45:36 +0200 Subject: [PATCH 001/404] Add C019 stub for ESPEasy-Now controller --- src/_C019.ino | 109 ++++++++++++++++++ src/define_plugin_sets.h | 3 +- .../ControllerQueue/C019_queue_element.cpp | 29 +++++ src/src/ControllerQueue/C019_queue_element.h | 35 ++++++ src/src/ControllerQueue/DelayQueueElements.h | 10 +- tools/pio/pre_custom_esp32.py | 2 + tools/pio/pre_custom_esp82xx.py | 3 +- 7 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/_C019.ino create mode 100644 src/src/ControllerQueue/C019_queue_element.cpp create mode 100644 src/src/ControllerQueue/C019_queue_element.h diff --git a/src/_C019.ino b/src/_C019.ino new file mode 100644 index 0000000000..88070659b3 --- /dev/null +++ b/src/_C019.ino @@ -0,0 +1,109 @@ +#ifdef USES_C019 + +// ####################################################################################################### +// ################### Controller Plugin 019: ESPEasy-Now ################################################ +// ####################################################################################################### + +#define CPLUGIN_019 +#define CPLUGIN_ID_019 19 +#define CPLUGIN_NAME_019 "ESPEasy-Now" + +bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& string) +{ + bool success = false; + + switch (function) + { + case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: + { + Protocol[++protocolCount].Number = CPLUGIN_ID_019; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesTemplate = false; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = false; + Protocol[protocolCount].defaultPort = 0; + Protocol[protocolCount].usesID = false; + Protocol[protocolCount].Custom = false; + Protocol[protocolCount].usesHost = false; + Protocol[protocolCount].usesPort = false; + Protocol[protocolCount].usesQueue = false; + Protocol[protocolCount].usesCheckReply = false; + Protocol[protocolCount].usesTimeout = false; + Protocol[protocolCount].usesSampleSets = false; + Protocol[protocolCount].needsWiFi = false; + break; + } + + case CPlugin::Function::CPLUGIN_GET_DEVICENAME: + { + string = F(CPLUGIN_NAME_019); + break; + } + + case CPlugin::Function::CPLUGIN_INIT: + { + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + + // FIXME TD-er: Not sure if MQTT like formatting is the best here. + C019_DelayHandler.configureControllerSettings(ControllerSettings); + break; + } + + case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: + { + event->String1 = F("%sysname%/#"); + event->String2 = F("%sysname%/%tskname%/%valname%"); + break; + } + + case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: + { + success = C019_DelayHandler.addToQueue(C019_queue_element(event)); + scheduleNextDelayQueue(TIMER_C019_DELAY_QUEUE, C019_DelayHandler.getNextScheduleTime()); + break; + } + + case CPlugin::Function::CPLUGIN_PROTOCOL_RECV: + { + // FIXME TD-er: WHen should this be scheduled? + // protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(event->ControllerIndex); + // schedule_controller_event_timer(ProtocolIndex, CPlugin::Function::CPLUGIN_PROTOCOL_RECV, event); + break; + } + + case CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND: + { + // C019_data.async_loop(); + + // FIXME TD-er: Handle reading error state or return values. + break; + } + + case CPlugin::Function::CPLUGIN_FLUSH: + { + process_c019_delay_queue(); + delay(0); + break; + } + + default: + break; + } + + return success; +} + +// Uncrustify may change this into multi line, which will result in failed builds +// *INDENT-OFF* +bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings); +// *INDENT-ON* + +bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings) { + bool success = true; + + return success; +} + +#endif // ifdef USES_C019 diff --git a/src/define_plugin_sets.h b/src/define_plugin_sets.h index 233fb23583..11dce8c04a 100644 --- a/src/define_plugin_sets.h +++ b/src/define_plugin_sets.h @@ -878,6 +878,7 @@ To create/register a plugin, you have to : //#define USES_C015 // Blynk #define USES_C017 // Zabbix // #define USES_C018 // TTN RN2483 + // #define USES_C019 // ESPEasy-Now #endif @@ -1022,7 +1023,7 @@ To create/register a plugin, you have to : */ -#if defined(USES_C018) +#if defined(USES_C018) || defined(USES_C019) #define USES_PACKED_RAW_DATA #endif diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp new file mode 100644 index 0000000000..f4f7898713 --- /dev/null +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -0,0 +1,29 @@ +#include "../ControllerQueue/C019_queue_element.h" + +#include "../DataStructs/ESPEasy_EventStruct.h" +#include "../../ESPEasy_Log.h" + + +#ifdef USES_PACKED_RAW_DATA +String getPackedFromPlugin(struct EventStruct *event, + uint8_t sampleSetCount); +#endif // USES_PACKED_RAW_DATA + +C019_queue_element::C019_queue_element() {} + +C019_queue_element::C019_queue_element(struct EventStruct *event) : + controller_idx(event->ControllerIndex) +{ + #ifdef USES_PACKED_RAW_DATA + packed = getPackedFromPlugin(event, 0); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("C019 queue element: "); + log += packed; + addLog(LOG_LEVEL_INFO, log); + } + #endif // USES_PACKED_RAW_DATA +} + +size_t C019_queue_element::getSize() const { + return sizeof(*this) + packed.length(); +} diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h new file mode 100644 index 0000000000..b2eb519df6 --- /dev/null +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -0,0 +1,35 @@ +#ifndef CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H +#define CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H + +#include "../../ESPEasy_common.h" +#include "../DataStructs/ESPEasyLimits.h" +#include "../Globals/CPlugins.h" + + +struct EventStruct; + +// #ifdef USES_C019 + +/*********************************************************************************************\ +* C019_queue_element for queueing requests for C019: ESPEasy-Now +\*********************************************************************************************/ + + +class C019_queue_element { +public: + + C019_queue_element(); + + C019_queue_element(struct EventStruct *event); + + size_t getSize() const; + + String packed; + controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; + pluginID_t plugin_id = INVALID_PLUGIN_ID; +}; + +// #endif //USES_C019 + + +#endif // CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H diff --git a/src/src/ControllerQueue/DelayQueueElements.h b/src/src/ControllerQueue/DelayQueueElements.h index 9177f168fa..213d8aa93b 100644 --- a/src/src/ControllerQueue/DelayQueueElements.h +++ b/src/src/ControllerQueue/DelayQueueElements.h @@ -146,11 +146,11 @@ DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 18) #endif // ifdef USES_C018 -/* - #ifdef USES_C019 - DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 19) - #endif - */ +#ifdef USES_C019 +# include "../ControllerQueue/C019_queue_element.h" +DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 19) +#endif // ifdef USES_C019 + /* #ifdef USES_C020 diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index e510cb244d..7909fe8b3d 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -39,6 +39,8 @@ "USES_P097", # Touch (ESP32) "USES_P100", # Pulse Counter - DS2423 + "USES_C019", # ESPEasy-Now + "USE_SETTINGS_ARCHIVE", "FEATURE_I2CMULTIPLEXER", "FEATURE_ARDUINO_OTA" diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index c14b909acd..04f93421d9 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -44,7 +44,8 @@ "USES_C016", # Cache Controller "USES_C018", # TTN/RN2483 -# "USES_C015", # TTN/RN2483 + "USES_C015", # Blynk + "USES_C019", # ESPEasy-Now "FEATURE_MDNS", "FEATURE_SD", From 8c0b7e368aeaf533bbd56328848303d6f22daa09 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 9 May 2020 19:57:52 +0200 Subject: [PATCH 002/404] Add P098 ESPEasy-Now Receiver stub --- src/_P098_ESPEasyNowReceiver.ino | 83 ++++++++++++++++++++++++++++++++ src/define_plugin_sets.h | 1 + tools/pio/pre_custom_esp32.py | 1 + tools/pio/pre_custom_esp82xx.py | 1 + 4 files changed, 86 insertions(+) create mode 100644 src/_P098_ESPEasyNowReceiver.ino diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino new file mode 100644 index 0000000000..5130a5ed79 --- /dev/null +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -0,0 +1,83 @@ +#ifdef USES_P098 + +// ####################################################################################################### +// #################################### Plugin 098: ESPEasy-Now Receiver ################################# +// ####################################################################################################### + +#include "_Plugin_Helper.h" + +#define PLUGIN_098 +#define PLUGIN_ID_098 98 +#define PLUGIN_NAME_098 "Generic - ESPEasy-Now Receiver" +#define PLUGIN_VALUENAME1_098 "Value" +boolean Plugin_098(byte function, struct EventStruct *event, String& string) +{ + boolean success = false; + + switch (function) + { + case PLUGIN_DEVICE_ADD: + { + Device[++deviceCount].Number = PLUGIN_ID_098; + Device[deviceCount].Type = DEVICE_TYPE_DUMMY; + Device[deviceCount].VType = SENSOR_TYPE_STRING; // FIXME TD-er: Must make this the same as the sender. + Device[deviceCount].Ports = 0; + Device[deviceCount].PullUpOption = false; + Device[deviceCount].InverseLogicOption = false; + Device[deviceCount].FormulaOption = false; + Device[deviceCount].DecimalsOnly = true; + Device[deviceCount].ValueCount = 1; + Device[deviceCount].SendDataOption = true; + Device[deviceCount].TimerOption = true; + Device[deviceCount].GlobalSyncOption = false; + break; + } + + case PLUGIN_GET_DEVICENAME: + { + string = F(PLUGIN_NAME_098); + break; + } + + case PLUGIN_GET_DEVICEVALUENAMES: + { + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_098)); + break; + } + + case PLUGIN_WEBFORM_LOAD: + { + success = true; + break; + } + + case PLUGIN_WEBFORM_SAVE: + { + success = true; + break; + } + + case PLUGIN_INIT: + { + // Do not set the sensor type, or else it will be set for all instances of the Dummy plugin. + // sensorTypeHelper_setSensorType(event, 0); + success = true; + break; + } + + case PLUGIN_READ: + { + event->sensorType = PCONFIG(0); + success = true; + break; + } + + case PLUGIN_WRITE: + { + break; + } + } + return success; +} + +#endif // USES_P098 diff --git a/src/define_plugin_sets.h b/src/define_plugin_sets.h index 11dce8c04a..88c0860095 100644 --- a/src/define_plugin_sets.h +++ b/src/define_plugin_sets.h @@ -867,6 +867,7 @@ To create/register a plugin, you have to : //#define USES_P095 // TFT ILI9341 //#define USES_P096 // eInk (Needs lib_deps = Adafruit GFX Library, LOLIN_EPD ) #define USES_P097 // Touch (ESP32) + #define USES_P098 // ESPEasy-Now Reader #define USES_P100 // Pulse Counter - DS2423 #endif diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 7909fe8b3d..5585ff2f15 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -37,6 +37,7 @@ "USES_P082", # GPS "USES_P087", # Serial Proxy "USES_P097", # Touch (ESP32) + "USES_P098", # ESPEasy-Now Reader "USES_P100", # Pulse Counter - DS2423 "USES_C019", # ESPEasy-Now diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 04f93421d9..d7954a3eb1 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -41,6 +41,7 @@ # "USES_P087", # Serial Proxy # "USES_P094", # CUL Reader # "USES_P095", # TFT ILI9341 + "USES_P098", # ESPEasy-Now Reader "USES_C016", # Cache Controller "USES_C018", # TTN/RN2483 From e5e3b845e6bf4ce903c56b1f7368e259d15e17d9 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 9 May 2020 20:40:44 +0200 Subject: [PATCH 003/404] Transform defines in EventValueSource into enum --- src/_C019.ino | 3 +++ src/_P098_ESPEasyNowReceiver.ino | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/_C019.ino b/src/_C019.ino index 88070659b3..ef07b46fe1 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -4,6 +4,9 @@ // ################### Controller Plugin 019: ESPEasy-Now ################################################ // ####################################################################################################### +#include "src/Helpers/ESPEasy_now.h" + + #define CPLUGIN_019 #define CPLUGIN_ID_019 19 #define CPLUGIN_NAME_019 "ESPEasy-Now" diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 5130a5ed79..c7c9233bf8 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -5,6 +5,8 @@ // ####################################################################################################### #include "_Plugin_Helper.h" +#include "src/Helpers/ESPEasy_now.h" + #define PLUGIN_098 #define PLUGIN_ID_098 98 From 247d497d68dd002fbe290a970c691a13f0b872c9 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 10 May 2020 02:30:35 +0200 Subject: [PATCH 004/404] [ESPEasy_now] First setup to send MQTT either via ESP-now or MQTT Still a quick hack to use the existing MQTT controller. Still Need to make the actual starting of ESP-now based on WiFi events. --- platformio_esp32_envs.ini | 2 +- platformio_esp82xx_base.ini | 2 +- src/Controller.ino | 9 +++ src/ESPEasyWifi_ProcessEvent.cpp | 1 + src/_C005.ino | 1 + src/_P098_ESPEasyNowReceiver.ino | 68 ++++++++++++++++++- src/define_plugin_sets.h | 4 ++ .../ESPEasy_now_message_header_struct.cpp | 9 +++ .../ESPEasy_now_message_header_struct.h | 51 ++++++++++++++ src/src/DataStructs/EventValueSource.h | 1 + src/src/Globals/ESPEasy_now_state.cpp | 13 ++++ src/src/Globals/ESPEasy_now_state.h | 20 ++++++ src/src/Helpers/ESPEasy_now.cpp | 6 ++ src/src/Helpers/ESPEasy_now.h | 17 +++++ 14 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_now_message_header_struct.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_message_header_struct.h create mode 100644 src/src/Globals/ESPEasy_now_state.cpp create mode 100644 src/src/Globals/ESPEasy_now_state.h create mode 100644 src/src/Helpers/ESPEasy_now.cpp create mode 100644 src/src/Helpers/ESPEasy_now.h diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 00cf0d0eac..cd45253eaf 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -9,7 +9,7 @@ [esp32_common] extends = common, core_esp32_2_0_0 lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, ESP32_ping, HeatpumpIR -lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, Adafruit ILI9341, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO +lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, Adafruit ILI9341, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, WifiEspNow board_build.f_flash = 80000000L board_build.flash_mode = dout board_upload.maximum_size = 1900544 diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index e718635374..404dc465ca 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -52,7 +52,7 @@ extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT -lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, Adafruit ILI9341, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO +lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, Adafruit ILI9341, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, WifiEspNow lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS, LittleFS(esp8266) board = esp12e monitor_filters = esp8266_exception_decoder diff --git a/src/Controller.ino b/src/Controller.ino index 23c8d8c769..be6e53eb28 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -16,9 +16,18 @@ #include "src/Globals/Plugins.h" #include "src/Globals/Protocol.h" +#include "src/Helpers/ESPEasy_now.h" #include "src/Helpers/PortStatus.h" #include "src/Helpers/Rules_calculate.h" + +#ifndef ESPEASY_MESH_PEER +#define ESPEASY_MESH_PEER {0xA2, 0x20, 0xA6, 0x19, 0x2A, 0xBF} +#endif + +static uint8_t PEER[] ESPEASY_MESH_PEER; + + // ******************************************************************************** // Interface for Sending to Controllers // ******************************************************************************** diff --git a/src/ESPEasyWifi_ProcessEvent.cpp b/src/ESPEasyWifi_ProcessEvent.cpp index 7d065038d1..02bf85d1d6 100644 --- a/src/ESPEasyWifi_ProcessEvent.cpp +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -6,6 +6,7 @@ #include "ESPEasyWifi.h" #include "ESPEasy_fdwdecl.h" #include "src/Globals/ESPEasyWiFiEvent.h" +#include "src/Globals/ESPEasy_now_state.h" #include "src/Globals/ESPEasy_Scheduler.h" #include "src/Globals/EventQueue.h" #include "src/Globals/MQTT.h" diff --git a/src/_C005.ino b/src/_C005.ino index 4e967233c7..e899a4e14b 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -104,6 +104,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& { String pubname = CPlugin_005_pubname; bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; + statusLED(true); LoadTaskSettings(event->TaskIndex); parseControllerVariables(pubname, event, false); diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index c7c9233bf8..a7441128ef 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -12,6 +12,61 @@ #define PLUGIN_ID_098 98 #define PLUGIN_NAME_098 "Generic - ESPEasy-Now Receiver" #define PLUGIN_VALUENAME1_098 "Value" + + + + + +void p098_onReceive(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasyNow: Message from "); + log += formatMAC(mac); + addLog(LOG_LEVEL_INFO, log); + } + + #ifdef USES_MQTT + + // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + if (!validControllerIndex(controllerIndex)) { + return; + } + + static size_t topic_length = 0; + static size_t payload_length = 0; + String topic, payload; + topic.reserve(topic_length); + payload.reserve(payload_length); + bool topic_done = false; + for (size_t i = 0; i < count; ++i) { + if (!topic_done) { + if (buf[i] != 0) { + topic += static_cast(buf[i]); + } else { + // Update estimates for next call. + if (topic_length < i) { + topic_length = i; + } + if (payload_length < (count - i)) { + payload_length = (count - i); + } + topic_done = true; + } + } else { + if (buf[i] != 0) { + payload += static_cast(buf[i]); + } + } + } + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + + #endif +} + boolean Plugin_098(byte function, struct EventStruct *event, String& string) { boolean success = false; @@ -30,7 +85,7 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) Device[deviceCount].DecimalsOnly = true; Device[deviceCount].ValueCount = 1; Device[deviceCount].SendDataOption = true; - Device[deviceCount].TimerOption = true; + Device[deviceCount].TimerOption = false; Device[deviceCount].GlobalSyncOption = false; break; } @@ -63,6 +118,17 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) { // Do not set the sensor type, or else it will be set for all instances of the Dummy plugin. // sensorTypeHelper_setSensorType(event, 0); + + WifiEspNow.onReceive(p098_onReceive, nullptr); + + plugin_EspEasy_now_enabled = true; + success = true; + break; + } + + case PLUGIN_EXIT: + { + plugin_EspEasy_now_enabled = false; success = true; break; } diff --git a/src/define_plugin_sets.h b/src/define_plugin_sets.h index 88c0860095..e068e9e539 100644 --- a/src/define_plugin_sets.h +++ b/src/define_plugin_sets.h @@ -1028,6 +1028,10 @@ To create/register a plugin, you have to : #define USES_PACKED_RAW_DATA #endif +#if defined(USES_C019) || defined(USES_P098) + #define USES_ESPEASY_NOW +#endif + #if defined(USES_P085) || defined (USES_P052) || defined(USES_P078) #define USES_MODBUS #endif diff --git a/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp b/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp new file mode 100644 index 0000000000..9d63504963 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp @@ -0,0 +1,9 @@ +#include "ESPEasy_now_message_header_struct.h" + +#ifdef USES_ESPEASY_NOW + +ESPEasy_now_message_header_struct::ESPEasy_now_message_header_struct() { + // header_length = sizeof(ESPEasy_now_message_header_struct); +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_message_header_struct.h b/src/src/DataStructs/ESPEasy_now_message_header_struct.h new file mode 100644 index 0000000000..11882f5f5a --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_message_header_struct.h @@ -0,0 +1,51 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H +#define DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H + +/*********************************************************************************************\ +* ESPEasy_now_message_struct +\*********************************************************************************************/ + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +# include + +# include "../DataStructs/DeviceStruct.h" +# include "../DataStructs/ESPEasyLimits.h" +# include "../Globals/Plugins.h" + + +# define ESPEASY_NOW_HEADER_VERSION 1 + + +struct ESPEasy_now_message_header_struct { + enum class message_t : byte { + Acknowledgement = 0, + TaskName = 1, // Just the name of the task (null terminated string) + TaskValueName_TaskValue = 2, // Name of the Task value (null terminated string) + string formatted value + taskValue = 3, // Just the string formatted value (can be next part of the value, for SENSOR_TYPE_STRING) + }; + + ESPEasy_now_message_header_struct(); + + const byte header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions + const byte header_length = sizeof(ESPEasy_now_message_header_struct); // Length of the header + message_t message_type = message_t::Acknowledgement; + byte cur_message_nr = 0; // Current message number (start at 0, always < + // total_nr_messages) + byte total_nr_messages = 1; // Total number of messages needed to transfer all information + // (can be >1 for + // SENSOR_TYPE_STRING) + byte cur_payload_size = 0; // The size of the payload in this message. + byte VType = SENSOR_TYPE_NONE; // Type of value the plugin will return. e.g. SENSOR_TYPE_STRING + byte ValueCount = 0; // The number of output values of a plugin. + byte cur_taskvalue_index = 0; // Describing which task value is sent (start at 0, always < + // ValueCount) + taskIndex_t taskIndex = INVALID_TASK_INDEX; // Task index of the data origin when creating message + uint16_t plugin_id = INVALID_PLUGIN_ID; // FIXME TD-er: Change to pluginID_t when that one is switched + // to 16 bit value +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H diff --git a/src/src/DataStructs/EventValueSource.h b/src/src/DataStructs/EventValueSource.h index 181cb7856d..8834fa3917 100644 --- a/src/src/DataStructs/EventValueSource.h +++ b/src/src/DataStructs/EventValueSource.h @@ -14,6 +14,7 @@ class EventValueSource { VALUE_SOURCE_UDP = 5, VALUE_SOURCE_WEB_FRONTEND = 6, VALUE_SOURCE_RULES = 7, + VALUE_SOURCE_ESPEASY_NOW = 8, VALUE_SOURCE_NR_VALUES }; diff --git a/src/src/Globals/ESPEasy_now_state.cpp b/src/src/Globals/ESPEasy_now_state.cpp new file mode 100644 index 0000000000..e38bb9f7ab --- /dev/null +++ b/src/src/Globals/ESPEasy_now_state.cpp @@ -0,0 +1,13 @@ +#include "ESPEasy_now_state.h" + + + +#ifdef USES_ESPEASY_NOW + +bool use_EspEasy_now = false; +bool plugin_EspEasy_now_active = false; +bool plugin_EspEasy_now_enabled = false; +bool controller_EspEasy_now_active = false; +bool controller_EspEasy_now_enabled = false; + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/ESPEasy_now_state.h b/src/src/Globals/ESPEasy_now_state.h new file mode 100644 index 0000000000..0bee9e70a1 --- /dev/null +++ b/src/src/Globals/ESPEasy_now_state.h @@ -0,0 +1,20 @@ +#ifndef GLOBALS_ESPEASY_NOW_STATE_H +#define GLOBALS_ESPEASY_NOW_STATE_H + +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + +# include + +extern bool use_EspEasy_now; +extern bool plugin_EspEasy_now_active; +extern bool plugin_EspEasy_now_enabled; + +extern bool controller_EspEasy_now_active; +extern bool controller_EspEasy_now_enabled; + + +#endif // ifdef USES_ESPEASY_NOW + +#endif // GLOBALS_ESPEASY_NOW_STATE_H diff --git a/src/src/Helpers/ESPEasy_now.cpp b/src/src/Helpers/ESPEasy_now.cpp new file mode 100644 index 0000000000..2ce5ca9e3e --- /dev/null +++ b/src/src/Helpers/ESPEasy_now.cpp @@ -0,0 +1,6 @@ +#include "ESPEasy_now.h" + +#ifdef USES_ESPEASY_NOW + + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now.h b/src/src/Helpers/ESPEasy_now.h new file mode 100644 index 0000000000..2f605c24be --- /dev/null +++ b/src/src/Helpers/ESPEasy_now.h @@ -0,0 +1,17 @@ +#ifndef HELPERS_ESPEASY_NOW_H +#define HELPERS_ESPEASY_NOW_H + +# include "../Globals/ESPEasy_now_state.h" + +#ifdef USES_ESPEASY_NOW + +# include "../DataStructs/ESPEasy_now_message_header_struct.h" + + +class ESPEasy_now { + ESPEasy_now() {} +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // HELPERS_ESPEASY_NOW_H From 29e472071ba44eb83122b550d40c13f389c6a743 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 10 May 2020 17:13:02 +0200 Subject: [PATCH 005/404] [ESPEasy-Now] Initial success in forwarding MQTT controller data --- src/Controller.ino | 6 ---- src/ESPEasyWifi.cpp | 15 +++++++++ src/WebServer_ConfigPage.ino | 32 +++++++++++++++++++ src/WebServer_ControllerPage.ino | 14 ++++++++ src/WebServer_Markup_Forms.ino | 28 ++++++++++++++++ src/_C005.ino | 1 + src/_CPlugin_Helper_webform.ino | 7 ++++ src/_P098_ESPEasyNowReceiver.ino | 8 +++++ .../DataStructs/ControllerSettingsStruct.cpp | 10 ++++++ .../DataStructs/ControllerSettingsStruct.h | 4 +++ src/src/DataStructs/ESPEasyLimits.h | 10 ++++++ src/src/DataStructs/SecurityStruct.cpp | 16 ++++++++++ src/src/DataStructs/SecurityStruct.h | 4 +++ src/src/Globals/ESPEasy_now_state.cpp | 2 -- src/src/Globals/ESPEasy_now_state.h | 2 -- tools/pio/pre_custom_esp82xx.py | 2 +- 16 files changed, 150 insertions(+), 11 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index be6e53eb28..2bb463c308 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -21,12 +21,6 @@ #include "src/Helpers/Rules_calculate.h" -#ifndef ESPEASY_MESH_PEER -#define ESPEASY_MESH_PEER {0xA2, 0x20, 0xA6, 0x19, 0x2A, 0xBF} -#endif - -static uint8_t PEER[] ESPEASY_MESH_PEER; - // ******************************************************************************** // Interface for Sending to Controllers diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index a7029d0ae7..0f3c59b8fc 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -252,6 +252,16 @@ bool prepareWiFi() { WiFi.setSleepMode(WIFI_NONE_SLEEP); } + #ifdef USES_ESPEASY_NOW + if (plugin_EspEasy_now_enabled) { + setAP(true); + WiFi.softAP("ESPNOW", nullptr, 1); + WiFi.softAPdisconnect(false); + WifiEspNow.begin(); + } + #endif + + #endif // if defined(ESP8266) #if defined(ESP32) WiFi.setHostname(hostname); @@ -387,6 +397,11 @@ void initWiFi() // ******************************************************************************** void WifiDisconnect() { + // FIXME TD-er: Disconnect processing is done in several places. + #ifdef USES_ESPEASY_NOW + WifiEspNow.end(); + use_EspEasy_now = false; + #endif #if defined(ESP32) WiFi.disconnect(); WiFi.removeEvent(wm_event_id); diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index 90520d3ba9..7dc36e00f1 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -99,6 +99,28 @@ void handle_config() { break; } + #ifdef USES_ESPEASY_NOW + for (int peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + String id = F("peer"); + id += String(peer); + String peer_mac = web_server.arg(id); + if (peer_mac.length() == 0) { + peer_mac = F("00:00:00:00:00:00"); + } + byte mac[6] = {0}; + if (str2mac(peer_mac.c_str(), mac)) { + memcpy(SecuritySettings.EspEasyNowPeerMAC[peer], mac, 6); + } + /* + String log = F("MAC decoding "); + log += peer_mac; + log += F(" => "); + log += formatMAC(mac); + addLog(LOG_LEVEL_INFO, log); + */ + } + #endif + Settings.deepSleepOnFail = isFormItemChecked(F("deepsleeponfail")); str2ip(espip, Settings.IP); str2ip(espgateway, Settings.Gateway); @@ -169,6 +191,16 @@ void handle_config() { addFormNote(F("Leave empty for DHCP")); #endif +#ifdef USES_ESPEASY_NOW + addFormSubHeader(F("ESPEasy Now")); + for (int peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + String label = F("Peer "); + label += String(peer + 1); + String id = F("peer"); + id += String(peer); + addFormMACBox(label, id, SecuritySettings.EspEasyNowPeerMAC[peer]); + } +#endif addFormSubHeader(F("Sleep Mode")); diff --git a/src/WebServer_ControllerPage.ino b/src/WebServer_ControllerPage.ino index 8e0e1ecb50..47d38909e8 100644 --- a/src/WebServer_ControllerPage.ino +++ b/src/WebServer_ControllerPage.ino @@ -291,6 +291,20 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex } } addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PORT); + #ifdef USES_ESPEASY_NOW + if (Protocol[ProtocolIndex].usesMQTT) { + // FIXME TD-er: Currently only enabled for MQTT protocols, later for more + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK); + } + #endif + + if (Protocol[ProtocolIndex].usesQueue) { + addTableSeparator(F("Controller Queue"), 2, 3); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MIN_SEND_INTERVAL); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); + } if (Protocol[ProtocolIndex].usesQueue) { addTableSeparator(F("Controller Queue"), 2, 3); diff --git a/src/WebServer_Markup_Forms.ino b/src/WebServer_Markup_Forms.ino index c0e9e8251d..71142222e3 100644 --- a/src/WebServer_Markup_Forms.ino +++ b/src/WebServer_Markup_Forms.ino @@ -165,6 +165,34 @@ void addFormIPBox(const String& label, const String& id, const byte ip[4]) addHtml(html); } +// ******************************************************************************** +// Add a MAC Box form +// ******************************************************************************** +void addFormMACBox(const String& label, const String& id, const byte mac[6]) +{ + bool empty_MAC = true; + for (int i = 0; i < 6; ++i) { + if (mac[i] != 0) { + empty_MAC = false; + } + } + + addRowLabel_tr_id(label, id); + + String html; + html.reserve(80 + id.length()); + + html += F(""; + addHtml(html); +} + // ******************************************************************************** // Add a IP Access Control select dropdown list // ******************************************************************************** diff --git a/src/_C005.ino b/src/_C005.ino index e899a4e14b..07af68c494 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -104,6 +104,7 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& { String pubname = CPlugin_005_pubname; bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; + statusLED(true); LoadTaskSettings(event->TaskIndex); diff --git a/src/_CPlugin_Helper_webform.ino b/src/_CPlugin_Helper_webform.ino index 55f0c1baa8..d850e597cd 100644 --- a/src/_CPlugin_Helper_webform.ino +++ b/src/_CPlugin_Helper_webform.ino @@ -54,6 +54,7 @@ String getControllerParameterName(protocolIndex_t ProtocolInde case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: name = F("Send Binary"); break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: name = F("Client Timeout"); break; case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: name = F("Sample Set Initiator"); break; + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: name = F("Enable ESPEasy-Now Fallback"); break; case ControllerSettingsStruct::CONTROLLER_ENABLED: @@ -239,6 +240,9 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: addTaskSelectBox(displayName, internalName, ControllerSettings.SampleSetInitiator); break; + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: + addFormCheckBox(displayName, internalName, ControllerSettings.enableESPEasyNowFallback()); + break; case ControllerSettingsStruct::CONTROLLER_ENABLED: addFormCheckBox(displayName, internalName, Settings.ControllerEnabled[controllerindex]); break; @@ -355,6 +359,9 @@ void saveControllerParameterForm(ControllerSettingsStruct & ControllerSet case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: ControllerSettings.SampleSetInitiator = getFormItemInt(internalName, ControllerSettings.SampleSetInitiator); break; + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: + ControllerSettings.enableESPEasyNowFallback(isFormItemChecked(internalName)); + break; case ControllerSettingsStruct::CONTROLLER_ENABLED: Settings.ControllerEnabled[controllerindex] = isFormItemChecked(internalName); break; diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index a7441128ef..4eb5dfdb59 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -142,6 +142,14 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) case PLUGIN_WRITE: { + // FIXME TD-er: Create commands for ESPEasy_now receiver + String command = parseString(string, 1); + if (command == F("espeasynow")) { + String subcommand = parseString(string, 2); + if (subcommand == F("")) { + + } + } break; } } diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index e4af8e10e7..d054b89933 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -253,3 +253,13 @@ void ControllerSettingsStruct::sendBinary(bool value) { bitWrite(VariousFlags, 7, value); } + +bool ControllerSettingsStruct::enableESPEasyNowFallback() const +{ + return bitRead(MQTT_flags, 7); +} + +void ControllerSettingsStruct::enableESPEasyNowFallback(bool value) +{ + bitWrite(MQTT_flags, 7, value); +} diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index ff2a8f5624..b3f6b32ec5 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -83,6 +83,7 @@ struct ControllerSettingsStruct CONTROLLER_TIMEOUT, CONTROLLER_SAMPLE_SET_INITIATOR, CONTROLLER_SEND_BINARY, + CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK, // Keep this as last, is used to loop over all parameters CONTROLLER_ENABLED @@ -133,6 +134,9 @@ struct ControllerSettingsStruct bool sendBinary() const; void sendBinary(bool value); + bool enableESPEasyNowFallback() const; + void enableESPEasyNowFallback(bool value); + boolean UseDNS; byte IP[4]; unsigned int Port; diff --git a/src/src/DataStructs/ESPEasyLimits.h b/src/src/DataStructs/ESPEasyLimits.h index c78843c28f..7649f0fd37 100644 --- a/src/src/DataStructs/ESPEasyLimits.h +++ b/src/src/DataStructs/ESPEasyLimits.h @@ -63,6 +63,16 @@ #endif + +// *********************************************************************** +// * ESPEasy-Now related limits +// *********************************************************************** + +#ifndef ESPEASY_NOW_PEER_MAX + #define ESPEASY_NOW_PEER_MAX 10 // 10 when using encryption, 20 without encryption +#endif + + // *********************************************************************** // * The next limits affect memory usage // *********************************************************************** diff --git a/src/src/DataStructs/SecurityStruct.cpp b/src/src/DataStructs/SecurityStruct.cpp index faba2ce309..c7cf0022d3 100644 --- a/src/src/DataStructs/SecurityStruct.cpp +++ b/src/src/DataStructs/SecurityStruct.cpp @@ -15,6 +15,9 @@ SecurityStruct::SecurityStruct() { ZERO_FILL(ControllerUser[i]); ZERO_FILL(ControllerPassword[i]); } + for (byte i = 0; i < ESPEASY_NOW_PEER_MAX; ++i) { + ZERO_FILL(EspEasyNowPeerMAC[i]); + } ZERO_FILL(Password); } @@ -31,3 +34,16 @@ void SecurityStruct::validate() { } ZERO_TERMINATE(Password); } + + +bool SecurityStruct::peerMacSet(byte peer_index) const { + if (peer_index >= ESPEASY_NOW_PEER_MAX) { + return false; + } + for (int i = 0; i < 6; ++i) { + if (EspEasyNowPeerMAC[peer_index][i] != 0) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/src/DataStructs/SecurityStruct.h b/src/src/DataStructs/SecurityStruct.h index 27d33e891f..031f04c8e4 100644 --- a/src/src/DataStructs/SecurityStruct.h +++ b/src/src/DataStructs/SecurityStruct.h @@ -13,6 +13,8 @@ struct SecurityStruct void validate(); + bool peerMacSet(byte peer_index) const; + char WifiSSID[32]; char WifiKey[64]; char WifiSSID2[32]; @@ -28,6 +30,8 @@ struct SecurityStruct //its safe to extend this struct, up to 4096 bytes, default values in config are 0. Make sure crc is last uint8_t ProgmemMd5[16] = {0}; // crc of the binary that last saved the struct to file. uint8_t md5[16] = {0}; + + byte EspEasyNowPeerMAC[ESPEASY_NOW_PEER_MAX][6]; }; diff --git a/src/src/Globals/ESPEasy_now_state.cpp b/src/src/Globals/ESPEasy_now_state.cpp index e38bb9f7ab..f87575fb4b 100644 --- a/src/src/Globals/ESPEasy_now_state.cpp +++ b/src/src/Globals/ESPEasy_now_state.cpp @@ -7,7 +7,5 @@ bool use_EspEasy_now = false; bool plugin_EspEasy_now_active = false; bool plugin_EspEasy_now_enabled = false; -bool controller_EspEasy_now_active = false; -bool controller_EspEasy_now_enabled = false; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/ESPEasy_now_state.h b/src/src/Globals/ESPEasy_now_state.h index 0bee9e70a1..095e399c57 100644 --- a/src/src/Globals/ESPEasy_now_state.h +++ b/src/src/Globals/ESPEasy_now_state.h @@ -11,8 +11,6 @@ extern bool use_EspEasy_now; extern bool plugin_EspEasy_now_active; extern bool plugin_EspEasy_now_enabled; -extern bool controller_EspEasy_now_active; -extern bool controller_EspEasy_now_enabled; #endif // ifdef USES_ESPEASY_NOW diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index d7954a3eb1..e973abdd0a 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -39,7 +39,7 @@ "USES_P085", # AcuDC24x "USES_P100", # Pulse Counter - DS2423 # "USES_P087", # Serial Proxy -# "USES_P094", # CUL Reader + "USES_P094", # CUL Reader # "USES_P095", # TFT ILI9341 "USES_P098", # ESPEasy-Now Reader From aea9f0973f8219e37d00a03921bba8dece84ba6c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 10 May 2020 21:38:05 +0200 Subject: [PATCH 006/404] [ESPEasy-Now] Use status LED and allow sending without WiFi connection The controllers now can also send if the ESPEasy-Now fallback option is enabled. In normal use cases, one would like to use the ESPEasy-Now fallback option when there is no WiFi present. So it makes no sense to only allow to send when there is a WiFi connection. The ESPEasyNowReceiver plugin now also adds the peers upon init of the plugin. --- src/_P098_ESPEasyNowReceiver.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 4eb5dfdb59..5524da8c65 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -120,6 +120,11 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) // sensorTypeHelper_setSensorType(event, 0); WifiEspNow.onReceive(p098_onReceive, nullptr); + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + if (SecuritySettings.peerMacSet(peer)) { + WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer]); + } + } plugin_EspEasy_now_enabled = true; success = true; From dac9acd5e8a582877a008ad943cb08e2e7521a26 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 11 May 2020 13:05:26 +0200 Subject: [PATCH 007/404] [ESPEasy-Now] Use queue for received ESP-now packets (fix stability) ESP-now is doing the call-back from the high priority WiFi thread, so we must only copy the data and process it later. So now we're using a list with a buffer object to collect all ESP-now messages. --- src/_P098_ESPEasyNowReceiver.ino | 96 +++++++++----------- src/src/DataStructs/ESPEasy_Now_incoming.cpp | 34 +++++++ src/src/DataStructs/ESPEasy_Now_incoming.h | 24 +++++ 3 files changed, 103 insertions(+), 51 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_Now_incoming.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_incoming.h diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 5524da8c65..1794566778 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -5,6 +5,8 @@ // ####################################################################################################### #include "_Plugin_Helper.h" + +#include "src/DataStructs/ESPEasy_Now_incoming.h" #include "src/Helpers/ESPEasy_now.h" @@ -14,57 +16,17 @@ #define PLUGIN_VALUENAME1_098 "Value" +struct P098_data_struct : public PluginTaskData_base { + P098_data_struct() {} + ~P098_data_struct() {} +}; -void p098_onReceive(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasyNow: Message from "); - log += formatMAC(mac); - addLog(LOG_LEVEL_INFO, log); - } - - #ifdef USES_MQTT - - // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller +std::list p098_queue; - controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); - if (!validControllerIndex(controllerIndex)) { - return; - } - - static size_t topic_length = 0; - static size_t payload_length = 0; - String topic, payload; - topic.reserve(topic_length); - payload.reserve(payload_length); - bool topic_done = false; - for (size_t i = 0; i < count; ++i) { - if (!topic_done) { - if (buf[i] != 0) { - topic += static_cast(buf[i]); - } else { - // Update estimates for next call. - if (topic_length < i) { - topic_length = i; - } - if (payload_length < (count - i)) { - payload_length = (count - i); - } - topic_done = true; - } - } else { - if (buf[i] != 0) { - payload += static_cast(buf[i]); - } - } - } - - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); - - #endif +void p098_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { + p098_queue.emplace_back(mac, buf, count); } boolean Plugin_098(byte function, struct EventStruct *event, String& string) @@ -120,6 +82,7 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) // sensorTypeHelper_setSensorType(event, 0); WifiEspNow.onReceive(p098_onReceive, nullptr); + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { if (SecuritySettings.peerMacSet(peer)) { WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer]); @@ -127,14 +90,45 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) } plugin_EspEasy_now_enabled = true; - success = true; + success = true; break; } case PLUGIN_EXIT: { plugin_EspEasy_now_enabled = false; - success = true; + success = true; + break; + } + + case PLUGIN_FIFTY_PER_SECOND: + { + if (!p098_queue.empty()) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasyNow: Message from "); + log += formatMAC(p098_queue.front()._mac); + addLog(LOG_LEVEL_INFO, log); + } + #ifdef USES_MQTT + + // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + + if (validControllerIndex(controllerIndex)) { + String topic = p098_queue.front().getString(0); + String payload = p098_queue.front().getString(topic.length()); + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + } + + #endif // ifdef USES_MQTT + + // FIXME TD-er: What to do when publish fails? + p098_queue.pop_front(); + } break; } @@ -149,11 +143,11 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) { // FIXME TD-er: Create commands for ESPEasy_now receiver String command = parseString(string, 1); + if (command == F("espeasynow")) { String subcommand = parseString(string, 2); - if (subcommand == F("")) { - } + if (subcommand == F("")) {} } break; } diff --git a/src/src/DataStructs/ESPEasy_Now_incoming.cpp b/src/src/DataStructs/ESPEasy_Now_incoming.cpp new file mode 100644 index 0000000000..75981ab6dc --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_incoming.cpp @@ -0,0 +1,34 @@ +#include "ESPEasy_Now_incoming.h" + +ESPEasy_Now_incoming::ESPEasy_Now_incoming(const uint8_t mac[6], const uint8_t *buf, size_t count) +{ + _buf.resize(count); + memcpy(_mac, mac, 6); + memcpy(&_buf[0], buf, count); +} + +size_t ESPEasy_Now_incoming::getSize() const +{ + return _buf.size(); +} + +String ESPEasy_Now_incoming::getString(size_t pos) const +{ + String res; + const size_t size = getSize(); + + while (pos < size && _buf[pos] == 0) { + ++pos; + } + + if (pos >= size) { return res; } + + const size_t maxlen = size - pos; + size_t strlength = strnlen(reinterpret_cast(&_buf[pos]), maxlen); + res.reserve(strlength); + + for (size_t i = 0; i < strlength; ++i) { + res += static_cast(_buf[pos + i]); + } + return res; +} diff --git a/src/src/DataStructs/ESPEasy_Now_incoming.h b/src/src/DataStructs/ESPEasy_Now_incoming.h new file mode 100644 index 0000000000..0f62c02f72 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_incoming.h @@ -0,0 +1,24 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_INCOMING_H +#define DATASTRUCTS_ESPEASY_NOW_INCOMING_H + +#include + +class ESPEasy_Now_incoming { +public: + + ESPEasy_Now_incoming(const uint8_t mac[6], + const uint8_t *buf, + size_t count); + + size_t getSize() const; + + // Return a string starting from position pos in the buffer. + String getString(size_t pos = 0) const; + + + uint8_t _mac[6] = { 0 }; + std::vector_buf; +}; + + +#endif // DATASTRUCTS_ESPEASY_NOW_INCOMING_H From 1428a96c7550eb930e33d646f12e760027e5f7b3 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 11 May 2020 15:26:18 +0200 Subject: [PATCH 008/404] [ESPEasy-Now] Use a separate ESPEasy_now_handler object --- src/Controller.ino | 1 + src/_C019.ino | 2 +- src/_P098_ESPEasyNowReceiver.ino | 10 ++----- src/src/Globals/ESPEasy_now_handler.cpp | 4 +++ src/src/Globals/ESPEasy_now_handler.h | 15 ++++++++++ src/src/Helpers/ESPEasy_now.cpp | 6 ---- src/src/Helpers/ESPEasy_now.h | 17 ------------ src/src/Helpers/ESPEasy_now_handler.cpp | 37 +++++++++++++++++++++++++ src/src/Helpers/ESPEasy_now_handler.h | 22 +++++++++++++++ 9 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 src/src/Globals/ESPEasy_now_handler.cpp create mode 100644 src/src/Globals/ESPEasy_now_handler.h delete mode 100644 src/src/Helpers/ESPEasy_now.cpp delete mode 100644 src/src/Helpers/ESPEasy_now.h create mode 100644 src/src/Helpers/ESPEasy_now_handler.cpp create mode 100644 src/src/Helpers/ESPEasy_now_handler.h diff --git a/src/Controller.ino b/src/Controller.ino index 2bb463c308..d2cf7033ef 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -15,6 +15,7 @@ #include "src/Globals/MQTT.h" #include "src/Globals/Plugins.h" #include "src/Globals/Protocol.h" +#include "src/Globals/ESPEasy_now_handler.h" #include "src/Helpers/ESPEasy_now.h" #include "src/Helpers/PortStatus.h" diff --git a/src/_C019.ino b/src/_C019.ino index ef07b46fe1..63f637635c 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -4,7 +4,7 @@ // ################### Controller Plugin 019: ESPEasy-Now ################################################ // ####################################################################################################### -#include "src/Helpers/ESPEasy_now.h" +#include "src/Globals/ESPEasy_now_handler.h" #define CPLUGIN_019 diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 1794566778..3bb765f276 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -7,7 +7,7 @@ #include "_Plugin_Helper.h" #include "src/DataStructs/ESPEasy_Now_incoming.h" -#include "src/Helpers/ESPEasy_now.h" +#include "src/Globals/ESPEasy_now_handler.h" #define PLUGIN_098 @@ -25,7 +25,7 @@ struct P098_data_struct : public PluginTaskData_base { std::list p098_queue; -void p098_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { +void ICACHE_FLASH_ATTR p098_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { p098_queue.emplace_back(mac, buf, count); } @@ -83,12 +83,6 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) WifiEspNow.onReceive(p098_onReceive, nullptr); - for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { - if (SecuritySettings.peerMacSet(peer)) { - WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer]); - } - } - plugin_EspEasy_now_enabled = true; success = true; break; diff --git a/src/src/Globals/ESPEasy_now_handler.cpp b/src/src/Globals/ESPEasy_now_handler.cpp new file mode 100644 index 0000000000..9d972176a0 --- /dev/null +++ b/src/src/Globals/ESPEasy_now_handler.cpp @@ -0,0 +1,4 @@ +#include "ESPEasy_now_handler.h" + + +ESPEasy_now_handler_t ESPEasy_now_handler; \ No newline at end of file diff --git a/src/src/Globals/ESPEasy_now_handler.h b/src/src/Globals/ESPEasy_now_handler.h new file mode 100644 index 0000000000..e259904b65 --- /dev/null +++ b/src/src/Globals/ESPEasy_now_handler.h @@ -0,0 +1,15 @@ +#ifndef GLOBALS_ESPEASY_NOW_H +#define GLOBALS_ESPEASY_NOW_H + +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + +# include "../Helpers/ESPEasy_now_handler.h" + +extern ESPEasy_now_handler_t ESPEasy_now_handler; + + +#endif // ifdef USES_ESPEASY_NOW + +#endif // GLOBALS_ESPEASY_NOW_H diff --git a/src/src/Helpers/ESPEasy_now.cpp b/src/src/Helpers/ESPEasy_now.cpp deleted file mode 100644 index 2ce5ca9e3e..0000000000 --- a/src/src/Helpers/ESPEasy_now.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ESPEasy_now.h" - -#ifdef USES_ESPEASY_NOW - - -#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now.h b/src/src/Helpers/ESPEasy_now.h deleted file mode 100644 index 2f605c24be..0000000000 --- a/src/src/Helpers/ESPEasy_now.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HELPERS_ESPEASY_NOW_H -#define HELPERS_ESPEASY_NOW_H - -# include "../Globals/ESPEasy_now_state.h" - -#ifdef USES_ESPEASY_NOW - -# include "../DataStructs/ESPEasy_now_message_header_struct.h" - - -class ESPEasy_now { - ESPEasy_now() {} -}; - -#endif // ifdef USES_ESPEASY_NOW - -#endif // HELPERS_ESPEASY_NOW_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp new file mode 100644 index 0000000000..5d35cc4047 --- /dev/null +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -0,0 +1,37 @@ +#include "ESPEasy_now_handler.h" + +#ifdef USES_ESPEASY_NOW + +#include "../../ESPEasy_Log.h" +#include "../../ESPEasy_fdwdecl.h" + +#include "../Globals/SecuritySettings.h" + +bool ESPEasy_now_handler_t::begin() +{ + if (!WifiEspNow.begin()) { return false; } + + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + if (SecuritySettings.peerMacSet(peer)) { + if (!WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer])) { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log; + log.reserve(48); + log = F("ESPEasy_Now: Failed to add peer "); + log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); + addLog(LOG_LEVEL_ERROR, log); + } + } + } + } + use_EspEasy_now = true; + return true; +} + +void ESPEasy_now_handler_t::end() +{ + use_EspEasy_now = false; + WifiEspNow.end(); +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h new file mode 100644 index 0000000000..2a22619a66 --- /dev/null +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -0,0 +1,22 @@ +#ifndef HELPERS_ESPEASY_NOW_HANDLER_H +#define HELPERS_ESPEASY_NOW_HANDLER_H + +#include "../Globals/ESPEasy_now_state.h" + +#ifdef USES_ESPEASY_NOW + +# include "../DataStructs/ESPEasy_now_message_header_struct.h" + + +class ESPEasy_now_handler_t { +public: + + ESPEasy_now_handler_t() {} + + bool begin(); + void end(); +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // HELPERS_ESPEASY_NOW_HANDLER_H From f640fab0213ee5ae5c1d85b837469ce0cd14b6cc Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 12 May 2020 15:03:44 +0200 Subject: [PATCH 009/404] [ESPEasy-Now] Create ESPEasy_Now_packet with headers --- src/_P098_ESPEasyNowReceiver.ino | 37 +---- src/src/DataStructs/ESPEasy_Now_incoming.cpp | 34 ----- src/src/DataStructs/ESPEasy_Now_incoming.h | 24 ---- src/src/DataStructs/ESPEasy_Now_packet.cpp | 107 +++++++++++++++ src/src/DataStructs/ESPEasy_Now_packet.h | 52 +++++++ src/src/DataStructs/ESPEasy_Now_peerInfo.cpp | 1 + src/src/DataStructs/ESPEasy_Now_peerInfo.h | 24 ++++ src/src/DataStructs/ESPEasy_now_hdr.cpp | 32 +++++ src/src/DataStructs/ESPEasy_now_hdr.h | 51 +++++++ .../ESPEasy_now_message_header_struct.cpp | 9 -- .../ESPEasy_now_message_header_struct.h | 51 ------- src/src/Helpers/ESPEasy_now_handler.cpp | 129 +++++++++++++++++- src/src/Helpers/ESPEasy_now_handler.h | 22 ++- 13 files changed, 415 insertions(+), 158 deletions(-) delete mode 100644 src/src/DataStructs/ESPEasy_Now_incoming.cpp delete mode 100644 src/src/DataStructs/ESPEasy_Now_incoming.h create mode 100644 src/src/DataStructs/ESPEasy_Now_packet.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_packet.h create mode 100644 src/src/DataStructs/ESPEasy_Now_peerInfo.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_peerInfo.h create mode 100644 src/src/DataStructs/ESPEasy_now_hdr.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_hdr.h delete mode 100644 src/src/DataStructs/ESPEasy_now_message_header_struct.cpp delete mode 100644 src/src/DataStructs/ESPEasy_now_message_header_struct.h diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 3bb765f276..8434864e17 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -6,7 +6,6 @@ #include "_Plugin_Helper.h" -#include "src/DataStructs/ESPEasy_Now_incoming.h" #include "src/Globals/ESPEasy_now_handler.h" @@ -22,13 +21,6 @@ struct P098_data_struct : public PluginTaskData_base { ~P098_data_struct() {} }; - -std::list p098_queue; - -void ICACHE_FLASH_ATTR p098_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { - p098_queue.emplace_back(mac, buf, count); -} - boolean Plugin_098(byte function, struct EventStruct *event, String& string) { boolean success = false; @@ -81,8 +73,6 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) // Do not set the sensor type, or else it will be set for all instances of the Dummy plugin. // sensorTypeHelper_setSensorType(event, 0); - WifiEspNow.onReceive(p098_onReceive, nullptr); - plugin_EspEasy_now_enabled = true; success = true; break; @@ -97,31 +87,8 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) case PLUGIN_FIFTY_PER_SECOND: { - if (!p098_queue.empty()) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasyNow: Message from "); - log += formatMAC(p098_queue.front()._mac); - addLog(LOG_LEVEL_INFO, log); - } - #ifdef USES_MQTT - - // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller - - controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); - - if (validControllerIndex(controllerIndex)) { - String topic = p098_queue.front().getString(0); - String payload = p098_queue.front().getString(topic.length()); - - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); - } - - #endif // ifdef USES_MQTT - - // FIXME TD-er: What to do when publish fails? - p098_queue.pop_front(); + if (ESPEasy_now_handler.loop()) { + // Some packet was handled, check if it is something for this plugin } break; } diff --git a/src/src/DataStructs/ESPEasy_Now_incoming.cpp b/src/src/DataStructs/ESPEasy_Now_incoming.cpp deleted file mode 100644 index 75981ab6dc..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_incoming.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "ESPEasy_Now_incoming.h" - -ESPEasy_Now_incoming::ESPEasy_Now_incoming(const uint8_t mac[6], const uint8_t *buf, size_t count) -{ - _buf.resize(count); - memcpy(_mac, mac, 6); - memcpy(&_buf[0], buf, count); -} - -size_t ESPEasy_Now_incoming::getSize() const -{ - return _buf.size(); -} - -String ESPEasy_Now_incoming::getString(size_t pos) const -{ - String res; - const size_t size = getSize(); - - while (pos < size && _buf[pos] == 0) { - ++pos; - } - - if (pos >= size) { return res; } - - const size_t maxlen = size - pos; - size_t strlength = strnlen(reinterpret_cast(&_buf[pos]), maxlen); - res.reserve(strlength); - - for (size_t i = 0; i < strlength; ++i) { - res += static_cast(_buf[pos + i]); - } - return res; -} diff --git a/src/src/DataStructs/ESPEasy_Now_incoming.h b/src/src/DataStructs/ESPEasy_Now_incoming.h deleted file mode 100644 index 0f62c02f72..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_incoming.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_INCOMING_H -#define DATASTRUCTS_ESPEASY_NOW_INCOMING_H - -#include - -class ESPEasy_Now_incoming { -public: - - ESPEasy_Now_incoming(const uint8_t mac[6], - const uint8_t *buf, - size_t count); - - size_t getSize() const; - - // Return a string starting from position pos in the buffer. - String getString(size_t pos = 0) const; - - - uint8_t _mac[6] = { 0 }; - std::vector_buf; -}; - - -#endif // DATASTRUCTS_ESPEASY_NOW_INCOMING_H diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp new file mode 100644 index 0000000000..0ed60dbc3f --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -0,0 +1,107 @@ +#include "ESPEasy_Now_packet.h" + +#ifdef USES_ESPEASY_NOW + + +# define ESPEASY_NOW_MAX_PACKET_SIZE 250 + +ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr &header, size_t payloadSize) +{ + setSize(payloadSize + sizeof(ESPEasy_now_hdr)); + setHeader(header); +} + +ESPEasy_Now_packet::ESPEasy_Now_packet(const uint8_t mac[6], const uint8_t *buf, size_t packetSize) +{ + setSize(packetSize); + memcpy(_mac, mac, 6); + memcpy(&_buf[0], buf, packetSize); +} + +void ESPEasy_Now_packet::setSize(size_t packetSize) +{ + if (packetSize > ESPEASY_NOW_MAX_PACKET_SIZE) { + _buf.resize(ESPEASY_NOW_MAX_PACKET_SIZE); + } + else { + _buf.resize(packetSize); + } +} + +size_t ESPEasy_Now_packet::getSize() const +{ + return _buf.size(); +} + +size_t ESPEasy_Now_packet::getPayloadSize() const +{ + size_t size = getSize(); + if (size < sizeof(ESPEasy_now_hdr)) { + // should not happen + return 0; + } + return size - sizeof(ESPEasy_now_hdr); +} + +ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const +{ + ESPEasy_now_hdr header; + if (getSize() >= sizeof(ESPEasy_now_hdr)) { + memcpy(&header, &_buf[0], sizeof(ESPEasy_now_hdr)); + } + if (!header.checksumValid()) { + header.message_type = ESPEasy_now_hdr::message_t::ChecksumError; + } + return header; +} + +void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) +{ + header.setChecksum(); + memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); +} + +size_t ESPEasy_Now_packet::addString(const String& string, size_t payload_pos) +{ + const size_t payload_size = getPayloadSize(); + + if (payload_pos > payload_size) { + return 0; + } + size_t bytesToWrite = string.length() + 1; // include null-termination + const size_t payload_free = payload_size - payload_pos; + + if (bytesToWrite > payload_free) { + bytesToWrite = payload_free; + } + + // Copy the string including null-termination. + // If the null-termination does not fit, no other string can be added anyway. + size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); + memcpy(&_buf[buf_pos], reinterpret_cast(string.c_str()), bytesToWrite); + return bytesToWrite; +} + +String ESPEasy_Now_packet::getString(size_t payload_pos) const +{ + String res; + const size_t size = getSize(); + size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); + + while (buf_pos < size && _buf[buf_pos] == 0) { + ++buf_pos; + } + + if (buf_pos >= size) { return res; } + + const size_t maxlen = size - buf_pos; + size_t strlength = strnlen(reinterpret_cast(&_buf[buf_pos]), maxlen); + res.reserve(strlength); + + for (size_t i = 0; i < strlength; ++i) { + res += static_cast(_buf[buf_pos + i]); + } + return res; +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h new file mode 100644 index 0000000000..1c8bf6d74e --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -0,0 +1,52 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_INCOMING_H +#define DATASTRUCTS_ESPEASY_NOW_INCOMING_H + +#include + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +# include "ESPEasy_now_hdr.h" +class ESPEasy_Now_packet { +public: + + // Constructor for sending a packet + ESPEasy_Now_packet(const ESPEasy_now_hdr& header, + size_t payloadSize); + + // Constructor for receiving a packet + ESPEasy_Now_packet(const uint8_t mac[6], + const uint8_t *buf, + size_t packetSize); + + size_t getSize() const; + + size_t getPayloadSize() const; + + ESPEasy_now_hdr getHeader() const; + + void setHeader(ESPEasy_now_hdr header); + + // Add a string to the packet, starting at payload position payload_pos + size_t addString(const String& string, + size_t payload_pos = 0); + + // Return a string starting from position pos in the buffer. + String getString(size_t pos = 0) const; + + const uint8_t * operator[](size_t idx) const { + return &_buf[idx]; + } + + uint8_t _mac[6] = { 0 }; + +private: + + std::vector_buf; + + void setSize(size_t packetSize); +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_INCOMING_H diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp new file mode 100644 index 0000000000..381350f73e --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp @@ -0,0 +1 @@ +#include "ESPEasy_Now_peerInfo.h" \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.h b/src/src/DataStructs/ESPEasy_Now_peerInfo.h new file mode 100644 index 0000000000..291cb05df0 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.h @@ -0,0 +1,24 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H +#define DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H + +#include + +#include + +struct ESPEasy_Now_peerInfo_meta { + String nodeName; + uint8_t channel = 0; + uint8_t distance = 0; + bool encrypt = false; +}; + + +struct ESPEasy_Now_peerInfo { + ESPEasy_Now_peerInfo_meta meta; + uint8_t mac[6] = { 0 }; +}; + +typedef std::map peerInfoMap_t; + + +#endif // DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp new file mode 100644 index 0000000000..b2dd47f28a --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -0,0 +1,32 @@ +#include "ESPEasy_now_hdr.h" + +#ifdef USES_ESPEASY_NOW + +ESPEasy_now_hdr::ESPEasy_now_hdr() {} + +ESPEasy_now_hdr::ESPEasy_now_hdr(ESPEasy_now_hdr::message_t messageType) + : message_type(messageType) {} + +void ESPEasy_now_hdr::setChecksum() +{ + checksum = computeChecksum(); +} + +bool ESPEasy_now_hdr::checksumValid() const +{ + return computeChecksum() == checksum; +} + +uint8_t ESPEasy_now_hdr::computeChecksum() const +{ + // TODO TD-er: Maybe better to have this as a for loop over *this + uint8_t res = header_version; + res ^= static_cast(message_type); + res ^= cur_message_nr; + res ^= last_message_nr; + res ^= notUsed1; + res ^= notUsed2; + return res; +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h new file mode 100644 index 0000000000..15c8de9e29 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -0,0 +1,51 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H +#define DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H + +/*********************************************************************************************\ +* ESPEasy_now_message_struct +\*********************************************************************************************/ + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +# include + +# define ESPEASY_NOW_HEADER_VERSION 1 + +struct ESPEasy_now_hdr { + // Do not change the order of this enum as the value will be sent to other nodes. + enum class message_t : uint8_t { + NotSet = 0, + Acknowledgement, + Announcement, + MQTTControllerMessage, + + ChecksumError = 255 + }; + + ESPEasy_now_hdr(); + + ESPEasy_now_hdr(message_t messageType); + + void setChecksum(); + + bool checksumValid() const; + +private: + + uint8_t computeChecksum() const; + +public: + + const uint8_t header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions + message_t message_type = message_t::NotSet; + uint8_t cur_message_nr = 0; // Current message number (start at 0) + uint8_t last_message_nr = 0; // The highest message number of this sequence + uint8_t notUsed1 = 0; // reserved + uint8_t notUsed2 = 0; // reserved + uint8_t checksum = 0; // checksum +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H diff --git a/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp b/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp deleted file mode 100644 index 9d63504963..0000000000 --- a/src/src/DataStructs/ESPEasy_now_message_header_struct.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "ESPEasy_now_message_header_struct.h" - -#ifdef USES_ESPEASY_NOW - -ESPEasy_now_message_header_struct::ESPEasy_now_message_header_struct() { - // header_length = sizeof(ESPEasy_now_message_header_struct); -} - -#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_message_header_struct.h b/src/src/DataStructs/ESPEasy_now_message_header_struct.h deleted file mode 100644 index 11882f5f5a..0000000000 --- a/src/src/DataStructs/ESPEasy_now_message_header_struct.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H -#define DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H - -/*********************************************************************************************\ -* ESPEasy_now_message_struct -\*********************************************************************************************/ - -#include "../Globals/ESPEasy_now_state.h" -#ifdef USES_ESPEASY_NOW - -# include - -# include "../DataStructs/DeviceStruct.h" -# include "../DataStructs/ESPEasyLimits.h" -# include "../Globals/Plugins.h" - - -# define ESPEASY_NOW_HEADER_VERSION 1 - - -struct ESPEasy_now_message_header_struct { - enum class message_t : byte { - Acknowledgement = 0, - TaskName = 1, // Just the name of the task (null terminated string) - TaskValueName_TaskValue = 2, // Name of the Task value (null terminated string) + string formatted value - taskValue = 3, // Just the string formatted value (can be next part of the value, for SENSOR_TYPE_STRING) - }; - - ESPEasy_now_message_header_struct(); - - const byte header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions - const byte header_length = sizeof(ESPEasy_now_message_header_struct); // Length of the header - message_t message_type = message_t::Acknowledgement; - byte cur_message_nr = 0; // Current message number (start at 0, always < - // total_nr_messages) - byte total_nr_messages = 1; // Total number of messages needed to transfer all information - // (can be >1 for - // SENSOR_TYPE_STRING) - byte cur_payload_size = 0; // The size of the payload in this message. - byte VType = SENSOR_TYPE_NONE; // Type of value the plugin will return. e.g. SENSOR_TYPE_STRING - byte ValueCount = 0; // The number of output values of a plugin. - byte cur_taskvalue_index = 0; // Describing which task value is sent (start at 0, always < - // ValueCount) - taskIndex_t taskIndex = INVALID_TASK_INDEX; // Task index of the data origin when creating message - uint16_t plugin_id = INVALID_PLUGIN_ID; // FIXME TD-er: Change to pluginID_t when that one is switched - // to 16 bit value -}; - -#endif // ifdef USES_ESPEASY_NOW - -#endif // DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 5d35cc4047..445021c00f 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -2,10 +2,19 @@ #ifdef USES_ESPEASY_NOW -#include "../../ESPEasy_Log.h" -#include "../../ESPEasy_fdwdecl.h" +# include "ESPEasy_time_calc.h" +# include "../DataStructs/ESPEasy_Now_packet.h" +# include "../Globals/SecuritySettings.h" +# include "../../ESPEasy_fdwdecl.h" +# include "../../ESPEasy_Log.h" -#include "../Globals/SecuritySettings.h" +# include + +std::list ESPEasy_now_in_queue; + +void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { + ESPEasy_now_in_queue.emplace_back(mac, buf, count); +} bool ESPEasy_now_handler_t::begin() { @@ -24,6 +33,10 @@ bool ESPEasy_now_handler_t::begin() } } } + + // FIXME TD-er: Must check in settings if enabled + WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); + use_EspEasy_now = true; return true; } @@ -31,7 +44,115 @@ bool ESPEasy_now_handler_t::begin() void ESPEasy_now_handler_t::end() { use_EspEasy_now = false; - WifiEspNow.end(); + WifiEspNow.end(); +} + +bool ESPEasy_now_handler_t::loop() +{ + if (!ESPEasy_now_in_queue.empty()) { + bool validPacket = ESPEasy_now_in_queue.front().getHeader().checksumValid(); + const byte loglevel = validPacket ? LOG_LEVEL_INFO : LOG_LEVEL_ERROR; + + if (loglevelActiveFor(loglevel)) { + String log = F("ESPEasyNow: Message from "); + log += formatMAC(ESPEasy_now_in_queue.front()._mac); + + if (!validPacket) { + log += F(" INVALID CHECKSUM!"); + } + addLog(loglevel, log); + } + + if (!validPacket) { + ESPEasy_now_in_queue.pop_front(); + return false; + } + + # ifdef USES_MQTT + + // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + + if (validControllerIndex(controllerIndex)) { + String topic = ESPEasy_now_in_queue.front().getString(0); + String payload = ESPEasy_now_in_queue.front().getString(topic.length()); + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + } + + # endif // ifdef USES_MQTT + + // FIXME TD-er: What to do when publish fails? + ESPEasy_now_in_queue.pop_front(); + return true; + } + return false; +} + +void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) +{} + +bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) +{ + if (!use_EspEasy_now) { return false; } + + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + + bool processed = false; + + if (ControllerSettings.enableESPEasyNowFallback() /*&& !WiFiConnected(10) */) { + const size_t topic_length = topic.length(); + const size_t payload_length = payload.length(); + + // Todo: Add cpluginID_t cpluginID; to the message + size_t len = topic_length + payload_length + 1; + + ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::MQTTControllerMessage); + ESPEasy_Now_packet msg(header, len); + + size_t pos = 0; + pos += msg.addString(topic); + pos += msg.addString(payload, pos); + + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX && !processed; ++peer) { + // FIXME TD-er: This must be optimized to keep the last working index. + // Or else it may take quite a while to send each message + if (SecuritySettings.peerMacSet(peer)) { + if (WifiEspNow.send(SecuritySettings.EspEasyNowPeerMAC[peer], msg[0], msg.getSize())) { + unsigned long timer = millis() + 500; + WifiEspNowSendStatus sendStatus = WifiEspNow.getSendStatus(); + + while (!timeOutReached(timer) && sendStatus == WifiEspNowSendStatus::NONE) { + sendStatus = WifiEspNow.getSendStatus(); + delay(1); + } + + if (sendStatus == WifiEspNowSendStatus::OK) { + processed = true; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy Now: Sent via ESP-NOW to: "); + log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); + addLog(LOG_LEVEL_INFO, log); + } + } + } else { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy Now: Sent via ESP-NOW failed to: "); + log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); + addLog(LOG_LEVEL_INFO, log); + } + } + } + } + + } + return processed; } #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 2a22619a66..afce8ecaee 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -5,7 +5,9 @@ #ifdef USES_ESPEASY_NOW -# include "../DataStructs/ESPEasy_now_message_header_struct.h" +# include "../DataStructs/ESPEasy_now_hdr.h" +# include "../DataStructs/ESPEasy_Now_peerInfo.h" +# include "../Globals/CPlugins.h" class ESPEasy_now_handler_t { @@ -14,9 +16,27 @@ class ESPEasy_now_handler_t { ESPEasy_now_handler_t() {} bool begin(); + void end(); + + bool loop(); + + // Send out the discovery announcement via broadcast. + // This may be picked up by others + void sendDiscoveryAnnounce(byte channel); + + bool sendToMQTT(controllerIndex_t controllerIndex, + const String & topic, + const String & payload); + + +private: + + peerInfoMap_t _peerInfoMap; + }; + #endif // ifdef USES_ESPEASY_NOW #endif // HELPERS_ESPEASY_NOW_HANDLER_H From 12965b4985c531c37360a33fa9f090ad50ce3b55 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 12 May 2020 18:03:52 +0200 Subject: [PATCH 010/404] [ESPEasy-Now] Add node discovery --- src/WebServer_ConfigPage.ino | 5 + src/src/DataStructs/ESPEasy_Now_packet.cpp | 24 ++- src/src/DataStructs/ESPEasy_Now_packet.h | 12 +- src/src/DataStructs/ESPEasy_Now_peerInfo.cpp | 40 +++- src/src/DataStructs/ESPEasy_Now_peerInfo.h | 22 ++- src/src/Helpers/ESPEasy_now_handler.cpp | 191 ++++++++++++++----- src/src/Helpers/ESPEasy_now_handler.h | 19 +- 7 files changed, 254 insertions(+), 59 deletions(-) diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index 7dc36e00f1..62e220e4d4 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -199,6 +199,11 @@ void handle_config() { String id = F("peer"); id += String(peer); addFormMACBox(label, id, SecuritySettings.EspEasyNowPeerMAC[peer]); + ESPEasy_Now_peerInfo_meta meta; + if (ESPEasy_now_handler.getPeerInfo(SecuritySettings.EspEasyNowPeerMAC[peer], meta)) + { + addFormNote(meta.nodeName); + } } #endif diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 0ed60dbc3f..03e81e0f48 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -61,7 +61,7 @@ void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); } -size_t ESPEasy_Now_packet::addString(const String& string, size_t payload_pos) +size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) { const size_t payload_size = getPayloadSize(); @@ -79,10 +79,24 @@ size_t ESPEasy_Now_packet::addString(const String& string, size_t payload_pos) // If the null-termination does not fit, no other string can be added anyway. size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); memcpy(&_buf[buf_pos], reinterpret_cast(string.c_str()), bytesToWrite); + payload_pos += bytesToWrite; return bytesToWrite; } -String ESPEasy_Now_packet::getString(size_t payload_pos) const +void ESPEasy_Now_packet::setMac(uint8_t mac[6]) +{ + memcpy(_mac, mac, 6); +} + +void ESPEasy_Now_packet::setBroadcast() +{ + for (byte i = 0; i < 6; ++i) + { + _mac[i] = 0xFF; + } +} + +String ESPEasy_Now_packet::getString(size_t& payload_pos) const { String res; const size_t size = getSize(); @@ -90,6 +104,7 @@ String ESPEasy_Now_packet::getString(size_t payload_pos) const while (buf_pos < size && _buf[buf_pos] == 0) { ++buf_pos; + ++payload_pos; } if (buf_pos >= size) { return res; } @@ -97,9 +112,10 @@ String ESPEasy_Now_packet::getString(size_t payload_pos) const const size_t maxlen = size - buf_pos; size_t strlength = strnlen(reinterpret_cast(&_buf[buf_pos]), maxlen); res.reserve(strlength); + const size_t max_buf_pos = buf_pos + strlength; - for (size_t i = 0; i < strlength; ++i) { - res += static_cast(_buf[buf_pos + i]); + for ( ; buf_pos < max_buf_pos; ++buf_pos, ++payload_pos) { + res += static_cast(_buf[buf_pos]); } return res; } diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 1c8bf6d74e..04a57601f5 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -27,12 +27,18 @@ class ESPEasy_Now_packet { void setHeader(ESPEasy_now_hdr header); + void setMac(uint8_t mac[6]); + + void setBroadcast(); + // Add a string to the packet, starting at payload position payload_pos - size_t addString(const String& string, - size_t payload_pos = 0); + // Return the number of bytes added (can be 1 more than the given string) + size_t addString(const String& string, + size_t & payload_pos); // Return a string starting from position pos in the buffer. - String getString(size_t pos = 0) const; + // payload_pos will contain the new position to start for a next string + String getString(size_t& payload_pos) const; const uint8_t * operator[](size_t idx) const { return &_buf[idx]; diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp index 381350f73e..22a8fb6b0d 100644 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp @@ -1 +1,39 @@ -#include "ESPEasy_Now_peerInfo.h" \ No newline at end of file +#include "ESPEasy_Now_peerInfo.h" + + +static uint64_t mac_to_key(const uint8_t *mac) +{ + uint64_t key = 0; + + for (byte i = 0; i < 6; ++i) { + key = key << 8; + key += mac[i]; + } + return key; +} + +void ESPEasy_Now_peerInfo::addPeer(const uint8_t *mac, const ESPEasy_Now_peerInfo_meta& meta) +{ + uint64_t key = mac_to_key(mac); + + peer_map[key] = meta; +} + +bool ESPEasy_Now_peerInfo::hasPeer(const uint8_t *mac) const +{ + uint64_t key = mac_to_key(mac); + + return peer_map.find(key) != peer_map.end(); +} + +bool ESPEasy_Now_peerInfo::getPeer(const uint8_t *mac, + ESPEasy_Now_peerInfo_meta& meta) const +{ + uint64_t key = mac_to_key(mac); + auto it = peer_map.find(key); + + if (it == peer_map.end()) { return false; } + meta = it->second; + + return true; +} diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.h b/src/src/DataStructs/ESPEasy_Now_peerInfo.h index 291cb05df0..7d9750d6e1 100644 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.h +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.h @@ -5,20 +5,30 @@ #include + struct ESPEasy_Now_peerInfo_meta { String nodeName; - uint8_t channel = 0; + uint8_t channel = 0; uint8_t distance = 0; - bool encrypt = false; + bool encrypt = false; }; +typedef std::map peerInfoMap_t; + struct ESPEasy_Now_peerInfo { - ESPEasy_Now_peerInfo_meta meta; - uint8_t mac[6] = { 0 }; -}; + void addPeer(const uint8_t *mac, + const ESPEasy_Now_peerInfo_meta& meta); + + bool hasPeer(const uint8_t *mac) const; -typedef std::map peerInfoMap_t; + bool getPeer(const uint8_t *mac, + ESPEasy_Now_peerInfo_meta& meta) const; + +private: + + peerInfoMap_t peer_map; +}; #endif // DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 445021c00f..4a626fdde0 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -5,6 +5,7 @@ # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_packet.h" # include "../Globals/SecuritySettings.h" +# include "../Globals/Settings.h" # include "../../ESPEasy_fdwdecl.h" # include "../../ESPEasy_Log.h" @@ -37,6 +38,8 @@ bool ESPEasy_now_handler_t::begin() // FIXME TD-er: Must check in settings if enabled WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); + sendDiscoveryAnnounce(); + use_EspEasy_now = true; return true; } @@ -59,6 +62,12 @@ bool ESPEasy_now_handler_t::loop() if (!validPacket) { log += F(" INVALID CHECKSUM!"); + } else { + log += F(" ("); + log += ESPEasy_now_in_queue.front().getHeader().cur_message_nr + 1; + log += '/'; + log += ESPEasy_now_in_queue.front().getHeader().last_message_nr + 1; + log += ')'; } addLog(loglevel, log); } @@ -68,32 +77,44 @@ bool ESPEasy_now_handler_t::loop() return false; } - # ifdef USES_MQTT - - // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller - - controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); - - if (validControllerIndex(controllerIndex)) { - String topic = ESPEasy_now_in_queue.front().getString(0); - String payload = ESPEasy_now_in_queue.front().getString(topic.length()); - - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + bool handled = false; + + switch (ESPEasy_now_in_queue.front().getHeader().message_type) + { + case ESPEasy_now_hdr::message_t::NotSet: + case ESPEasy_now_hdr::message_t::ChecksumError: + break; + case ESPEasy_now_hdr::message_t::Acknowledgement: + break; + case ESPEasy_now_hdr::message_t::Announcement: + handled = handle_DiscoveryAnnounce(ESPEasy_now_in_queue.front()); + break; + case ESPEasy_now_hdr::message_t::MQTTControllerMessage: + handled = handle_MQTTControllerMessage(ESPEasy_now_in_queue.front()); + break; } - # endif // ifdef USES_MQTT - - // FIXME TD-er: What to do when publish fails? + // FIXME TD-er: What to do when packet is not handled? ESPEasy_now_in_queue.pop_front(); - return true; + return handled; } return false; } void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) -{} +{ + String hostname = Settings.getHostname(); + size_t len = hostname.length(); + ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::Announcement); + ESPEasy_Now_packet msg(header, len); + + msg.setBroadcast(); + + size_t pos = 0; + msg.addString(hostname, pos); + + send(msg); +} bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) { @@ -111,48 +132,132 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const // Todo: Add cpluginID_t cpluginID; to the message size_t len = topic_length + payload_length + 1; - + ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::MQTTControllerMessage); ESPEasy_Now_packet msg(header, len); size_t pos = 0; - pos += msg.addString(topic); - pos += msg.addString(payload, pos); + msg.addString(topic, pos); + msg.addString(payload, pos); for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX && !processed; ++peer) { // FIXME TD-er: This must be optimized to keep the last working index. // Or else it may take quite a while to send each message if (SecuritySettings.peerMacSet(peer)) { - if (WifiEspNow.send(SecuritySettings.EspEasyNowPeerMAC[peer], msg[0], msg.getSize())) { - unsigned long timer = millis() + 500; - WifiEspNowSendStatus sendStatus = WifiEspNow.getSendStatus(); + msg.setMac(SecuritySettings.EspEasyNowPeerMAC[peer]); + WifiEspNowSendStatus sendStatus = send(msg, millis() + ControllerSettings.ClientTimeout); - while (!timeOutReached(timer) && sendStatus == WifiEspNowSendStatus::NONE) { - sendStatus = WifiEspNow.getSendStatus(); - delay(1); - } - - if (sendStatus == WifiEspNowSendStatus::OK) { + switch (sendStatus) { + case WifiEspNowSendStatus::OK: + { processed = true; - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy Now: Sent via ESP-NOW to: "); - log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); - addLog(LOG_LEVEL_INFO, log); - } - } - } else { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy Now: Sent via ESP-NOW failed to: "); - log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); - addLog(LOG_LEVEL_INFO, log); + break; } + default: break; } } } - } return processed; } +bool ESPEasy_now_handler_t::getPeerInfo(const uint8_t *mac, + ESPEasy_Now_peerInfo_meta& meta) const +{ + return _peerInfoMap.getPeer(mac, meta); +} + +bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { + bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + + if (success) { + log = F("ESPEasy Now: Sent to: "); + } else { + log = F("ESPEasy Now: Sent FAILED to: "); + } + log += formatMAC(packet._mac); + addLog(LOG_LEVEL_INFO, log); + } + return success; +} + +WifiEspNowSendStatus ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet, size_t timeout) +{ + if (!send(packet)) { + return WifiEspNowSendStatus::NONE; + } + WifiEspNowSendStatus sendStatus = waitForSendStatus(timeout); + + if (sendStatus == WifiEspNowSendStatus::NONE) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy Now: TIMEOUT to: "); + log += formatMAC(packet._mac); + addLog(LOG_LEVEL_INFO, log); + } + } + return sendStatus; +} + +WifiEspNowSendStatus ESPEasy_now_handler_t::waitForSendStatus(size_t timeout) const +{ + WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; + + while (!timeOutReached(timeout) && sendStatus == WifiEspNowSendStatus::NONE) { + sendStatus = WifiEspNow.getSendStatus(); + delay(1); + } + return sendStatus; +} + +bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet) +{ + size_t payload_pos = 0; + ESPEasy_Now_peerInfo_meta meta; + + meta.nodeName = packet.getString(payload_pos); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + size_t payloadSize = packet.getPayloadSize(); + log.reserve(payloadSize + 40); + log = F("ESPEasy Now discovery: "); + log += formatMAC(packet._mac); + log += '\n'; + log += meta.nodeName; + + while (payload_pos < payloadSize) { + log += '\n'; + log += packet.getString(payload_pos); + } + addLog(LOG_LEVEL_INFO, log); + } + _peerInfoMap.addPeer(packet._mac, meta); + return true; +} + +bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet) +{ + # ifdef USES_MQTT + + // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + + if (validControllerIndex(controllerIndex)) { + size_t pos = 0; + String topic = packet.getString(pos); + String payload = packet.getString(pos); + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + return MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + } + + # endif // ifdef USES_MQTT + return false; +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index afce8ecaee..8fd4a30a8e 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -6,6 +6,7 @@ #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_now_hdr.h" +# include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_Now_peerInfo.h" # include "../Globals/CPlugins.h" @@ -23,16 +24,30 @@ class ESPEasy_now_handler_t { // Send out the discovery announcement via broadcast. // This may be picked up by others - void sendDiscoveryAnnounce(byte channel); + void sendDiscoveryAnnounce(byte channel = 0); bool sendToMQTT(controllerIndex_t controllerIndex, const String & topic, const String & payload); + bool getPeerInfo(const uint8_t *mac, + ESPEasy_Now_peerInfo_meta& meta) const; private: - peerInfoMap_t _peerInfoMap; + bool send(const ESPEasy_Now_packet& packet); + WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, size_t timeout); + + WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; + + + + bool handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet); + + bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); + + + ESPEasy_Now_peerInfo _peerInfoMap; }; From 7c1bb112121c604be6f621091d6a26d678a1ce23 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 12 May 2020 23:05:03 +0200 Subject: [PATCH 011/404] [ESPEasy-Now] Improve p2p NodeStruct + extend for ESPEasy-Now Also added the webserver port in PR #3053 --- src/Networking.ino | 68 ++++++-------------- src/WebServer_CustomPage.ino | 4 +- src/WebServer_DevicesPage.ino | 2 +- src/WebServer_JSON.ino | 14 ++-- src/WebServer_RootPage.ino | 6 +- src/src/DataStructs/ESPEasy_Now_peerInfo.cpp | 19 ++++++ src/src/DataStructs/ESPEasy_Now_peerInfo.h | 16 +++-- src/src/DataStructs/NodeStruct.cpp | 50 ++++++++++++++ src/src/DataStructs/NodeStruct.h | 44 ++++++++++--- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 14 ++-- src/src/Helpers/ESPEasy_now_handler.h | 13 ++-- 12 files changed, 161 insertions(+), 91 deletions(-) diff --git a/src/Networking.ino b/src/Networking.ino index e60cdfa649..86b18520fa 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -219,51 +219,25 @@ void checkUDP() if (len < 13) { break; } - byte unit = packetBuffer[12]; -#ifndef BUILD_NO_DEBUG - byte mac[6]; - byte ip[4]; - - for (byte x = 0; x < 6; x++) { - mac[x] = packetBuffer[x + 2]; - } - - for (byte x = 0; x < 4; x++) { - ip[x] = packetBuffer[x + 8]; - } -#endif // ifndef BUILD_NO_DEBUG - Nodes[unit].age = 0; // Create a new element when not present - NodesMap::iterator it = Nodes.find(unit); - - if (it != Nodes.end()) { - for (byte x = 0; x < 4; x++) { - it->second.ip[x] = packetBuffer[x + 8]; - } - it->second.age = 0; // reset 'age counter' - - if (len >= 41) // extended packet size - { - it->second.build = makeWord(packetBuffer[14], packetBuffer[13]); - char tmpNodeName[26] = { 0 }; - memcpy(&tmpNodeName[0], reinterpret_cast(&packetBuffer[15]), 25); - tmpNodeName[25] = 0; - it->second.nodeName = tmpNodeName; - it->second.nodeName.trim(); - it->second.nodeType = packetBuffer[40]; - it->second.webgui_portnumber = 80; - if (len >= 43 && it->second.build >= 20107) { - it->second.webgui_portnumber = makeWord(packetBuffer[42],packetBuffer[41]); - } - } + int copy_length = sizeof(NodeStruct); + if (copy_length > len) { + copy_length = len; } + NodeStruct received; + memcpy(&received, &packetBuffer[2], copy_length); + received.age = 0; // Data just got in, so age = 0 + Nodes[received.unit] = received; // Create a new element when not present #ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - char macaddress[20]; - formatMAC(mac, macaddress); - char log[80] = { 0 }; - sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, formatIP(ip).c_str(), unit); + String log; + log.reserve(64); + log = F("UDP : "); + log += formatMAC(received.mac); + log += ','; + log += formatIP(received.ip); + log += ','; + log += received.unit; addLog(LOG_LEVEL_DEBUG_MORE, log); } #endif // ifndef BUILD_NO_DEBUG @@ -402,21 +376,18 @@ void sendSysInfoUDP(byte repeats) return; } - // TODO: make a nice struct of it and clean up // 1 byte 'binary token 255' // 1 byte id '1' - // 6 byte mac - // 4 byte ip - // 1 byte unit - // 2 byte build - // 25 char name - // 1 byte node type id + // NodeStruct object (packed data struct) // send my info to the world... #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG_MORE, F("UDP : Send Sysinfo message")); #endif // ifndef BUILD_NO_DEBUG + NodeStruct thisNode; + thisNode.setLocalData(); + for (byte counter = 0; counter < repeats; counter++) { uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; @@ -425,6 +396,7 @@ void sendSysInfoUDP(byte repeats) byte data[80] = {0}; data[0] = 255; data[1] = 1; + memcpy(&data[2], &thisNode, sizeof(NodeStruct)); for (byte x = 0; x < 6; x++) { data[x + 2] = macread[x]; diff --git a/src/WebServer_CustomPage.ino b/src/WebServer_CustomPage.ino index 7ebe369767..d0e9284cb1 100644 --- a/src/WebServer_CustomPage.ino +++ b/src/WebServer_CustomPage.ino @@ -41,7 +41,7 @@ boolean handle_custom(String path) { TXBuffer.startStream(); sendHeadandTail(F("TmplDsh"), _HEAD); addHtml(F("second.ip.toString()); + addHtml(it->second.IP().toString()); addHtml(F("/dashboard.esp\">")); sendHeadandTail(F("TmplDsh"), _TAIL); TXBuffer.endStream(); @@ -65,7 +65,7 @@ boolean handle_custom(String path) { String name = String(it->first) + F(" - "); if (it->first != Settings.Unit) { - name += it->second.nodeName; + name += it->second.getNodeName(); } else { name += Settings.Name; diff --git a/src/WebServer_DevicesPage.ino b/src/WebServer_DevicesPage.ino index b9b3a35195..8269d57d0a 100644 --- a/src/WebServer_DevicesPage.ino +++ b/src/WebServer_DevicesPage.ino @@ -889,7 +889,7 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, byte page) NodesMap::iterator it = Nodes.find(remoteUnit); if (it != Nodes.end()) { - addUnit(it->second.nodeName); + addUnit(it->second.getNodeName()); } else { addUnit(F("Unknown Unit Name")); } diff --git a/src/WebServer_JSON.ino b/src/WebServer_JSON.ino index 63ffbe6b18..5c485811f2 100644 --- a/src/WebServer_JSON.ino +++ b/src/WebServer_JSON.ino @@ -214,20 +214,16 @@ void handle_json() addHtml("{"); stream_next_json_object_value(F("nr"), String(it->first)); stream_next_json_object_value(F("name"), - (it->first != Settings.Unit) ? it->second.nodeName : Settings.Name); + (it->first != Settings.Unit) ? it->second.getNodeName() : Settings.Name); if (it->second.build) { stream_next_json_object_value(F("build"), String(it->second.build)); } if (it->second.nodeType) { - String platform = getNodeTypeDisplayString(it->second.nodeType); - - if (platform.length() > 0) { - stream_next_json_object_value(F("platform"), platform); - } + stream_next_json_object_value(F("platform"), it->second.getNodeTypeDisplayString()); } - stream_next_json_object_value(F("ip"), it->second.ip.toString()); + stream_next_json_object_value(F("ip"), it->second.IP().toString()); stream_last_json_object_value(F("age"), String(it->second.age)); } // if node info exists } // for loop @@ -410,10 +406,10 @@ void handle_nodes_list_json() { } json_number(F("first"), String(it->first)); - json_prop(F("name"), isThisUnit ? Settings.Name : it->second.nodeName); + json_prop(F("name"), isThisUnit ? Settings.Name : it->second.getNodeName()); if (it->second.build) { json_prop(F("build"), String(it->second.build)); } - json_prop(F("type"), getNodeTypeDisplayString(it->second.nodeType)); + json_prop(F("type"), it->second.getNodeTypeDisplayString()); json_prop(F("ip"), it->second.ip.toString()); json_number(F("age"), String(it->second.age)); json_close(); diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 77f14cc36d..aea4c57b20 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -180,7 +180,7 @@ void handle_root() { addHtml(Settings.Name); } else { - addHtml(it->second.nodeName); + addHtml(it->second.getNodeName()); } html_TD(); @@ -188,7 +188,7 @@ void handle_root() { addHtml(String(it->second.build)); } html_TD(); - addHtml(getNodeTypeDisplayString(it->second.nodeType)); + addHtml(it->second.getNodeTypeDisplayString()); html_TD(); html_add_wide_button_prefix(); { @@ -203,7 +203,7 @@ void handle_root() { html += String(port); } html += "'>"; - html += it->second.ip.toString(); + html += it->second.IP().toString(); html += ""; addHtml(html); } diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp index 22a8fb6b0d..618e9642ec 100644 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp @@ -1,5 +1,7 @@ #include "ESPEasy_Now_peerInfo.h" +#include "../../ESPEasy_fdwdecl.h" + static uint64_t mac_to_key(const uint8_t *mac) { @@ -37,3 +39,20 @@ bool ESPEasy_Now_peerInfo::getPeer(const uint8_t *mac, return true; } + +String ESPEasy_Now_peerInfo::formatPeerInfo(const uint8_t *mac) const +{ + uint64_t key = mac_to_key(mac); + auto it = peer_map.find(key); + String res; + + res = formatMAC(mac); + + if (it == peer_map.end()) { return res; } + + res.reserve(128); + res += F(" \""); + res += it->second.nodeName; + res += '"'; + return res; +} diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.h b/src/src/DataStructs/ESPEasy_Now_peerInfo.h index 7d9750d6e1..05eca7fa7e 100644 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.h +++ b/src/src/DataStructs/ESPEasy_Now_peerInfo.h @@ -4,10 +4,12 @@ #include #include - +#include struct ESPEasy_Now_peerInfo_meta { String nodeName; + IPAddress ip; + byte unit; uint8_t channel = 0; uint8_t distance = 0; bool encrypt = false; @@ -17,13 +19,15 @@ typedef std::map peerInfoMap_t; struct ESPEasy_Now_peerInfo { - void addPeer(const uint8_t *mac, - const ESPEasy_Now_peerInfo_meta& meta); + void addPeer(const uint8_t *mac, + const ESPEasy_Now_peerInfo_meta& meta); + + bool hasPeer(const uint8_t *mac) const; - bool hasPeer(const uint8_t *mac) const; + bool getPeer(const uint8_t *mac, + ESPEasy_Now_peerInfo_meta& meta) const; - bool getPeer(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const; + String formatPeerInfo(const uint8_t *mac) const; private: diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index d68601332c..36d6144147 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -1,5 +1,8 @@ #include "NodeStruct.h" +#include "../Globals/Settings.h" +#include "../../ESPEasy-Globals.h" + String getNodeTypeDisplayString(byte nodeType) { switch (nodeType) { @@ -18,3 +21,50 @@ String getNodeTypeDisplayString(byte nodeType) { { for (byte i = 0; i < 4; ++i) { ip[i] = 0; } } + + +void NodeStruct::setLocalData() { + WiFi.macAddress(mac); + WiFi.softAPmacAddress(ap_mac); + { + IPAddress localIP = WiFi.localIP(); + for (byte i = 0; i < 4; ++i) { + ip[i] = localIP[i]; + } + } + + unit = Settings.Unit; + build = Settings.Build; + memcpy(nodeName, Settings.Name, 25); + nodeType = NODE_TYPE_ID; + +// webserverPort = Settings.WebserverPort; // PR #3053 +} + + +String NodeStruct::getNodeTypeDisplayString() const { + switch (nodeType) + { + case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); + case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); + case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); + case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); + case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); + case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); + } + return ""; +} + +String NodeStruct::getNodeName() const { + String res; + size_t length = strnlen(reinterpret_cast(nodeName), sizeof(nodeName)); + res.reserve(length); + for (size_t i = 0; i < length; ++i) { + res += static_cast(nodeName[i]); + } + return res; +} + +IPAddress NodeStruct::IP() const { + return IPAddress(ip[0], ip[1], ip[2], ip[3]); +} diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index c44f984a75..2c8e377d23 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -7,7 +7,7 @@ #define NODE_TYPE_ID_ESP_EASY_STD 1 -#define NODE_TYPE_ID_RPI_EASY_STD 5 // https://github.com/enesbcs/rpieasy +#define NODE_TYPE_ID_RPI_EASY_STD 5 // https://github.com/enesbcs/rpieasy #define NODE_TYPE_ID_ESP_EASYM_STD 17 #define NODE_TYPE_ID_ESP_EASY32_STD 33 #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 @@ -18,16 +18,44 @@ String getNodeTypeDisplayString(byte nodeType); /*********************************************************************************************\ * NodeStruct \*********************************************************************************************/ -struct NodeStruct +struct __attribute__((__packed__)) NodeStruct { NodeStruct(); - String nodeName; - IPAddress ip; - uint16_t build; - byte age; - byte nodeType; - uint16_t webgui_portnumber; + void setLocalData(); + String getNodeTypeDisplayString() const; + + String getNodeName() const; + + IPAddress IP() const; + + // Do not change the order of this data, as it is being sent via P2P UDP. + // 1 byte 'binary token 255' + // 1 byte id '1' + // 6 byte mac (STA interface) + // 4 byte ip + // 1 byte unit + // 2 byte build + // 25 char name + // 1 byte node type id + + // Added starting build '20107': + // 2 bytes webserver port + // 6 bytes AP MAC + + + + uint8_t mac[6] = { 0 }; // STA mode MAC + uint8_t ip[4] = { 0 }; + byte unit = 0; + uint16_t build = 0; + byte nodeName[25] = { 0 }; + byte nodeType = 0; + byte age = 0; + uint16_t webserverPort = 80; + uint8_t ap_mac[6] = { 0 }; // AP mode MAC + + }; typedef std::map NodesMap; diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index ae52a9cb25..f7a98970c8 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -85,7 +85,7 @@ void run_compiletime_checks() { #ifdef USES_NOTIFIER check_size(); #endif - check_size(); + check_size(); check_size(); check_size(); check_size(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4a626fdde0..4db3e1bd9f 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -28,7 +28,7 @@ bool ESPEasy_now_handler_t::begin() String log; log.reserve(48); log = F("ESPEasy_Now: Failed to add peer "); - log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); + log += _peerInfoMap.formatPeerInfo(SecuritySettings.EspEasyNowPeerMAC[peer]); addLog(LOG_LEVEL_ERROR, log); } } @@ -58,7 +58,7 @@ bool ESPEasy_now_handler_t::loop() if (loglevelActiveFor(loglevel)) { String log = F("ESPEasyNow: Message from "); - log += formatMAC(ESPEasy_now_in_queue.front()._mac); + log += _peerInfoMap.formatPeerInfo(ESPEasy_now_in_queue.front()._mac); if (!validPacket) { log += F(" INVALID CHECKSUM!"); @@ -178,7 +178,7 @@ bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { } else { log = F("ESPEasy Now: Sent FAILED to: "); } - log += formatMAC(packet._mac); + log += _peerInfoMap.formatPeerInfo(packet._mac); addLog(LOG_LEVEL_INFO, log); } return success; @@ -194,7 +194,7 @@ WifiEspNowSendStatus ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packe if (sendStatus == WifiEspNowSendStatus::NONE) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy Now: TIMEOUT to: "); - log += formatMAC(packet._mac); + log += _peerInfoMap.formatPeerInfo(packet._mac); addLog(LOG_LEVEL_INFO, log); } } @@ -219,12 +219,15 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& p meta.nodeName = packet.getString(payload_pos); + _peerInfoMap.addPeer(packet._mac, meta); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; size_t payloadSize = packet.getPayloadSize(); log.reserve(payloadSize + 40); log = F("ESPEasy Now discovery: "); - log += formatMAC(packet._mac); + log += _peerInfoMap.formatPeerInfo(packet._mac); log += '\n'; log += meta.nodeName; @@ -234,7 +237,6 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& p } addLog(LOG_LEVEL_INFO, log); } - _peerInfoMap.addPeer(packet._mac, meta); return true; } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 8fd4a30a8e..7da9239b0f 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -31,24 +31,23 @@ class ESPEasy_now_handler_t { const String & payload); bool getPeerInfo(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const; + ESPEasy_Now_peerInfo_meta& meta) const; private: - bool send(const ESPEasy_Now_packet& packet); - WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, size_t timeout); + bool send(const ESPEasy_Now_packet& packet); + WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, + size_t timeout); WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; + bool handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet); - bool handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet); + bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); - bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); - ESPEasy_Now_peerInfo _peerInfoMap; - }; From a4a9d472ffff4fcec2c2095aae060c29f962b8e1 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 13 May 2020 01:52:54 +0200 Subject: [PATCH 012/404] [ESPEasy-Now] Extend NodeStruct + use it via ESPEasy-Now --- src/Networking.ino | 55 +++----------- src/WebServer_CustomPage.ino | 9 +-- src/WebServer_DevicesPage.ino | 2 +- src/WebServer_JSON.ino | 8 +- src/WebServer_RootPage.ino | 6 +- src/_C013.ino | 24 +++--- src/src/DataStructs/ESPEasy_Now_packet.cpp | 22 ++++++ src/src/DataStructs/ESPEasy_Now_packet.h | 4 + src/src/DataStructs/NodeStruct.cpp | 27 +++++-- src/src/DataStructs/NodeStruct.h | 12 ++- src/src/DataStructs/NodesHandler.cpp | 86 ++++++++++++++++++++++ src/src/DataStructs/NodesHandler.h | 37 ++++++++++ src/src/Globals/Nodes.cpp | 2 +- src/src/Globals/Nodes.h | 4 +- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 40 ++++------ src/src/Helpers/ESPEasy_now_handler.h | 1 + 17 files changed, 234 insertions(+), 107 deletions(-) create mode 100644 src/src/DataStructs/NodesHandler.cpp create mode 100644 src/src/DataStructs/NodesHandler.h diff --git a/src/Networking.ino b/src/Networking.ino index 86b18520fa..c2fdcb06b7 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -225,8 +225,7 @@ void checkUDP() } NodeStruct received; memcpy(&received, &packetBuffer[2], copy_length); - received.age = 0; // Data just got in, so age = 0 - Nodes[received.unit] = received; // Create a new element when not present + Nodes.addNode(received); // Create a new element when not present #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { @@ -282,7 +281,7 @@ void SendUDPCommand(byte destUnit, const char *data, byte dataLength) sendUDP(destUnit, (const byte *)data, dataLength); delay(10); } else { - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->first != Settings.Unit) { sendUDP(it->first, (const byte *)data, dataLength); delay(10); @@ -307,7 +306,7 @@ void sendUDP(byte unit, const byte *data, byte size) remoteNodeIP = { 255, 255, 255, 255 }; } else { - NodesMap::iterator it = Nodes.find(unit); + auto it = Nodes.find(unit); if (it == Nodes.end()) { return; @@ -339,32 +338,17 @@ void sendUDP(byte unit, const byte *data, byte size) \*********************************************************************************************/ void refreshNodeList() { - bool mustSendGratuitousARP = false; + unsigned long max_age; + const unsigned long max_age_allowed = 10 * 60 * 1000; // 10 minutes + Nodes.refreshNodeList(max_age_allowed, max_age); - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end();) { - bool mustRemove = true; - - if (it->second.ip[0] != 0) { - if (it->second.age > 8) { - // Increase frequency sending ARP requests for 2 minutes - mustSendGratuitousARP = true; - } - - if (it->second.age < 10) { - it->second.age++; - mustRemove = false; - ++it; - } - } - - if (mustRemove) { - it = Nodes.erase(it); - } - } - - if (mustSendGratuitousARP) { + if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); } + sendSysInfoUDP(1); + #ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.sendDiscoveryAnnounce(); + #endif } /*********************************************************************************************\ @@ -387,6 +371,7 @@ void sendSysInfoUDP(byte repeats) NodeStruct thisNode; thisNode.setLocalData(); + Nodes.addNode(thisNode); for (byte counter = 0; counter < repeats; counter++) { @@ -425,22 +410,6 @@ void sendSysInfoUDP(byte repeats) delay(500); } } - - Nodes[Settings.Unit].age = 0; // Create new node when not already present. - // store my own info also in the list - NodesMap::iterator it = Nodes.find(Settings.Unit); - - if (it != Nodes.end()) - { - IPAddress ip = NetworkLocalIP(); - - for (byte x = 0; x < 4; x++) { - it->second.ip[x] = ip[x]; - } - it->second.age = 0; - it->second.build = Settings.Build; - it->second.nodeType = NODE_TYPE_ID; - } } #if defined(ESP8266) diff --git a/src/WebServer_CustomPage.ino b/src/WebServer_CustomPage.ino index d0e9284cb1..cf98a15c4a 100644 --- a/src/WebServer_CustomPage.ino +++ b/src/WebServer_CustomPage.ino @@ -35,7 +35,7 @@ boolean handle_custom(String path) { if (unit && (unit != Settings.Unit)) { - NodesMap::iterator it = Nodes.find(unit); + auto it = Nodes.find(unit); if (it != Nodes.end()) { TXBuffer.startStream(); @@ -58,7 +58,7 @@ boolean handle_custom(String path) { addSelector_Head_reloadOnChange(F("unit")); byte choice = Settings.Unit; - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if ((it->second.ip[0] != 0) || (it->first == Settings.Unit)) { @@ -78,10 +78,9 @@ boolean handle_custom(String path) { // create <> navigation buttons byte prev = Settings.Unit; byte next = Settings.Unit; - NodesMap::iterator it; for (byte x = Settings.Unit - 1; x > 0; x--) { - it = Nodes.find(x); + auto it = Nodes.find(x); if (it != Nodes.end()) { if (it->second.ip[0] != 0) { prev = x; break; } @@ -89,7 +88,7 @@ boolean handle_custom(String path) { } for (byte x = Settings.Unit + 1; x < UNIT_NUMBER_MAX; x++) { - it = Nodes.find(x); + auto it = Nodes.find(x); if (it != Nodes.end()) { if (it->second.ip[0] != 0) { next = x; break; } diff --git a/src/WebServer_DevicesPage.ino b/src/WebServer_DevicesPage.ino index 8269d57d0a..6752650625 100644 --- a/src/WebServer_DevicesPage.ino +++ b/src/WebServer_DevicesPage.ino @@ -886,7 +886,7 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, byte page) addFormNumericBox(F("Remote Unit"), F("RemoteUnit"), remoteUnit, 0, 255); if (remoteUnit != 255) { - NodesMap::iterator it = Nodes.find(remoteUnit); + auto it = Nodes.find(remoteUnit); if (it != Nodes.end()) { addUnit(it->second.getNodeName()); diff --git a/src/WebServer_JSON.ino b/src/WebServer_JSON.ino index 5c485811f2..4240b7a02c 100644 --- a/src/WebServer_JSON.ino +++ b/src/WebServer_JSON.ino @@ -200,7 +200,7 @@ void handle_json() if (showNodes) { bool comma_between = false; - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->second.ip[0] != 0) { @@ -224,7 +224,7 @@ void handle_json() stream_next_json_object_value(F("platform"), it->second.getNodeTypeDisplayString()); } stream_next_json_object_value(F("ip"), it->second.IP().toString()); - stream_last_json_object_value(F("age"), String(it->second.age)); + stream_last_json_object_value(F("age"), String(it->second.getAge() / 1000)); // time in seconds } // if node info exists } // for loop @@ -394,7 +394,7 @@ void handle_nodes_list_json() { json_init(); json_open(true); - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->second.ip[0] != 0) { @@ -411,7 +411,7 @@ void handle_nodes_list_json() { if (it->second.build) { json_prop(F("build"), String(it->second.build)); } json_prop(F("type"), it->second.getNodeTypeDisplayString()); json_prop(F("ip"), it->second.ip.toString()); - json_number(F("age"), String(it->second.age)); + json_number(F("age"), String(it->second.getAge() / 1000)); // time in seconds json_close(); } } diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index aea4c57b20..1c5ba45189 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -157,9 +157,9 @@ void handle_root() { html_table_header(getLabel(LabelType::BUILD_DESC)); html_table_header("Type"); html_table_header("IP", 160); // Should fit "255.255.255.255" - html_table_header("Age"); + html_table_header("Age (s)"); - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->second.ip[0] != 0) { @@ -208,7 +208,7 @@ void handle_root() { addHtml(html); } html_TD(); - addHtml(String(it->second.age)); + addHtml(String(it->second.getAge()/1000)); // time in seconds } } diff --git a/src/_C013.ino b/src/_C013.ino index 7690c8d93f..7645ccfabe 100644 --- a/src/_C013.ino +++ b/src/_C013.ino @@ -123,7 +123,7 @@ void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskInde C013_sendUDP(destUnit, (byte *)&infoReply, sizeof(C013_SensorInfoStruct)); delay(10); } else { - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->first != Settings.Unit) { infoReply.destUnit = it->first; C013_sendUDP(it->first, (byte *)&infoReply, sizeof(C013_SensorInfoStruct)); @@ -158,7 +158,7 @@ void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskInde C013_sendUDP(destUnit, (byte *)&dataReply, sizeof(C013_SensorDataStruct)); delay(10); } else { - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->first != Settings.Unit) { dataReply.destUnit = it->first; C013_sendUDP(it->first, (byte *)&dataReply, sizeof(C013_SensorDataStruct)); @@ -177,10 +177,13 @@ void C013_sendUDP(byte unit, byte *data, byte size) if (!NetworkConnected(10)) { return; } - NodesMap::iterator it; - if (unit != 255) { - it = Nodes.find(unit); + IPAddress remoteNodeIP; + if (unit == 255) { + remoteNodeIP = { 255, 255, 255, 255 }; + } + else { + auto it = Nodes.find(unit); if (it == Nodes.end()) { return; @@ -189,7 +192,9 @@ void C013_sendUDP(byte unit, byte *data, byte size) if (it->second.ip[0] == 0) { return; } + remoteNodeIP = it->second.ip; } + #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { @@ -201,15 +206,6 @@ void C013_sendUDP(byte unit, byte *data, byte size) statusLED(true); - IPAddress remoteNodeIP; - - if (unit == 255) { - remoteNodeIP = { 255, 255, 255, 255 }; - } - else { - remoteNodeIP = it->second.ip; - } - if (!beginWiFiUDP_randomPort(C013_portUDP)) { return; } if (C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort) == 0) { return; } diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 03e81e0f48..9ba564def4 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -96,6 +96,28 @@ void ESPEasy_Now_packet::setBroadcast() } } +size_t ESPEasy_Now_packet::addBinaryData(uint8_t* data, size_t length) +{ + const size_t payload_size = getPayloadSize(); + if (length > payload_size) { + length = payload_size; + } + size_t buf_pos = sizeof(ESPEasy_now_hdr); + memcpy(&_buf[buf_pos], data, length); + return length; +} + +bool ESPEasy_Now_packet::getBinaryData(uint8_t* data, size_t length) const +{ + const size_t payload_size = getPayloadSize(); + if (length > payload_size) { + length = payload_size; + } + size_t buf_pos = sizeof(ESPEasy_now_hdr); + memcpy(data, &_buf[buf_pos], length); + return length; +} + String ESPEasy_Now_packet::getString(size_t& payload_pos) const { String res; diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 04a57601f5..2cd798a7b4 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -31,6 +31,10 @@ class ESPEasy_Now_packet { void setBroadcast(); + size_t addBinaryData(uint8_t* data, size_t length); + + bool getBinaryData(uint8_t* data, size_t length) const; + // Add a string to the packet, starting at payload position payload_pos // Return the number of bytes added (can be 1 more than the given string) size_t addString(const String& string, diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 36d6144147..38f24eae83 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -28,20 +28,20 @@ void NodeStruct::setLocalData() { WiFi.softAPmacAddress(ap_mac); { IPAddress localIP = WiFi.localIP(); + for (byte i = 0; i < 4; ++i) { ip[i] = localIP[i]; } } - - unit = Settings.Unit; + + unit = Settings.Unit; build = Settings.Build; memcpy(nodeName, Settings.Name, 25); nodeType = NODE_TYPE_ID; -// webserverPort = Settings.WebserverPort; // PR #3053 + // webserverPort = Settings.WebserverPort; // PR #3053 } - String NodeStruct::getNodeTypeDisplayString() const { switch (nodeType) { @@ -57,8 +57,10 @@ String NodeStruct::getNodeTypeDisplayString() const { String NodeStruct::getNodeName() const { String res; - size_t length = strnlen(reinterpret_cast(nodeName), sizeof(nodeName)); + size_t length = strnlen(reinterpret_cast(nodeName), sizeof(nodeName)); + res.reserve(length); + for (size_t i = 0; i < length; ++i) { res += static_cast(nodeName[i]); } @@ -68,3 +70,18 @@ String NodeStruct::getNodeName() const { IPAddress NodeStruct::IP() const { return IPAddress(ip[0], ip[1], ip[2], ip[3]); } + +unsigned long NodeStruct::getAge() const { + return timePassedSince(lastSeenTimestamp); +} + +String NodeStruct::getSummary() const { + String res; + res.reserve(48); + res = F("Unit: "); + res += unit; + res += F(" \""); + res += getNodeName(); + res += '"'; + return res; +} \ No newline at end of file diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 2c8e377d23..b27ed0453f 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -29,9 +29,12 @@ struct __attribute__((__packed__)) NodeStruct IPAddress IP() const; + unsigned long getAge() const; + + String getSummary() const; + + // Do not change the order of this data, as it is being sent via P2P UDP. - // 1 byte 'binary token 255' - // 1 byte id '1' // 6 byte mac (STA interface) // 4 byte ip // 1 byte unit @@ -51,10 +54,13 @@ struct __attribute__((__packed__)) NodeStruct uint16_t build = 0; byte nodeName[25] = { 0 }; byte nodeType = 0; - byte age = 0; uint16_t webserverPort = 80; uint8_t ap_mac[6] = { 0 }; // AP mode MAC + // Data not being sent to other nodes. + unsigned long lastSeenTimestamp = 0; + + }; typedef std::map NodesMap; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp new file mode 100644 index 0000000000..2aa20a0a55 --- /dev/null +++ b/src/src/DataStructs/NodesHandler.cpp @@ -0,0 +1,86 @@ +#include "NodesHandler.h" + + +static bool mac_equal(const uint8_t *mac1, const uint8_t *mac2) +{ + for (byte i = 0; i < 6; ++i) { + if (mac1[i] != mac2[i]) { return false; } + } + return true; +} + +void NodesHandler::addNode(const NodeStruct& node) +{ + _nodes[node.unit] = node; + _nodes[node.unit].lastSeenTimestamp = millis(); +} + +bool NodesHandler::hasNode(uint8_t unit_nr) const +{ + return _nodes.find(unit_nr) != _nodes.end(); +} + +bool NodesHandler::hasNode(const uint8_t *mac) const +{ + return getNode(mac) != nullptr; +} + +const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const +{ + auto it = _nodes.find(unit_nr); + + if (it == _nodes.end()) { + return nullptr; + } + return &(it->second); +} + +const NodeStruct * NodesHandler::getNode(const uint8_t *mac) const +{ + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) + { + if (mac_equal(mac, it->second.mac) || mac_equal(mac, it->second.ap_mac)) { + return &(it->second); + } + } + return nullptr; +} + +NodeStruct* NodesHandler::getNode(const uint8_t *mac) +{ + const NodeStruct *node = getNode(mac); + + return const_cast(node); +} + +NodesMap::const_iterator NodesHandler::begin() const { + return _nodes.begin(); +} + +NodesMap::const_iterator NodesHandler::end() const { + return _nodes.end(); +} + +NodesMap::const_iterator NodesHandler::find(uint8_t unit_nr) const +{ + return _nodes.find(unit_nr); +} + +bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& max_age) +{ + max_age = 0; + bool nodeRemoved = false; + for (auto it = _nodes.begin(); it != _nodes.end(); ) { + unsigned long age = it->second.getAge(); + if (age > max_age_allowed) { + it = _nodes.erase(it); + nodeRemoved = true; + } else { + ++it; + if (age > max_age) { + max_age = age; + } + } + } + return nodeRemoved; +} \ No newline at end of file diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h new file mode 100644 index 0000000000..170accb2a5 --- /dev/null +++ b/src/src/DataStructs/NodesHandler.h @@ -0,0 +1,37 @@ +#ifndef DATASTRUCTS_NODESHANDLER_H +#define DATASTRUCTS_NODESHANDLER_H + +#include "NodeStruct.h" + +class NodesHandler { +public: + void addNode(const NodeStruct& node); + + bool hasNode(uint8_t unit_nr) const; + + bool hasNode(const uint8_t* mac) const; + + const NodeStruct* getNode(uint8_t unit_nr) const; + + const NodeStruct* getNode(const uint8_t* mac) const; + + NodeStruct* getNode(const uint8_t* mac); + + NodesMap::const_iterator begin() const; + + NodesMap::const_iterator end() const; + NodesMap::const_iterator find(uint8_t unit_nr) const; + + // Remove nodes in list older than max_age_allowed (msec) + // Returns oldest age, max_age (msec) not removed from the list. + // Return true if a node has been removed. + bool refreshNodeList(unsigned long max_age_allowed, unsigned long& max_age); + +private: + + NodesMap _nodes; + +}; + + +#endif // DATASTRUCTS_NODESHANDLER_H \ No newline at end of file diff --git a/src/src/Globals/Nodes.cpp b/src/src/Globals/Nodes.cpp index 7acb0f0d81..b3f727515c 100644 --- a/src/src/Globals/Nodes.cpp +++ b/src/src/Globals/Nodes.cpp @@ -1,4 +1,4 @@ #include "../Globals/Nodes.h" -NodesMap Nodes; \ No newline at end of file +NodesHandler Nodes; \ No newline at end of file diff --git a/src/src/Globals/Nodes.h b/src/src/Globals/Nodes.h index f9c0eed8df..16bd6e0eca 100644 --- a/src/src/Globals/Nodes.h +++ b/src/src/Globals/Nodes.h @@ -1,9 +1,9 @@ #ifndef GLOBALS_NODES_H #define GLOBALS_NODES_H -#include "../DataStructs/NodeStruct.h" +#include "../DataStructs/NodesHandler.h" -extern NodesMap Nodes; +extern NodesHandler Nodes; #endif // GLOBALS_NODES_H diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index f7a98970c8..5a06bd2019 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -85,7 +85,7 @@ void run_compiletime_checks() { #ifdef USES_NOTIFIER check_size(); #endif - check_size(); + check_size(); check_size(); check_size(); check_size(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4db3e1bd9f..1c19889a44 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -4,6 +4,8 @@ # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/NodeStruct.h" +# include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" # include "../Globals/Settings.h" # include "../../ESPEasy_fdwdecl.h" @@ -28,7 +30,7 @@ bool ESPEasy_now_handler_t::begin() String log; log.reserve(48); log = F("ESPEasy_Now: Failed to add peer "); - log += _peerInfoMap.formatPeerInfo(SecuritySettings.EspEasyNowPeerMAC[peer]); + log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); addLog(LOG_LEVEL_ERROR, log); } } @@ -58,7 +60,7 @@ bool ESPEasy_now_handler_t::loop() if (loglevelActiveFor(loglevel)) { String log = F("ESPEasyNow: Message from "); - log += _peerInfoMap.formatPeerInfo(ESPEasy_now_in_queue.front()._mac); + log += formatMAC(ESPEasy_now_in_queue.front()._mac); if (!validPacket) { log += F(" INVALID CHECKSUM!"); @@ -103,16 +105,13 @@ bool ESPEasy_now_handler_t::loop() void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) { - String hostname = Settings.getHostname(); - size_t len = hostname.length(); + NodeStruct thisNode; + thisNode.setLocalData(); + size_t len = sizeof(NodeStruct); ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::Announcement); ESPEasy_Now_packet msg(header, len); - + msg.addBinaryData(reinterpret_cast(&thisNode), len); msg.setBroadcast(); - - size_t pos = 0; - msg.addString(hostname, pos); - send(msg); } @@ -178,7 +177,7 @@ bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { } else { log = F("ESPEasy Now: Sent FAILED to: "); } - log += _peerInfoMap.formatPeerInfo(packet._mac); + log += formatMAC(packet._mac); addLog(LOG_LEVEL_INFO, log); } return success; @@ -194,7 +193,7 @@ WifiEspNowSendStatus ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packe if (sendStatus == WifiEspNowSendStatus::NONE) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy Now: TIMEOUT to: "); - log += _peerInfoMap.formatPeerInfo(packet._mac); + log += formatMAC(packet._mac); addLog(LOG_LEVEL_INFO, log); } } @@ -214,27 +213,18 @@ WifiEspNowSendStatus ESPEasy_now_handler_t::waitForSendStatus(size_t timeout) co bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet) { - size_t payload_pos = 0; - ESPEasy_Now_peerInfo_meta meta; - - meta.nodeName = packet.getString(payload_pos); - - _peerInfoMap.addPeer(packet._mac, meta); - + NodeStruct received; + packet.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct)); + Nodes.addNode(received); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; size_t payloadSize = packet.getPayloadSize(); log.reserve(payloadSize + 40); log = F("ESPEasy Now discovery: "); - log += _peerInfoMap.formatPeerInfo(packet._mac); + log += formatMAC(packet._mac); log += '\n'; - log += meta.nodeName; - - while (payload_pos < payloadSize) { - log += '\n'; - log += packet.getString(payload_pos); - } + log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); } return true; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 7da9239b0f..09790b0e4d 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -47,6 +47,7 @@ class ESPEasy_now_handler_t { bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); + // FIXME TD-er: Must remove ESPEasy_Now_peerInfo _peerInfoMap; }; From ea19fe0bdd7e2e2ee7b60bb652f1ab150e16101b Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 13 May 2020 02:26:30 +0200 Subject: [PATCH 013/404] [ESPEasy-Now] Clean up no longer needed peer info objects We're now using NodeStruct which was also used for p2p info sharing. --- src/WebServer_ConfigPage.ino | 11 +++- src/src/DataStructs/ESPEasy_Now_peerInfo.cpp | 58 -------------------- src/src/DataStructs/ESPEasy_Now_peerInfo.h | 38 ------------- src/src/Globals/ESPEasy_now_handler.cpp | 5 +- src/src/Helpers/ESPEasy_now_handler.cpp | 5 -- src/src/Helpers/ESPEasy_now_handler.h | 7 --- 6 files changed, 12 insertions(+), 112 deletions(-) delete mode 100644 src/src/DataStructs/ESPEasy_Now_peerInfo.cpp delete mode 100644 src/src/DataStructs/ESPEasy_Now_peerInfo.h diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index 62e220e4d4..1c905d8a58 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -199,11 +199,16 @@ void handle_config() { String id = F("peer"); id += String(peer); addFormMACBox(label, id, SecuritySettings.EspEasyNowPeerMAC[peer]); - ESPEasy_Now_peerInfo_meta meta; - if (ESPEasy_now_handler.getPeerInfo(SecuritySettings.EspEasyNowPeerMAC[peer], meta)) + + // FIXME TD-er: Crash + /* + NodeStruct* nodeInfo = Nodes.getNode(SecuritySettings.EspEasyNowPeerMAC[peer]); + if (nodeInfo != nullptr) { - addFormNote(meta.nodeName); + + addFormNote(nodeInfo->getSummary()); } + */ } #endif diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp b/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp deleted file mode 100644 index 618e9642ec..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "ESPEasy_Now_peerInfo.h" - -#include "../../ESPEasy_fdwdecl.h" - - -static uint64_t mac_to_key(const uint8_t *mac) -{ - uint64_t key = 0; - - for (byte i = 0; i < 6; ++i) { - key = key << 8; - key += mac[i]; - } - return key; -} - -void ESPEasy_Now_peerInfo::addPeer(const uint8_t *mac, const ESPEasy_Now_peerInfo_meta& meta) -{ - uint64_t key = mac_to_key(mac); - - peer_map[key] = meta; -} - -bool ESPEasy_Now_peerInfo::hasPeer(const uint8_t *mac) const -{ - uint64_t key = mac_to_key(mac); - - return peer_map.find(key) != peer_map.end(); -} - -bool ESPEasy_Now_peerInfo::getPeer(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const -{ - uint64_t key = mac_to_key(mac); - auto it = peer_map.find(key); - - if (it == peer_map.end()) { return false; } - meta = it->second; - - return true; -} - -String ESPEasy_Now_peerInfo::formatPeerInfo(const uint8_t *mac) const -{ - uint64_t key = mac_to_key(mac); - auto it = peer_map.find(key); - String res; - - res = formatMAC(mac); - - if (it == peer_map.end()) { return res; } - - res.reserve(128); - res += F(" \""); - res += it->second.nodeName; - res += '"'; - return res; -} diff --git a/src/src/DataStructs/ESPEasy_Now_peerInfo.h b/src/src/DataStructs/ESPEasy_Now_peerInfo.h deleted file mode 100644 index 05eca7fa7e..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_peerInfo.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H -#define DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H - -#include - -#include -#include - -struct ESPEasy_Now_peerInfo_meta { - String nodeName; - IPAddress ip; - byte unit; - uint8_t channel = 0; - uint8_t distance = 0; - bool encrypt = false; -}; - -typedef std::map peerInfoMap_t; - - -struct ESPEasy_Now_peerInfo { - void addPeer(const uint8_t *mac, - const ESPEasy_Now_peerInfo_meta& meta); - - bool hasPeer(const uint8_t *mac) const; - - bool getPeer(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const; - - String formatPeerInfo(const uint8_t *mac) const; - -private: - - peerInfoMap_t peer_map; -}; - - -#endif // DATASTRUCTS_ESPEASY_NOW_PEERINFOR_H diff --git a/src/src/Globals/ESPEasy_now_handler.cpp b/src/src/Globals/ESPEasy_now_handler.cpp index 9d972176a0..271820404e 100644 --- a/src/src/Globals/ESPEasy_now_handler.cpp +++ b/src/src/Globals/ESPEasy_now_handler.cpp @@ -1,4 +1,7 @@ #include "ESPEasy_now_handler.h" +#ifdef USES_ESPEASY_NOW -ESPEasy_now_handler_t ESPEasy_now_handler; \ No newline at end of file +ESPEasy_now_handler_t ESPEasy_now_handler; + +#endif \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 1c19889a44..f0f746f065 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -160,11 +160,6 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return processed; } -bool ESPEasy_now_handler_t::getPeerInfo(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const -{ - return _peerInfoMap.getPeer(mac, meta); -} bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 09790b0e4d..0f76a1f03e 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -7,7 +7,6 @@ # include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/ESPEasy_Now_packet.h" -# include "../DataStructs/ESPEasy_Now_peerInfo.h" # include "../Globals/CPlugins.h" @@ -30,9 +29,6 @@ class ESPEasy_now_handler_t { const String & topic, const String & payload); - bool getPeerInfo(const uint8_t *mac, - ESPEasy_Now_peerInfo_meta& meta) const; - private: bool send(const ESPEasy_Now_packet& packet); @@ -46,9 +42,6 @@ class ESPEasy_now_handler_t { bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); - - // FIXME TD-er: Must remove - ESPEasy_Now_peerInfo _peerInfoMap; }; From 3413381960d7fef18999de2398e20d654dcbb820 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 13 May 2020 11:57:08 +0200 Subject: [PATCH 014/404] [ESPEasy-Now] Add view of other nodes info on peer MAC config tab --- src/WebServer_ConfigPage.ino | 12 ++++++---- src/src/DataStructs/NodeStruct.cpp | 2 +- src/src/DataStructs/NodeStruct.h | 2 ++ src/src/DataStructs/NodesHandler.cpp | 35 ++++++++++++++++++++-------- src/src/DataStructs/NodesHandler.h | 4 +--- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index 1c905d8a58..efcbe84456 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -201,14 +201,16 @@ void handle_config() { addFormMACBox(label, id, SecuritySettings.EspEasyNowPeerMAC[peer]); // FIXME TD-er: Crash - /* - NodeStruct* nodeInfo = Nodes.getNode(SecuritySettings.EspEasyNowPeerMAC[peer]); + + bool match_STA; + const NodeStruct* nodeInfo = Nodes.getNodeByMac(SecuritySettings.EspEasyNowPeerMAC[peer], match_STA); if (nodeInfo != nullptr) { - - addFormNote(nodeInfo->getSummary()); + String summary = nodeInfo->getSummary(); + summary += match_STA ? F(" (STA)") : F(" (AP)"); + addFormNote(summary); } - */ + } #endif diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 38f24eae83..969b0eb6f1 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -84,4 +84,4 @@ String NodeStruct::getSummary() const { res += getNodeName(); res += '"'; return res; -} \ No newline at end of file +} diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index b27ed0453f..f7f3c4b593 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -34,6 +34,8 @@ struct __attribute__((__packed__)) NodeStruct String getSummary() const; + + // Do not change the order of this data, as it is being sent via P2P UDP. // 6 byte mac (STA interface) // 4 byte ip diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 2aa20a0a55..9d35a879ad 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -9,6 +9,16 @@ static bool mac_equal(const uint8_t *mac1, const uint8_t *mac2) return true; } +static bool mac_empty(const uint8_t *mac) +{ + for (byte i = 0; i < 6; ++i) { + if (mac[i] != 0) { + return false; + } + } + return true; +} + void NodesHandler::addNode(const NodeStruct& node) { _nodes[node.unit] = node; @@ -22,7 +32,8 @@ bool NodesHandler::hasNode(uint8_t unit_nr) const bool NodesHandler::hasNode(const uint8_t *mac) const { - return getNode(mac) != nullptr; + bool dummy; + return getNodeByMac(mac, dummy) != nullptr; } const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const @@ -35,24 +46,28 @@ const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const return &(it->second); } -const NodeStruct * NodesHandler::getNode(const uint8_t *mac) const +const NodeStruct * NodesHandler::getNodeByMac(const uint8_t *mac, bool& match_STA) const { + if (mac_empty(mac)) { + return nullptr; + } + delay(0); for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { - if (mac_equal(mac, it->second.mac) || mac_equal(mac, it->second.ap_mac)) { + + if (mac_equal(mac, it->second.mac)) { + match_STA = true; + return &(it->second); + } + + if (mac_equal(mac, it->second.ap_mac)) { + match_STA = false; return &(it->second); } } return nullptr; } -NodeStruct* NodesHandler::getNode(const uint8_t *mac) -{ - const NodeStruct *node = getNode(mac); - - return const_cast(node); -} - NodesMap::const_iterator NodesHandler::begin() const { return _nodes.begin(); } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 170accb2a5..04e4130f47 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -13,9 +13,7 @@ class NodesHandler { const NodeStruct* getNode(uint8_t unit_nr) const; - const NodeStruct* getNode(const uint8_t* mac) const; - - NodeStruct* getNode(const uint8_t* mac); + const NodeStruct* getNodeByMac(const uint8_t* mac, bool& match_STA) const; NodesMap::const_iterator begin() const; From e6860d354002b61da5c3cba3c94073468237286c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 13 May 2020 18:18:11 +0200 Subject: [PATCH 015/404] [ESPEasy-Now] Add packet merger for messages > 250 bytes --- src/WebServer_ConfigPage.ino | 2 - src/src/DataStructs/ESPEasy_Now_packet.cpp | 7 +- src/src/DataStructs/ESPEasy_Now_packet.h | 13 +- src/src/DataStructs/ESPEasy_now_hdr.cpp | 20 ++- src/src/DataStructs/ESPEasy_now_hdr.h | 16 ++- src/src/DataStructs/ESPEasy_now_merger.cpp | 152 +++++++++++++++++++++ src/src/DataStructs/ESPEasy_now_merger.h | 63 +++++++++ src/src/Helpers/ESPEasy_now_handler.cpp | 143 ++++++++++++------- src/src/Helpers/ESPEasy_now_handler.h | 7 +- 9 files changed, 355 insertions(+), 68 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_now_merger.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_merger.h diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index efcbe84456..f132c1e38b 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -200,8 +200,6 @@ void handle_config() { id += String(peer); addFormMACBox(label, id, SecuritySettings.EspEasyNowPeerMAC[peer]); - // FIXME TD-er: Crash - bool match_STA; const NodeStruct* nodeInfo = Nodes.getNodeByMac(SecuritySettings.EspEasyNowPeerMAC[peer], match_STA); if (nodeInfo != nullptr) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 9ba564def4..e84c1109fa 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -107,7 +107,7 @@ size_t ESPEasy_Now_packet::addBinaryData(uint8_t* data, size_t length) return length; } -bool ESPEasy_Now_packet::getBinaryData(uint8_t* data, size_t length) const +size_t ESPEasy_Now_packet::getBinaryData(uint8_t* data, size_t length) const { const size_t payload_size = getPayloadSize(); if (length > payload_size) { @@ -142,4 +142,9 @@ String ESPEasy_Now_packet::getString(size_t& payload_pos) const return res; } +const uint8_t * ESPEasy_Now_packet::begin() const +{ + return &_buf[sizeof(ESPEasy_now_hdr)]; +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 2cd798a7b4..8a0b1a2483 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -7,6 +7,9 @@ #ifdef USES_ESPEASY_NOW # include "ESPEasy_now_hdr.h" + +#include +#include class ESPEasy_Now_packet { public: @@ -33,7 +36,7 @@ class ESPEasy_Now_packet { size_t addBinaryData(uint8_t* data, size_t length); - bool getBinaryData(uint8_t* data, size_t length) const; + size_t getBinaryData(uint8_t* data, size_t length) const; // Add a string to the packet, starting at payload position payload_pos // Return the number of bytes added (can be 1 more than the given string) @@ -44,6 +47,9 @@ class ESPEasy_Now_packet { // payload_pos will contain the new position to start for a next string String getString(size_t& payload_pos) const; + // Get pointer to the begin of the payload + const uint8_t * begin() const; + const uint8_t * operator[](size_t idx) const { return &_buf[idx]; } @@ -57,6 +63,11 @@ class ESPEasy_Now_packet { void setSize(size_t packetSize); }; +typedef std::list ESPEasy_Now_packet_list; + +typedef std::map ESPEasy_Now_packet_map; + + #endif // ifdef USES_ESPEASY_NOW #endif // DATASTRUCTS_ESPEASY_NOW_INCOMING_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index b2dd47f28a..18e74fa293 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -7,6 +7,20 @@ ESPEasy_now_hdr::ESPEasy_now_hdr() {} ESPEasy_now_hdr::ESPEasy_now_hdr(ESPEasy_now_hdr::message_t messageType) : message_type(messageType) {} +ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr &other) +{ + if(&other == this) + return *this; + header_version = other.header_version; + message_type = other.message_type; + packet_nr = other.packet_nr; + nr_packets = other.nr_packets; + message_count = other.message_count; + notUsed1 = other.notUsed1; + checksum = other.checksum; + return *this; +} + void ESPEasy_now_hdr::setChecksum() { checksum = computeChecksum(); @@ -22,10 +36,10 @@ uint8_t ESPEasy_now_hdr::computeChecksum() const // TODO TD-er: Maybe better to have this as a for loop over *this uint8_t res = header_version; res ^= static_cast(message_type); - res ^= cur_message_nr; - res ^= last_message_nr; + res ^= packet_nr; + res ^= nr_packets; + res ^= message_count; res ^= notUsed1; - res ^= notUsed2; return res; } diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 15c8de9e29..67880c406a 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -27,6 +27,8 @@ struct ESPEasy_now_hdr { ESPEasy_now_hdr(message_t messageType); + ESPEasy_now_hdr& operator=(const ESPEasy_now_hdr& other); + void setChecksum(); bool checksumValid() const; @@ -37,13 +39,13 @@ struct ESPEasy_now_hdr { public: - const uint8_t header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions - message_t message_type = message_t::NotSet; - uint8_t cur_message_nr = 0; // Current message number (start at 0) - uint8_t last_message_nr = 0; // The highest message number of this sequence - uint8_t notUsed1 = 0; // reserved - uint8_t notUsed2 = 0; // reserved - uint8_t checksum = 0; // checksum + uint8_t header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions + message_t message_type = message_t::NotSet; + uint8_t packet_nr = 0; // Current message number (start at 0) + uint8_t nr_packets = 1; // The highest message number of this sequence + uint8_t message_count = 1; // A set of messages all have the same message_count + uint8_t notUsed1 = 0; // reserved + uint8_t checksum = 0; // checksum }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp new file mode 100644 index 0000000000..b370ccac3b --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -0,0 +1,152 @@ +#include "ESPEasy_now_merger.h" + +#ifdef USES_ESPEASY_NOW + +#include "../Helpers/ESPEasy_time_calc.h" +#include "../../ESPEasy_fdwdecl.h" + +ESPEasy_now_merger::ESPEasy_now_merger() { + _firstPacketTimestamp = millis(); +} + +void ESPEasy_now_merger::addPacket( + uint8_t packet_nr, + const uint8_t mac[6], + const uint8_t *buf, + size_t packetSize) +{ + _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet(mac, buf, packetSize))); + _firstPacketTimestamp = millis(); +} + +bool ESPEasy_now_merger::messageComplete() const +{ + return _queue.size() >= getFirstHeader().nr_packets; +} + +bool ESPEasy_now_merger::expired() const +{ + return timePassedSince(_firstPacketTimestamp) > 5000; +} + +uint8_t ESPEasy_now_merger::receivedCount(uint8_t& nr_packets) const +{ + nr_packets = getFirstHeader().nr_packets; + return _queue.size(); +} + +ESPEasy_Now_packet_map::const_iterator ESPEasy_now_merger::find(uint8_t packet_nr) const +{ + return _queue.find(packet_nr); +} + +ESPEasy_now_hdr ESPEasy_now_merger::getFirstHeader() const +{ + ESPEasy_now_hdr header; + auto it = _queue.find(0); + if (it != _queue.end()) { + header = it->second.getHeader(); + } + return header; +} + +bool ESPEasy_now_merger::getMac(uint8_t* mac) const +{ + auto it = _queue.find(0); + if (it == _queue.end()) { + return false; + } + memcpy(mac, it->second._mac, 6); + return true; +} + +String ESPEasy_now_merger::getLogString() const +{ + uint8_t mac[6] = { 0 }; + getMac(mac); + String log; + log = F("ESPEasyNow: Message from "); + log += formatMAC(mac); + log += F(" ("); + log += _queue.size(); + log += '/'; + log += getFirstHeader().nr_packets; + log += ')'; + return log; +} + +size_t ESPEasy_now_merger::getPayloadSize() const +{ + if (!messageComplete()) return 0; + size_t payloadSize = 0; + for (auto it = _queue.begin(); it != _queue.end(); ++it) { + payloadSize += it->second.getPayloadSize(); + } + return payloadSize; +} + +String ESPEasy_now_merger::getString(size_t& payload_pos) const +{ + String res; + size_t packet_start_payload_pos; + uint8_t packet_nr = findPacketWithPayloadPos(payload_pos, packet_start_payload_pos); + if (packet_nr >= getFirstHeader().nr_packets) + return res; + + auto it = _queue.find(packet_nr); + size_t offset = payload_pos - packet_start_payload_pos; + while (it != _queue.end()) { + { + String tmp = it->second.getString(offset); + res += tmp; + size_t tmp_len = tmp.length(); + payload_pos += tmp_len; + if (tmp_len < (it->second.getPayloadSize() - offset)) { + // FIXME TD-er: Must store the length in the multi-packet. + // All is read. + return res; + } + } + offset = 0; + ++packet_nr; + it = _queue.find(packet_nr); + } + return res; +} + +size_t ESPEasy_now_merger::getBinaryData(uint8_t* data, size_t length) const +{ + uint8_t packet_nr = 0; + auto it = _queue.find(packet_nr); + size_t data_pos = 0; + while (it != _queue.end() && data_pos < length) { + size_t added_length = it->second.getBinaryData(data, length - data_pos); + data += added_length; + data_pos += added_length; + ++packet_nr; + it = _queue.find(packet_nr); + } + return data_pos; +} + +uint8_t ESPEasy_now_merger::findPacketWithPayloadPos(size_t payload_pos , size_t & packet_start_payload_pos) const +{ + // First find the place in the queue to continue based on the payload_pos + uint8_t packet_nr = 0; + auto it = _queue.find(packet_nr); + packet_start_payload_pos = 0; + while (it != _queue.end()) { + if (packet_start_payload_pos <= payload_pos) { + if ((packet_start_payload_pos + it->second.getPayloadSize()) > payload_pos) { + return packet_nr; + } + packet_start_payload_pos += it->second.getPayloadSize(); + + ++packet_nr; + it = _queue.find(packet_nr); + } + } + return 255; // Error value +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h new file mode 100644 index 0000000000..e70bda3f90 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -0,0 +1,63 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_MERGER_H +#define DATASTRUCTS_ESPEASY_NOW_MERGER_H + +#include "ESPEasy_Now_packet.h" + +#ifdef USES_ESPEASY_NOW + + +// Class to process all incoming messages from a single sender. +// One or more packets form a complete message. +// This class only contains packets which have the same: +// - Sender mac +// - Message Count +// - Message Type +class ESPEasy_now_merger { +public: + + ESPEasy_now_merger(); + + void addPacket( + uint8_t packet_nr, + const uint8_t mac[6], + const uint8_t *buf, + size_t packetSize); + + // Check if all parts of the packet have been received + bool messageComplete() const; + + uint8_t receivedCount(uint8_t& nr_packets) const; + + // Check of set has expired (not all packets received within timeout) + bool expired() const; + + ESPEasy_Now_packet_map::const_iterator find(uint8_t packet_nr) const; + + // Get combined size of all packets. + size_t getPayloadSize() const; + + // Return a string starting from position pos in the buffer. + // payload_pos will contain the new position to start for a next string + String getString(size_t& payload_pos) const; + + size_t getBinaryData(uint8_t* data, size_t length) const; + + ESPEasy_now_hdr getFirstHeader() const; + + bool getMac(uint8_t* mac) const; + + String getLogString() const; + +private: + + uint8_t findPacketWithPayloadPos(size_t payload_pos, + size_t& packet_start_payload_pos) const; + + unsigned long _firstPacketTimestamp = 0; + std::map _queue; + uint8_t _nr_packets = 255; +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_MERGER_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f0f746f065..d79031ae0f 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -13,10 +13,35 @@ # include -std::list ESPEasy_now_in_queue; + +static uint64_t mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messageType, uint8_t message_count) +{ + uint64_t key = message_count; + + key = key << 8; + key += static_cast(messageType); + + for (byte i = 0; i < 6; ++i) { + key = key << 8; + key += mac[i]; + } + return key; +} + +std::map ESPEasy_now_in_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { - ESPEasy_now_in_queue.emplace_back(mac, buf, count); + if (count < sizeof(ESPEasy_now_hdr)) { + return; // Too small + } + ESPEasy_now_hdr header; + memcpy(&header, buf, sizeof(ESPEasy_now_hdr)); + + if (!header.checksumValid()) { + return; + } + uint64_t key = mac_to_key(mac, header.message_type, header.message_count); + ESPEasy_now_in_queue[key].addPacket(header.packet_nr, mac, buf, count); } bool ESPEasy_now_handler_t::begin() @@ -54,63 +79,50 @@ void ESPEasy_now_handler_t::end() bool ESPEasy_now_handler_t::loop() { - if (!ESPEasy_now_in_queue.empty()) { - bool validPacket = ESPEasy_now_in_queue.front().getHeader().checksumValid(); - const byte loglevel = validPacket ? LOG_LEVEL_INFO : LOG_LEVEL_ERROR; + bool somethingProcessed = false; - if (loglevelActiveFor(loglevel)) { - String log = F("ESPEasyNow: Message from "); - log += formatMAC(ESPEasy_now_in_queue.front()._mac); - - if (!validPacket) { - log += F(" INVALID CHECKSUM!"); + if (!ESPEasy_now_in_queue.empty()) { + for (auto it = ESPEasy_now_in_queue.begin(); it != ESPEasy_now_in_queue.end();) { + bool removeMessage = true; + + if (!it->second.messageComplete()) { + if (it->second.expired()) { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log = it->second.getLogString(); + log += F(" Expired!"); + addLog(LOG_LEVEL_ERROR, log); + } + } else { + removeMessage = false; + } } else { - log += F(" ("); - log += ESPEasy_now_in_queue.front().getHeader().cur_message_nr + 1; - log += '/'; - log += ESPEasy_now_in_queue.front().getHeader().last_message_nr + 1; - log += ')'; + // Process it + somethingProcessed = processMessage(it->second); } - addLog(loglevel, log); - } - - if (!validPacket) { - ESPEasy_now_in_queue.pop_front(); - return false; - } - bool handled = false; - - switch (ESPEasy_now_in_queue.front().getHeader().message_type) - { - case ESPEasy_now_hdr::message_t::NotSet: - case ESPEasy_now_hdr::message_t::ChecksumError: - break; - case ESPEasy_now_hdr::message_t::Acknowledgement: - break; - case ESPEasy_now_hdr::message_t::Announcement: - handled = handle_DiscoveryAnnounce(ESPEasy_now_in_queue.front()); - break; - case ESPEasy_now_hdr::message_t::MQTTControllerMessage: - handled = handle_MQTTControllerMessage(ESPEasy_now_in_queue.front()); - break; + if (removeMessage) { + it = ESPEasy_now_in_queue.erase(it); + // FIXME TD-er: For now only process one item and then wait for the next loop. + if (somethingProcessed) { + return true; + } + } else { + ++it; + } } - - // FIXME TD-er: What to do when packet is not handled? - ESPEasy_now_in_queue.pop_front(); - return handled; } - return false; + return somethingProcessed; } void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) { NodeStruct thisNode; + thisNode.setLocalData(); size_t len = sizeof(NodeStruct); ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::Announcement); ESPEasy_Now_packet msg(header, len); - msg.addBinaryData(reinterpret_cast(&thisNode), len); + msg.addBinaryData(reinterpret_cast(&thisNode), len); msg.setBroadcast(); send(msg); } @@ -160,7 +172,6 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return processed; } - bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); @@ -206,18 +217,46 @@ WifiEspNowSendStatus ESPEasy_now_handler_t::waitForSendStatus(size_t timeout) co return sendStatus; } -bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet) +bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) +{ + + addLog(LOG_LEVEL_INFO, message.getLogString()); + bool handled = false; + + switch (message.getFirstHeader().message_type) + { + case ESPEasy_now_hdr::message_t::NotSet: + case ESPEasy_now_hdr::message_t::ChecksumError: + break; + case ESPEasy_now_hdr::message_t::Acknowledgement: + break; + case ESPEasy_now_hdr::message_t::Announcement: + handled = handle_DiscoveryAnnounce(message); + break; + case ESPEasy_now_hdr::message_t::MQTTControllerMessage: + handled = handle_MQTTControllerMessage(message); + break; + } + + return handled; +} + + +bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) { NodeStruct received; - packet.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct)); + + message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct)); Nodes.addNode(received); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; - size_t payloadSize = packet.getPayloadSize(); + uint8_t mac[6] = {0}; + message.getMac(mac); + size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); log = F("ESPEasy Now discovery: "); - log += formatMAC(packet._mac); + log += formatMAC(mac); log += '\n'; log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); @@ -225,7 +264,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_Now_packet& p return true; } -bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet) +bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message) { # ifdef USES_MQTT @@ -235,8 +274,8 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_Now_packe if (validControllerIndex(controllerIndex)) { size_t pos = 0; - String topic = packet.getString(pos); - String payload = packet.getString(pos); + String topic = message.getString(pos); + String payload = message.getString(pos); MakeControllerSettings(ControllerSettings); LoadControllerSettings(controllerIndex, ControllerSettings); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 0f76a1f03e..33f9848105 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -7,6 +7,7 @@ # include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_now_merger.h" # include "../Globals/CPlugins.h" @@ -37,10 +38,12 @@ class ESPEasy_now_handler_t { WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; + bool processMessage(const ESPEasy_now_merger& message); - bool handle_DiscoveryAnnounce(const ESPEasy_Now_packet& packet); - bool handle_MQTTControllerMessage(const ESPEasy_Now_packet& packet); + bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message); + + bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message); }; From 4c160ad7b684d5e18e2c2baf917a903f2114594a Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 14 May 2020 02:03:06 +0200 Subject: [PATCH 016/404] [ESPEasy-Now] Start with packet splitter --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 10 ++- src/src/DataStructs/ESPEasy_Now_packet.h | 4 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 84 ++++++++++++++++++++ src/src/DataStructs/ESPEasy_now_splitter.h | 45 +++++++++++ 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_now_splitter.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_splitter.h diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index e84c1109fa..6e99db916a 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -43,6 +43,11 @@ size_t ESPEasy_Now_packet::getPayloadSize() const return size - sizeof(ESPEasy_now_hdr); } +size_t ESPEasy_Now_packet::getMaxPayloadSize() +{ + return ESPEASY_NOW_MAX_PACKET_SIZE - sizeof(ESPEasy_now_hdr); +} + ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const { ESPEasy_now_hdr header; @@ -63,7 +68,7 @@ void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) { - const size_t payload_size = getPayloadSize(); + const size_t payload_size = getPayloadSize() - 1; if (payload_pos > payload_size) { return 0; @@ -76,7 +81,6 @@ size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) } // Copy the string including null-termination. - // If the null-termination does not fit, no other string can be added anyway. size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); memcpy(&_buf[buf_pos], reinterpret_cast(string.c_str()), bytesToWrite); payload_pos += bytesToWrite; @@ -96,7 +100,7 @@ void ESPEasy_Now_packet::setBroadcast() } } -size_t ESPEasy_Now_packet::addBinaryData(uint8_t* data, size_t length) +size_t ESPEasy_Now_packet::addBinaryData(const uint8_t* data, size_t length) { const size_t payload_size = getPayloadSize(); if (length > payload_size) { diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 8a0b1a2483..6932daeb0f 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -26,6 +26,8 @@ class ESPEasy_Now_packet { size_t getPayloadSize() const; + static size_t getMaxPayloadSize(); + ESPEasy_now_hdr getHeader() const; void setHeader(ESPEasy_now_hdr header); @@ -34,7 +36,7 @@ class ESPEasy_Now_packet { void setBroadcast(); - size_t addBinaryData(uint8_t* data, size_t length); + size_t addBinaryData(const uint8_t* data, size_t length); size_t getBinaryData(uint8_t* data, size_t length) const; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp new file mode 100644 index 0000000000..c288e695fe --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -0,0 +1,84 @@ +#include "ESPEasy_now_splitter.h" + +#ifdef USES_ESPEASY_NOW + +static uint8_t ESPEasy_now_message_count = 1; + +ESPEasy_now_splitter::ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_type, size_t totalSize) + : _header(message_type), _totalSize(totalSize) +{ + _header.message_count = ++ESPEasy_now_message_count; +} + +size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) +{ + size_t data_left = length; + + while (data_left > 0) { + createNextPacket(data_left); + size_t bytesAdded = _queue.back().addBinaryData(data, data_left); + data_left -= bytesAdded; + data += bytesAdded; + _payload_pos += bytesAdded; + _bytesStored += bytesAdded; + } + return length; +} + +size_t ESPEasy_now_splitter::addString(const String& string) +{ + size_t length = string.length() + 1; // Store the extra null-termination + return addBinaryData(reinterpret_cast(string.c_str()), length); +} + +bool ESPEasy_now_splitter::send(uint8_t mac[6]) +{} + + +void ESPEasy_now_splitter::createNextPacket(size_t data_left) +{ + size_t maxPayloadSize = ESPEasy_Now_packet::getMaxPayloadSize() - 1; + + if (maxPayloadSize > _payload_pos) { + if ((_payload_pos + data_left) == maxPayloadSize) { + // Special case where we must decrease next packet slightly + maxPayloadSize -= 2; + } else { + // No need to create a new file yet + return; + } + } + + // Determine size of next packet + size_t message_bytes_left = _totalSize - _bytesStored; + size_t packetSize = message_bytes_left; + + if (packetSize > maxPayloadSize) { + packetSize = maxPayloadSize; + } + if (packetSize == data_left) { + packetSize -= 2; + } + _queue.emplace_back(_header, packetSize); + _payload_pos = 0; + + // Set the packet number for the next packet. + // Total packet count will be set right before sending them. + _header.packet_nr++; +} + +void ESPEasy_now_splitter::setMac(uint8_t mac[6]) +{} + +bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) +{} + +WifiEspNowSendStatus ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, + size_t timeout) +{} + +WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) const +{} + + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h new file mode 100644 index 0000000000..a151719d29 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -0,0 +1,45 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_SPLITTER_H +#define DATASTRUCTS_ESPEASY_NOW_SPLITTER_H + +#include "ESPEasy_Now_packet.h" + +#ifdef USES_ESPEASY_NOW + +class ESPEasy_now_splitter { +public: + + ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_type, size_t totalSize); + + size_t addBinaryData(const uint8_t *data, + size_t length); + + size_t addString(const String& string); + + bool send(uint8_t mac[6]); + +private: + + // Create next packet when needed. + void createNextPacket(size_t data_left); + + size_t getPayloadPos() const; + + void setMac(uint8_t mac[6]); + + bool send(const ESPEasy_Now_packet& packet); + WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, + size_t timeout); + + WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; + + std::vector _queue; + ESPEasy_now_hdr _header; + size_t _payload_pos = 255; // Position in the last packet where we left of. + const size_t _totalSize = 0; // Total size as we intend to send. + size_t _bytesStored = 0; // Total number of bytes already stored as payload + +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_SPLITTER_H From cd0056596456e757fea2bb39cce73c44b8bc5424 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 14 May 2020 14:07:02 +0200 Subject: [PATCH 017/404] [ESPEasy-Now] Add message splitter to create multi-packet messages --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 92 ++++++------ src/src/DataStructs/ESPEasy_Now_packet.h | 8 +- src/src/DataStructs/ESPEasy_now_merger.cpp | 104 ++++++++------ src/src/DataStructs/ESPEasy_now_merger.h | 13 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 141 ++++++++++++++----- src/src/DataStructs/ESPEasy_now_splitter.h | 33 +++-- src/src/Helpers/ESPEasy_now_handler.cpp | 76 ++-------- src/src/Helpers/ESPEasy_now_handler.h | 8 +- 8 files changed, 267 insertions(+), 208 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 6e99db916a..c08d2f8b11 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -2,10 +2,11 @@ #ifdef USES_ESPEASY_NOW +# include "../../ESPEasy_fdwdecl.h" # define ESPEASY_NOW_MAX_PACKET_SIZE 250 -ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr &header, size_t payloadSize) +ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { setSize(payloadSize + sizeof(ESPEasy_now_hdr)); setHeader(header); @@ -36,6 +37,7 @@ size_t ESPEasy_Now_packet::getSize() const size_t ESPEasy_Now_packet::getPayloadSize() const { size_t size = getSize(); + if (size < sizeof(ESPEasy_now_hdr)) { // should not happen return 0; @@ -51,12 +53,11 @@ size_t ESPEasy_Now_packet::getMaxPayloadSize() ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const { ESPEasy_now_hdr header; + if (getSize() >= sizeof(ESPEasy_now_hdr)) { memcpy(&header, &_buf[0], sizeof(ESPEasy_now_hdr)); } - if (!header.checksumValid()) { - header.message_type = ESPEasy_now_hdr::message_t::ChecksumError; - } + return header; } @@ -68,23 +69,9 @@ void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) { - const size_t payload_size = getPayloadSize() - 1; - - if (payload_pos > payload_size) { - return 0; - } - size_t bytesToWrite = string.length() + 1; // include null-termination - const size_t payload_free = payload_size - payload_pos; + size_t length = string.length() + 1; // Try to Store the extra null-termination (may fail) - if (bytesToWrite > payload_free) { - bytesToWrite = payload_free; - } - - // Copy the string including null-termination. - size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); - memcpy(&_buf[buf_pos], reinterpret_cast(string.c_str()), bytesToWrite); - payload_pos += bytesToWrite; - return bytesToWrite; + return addBinaryData(reinterpret_cast(string.c_str()), length, payload_pos); } void ESPEasy_Now_packet::setMac(uint8_t mac[6]) @@ -100,52 +87,73 @@ void ESPEasy_Now_packet::setBroadcast() } } -size_t ESPEasy_Now_packet::addBinaryData(const uint8_t* data, size_t length) +size_t ESPEasy_Now_packet::addBinaryData(const uint8_t *data, size_t length, + size_t& payload_pos) { - const size_t payload_size = getPayloadSize(); - if (length > payload_size) { - length = payload_size; + size_t bytes_left = getPayloadSize(); + + if (payload_pos > bytes_left) { return 0; } + bytes_left -= payload_pos; + + if (length > bytes_left) { + length = bytes_left; } - size_t buf_pos = sizeof(ESPEasy_now_hdr); + size_t buf_pos = sizeof(ESPEasy_now_hdr) + payload_pos; memcpy(&_buf[buf_pos], data, length); + payload_pos += length; return length; } -size_t ESPEasy_Now_packet::getBinaryData(uint8_t* data, size_t length) const +size_t ESPEasy_Now_packet::getBinaryData(uint8_t *data, size_t length, + size_t& payload_pos) const { - const size_t payload_size = getPayloadSize(); - if (length > payload_size) { - length = payload_size; + size_t bytes_left = getPayloadSize(); + + if (payload_pos > bytes_left) { return 0; } + bytes_left -= payload_pos; + + if (length > bytes_left) { + length = bytes_left; } - size_t buf_pos = sizeof(ESPEasy_now_hdr); + size_t buf_pos = sizeof(ESPEasy_now_hdr) + payload_pos; memcpy(data, &_buf[buf_pos], length); + payload_pos += length; return length; } String ESPEasy_Now_packet::getString(size_t& payload_pos) const { String res; - const size_t size = getSize(); - size_t buf_pos = payload_pos + sizeof(ESPEasy_now_hdr); - - while (buf_pos < size && _buf[buf_pos] == 0) { - ++buf_pos; - ++payload_pos; - } + size_t bytes_left = getPayloadSize(); - if (buf_pos >= size) { return res; } - - const size_t maxlen = size - buf_pos; - size_t strlength = strnlen(reinterpret_cast(&_buf[buf_pos]), maxlen); + if (payload_pos > bytes_left) { return res; } + bytes_left -= payload_pos; + size_t buf_pos = sizeof(ESPEasy_now_hdr) + payload_pos; + size_t strlength = strnlen(reinterpret_cast(&_buf[buf_pos]), bytes_left); res.reserve(strlength); const size_t max_buf_pos = buf_pos + strlength; - for ( ; buf_pos < max_buf_pos; ++buf_pos, ++payload_pos) { + for (; buf_pos < max_buf_pos; ++buf_pos, ++payload_pos) { res += static_cast(_buf[buf_pos]); } return res; } +String ESPEasy_Now_packet::getLogString() const +{ + ESPEasy_now_hdr header = getHeader(); + String log; + log.reserve(30); + log += formatMAC(_mac); + log += F(" ("); + log += header.packet_nr; + log += '/'; + log += header.nr_packets; + log += ')'; + return log; +} + + const uint8_t * ESPEasy_Now_packet::begin() const { return &_buf[sizeof(ESPEasy_now_hdr)]; diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 6932daeb0f..dec5465a67 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -36,9 +36,11 @@ class ESPEasy_Now_packet { void setBroadcast(); - size_t addBinaryData(const uint8_t* data, size_t length); + size_t addBinaryData(const uint8_t* data, size_t length, + size_t & payload_pos); - size_t getBinaryData(uint8_t* data, size_t length) const; + size_t getBinaryData(uint8_t* data, size_t length, + size_t & payload_pos) const; // Add a string to the packet, starting at payload position payload_pos // Return the number of bytes added (can be 1 more than the given string) @@ -56,6 +58,8 @@ class ESPEasy_Now_packet { return &_buf[idx]; } + String getLogString() const; + uint8_t _mac[6] = { 0 }; private: diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index b370ccac3b..7924120af5 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -2,8 +2,8 @@ #ifdef USES_ESPEASY_NOW -#include "../Helpers/ESPEasy_time_calc.h" -#include "../../ESPEasy_fdwdecl.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../../ESPEasy_fdwdecl.h" ESPEasy_now_merger::ESPEasy_now_merger() { _firstPacketTimestamp = millis(); @@ -44,15 +44,17 @@ ESPEasy_now_hdr ESPEasy_now_merger::getFirstHeader() const { ESPEasy_now_hdr header; auto it = _queue.find(0); + if (it != _queue.end()) { header = it->second.getHeader(); } return header; } -bool ESPEasy_now_merger::getMac(uint8_t* mac) const +bool ESPEasy_now_merger::getMac(uint8_t *mac) const { auto it = _queue.find(0); + if (it == _queue.end()) { return false; } @@ -63,9 +65,9 @@ bool ESPEasy_now_merger::getMac(uint8_t* mac) const String ESPEasy_now_merger::getLogString() const { uint8_t mac[6] = { 0 }; + getMac(mac); String log; - log = F("ESPEasyNow: Message from "); log += formatMAC(mac); log += F(" ("); log += _queue.size(); @@ -77,8 +79,9 @@ String ESPEasy_now_merger::getLogString() const size_t ESPEasy_now_merger::getPayloadSize() const { - if (!messageComplete()) return 0; + if (!messageComplete()) { return 0; } size_t payloadSize = 0; + for (auto it = _queue.begin(); it != _queue.end(); ++it) { payloadSize += it->second.getPayloadSize(); } @@ -87,64 +90,83 @@ size_t ESPEasy_now_merger::getPayloadSize() const String ESPEasy_now_merger::getString(size_t& payload_pos) const { + const size_t bufsize = 128; + std::vector buf; + + buf.resize(bufsize); + String res; - size_t packet_start_payload_pos; - uint8_t packet_nr = findPacketWithPayloadPos(payload_pos, packet_start_payload_pos); - if (packet_nr >= getFirstHeader().nr_packets) - return res; - - auto it = _queue.find(packet_nr); - size_t offset = payload_pos - packet_start_payload_pos; - while (it != _queue.end()) { - { - String tmp = it->second.getString(offset); - res += tmp; - size_t tmp_len = tmp.length(); - payload_pos += tmp_len; - if (tmp_len < (it->second.getPayloadSize() - offset)) { - // FIXME TD-er: Must store the length in the multi-packet. - // All is read. - return res; + res.reserve(bufsize * 2); + + bool done = false; + + // We do fetch more data from the message than the string size, so copy payload_pos first + size_t tmp_payload_pos = payload_pos; + + while (!done) { + size_t received = getBinaryData(&buf[0], bufsize, tmp_payload_pos); + + for (size_t buf_pos = 0; buf_pos < received && !done; ++buf_pos) { + char c = static_cast(buf[buf_pos]); + + if (c == 0) { + done = true; + } else { + res += c; } } - offset = 0; - ++packet_nr; - it = _queue.find(packet_nr); + + if (received < bufsize) { done = true; } } + payload_pos += res.length() + 1; // Store the position of the null termination return res; } -size_t ESPEasy_now_merger::getBinaryData(uint8_t* data, size_t length) const +size_t ESPEasy_now_merger::getBinaryData(uint8_t *data, size_t length, size_t& payload_pos) const { - uint8_t packet_nr = 0; - auto it = _queue.find(packet_nr); + size_t payload_pos_in_packet; + uint8_t packet_nr = findPacketWithPayloadPos(payload_pos, payload_pos_in_packet); + + if (packet_nr >= getFirstHeader().nr_packets) { + return 0; + } + + auto it = _queue.find(packet_nr); size_t data_pos = 0; + while (it != _queue.end() && data_pos < length) { - size_t added_length = it->second.getBinaryData(data, length - data_pos); - data += added_length; + size_t added_length = it->second.getBinaryData(data, length - data_pos, payload_pos_in_packet); + data += added_length; data_pos += added_length; + + // Continue in next packet + payload_pos_in_packet = 0; ++packet_nr; it = _queue.find(packet_nr); } return data_pos; } -uint8_t ESPEasy_now_merger::findPacketWithPayloadPos(size_t payload_pos , size_t & packet_start_payload_pos) const +uint8_t ESPEasy_now_merger::findPacketWithPayloadPos(size_t payload_pos, size_t& payload_pos_in_packet) const { // First find the place in the queue to continue based on the payload_pos uint8_t packet_nr = 0; - auto it = _queue.find(packet_nr); - packet_start_payload_pos = 0; - while (it != _queue.end()) { - if (packet_start_payload_pos <= payload_pos) { - if ((packet_start_payload_pos + it->second.getPayloadSize()) > payload_pos) { - return packet_nr; - } - packet_start_payload_pos += it->second.getPayloadSize(); + payload_pos_in_packet = 0; + auto it = _queue.find(packet_nr); + + // Position in message payload at the start of a packet + size_t packet_start_payload_pos = 0; - ++packet_nr; - it = _queue.find(packet_nr); + while (it != _queue.end() && packet_start_payload_pos <= payload_pos) { + if ((packet_start_payload_pos + it->second.getPayloadSize()) >= payload_pos) { + // Message payload position is in current packet. + payload_pos_in_packet = payload_pos - packet_start_payload_pos; + return packet_nr; } + packet_start_payload_pos += it->second.getPayloadSize(); + + ++packet_nr; + it = _queue.find(packet_nr); } return 255; // Error value } diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index e70bda3f90..3ed87823f5 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -40,21 +40,24 @@ class ESPEasy_now_merger { // payload_pos will contain the new position to start for a next string String getString(size_t& payload_pos) const; - size_t getBinaryData(uint8_t* data, size_t length) const; + size_t getBinaryData(uint8_t *data, + size_t length, + size_t & payload_pos) const; ESPEasy_now_hdr getFirstHeader() const; - bool getMac(uint8_t* mac) const; + bool getMac(uint8_t *mac) const; - String getLogString() const; + String getLogString() const; private: + // Find packet + payload position in packet for payload_pos of entire message uint8_t findPacketWithPayloadPos(size_t payload_pos, - size_t& packet_start_payload_pos) const; + size_t& payload_pos_in_packet) const; unsigned long _firstPacketTimestamp = 0; - std::map _queue; + std::map_queue; uint8_t _nr_packets = 255; }; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index c288e695fe..08500606b7 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -2,6 +2,9 @@ #ifdef USES_ESPEASY_NOW +# include "../../ESPEasy_Log.h" +# include "../Helpers/ESPEasy_time_calc.h" + static uint8_t ESPEasy_now_message_count = 1; ESPEasy_now_splitter::ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_type, size_t totalSize) @@ -14,12 +17,11 @@ size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) { size_t data_left = length; - while (data_left > 0) { - createNextPacket(data_left); - size_t bytesAdded = _queue.back().addBinaryData(data, data_left); + while ((data_left > 0) && (_totalSize > _bytesStored)) { + createNextPacket(); + size_t bytesAdded = _queue.back().addBinaryData(data, data_left, _payload_pos); data_left -= bytesAdded; data += bytesAdded; - _payload_pos += bytesAdded; _bytesStored += bytesAdded; } return length; @@ -28,38 +30,31 @@ size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) size_t ESPEasy_now_splitter::addString(const String& string) { size_t length = string.length() + 1; // Store the extra null-termination + return addBinaryData(reinterpret_cast(string.c_str()), length); } -bool ESPEasy_now_splitter::send(uint8_t mac[6]) -{} - - -void ESPEasy_now_splitter::createNextPacket(size_t data_left) +void ESPEasy_now_splitter::createNextPacket() { - size_t maxPayloadSize = ESPEasy_Now_packet::getMaxPayloadSize() - 1; - - if (maxPayloadSize > _payload_pos) { - if ((_payload_pos + data_left) == maxPayloadSize) { - // Special case where we must decrease next packet slightly - maxPayloadSize -= 2; - } else { - // No need to create a new file yet - return; - } + size_t current_PayloadSize = ESPEasy_Now_packet::getMaxPayloadSize(); + if (_queue.size() > 0) { + current_PayloadSize = _queue.back().getPayloadSize(); + } + + if (current_PayloadSize > _payload_pos) { + // No need to create a new file yet + /* + String log; + log = F("createNextPacket "); + log += data_left; + addLog(LOG_LEVEL_INFO, log); + */ + return; } // Determine size of next packet size_t message_bytes_left = _totalSize - _bytesStored; - size_t packetSize = message_bytes_left; - - if (packetSize > maxPayloadSize) { - packetSize = maxPayloadSize; - } - if (packetSize == data_left) { - packetSize -= 2; - } - _queue.emplace_back(_header, packetSize); + _queue.emplace_back(_header, message_bytes_left); _payload_pos = 0; // Set the packet number for the next packet. @@ -67,18 +62,92 @@ void ESPEasy_now_splitter::createNextPacket(size_t data_left) _header.packet_nr++; } -void ESPEasy_now_splitter::setMac(uint8_t mac[6]) -{} +bool ESPEasy_now_splitter::sendToBroadcast() +{ + uint8_t mac[6]; + + for (int i = 0; i < 6; ++i) { + mac[i] = 0xFF; + } + return send(mac); +} + +bool ESPEasy_now_splitter::send(uint8_t mac[6]) +{ + prepareForSend(mac); + + const size_t nr_packets = _queue.size(); + + for (uint8_t i = 0; i < nr_packets; ++i) { + if (!send(_queue[i])) { return false; } + } + return true; +} + +WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) +{ + prepareForSend(mac); + + WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; + + const size_t nr_packets = _queue.size(); + + for (uint8_t i = 0; i < nr_packets; ++i) { + if (!send(_queue[i])) { return WifiEspNowSendStatus::NONE; } + sendStatus = waitForSendStatus(timeout); + + if (sendStatus == WifiEspNowSendStatus::NONE) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy Now: TIMEOUT to: "); + log += _queue[i].getLogString(); + addLog(LOG_LEVEL_INFO, log); + } + return sendStatus; + } + } + return sendStatus; +} -bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) -{} +bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) +{ + bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + delay(0); -WifiEspNowSendStatus ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, - size_t timeout) -{} + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + + if (success) { + log = F("ESPEasy Now: Sent to: "); + } else { + log = F("ESPEasy Now: Sent FAILED to: "); + } + log += packet.getLogString(); + addLog(LOG_LEVEL_INFO, log); + } + return success; +} WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) const -{} +{ + WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; + while (!timeOutReached(timeout) && sendStatus == WifiEspNowSendStatus::NONE) { + sendStatus = WifiEspNow.getSendStatus(); + delay(1); + } + return sendStatus; +} + +void ESPEasy_now_splitter::prepareForSend(uint8_t mac[6]) +{ + size_t nr_packets = _queue.size(); + + for (uint8_t i = 0; i < nr_packets; ++i) { + ESPEasy_now_hdr header = _queue[i].getHeader(); + header.nr_packets = nr_packets; + _queue[i].setHeader(header); + _queue[i].setMac(mac); + } +} #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index a151719d29..0a64ad0558 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -8,36 +8,39 @@ class ESPEasy_now_splitter { public: - ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_type, size_t totalSize); + ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_type, + size_t totalSize); - size_t addBinaryData(const uint8_t *data, - size_t length); + size_t addBinaryData(const uint8_t *data, + size_t length); - size_t addString(const String& string); + size_t addString(const String& string); - bool send(uint8_t mac[6]); + bool sendToBroadcast(); + bool send(uint8_t mac[6]); + + WifiEspNowSendStatus send(uint8_t mac[6], + size_t timeout); private: // Create next packet when needed. - void createNextPacket(size_t data_left); - - size_t getPayloadPos() const; + void createNextPacket(); - void setMac(uint8_t mac[6]); + size_t getPayloadPos() const; bool send(const ESPEasy_Now_packet& packet); - WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, - size_t timeout); + + void prepareForSend(uint8_t mac[6]); + WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; - std::vector _queue; + std::vector_queue; ESPEasy_now_hdr _header; - size_t _payload_pos = 255; // Position in the last packet where we left of. + size_t _payload_pos = 255; // Position in the last packet where we left of. const size_t _totalSize = 0; // Total size as we intend to send. - size_t _bytesStored = 0; // Total number of bytes already stored as payload - + size_t _bytesStored = 0; // Total number of bytes already stored as payload }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d79031ae0f..f05008efc0 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -4,6 +4,7 @@ # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" @@ -120,11 +121,9 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) thisNode.setLocalData(); size_t len = sizeof(NodeStruct); - ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::Announcement); - ESPEasy_Now_packet msg(header, len); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); msg.addBinaryData(reinterpret_cast(&thisNode), len); - msg.setBroadcast(); - send(msg); + msg.sendToBroadcast(); } bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) @@ -138,25 +137,23 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const bool processed = false; if (ControllerSettings.enableESPEasyNowFallback() /*&& !WiFiConnected(10) */) { - const size_t topic_length = topic.length(); - const size_t payload_length = payload.length(); + // each string has null termination + const size_t topic_length = topic.length() +1; + const size_t payload_length = payload.length() +1; // Todo: Add cpluginID_t cpluginID; to the message - size_t len = topic_length + payload_length + 1; + size_t len = topic_length + payload_length; - ESPEasy_now_hdr header(ESPEasy_now_hdr::message_t::MQTTControllerMessage); - ESPEasy_Now_packet msg(header, len); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTControllerMessage, len); - size_t pos = 0; - msg.addString(topic, pos); - msg.addString(payload, pos); + msg.addString(topic); + msg.addString(payload); for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX && !processed; ++peer) { // FIXME TD-er: This must be optimized to keep the last working index. // Or else it may take quite a while to send each message if (SecuritySettings.peerMacSet(peer)) { - msg.setMac(SecuritySettings.EspEasyNowPeerMAC[peer]); - WifiEspNowSendStatus sendStatus = send(msg, millis() + ControllerSettings.ClientTimeout); + WifiEspNowSendStatus sendStatus = msg.send(SecuritySettings.EspEasyNowPeerMAC[peer], millis() + ControllerSettings.ClientTimeout); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -172,51 +169,6 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return processed; } -bool ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet) { - bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - - if (success) { - log = F("ESPEasy Now: Sent to: "); - } else { - log = F("ESPEasy Now: Sent FAILED to: "); - } - log += formatMAC(packet._mac); - addLog(LOG_LEVEL_INFO, log); - } - return success; -} - -WifiEspNowSendStatus ESPEasy_now_handler_t::send(const ESPEasy_Now_packet& packet, size_t timeout) -{ - if (!send(packet)) { - return WifiEspNowSendStatus::NONE; - } - WifiEspNowSendStatus sendStatus = waitForSendStatus(timeout); - - if (sendStatus == WifiEspNowSendStatus::NONE) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy Now: TIMEOUT to: "); - log += formatMAC(packet._mac); - addLog(LOG_LEVEL_INFO, log); - } - } - return sendStatus; -} - -WifiEspNowSendStatus ESPEasy_now_handler_t::waitForSendStatus(size_t timeout) const -{ - WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; - - while (!timeOutReached(timeout) && sendStatus == WifiEspNowSendStatus::NONE) { - sendStatus = WifiEspNow.getSendStatus(); - delay(1); - } - return sendStatus; -} - bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) { @@ -246,7 +198,9 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m { NodeStruct received; - message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct)); + // Discovery messages have a single binary blob, starting at 0 + size_t payload_pos = 0; + message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); Nodes.addNode(received); if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -256,7 +210,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); log = F("ESPEasy Now discovery: "); - log += formatMAC(mac); + log += message.getLogString(); log += '\n'; log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 33f9848105..c99a2cb243 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -30,13 +30,9 @@ class ESPEasy_now_handler_t { const String & topic, const String & payload); -private: - - bool send(const ESPEasy_Now_packet& packet); - WifiEspNowSendStatus send(const ESPEasy_Now_packet& packet, - size_t timeout); + - WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; +private: bool processMessage(const ESPEasy_now_merger& message); From 42bc129197d62704c096c70998672a21af08c366 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 14 May 2020 16:53:43 +0200 Subject: [PATCH 018/404] [ESPEasy-Now] Fix in storing binary data Payload_pos value was not updated. This could lead to issues when appending multiple blobs of data, when storing after a binary blob. --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 4 +++- src/src/DataStructs/ESPEasy_now_merger.cpp | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index c08d2f8b11..6707e0c02c 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -145,8 +145,10 @@ String ESPEasy_Now_packet::getLogString() const String log; log.reserve(30); log += formatMAC(_mac); + log += F(" payload: "); + log += getPayloadSize(); log += F(" ("); - log += header.packet_nr; + log += header.packet_nr + 1; log += '/'; log += header.nr_packets; log += ')'; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 7924120af5..a3772a86ff 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -69,6 +69,8 @@ String ESPEasy_now_merger::getLogString() const getMac(mac); String log; log += formatMAC(mac); + log += F(" payload: "); + log += getPayloadSize(); log += F(" ("); log += _queue.size(); log += '/'; @@ -144,6 +146,7 @@ size_t ESPEasy_now_merger::getBinaryData(uint8_t *data, size_t length, size_t& p ++packet_nr; it = _queue.find(packet_nr); } + payload_pos += data_pos; return data_pos; } From d12992a439bb8c8af10bf9533cb39017485d3c0c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 14 May 2020 20:34:23 +0200 Subject: [PATCH 019/404] [ESPEasy-Now] Use packet checksum --- src/ESPEasy_fdwdecl.h | 2 + src/StringProvider.ino | 9 ++++- src/src/DataStructs/ESPEasy_Now_packet.cpp | 14 ++++++- src/src/DataStructs/ESPEasy_Now_packet.h | 24 +++++++----- src/src/DataStructs/ESPEasy_now_hdr.cpp | 39 +++++--------------- src/src/DataStructs/ESPEasy_now_hdr.h | 27 +++++--------- src/src/DataStructs/ESPEasy_now_merger.cpp | 3 +- src/src/DataStructs/ESPEasy_now_merger.h | 8 ++-- src/src/DataStructs/ESPEasy_now_splitter.cpp | 13 ++++--- src/src/Helpers/ESPEasy_now_handler.cpp | 25 +++++++++---- src/src/Helpers/ESPEasy_now_handler.h | 3 -- 11 files changed, 87 insertions(+), 80 deletions(-) diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index 3eb8bf3beb..a4a63202be 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -83,6 +83,8 @@ bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char void flushAndDisconnectAllClients(); +int calc_CRC16(const char *ptr, int count); + // Used in src/Commands/* void process_serialWriteBuffer(); void serialPrintln(const String& text); diff --git a/src/StringProvider.ino b/src/StringProvider.ino index 207c000c03..27c51c988a 100644 --- a/src/StringProvider.ino +++ b/src/StringProvider.ino @@ -229,7 +229,14 @@ String getValue(LabelType::Enum label) { case LabelType::CONNECTION_FAIL_THRESH: return String(Settings.ConnectionFailuresThreshold); case LabelType::BUILD_DESC: return String(BUILD); - case LabelType::GIT_BUILD: return String(F(BUILD_GIT)); + case LabelType::GIT_BUILD: + { + String res = F(BUILD_GIT); + if (res.length() == 0) { + return getValue(LabelType::BUILD_TIME); + } + return res; + } case LabelType::SYSTEM_LIBRARIES: return getSystemLibraryString(); case LabelType::PLUGIN_COUNT: return String(deviceCount + 1); case LabelType::PLUGIN_DESCRIPTION: return getPluginDescriptionString(); diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 6707e0c02c..969bfc092d 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -29,6 +29,16 @@ void ESPEasy_Now_packet::setSize(size_t packetSize) } } +uint16_t ESPEasy_Now_packet::computeChecksum() const +{ + return calc_CRC16(reinterpret_cast(begin()), getPayloadSize()); +} + +bool ESPEasy_Now_packet::checksumValid() const +{ + return getHeader().checksum == computeChecksum(); +} + size_t ESPEasy_Now_packet::getSize() const { return _buf.size(); @@ -63,7 +73,7 @@ ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) { - header.setChecksum(); + header.checksum = computeChecksum(); memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); } @@ -143,6 +153,7 @@ String ESPEasy_Now_packet::getLogString() const { ESPEasy_now_hdr header = getHeader(); String log; + log.reserve(30); log += formatMAC(_mac); log += F(" payload: "); @@ -155,7 +166,6 @@ String ESPEasy_Now_packet::getLogString() const return log; } - const uint8_t * ESPEasy_Now_packet::begin() const { return &_buf[sizeof(ESPEasy_now_hdr)]; diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index dec5465a67..276dded146 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -8,8 +8,8 @@ # include "ESPEasy_now_hdr.h" -#include -#include +# include +# include class ESPEasy_Now_packet { public: @@ -22,11 +22,13 @@ class ESPEasy_Now_packet { const uint8_t *buf, size_t packetSize); + bool checksumValid() const; + size_t getSize() const; size_t getPayloadSize() const; - static size_t getMaxPayloadSize(); + static size_t getMaxPayloadSize(); ESPEasy_now_hdr getHeader() const; @@ -36,11 +38,13 @@ class ESPEasy_Now_packet { void setBroadcast(); - size_t addBinaryData(const uint8_t* data, size_t length, - size_t & payload_pos); + size_t addBinaryData(const uint8_t *data, + size_t length, + size_t & payload_pos); - size_t getBinaryData(uint8_t* data, size_t length, - size_t & payload_pos) const; + size_t getBinaryData(uint8_t *data, + size_t length, + size_t & payload_pos) const; // Add a string to the packet, starting at payload position payload_pos // Return the number of bytes added (can be 1 more than the given string) @@ -58,7 +62,7 @@ class ESPEasy_Now_packet { return &_buf[idx]; } - String getLogString() const; + String getLogString() const; uint8_t _mac[6] = { 0 }; @@ -66,7 +70,9 @@ class ESPEasy_Now_packet { std::vector_buf; - void setSize(size_t packetSize); + void setSize(size_t packetSize); + + uint16_t computeChecksum() const; }; typedef std::list ESPEasy_Now_packet_list; diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index 18e74fa293..f8629f95f9 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -7,40 +7,19 @@ ESPEasy_now_hdr::ESPEasy_now_hdr() {} ESPEasy_now_hdr::ESPEasy_now_hdr(ESPEasy_now_hdr::message_t messageType) : message_type(messageType) {} -ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr &other) +ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr& other) { - if(&other == this) + if (&other == this) { return *this; + } header_version = other.header_version; - message_type = other.message_type; - packet_nr = other.packet_nr; - nr_packets = other.nr_packets; - message_count = other.message_count; - notUsed1 = other.notUsed1; - checksum = other.checksum; + message_type = other.message_type; + packet_nr = other.packet_nr; + nr_packets = other.nr_packets; + message_count = other.message_count; + notUsed1 = other.notUsed1; + checksum = other.checksum; return *this; } -void ESPEasy_now_hdr::setChecksum() -{ - checksum = computeChecksum(); -} - -bool ESPEasy_now_hdr::checksumValid() const -{ - return computeChecksum() == checksum; -} - -uint8_t ESPEasy_now_hdr::computeChecksum() const -{ - // TODO TD-er: Maybe better to have this as a for loop over *this - uint8_t res = header_version; - res ^= static_cast(message_type); - res ^= packet_nr; - res ^= nr_packets; - res ^= message_count; - res ^= notUsed1; - return res; -} - #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 67880c406a..2ac96bf005 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -10,9 +10,11 @@ # include -# define ESPEASY_NOW_HEADER_VERSION 1 +# define ESPEASY_NOW_HEADER_VERSION 2 + +class __attribute__((__packed__)) ESPEasy_now_hdr { +public: -struct ESPEasy_now_hdr { // Do not change the order of this enum as the value will be sent to other nodes. enum class message_t : uint8_t { NotSet = 0, @@ -29,23 +31,14 @@ struct ESPEasy_now_hdr { ESPEasy_now_hdr& operator=(const ESPEasy_now_hdr& other); - void setChecksum(); - - bool checksumValid() const; - -private: - - uint8_t computeChecksum() const; - -public: uint8_t header_version = ESPEASY_NOW_HEADER_VERSION; // To be used later to detect newer versions - message_t message_type = message_t::NotSet; - uint8_t packet_nr = 0; // Current message number (start at 0) - uint8_t nr_packets = 1; // The highest message number of this sequence - uint8_t message_count = 1; // A set of messages all have the same message_count - uint8_t notUsed1 = 0; // reserved - uint8_t checksum = 0; // checksum + message_t message_type = message_t::NotSet; + uint8_t packet_nr = 0; // Current message number (start at 0) + uint8_t nr_packets = 1; // The highest message number of this sequence + uint8_t message_count = 1; // A set of messages all have the same message_count + uint8_t notUsed1 = 0; // reserved + uint16_t checksum = 0; // checksum of the packet }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index a3772a86ff..3cbb1343a5 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -154,8 +154,9 @@ uint8_t ESPEasy_now_merger::findPacketWithPayloadPos(size_t payload_pos, size_t& { // First find the place in the queue to continue based on the payload_pos uint8_t packet_nr = 0; + payload_pos_in_packet = 0; - auto it = _queue.find(packet_nr); + auto it = _queue.find(packet_nr); // Position in message payload at the start of a packet size_t packet_start_payload_pos = 0; diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 3ed87823f5..d63aad3aa5 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -24,17 +24,17 @@ class ESPEasy_now_merger { size_t packetSize); // Check if all parts of the packet have been received - bool messageComplete() const; + bool messageComplete() const; - uint8_t receivedCount(uint8_t& nr_packets) const; + uint8_t receivedCount(uint8_t& nr_packets) const; // Check of set has expired (not all packets received within timeout) - bool expired() const; + bool expired() const; ESPEasy_Now_packet_map::const_iterator find(uint8_t packet_nr) const; // Get combined size of all packets. - size_t getPayloadSize() const; + size_t getPayloadSize() const; // Return a string starting from position pos in the buffer. // payload_pos will contain the new position to start for a next string diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 08500606b7..f48c4a512c 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -37,18 +37,20 @@ size_t ESPEasy_now_splitter::addString(const String& string) void ESPEasy_now_splitter::createNextPacket() { size_t current_PayloadSize = ESPEasy_Now_packet::getMaxPayloadSize(); + if (_queue.size() > 0) { current_PayloadSize = _queue.back().getPayloadSize(); } if (current_PayloadSize > _payload_pos) { // No need to create a new file yet + /* - String log; - log = F("createNextPacket "); - log += data_left; - addLog(LOG_LEVEL_INFO, log); - */ + String log; + log = F("createNextPacket "); + log += data_left; + addLog(LOG_LEVEL_INFO, log); + */ return; } @@ -111,6 +113,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) { bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + delay(0); if (loglevelActiveFor(LOG_LEVEL_INFO)) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f05008efc0..a5c43ac055 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -38,7 +38,16 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t ESPEasy_now_hdr header; memcpy(&header, buf, sizeof(ESPEasy_now_hdr)); - if (!header.checksumValid()) { + if (header.header_version != ESPEASY_NOW_HEADER_VERSION) { + return; + } + + size_t payload_length = count - sizeof(ESPEasy_now_hdr); + const uint8_t *payload = buf + sizeof(ESPEasy_now_hdr); + + const uint16_t checksum = calc_CRC16(reinterpret_cast(payload), payload_length); + + if (header.checksum != checksum) { return; } uint64_t key = mac_to_key(mac, header.message_type, header.message_count); @@ -98,11 +107,12 @@ bool ESPEasy_now_handler_t::loop() } } else { // Process it - somethingProcessed = processMessage(it->second); + somethingProcessed = processMessage(it->second); } if (removeMessage) { it = ESPEasy_now_in_queue.erase(it); + // FIXME TD-er: For now only process one item and then wait for the next loop. if (somethingProcessed) { return true; @@ -138,8 +148,8 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (ControllerSettings.enableESPEasyNowFallback() /*&& !WiFiConnected(10) */) { // each string has null termination - const size_t topic_length = topic.length() +1; - const size_t payload_length = payload.length() +1; + const size_t topic_length = topic.length() + 1; + const size_t payload_length = payload.length() + 1; // Todo: Add cpluginID_t cpluginID; to the message size_t len = topic_length + payload_length; @@ -171,7 +181,6 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) { - addLog(LOG_LEVEL_INFO, message.getLogString()); bool handled = false; @@ -193,19 +202,19 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) return handled; } - bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) { NodeStruct received; // Discovery messages have a single binary blob, starting at 0 size_t payload_pos = 0; + message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); Nodes.addNode(received); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - uint8_t mac[6] = {0}; + String log; + uint8_t mac[6] = { 0 }; message.getMac(mac); size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index c99a2cb243..b6b2db9410 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -30,8 +30,6 @@ class ESPEasy_now_handler_t { const String & topic, const String & payload); - - private: bool processMessage(const ESPEasy_now_merger& message); @@ -40,7 +38,6 @@ class ESPEasy_now_handler_t { bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message); bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message); - }; From dd134b52398704d64f37fcf2164fcc6a9148f7ad Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 16 May 2020 15:37:18 +0200 Subject: [PATCH 020/404] [ESPEasy Now] Add timing stats --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 +- src/src/DataStructs/ESPEasy_now_merger.cpp | 2 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 64 +++++++++++++------- src/src/DataStructs/TimingStats.cpp | 6 ++ src/src/DataStructs/TimingStats.h | 7 +++ src/src/Helpers/ESPEasy_now_handler.cpp | 7 ++- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 969bfc092d..af07575e12 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -4,7 +4,7 @@ # include "../../ESPEasy_fdwdecl.h" -# define ESPEASY_NOW_MAX_PACKET_SIZE 250 +# define ESPEASY_NOW_MAX_PACKET_SIZE 200 ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 3cbb1343a5..dc820a0d3e 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -93,7 +93,7 @@ size_t ESPEasy_now_merger::getPayloadSize() const String ESPEasy_now_merger::getString(size_t& payload_pos) const { const size_t bufsize = 128; - std::vector buf; + std::vector buf; buf.resize(bufsize); diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index f48c4a512c..22bbd6e636 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -3,6 +3,7 @@ #ifdef USES_ESPEASY_NOW # include "../../ESPEasy_Log.h" +# include "../DataStructs/TimingStats.h" # include "../Helpers/ESPEasy_time_calc.h" static uint8_t ESPEasy_now_message_count = 1; @@ -88,6 +89,7 @@ bool ESPEasy_now_splitter::send(uint8_t mac[6]) WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) { + START_TIMER; prepareForSend(mac); WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; @@ -95,39 +97,59 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - if (!send(_queue[i])) { return WifiEspNowSendStatus::NONE; } + send(_queue[i]); sendStatus = waitForSendStatus(timeout); - if (sendStatus == WifiEspNowSendStatus::NONE) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy Now: TIMEOUT to: "); - log += _queue[i].getLogString(); - addLog(LOG_LEVEL_INFO, log); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + + switch (sendStatus) { + case WifiEspNowSendStatus::NONE: + { + log = F("ESPEasy Now: TIMEOUT to: "); + break; + } + case WifiEspNowSendStatus::FAIL: + { + log = F("ESPEasy Now: Sent FAILED to: "); + break; + } + case WifiEspNowSendStatus::OK: + { + log = F("ESPEasy Now: Sent to: "); + break; + } + } + log += _queue[i].getLogString(); + addLog(LOG_LEVEL_INFO, log); + } + + + switch (sendStatus) { + case WifiEspNowSendStatus::NONE: + case WifiEspNowSendStatus::FAIL: + { + STOP_TIMER(ESPEASY_NOW_SEND_MSG_FAIL); + return sendStatus; + } + case WifiEspNowSendStatus::OK: + { + break; } - return sendStatus; } } + STOP_TIMER(ESPEASY_NOW_SEND_MSG_SUC); return sendStatus; } bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) { - bool success = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + START_TIMER; + bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + STOP_TIMER(ESPEASY_NOW_SEND_PCKT); delay(0); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - - if (success) { - log = F("ESPEasy Now: Sent to: "); - } else { - log = F("ESPEasy Now: Sent FAILED to: "); - } - log += packet.getLogString(); - addLog(LOG_LEVEL_INFO, log); - } - return success; + return res; } WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) const diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 1db0984a19..dbbb8f006d 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -228,6 +228,12 @@ String getMiscStatsName(int stat) { case PARSE_SYSVAR: return F("parseSystemVariables()"); case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); + case HANDLE_ESPEASY_NOW_LOOP: return F("Handle Received ESPEasy Now message"); + case EXPIRED_ESPEASY_NOW_LOOP: return F("ESPEasy Now incomplete expired"); + case RECEIVE_ESPEASY_NOW_LOOP: return F("ESPEasy_now_onReceive()"); + case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy Now send Message Success"); + case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy Now send Message Fail"); + case ESPEASY_NOW_SEND_PCKT: return F("ESPEasy Now send Packet"); case C001_DELAY_QUEUE: case C002_DELAY_QUEUE: case C003_DELAY_QUEUE: diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 6c97c8e0eb..ffbc0a818d 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -74,6 +74,13 @@ # define HANDLE_SCHEDULER_IDLE 53 # define HANDLE_SCHEDULER_TASK 54 # define HANDLE_SERVING_WEBPAGE 55 +# define HANDLE_ESPEASY_NOW_LOOP 56 +# define EXPIRED_ESPEASY_NOW_LOOP 57 +# define RECEIVE_ESPEASY_NOW_LOOP 58 +# define ESPEASY_NOW_SEND_MSG_SUC 59 +# define ESPEASY_NOW_SEND_MSG_FAIL 60 +# define ESPEASY_NOW_SEND_PCKT 61 + class TimingStats { public: diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index a5c43ac055..d889514670 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -6,6 +6,7 @@ # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" +# include "../DataStructs/TimingStats.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" # include "../Globals/Settings.h" @@ -35,6 +36,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t if (count < sizeof(ESPEasy_now_hdr)) { return; // Too small } + START_TIMER; ESPEasy_now_hdr header; memcpy(&header, buf, sizeof(ESPEasy_now_hdr)); @@ -52,6 +54,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t } uint64_t key = mac_to_key(mac, header.message_type, header.message_count); ESPEasy_now_in_queue[key].addPacket(header.packet_nr, mac, buf, count); + STOP_TIMER(RECEIVE_ESPEASY_NOW_LOOP); } bool ESPEasy_now_handler_t::begin() @@ -94,9 +97,10 @@ bool ESPEasy_now_handler_t::loop() if (!ESPEasy_now_in_queue.empty()) { for (auto it = ESPEasy_now_in_queue.begin(); it != ESPEasy_now_in_queue.end();) { bool removeMessage = true; - + START_TIMER; if (!it->second.messageComplete()) { if (it->second.expired()) { + STOP_TIMER(EXPIRED_ESPEASY_NOW_LOOP); if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = it->second.getLogString(); log += F(" Expired!"); @@ -108,6 +112,7 @@ bool ESPEasy_now_handler_t::loop() } else { // Process it somethingProcessed = processMessage(it->second); + STOP_TIMER(HANDLE_ESPEASY_NOW_LOOP); } if (removeMessage) { From 7be8e23feae193177f50a71a7643f111d980d2bf Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 16 May 2020 18:43:40 +0200 Subject: [PATCH 021/404] [ESPEasy-Now] Add load and distance to NodeStruct --- src/Networking.ino | 31 +++++++++++++++---------- src/WebServer_RootPage.ino | 3 +++ src/src/DataStructs/NodeStruct.cpp | 27 ++++++++++++++++++++- src/src/DataStructs/NodeStruct.h | 9 ++++++- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 1 + 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/Networking.ino b/src/Networking.ino index c2fdcb06b7..9071d2cadd 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -225,21 +225,23 @@ void checkUDP() } NodeStruct received; memcpy(&received, &packetBuffer[2], copy_length); - Nodes.addNode(received); // Create a new element when not present + if (received.validate()) { + Nodes.addNode(received); // Create a new element when not present #ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - String log; - log.reserve(64); - log = F("UDP : "); - log += formatMAC(received.mac); - log += ','; - log += formatIP(received.ip); - log += ','; - log += received.unit; - addLog(LOG_LEVEL_DEBUG_MORE, log); - } + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + String log; + log.reserve(64); + log = F("UDP : "); + log += formatMAC(received.mac); + log += ','; + log += formatIP(received.ip); + log += ','; + log += received.unit; + addLog(LOG_LEVEL_DEBUG_MORE, log); + } #endif // ifndef BUILD_NO_DEBUG + } break; } @@ -373,6 +375,11 @@ void sendSysInfoUDP(byte repeats) thisNode.setLocalData(); Nodes.addNode(thisNode); + // Prepare UDP packet to send + byte data[80]; + data[0] = 255; + data[1] = 1; + memcpy(&data[2], &thisNode, sizeof(NodeStruct)); for (byte counter = 0; counter < repeats; counter++) { uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 1c5ba45189..36a1ab2171 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -157,6 +157,7 @@ void handle_root() { html_table_header(getLabel(LabelType::BUILD_DESC)); html_table_header("Type"); html_table_header("IP", 160); // Should fit "255.255.255.255" + html_table_header("Load"); html_table_header("Age (s)"); for (auto it = Nodes.begin(); it != Nodes.end(); ++it) @@ -208,6 +209,8 @@ void handle_root() { addHtml(html); } html_TD(); + addHtml(String(it->second.getLoad())); + html_TD(); addHtml(String(it->second.getAge()/1000)); // time in seconds } } diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 969b0eb6f1..9d79d75df3 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -22,8 +22,19 @@ String getNodeTypeDisplayString(byte nodeType) { for (byte i = 0; i < 4; ++i) { ip[i] = 0; } } +bool NodeStruct::validate() { + if (build < 20107) { + // webserverPort introduced in 20107 + webserverPort = 80; + load = 0; + distance = 255; + } + + // FIXME TD-er: Must make some sanity checks to see if it is a valid message + return true; +} -void NodeStruct::setLocalData() { +void NodeStruct::setLocalData() { WiFi.macAddress(mac); WiFi.softAPmacAddress(ap_mac); { @@ -40,6 +51,12 @@ void NodeStruct::setLocalData() { nodeType = NODE_TYPE_ID; // webserverPort = Settings.WebserverPort; // PR #3053 + int load_int = getCPUload() * 2.55; + if (load_int > 255) { + load = 255; + } else { + load = load_int; + } } String NodeStruct::getNodeTypeDisplayString() const { @@ -75,6 +92,10 @@ unsigned long NodeStruct::getAge() const { return timePassedSince(lastSeenTimestamp); } +float NodeStruct::getLoad() const { + return load / 2.55; +} + String NodeStruct::getSummary() const { String res; res.reserve(48); @@ -83,5 +104,9 @@ String NodeStruct::getSummary() const { res += F(" \""); res += getNodeName(); res += '"'; + res += F(" load: "); + res += String(getLoad(), 1); + res += F(" dst: "); + res += distance; return res; } diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index f7f3c4b593..00292372f1 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -22,6 +22,8 @@ struct __attribute__((__packed__)) NodeStruct { NodeStruct(); + bool validate(); + void setLocalData(); String getNodeTypeDisplayString() const; @@ -30,12 +32,13 @@ struct __attribute__((__packed__)) NodeStruct IPAddress IP() const; unsigned long getAge() const; + + float getLoad() const; String getSummary() const; - // Do not change the order of this data, as it is being sent via P2P UDP. // 6 byte mac (STA interface) // 4 byte ip @@ -47,6 +50,8 @@ struct __attribute__((__packed__)) NodeStruct // Added starting build '20107': // 2 bytes webserver port // 6 bytes AP MAC + // 1 byte system load + // 1 byte administrative distance @@ -58,6 +63,8 @@ struct __attribute__((__packed__)) NodeStruct byte nodeType = 0; uint16_t webserverPort = 80; uint8_t ap_mac[6] = { 0 }; // AP mode MAC + uint8_t load = 127; // Default to average load + uint8_t distance = 255; // Administrative distance for routing // Data not being sent to other nodes. unsigned long lastSeenTimestamp = 0; diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 5a06bd2019..956b49fbd5 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -85,7 +85,7 @@ void run_compiletime_checks() { #ifdef USES_NOTIFIER check_size(); #endif - check_size(); + check_size(); check_size(); check_size(); check_size(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d889514670..aa36d2a9be 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -215,6 +215,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m size_t payload_pos = 0; message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); + if (!received.validate()) return false; Nodes.addNode(received); if (loglevelActiveFor(LOG_LEVEL_INFO)) { From 756e35ee0e07b214f3a53fdf1608f55beabc6ae8 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 17 May 2020 01:58:21 +0200 Subject: [PATCH 022/404] [ESPEasy-Now] Add NTP support for peer-2-peer --- src/Networking.ino | 1 + src/_P082_GPS.ino | 2 +- src/src/Commands/Time.cpp | 24 +- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 279 +++++++++++++++ src/src/DataStructs/ESPEasy_Now_NTP_query.h | 58 +++ src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/DataStructs/ESPEasy_now_merger.cpp | 5 + src/src/DataStructs/ESPEasy_now_merger.h | 2 + src/src/DataStructs/ESPEasy_now_splitter.cpp | 9 + src/src/DataStructs/NodeStruct.cpp | 23 +- src/src/DataStructs/NodeStruct.h | 51 ++- src/src/DataStructs/NodesHandler.cpp | 2 +- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 81 ++++- src/src/Helpers/ESPEasy_now_handler.h | 10 + src/src/Helpers/ESPEasy_time.cpp | 140 +++++--- src/src/Helpers/ESPEasy_time.h | 338 ++++++++++-------- 17 files changed, 773 insertions(+), 255 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_Now_NTP_query.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_NTP_query.h diff --git a/src/Networking.ino b/src/Networking.ino index 9071d2cadd..b52a9f002f 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -350,6 +350,7 @@ void refreshNodeList() sendSysInfoUDP(1); #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.sendDiscoveryAnnounce(); + ESPEasy_now_handler.sendNTPquery(); #endif } diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index 569ee649d8..8538a270ac 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -762,7 +762,7 @@ void P082_setSystemTime(struct EventStruct *event) { // and the given offset in centisecond. double time = makeTime(dateTime); time += static_cast(age) / 1000.0; - node_time.setExternalTimeSource(time, GPS_time_source); + node_time.setExternalTimeSource(time, timeSource_t::GPS_time_source); node_time.initTime(); } P082_pps_time = 0; diff --git a/src/src/Commands/Time.cpp b/src/src/Commands/Time.cpp index 0e342393d6..db6cfa274d 100644 --- a/src/src/Commands/Time.cpp +++ b/src/src/Commands/Time.cpp @@ -64,27 +64,27 @@ String Command_DateTime(struct EventStruct *event, const char *Line) String TmpStr1; if (GetArgv(Line, TmpStr1, 2)) { - struct tm tm; + struct tm newtime; int yr, mnth, d; sscanf(TmpStr1.c_str(), "%4d-%2d-%2d", &yr, &mnth, &d); - tm.tm_year = yr - 1970; - tm.tm_mon = mnth; - tm.tm_mday = d; + newtime.tm_year = yr - 1970; + newtime.tm_mon = mnth; + newtime.tm_mday = d; if (GetArgv(Line, TmpStr1, 3)) { int h, m, s; sscanf(TmpStr1.c_str(), "%2d:%2d:%2d", &h, &m, &s); - tm.tm_hour = h; - tm.tm_min = m; - tm.tm_sec = s; + newtime.tm_hour = h; + newtime.tm_min = m; + newtime.tm_sec = s; } else { - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; + newtime.tm_hour = 0; + newtime.tm_min = 0; + newtime.tm_sec = 0; } - node_time.sysTime = makeTime(tm); - node_time.timeSource = Manual_set; + // Please note the time set in this command is in UTC time, not local time. + node_time.setExternalTimeSource(makeTime(newtime), timeSource_t::Manual_set); } else { // serialPrintln(); String result = F("Datetime:"); diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp new file mode 100644 index 0000000000..aa185a0437 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -0,0 +1,279 @@ +#include "ESPEasy_Now_NTP_query.h" + +#ifdef USES_ESPEASY_NOW + + +// Typical time wander for ESP nodes is 0.04 ms/sec +// Meaning per 25 sec, the time may wander 1 msec. +# define TIME_WANDER_FACTOR 25000 + +// Max time it may take to get a reply. +# define MAX_DELAY_FOR_REPLY 5000 + +# define MINIMUM_TIME_BETWEEN_UPDATES (1800 * 1000) // Half an hour + +# include "../Globals/ESPEasy_time.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../../ESPEasy_Log.h" +# include "../../ESPEasy_fdwdecl.h" + +ESPEasy_Now_NTP_query::ESPEasy_Now_NTP_query() +{ + reset(true); +} + +bool ESPEasy_Now_NTP_query::getMac(uint8_t mac[6]) const +{ + if (_timeSource == timeSource_t::No_time_source) { return false; } + + for (byte i = 0; i < 6; ++i) { + mac[i] = _mac[i]; + } + return true; +} + +// Only use peers if there is no external source available. +// A network without external synced source may drift as a whole +// All nodes in the network may be in sync with each other, but get out of sync with the rest of the world. +// Therefore use a strong bias for external synced nodes. +// But also must make sure the same NTP synced node will be held responsible for the entire network. +unsigned long ESPEasy_Now_NTP_query::computeExpectedWander(timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync) +{ + unsigned long expectedWander_ms = timePassedSinceLastTimeSync / TIME_WANDER_FACTOR; + + switch (timeSource) { + case timeSource_t::GPS_PPS_time_source: + { + expectedWander_ms += 1; + break; + } + case timeSource_t::GPS_time_source: + { + expectedWander_ms += 10; + break; + } + case timeSource_t::NTP_time_source: + { + expectedWander_ms += 10; + break; + } + + case timeSource_t::ESP_now_peer: + { + expectedWander_ms += 100; + break; + } + + case timeSource_t::Restore_RTC_time_source: + { + expectedWander_ms += 2000; + break; + } + case timeSource_t::Manual_set: + { + expectedWander_ms += 10000; + break; + } + case timeSource_t::No_time_source: + { + // Cannot sync from it. + return 1 << 30; + } + } + return expectedWander_ms; +} + +void ESPEasy_Now_NTP_query::find_best_NTP(const uint8_t mac[6], + timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync) +{ + if (_millis_out != 0) { + if (timePassedSince(_millis_out) > MAX_DELAY_FOR_REPLY) { + reset(false); + + // A query was sent, but didn't get a reply in time. + } else { + // A query is still pending, so don't add new possible best NTP. + return; + } + } + bool updated = false; + unsigned long expectedWander_ms = + computeExpectedWander(timeSource, timePassedSinceLastTimeSync); + + // First check if it matches the current best candidate. + bool matches_current_best = true; + + for (byte i = 0; i < 6 && matches_current_best; ++i) { + matches_current_best = (_mac[i] == mac[i]); + } + + if (matches_current_best) { + // Update expected wander based on current time since last sync + updated = true; + } else { + if (_expectedWander_ms > expectedWander_ms) { + // We found a good new candidate + bool matches_prev_fail = true; + + for (byte i = 0; i < 6 && matches_prev_fail; ++i) { + matches_prev_fail = (_mac_prev_fail[i] == mac[i]); + } + + if (matches_prev_fail) { + // No need to retry. + return; + } + + for (byte i = 0; i < 6; ++i) { + _mac[i] = mac[i]; + } + updated = true; + } + } + + if (updated) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log.reserve(64); + log = F("ESPEasy Now: Best NTP peer: "); + log += formatMAC(_mac); + log += F(" Wander "); + log += _expectedWander_ms; + log += F(" ms -> "); + log += expectedWander_ms; + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); + } + _timeSource = timeSource; + _expectedWander_ms = expectedWander_ms; + } +} + +void ESPEasy_Now_NTP_query::reset(bool success) +{ + // FIXME TD-er: For now also clear failed MAC. Have to think of a mechanism for multiple failed attempts + success = true; + _unixTime_d = 0.0; + _millis_in = 0; + _millis_out = 0; + _expectedWander_ms = (1 << 30); + _timeSource = timeSource_t::No_time_source; + + for (byte i = 0; i < 6; ++i) { + _mac_prev_fail[i] = success ? 0 : _mac[i]; + } + + for (byte i = 0; i < 6; ++i) { + _mac[i] = 0; + } +} + +bool ESPEasy_Now_NTP_query::hasLowerWander() const +{ + const long timePassed = timePassedSince(node_time.lastSyncTime); + unsigned long currentExpectedWander_ms = computeExpectedWander(node_time.timeSource, timePassed); + + if (node_time.timeSource < _timeSource) { + // Current time source is of better category than the best other. + // So only update from the other if ours was too long ago. + if (currentExpectedWander_ms < 1000) { return false; } + } + + if (node_time.timeSource == _timeSource) { + // Same time source category. + // Try to limit the number of time updates by only accepting updates if time since last sync is over N seconds + if (timePassed < MINIMUM_TIME_BETWEEN_UPDATES) { return false; } + } + + return _expectedWander_ms < currentExpectedWander_ms; +} + +bool ESPEasy_Now_NTP_query::isBroadcast() const +{ + for (byte i = 0; i < 6; ++i) { + if (_mac[i] != 0xFF) { return false; } + } + return true; +} + +void ESPEasy_Now_NTP_query::markSendTime() +{ + _millis_out = millis(); +} + +void ESPEasy_Now_NTP_query::createBroadcastNTP() +{ + for (byte i = 0; i < 6; ++i) + { + _mac[i] = 0xFF; + } + createReply(0); +} + +void ESPEasy_Now_NTP_query::createReply(unsigned long queryReceiveTimestamp) +{ + _millis_in = queryReceiveTimestamp; + node_time.now(); + _timeSource = node_time.timeSource; + _unixTime_d = node_time.sysTime; + _expectedWander_ms = computeExpectedWander(node_time.timeSource, timePassedSince(node_time.lastSyncTime)); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log.reserve(64); + log = F("ESPEasy Now: Create NTP reply to: "); + log += formatMAC(_mac); + log += F(" Wander "); + log += _expectedWander_ms; + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); + } + markSendTime(); +} + +bool ESPEasy_Now_NTP_query::processReply(const ESPEasy_Now_NTP_query& received, unsigned long receiveTimestamp) +{ + if (!received.hasLowerWander()) { return false; } + + bool isBroadcast = received.isBroadcast(); + long air_time = 0; + + if (isBroadcast) { + // Average air time for an ESP-now message is roughly 1 msec. + air_time = 1; + } else { + // Not a broadcast NTP update, so we must have initiated it ourselves. + // Check how long it took to get a reply. + const long timediff_source = timeDiff(_millis_out, receiveTimestamp); + + if (timediff_source > MAX_DELAY_FOR_REPLY) { + // Took too long, discard it. + reset(false); + return false; + } + + const long timediff_reply = timeDiff(received._millis_in, received._millis_out); + air_time = (timediff_source - timediff_reply) / 2; + } + double compensation_ms = air_time + timePassedSince(receiveTimestamp); + double new_unixTime_d = received._unixTime_d + (compensation_ms / 1000); + node_time.setExternalTimeSource(new_unixTime_d, timeSource_t::ESP_now_peer); + node_time.now(); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log.reserve(64); + log = F("ESPEasy_Now_NTP: air time: "); + log += air_time; + log += F(" Compensation: "); + log += String(compensation_ms, 1); + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); + } + reset(true); + return true; +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h new file mode 100644 index 0000000000..be408b6676 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -0,0 +1,58 @@ +#ifndef DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H +#define DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H + +#include + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +# include "../Helpers/ESPEasy_time.h" + + +class ESPEasy_Now_NTP_query { +public: + + ESPEasy_Now_NTP_query(); + + bool getMac(uint8_t mac[6]) const; + + void find_best_NTP(const uint8_t mac[6], + timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync); + + void reset(bool success); + + static unsigned long computeExpectedWander(timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync); + + bool hasLowerWander() const; + + bool isBroadcast() const; + + void markSendTime(); + + void createBroadcastNTP(); + + void createReply(unsigned long queryReceiveTimestamp); + + bool processReply(const ESPEasy_Now_NTP_query& received, + unsigned long receiveTimestamp); + + // FIXME TD-er: These members could all be private, but the processReply function must then be a friend function. + // However this gives lots of warnings as the class is then a friend of itself. + + double _unixTime_d; + unsigned long _millis_in; + unsigned long _millis_out; + unsigned long _expectedWander_ms; + timeSource_t _timeSource = timeSource_t::No_time_source; + uint8_t _mac[6] = { 0 }; + + // if previous best choice failed, keep track of it. + // so we will not get stuck retrying the one that does not reply + uint8_t _mac_prev_fail[6] = { 0 }; +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 2ac96bf005..94f1cb66b2 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -21,6 +21,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { Acknowledgement, Announcement, MQTTControllerMessage, + NTP_Query, ChecksumError = 255 }; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index dc820a0d3e..9ef003b271 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -51,6 +51,11 @@ ESPEasy_now_hdr ESPEasy_now_merger::getFirstHeader() const return header; } +unsigned long ESPEasy_now_merger::getFirstPacketTimestamp() const +{ + return _firstPacketTimestamp; +} + bool ESPEasy_now_merger::getMac(uint8_t *mac) const { auto it = _queue.find(0); diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index d63aad3aa5..561e08e8a1 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -50,6 +50,8 @@ class ESPEasy_now_merger { String getLogString() const; + unsigned long getFirstPacketTimestamp() const; + private: // Find packet + payload position in packet for payload_pos of entire message diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 22bbd6e636..d86ac4923d 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -145,7 +145,16 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) { START_TIMER; + bool has_peer = WifiEspNow.hasPeer(packet._mac); + + if (!has_peer) { + WifiEspNow.addPeer(packet._mac); + } bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + + if (!has_peer) { + WifiEspNow.removePeer(packet._mac); + } STOP_TIMER(ESPEASY_NOW_SEND_PCKT); delay(0); diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 9d79d75df3..4d5a19c589 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -2,6 +2,7 @@ #include "../Globals/Settings.h" #include "../../ESPEasy-Globals.h" +#include "../../ESPEasyTimeTypes.h" String getNodeTypeDisplayString(byte nodeType) { switch (nodeType) @@ -26,8 +27,8 @@ bool NodeStruct::validate() { if (build < 20107) { // webserverPort introduced in 20107 webserverPort = 80; - load = 0; - distance = 255; + load = 0; + distance = 255; } // FIXME TD-er: Must make some sanity checks to see if it is a valid message @@ -52,11 +53,24 @@ void NodeStruct::setLocalData() { // webserverPort = Settings.WebserverPort; // PR #3053 int load_int = getCPUload() * 2.55; + if (load_int > 255) { load = 255; } else { load = load_int; } + timeSource = static_cast(node_time.timeSource); + + switch (node_time.timeSource) { + case timeSource_t::No_time_source: + lastUpdated = (1 << 30); + break; + default: + { + lastUpdated = timePassedSince(node_time.lastSyncTime); + break; + } + } } String NodeStruct::getNodeTypeDisplayString() const { @@ -89,7 +103,7 @@ IPAddress NodeStruct::IP() const { } unsigned long NodeStruct::getAge() const { - return timePassedSince(lastSeenTimestamp); + return timePassedSince(lastUpdated); } float NodeStruct::getLoad() const { @@ -98,8 +112,9 @@ float NodeStruct::getLoad() const { String NodeStruct::getSummary() const { String res; + res.reserve(48); - res = F("Unit: "); + res = F("Unit: "); res += unit; res += F(" \""); res += getNodeName(); diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 00292372f1..f08d098240 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -2,6 +2,7 @@ #define DATASTRUCTS_NODESTRUCT_H #include "../../ESPEasy_common.h" +#include "../Helpers/ESPEasy_time.h" #include #include @@ -21,22 +22,22 @@ String getNodeTypeDisplayString(byte nodeType); struct __attribute__((__packed__)) NodeStruct { NodeStruct(); + + bool validate(); - bool validate(); - - void setLocalData(); - String getNodeTypeDisplayString() const; + void setLocalData(); + + String getNodeTypeDisplayString() const; - String getNodeName() const; + String getNodeName() const; - IPAddress IP() const; + IPAddress IP() const; unsigned long getAge() const; - - float getLoad() const; - String getSummary() const; + float getLoad() const; + String getSummary() const; // Do not change the order of this data, as it is being sent via P2P UDP. @@ -54,23 +55,21 @@ struct __attribute__((__packed__)) NodeStruct // 1 byte administrative distance - - uint8_t mac[6] = { 0 }; // STA mode MAC - uint8_t ip[4] = { 0 }; - byte unit = 0; - uint16_t build = 0; - byte nodeName[25] = { 0 }; - byte nodeType = 0; - uint16_t webserverPort = 80; - uint8_t ap_mac[6] = { 0 }; // AP mode MAC - uint8_t load = 127; // Default to average load - uint8_t distance = 255; // Administrative distance for routing - - // Data not being sent to other nodes. - unsigned long lastSeenTimestamp = 0; - - - + uint8_t mac[6] = { 0 }; // STA mode MAC + uint8_t ip[4] = { 0 }; + byte unit = 0; + uint16_t build = 0; + byte nodeName[25] = { 0 }; + byte nodeType = 0; + uint16_t webserverPort = 80; + uint8_t ap_mac[6] = { 0 }; // AP mode MAC + uint8_t load = 127; // Default to average load + uint8_t distance = 255; // Administrative distance for routing + uint8_t timeSource = static_cast(timeSource_t::No_time_source); + + // When sending system info, this value contains the time since last time sync. + // When kept as node info, this is the last time stamp the node info was updated. + unsigned long lastUpdated = (1 << 30); }; typedef std::map NodesMap; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 9d35a879ad..69dda4dd84 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -22,7 +22,7 @@ static bool mac_empty(const uint8_t *mac) void NodesHandler::addNode(const NodeStruct& node) { _nodes[node.unit] = node; - _nodes[node.unit].lastSeenTimestamp = millis(); + _nodes[node.unit].lastUpdated = millis(); } bool NodesHandler::hasNode(uint8_t unit_nr) const diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 956b49fbd5..cdf4499215 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -85,7 +85,7 @@ void run_compiletime_checks() { #ifdef USES_NOTIFIER check_size(); #endif - check_size(); + check_size(); check_size(); check_size(); check_size(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index aa36d2a9be..aa2d6c6834 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -7,6 +7,7 @@ # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" # include "../DataStructs/TimingStats.h" +# include "../Globals/ESPEasy_time.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" # include "../Globals/Settings.h" @@ -98,9 +99,11 @@ bool ESPEasy_now_handler_t::loop() for (auto it = ESPEasy_now_in_queue.begin(); it != ESPEasy_now_in_queue.end();) { bool removeMessage = true; START_TIMER; + if (!it->second.messageComplete()) { if (it->second.expired()) { STOP_TIMER(EXPIRED_ESPEASY_NOW_LOOP); + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = it->second.getLogString(); log += F(" Expired!"); @@ -141,6 +144,37 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) msg.sendToBroadcast(); } +void ESPEasy_now_handler_t::sendNTPquery() +{ + if (!_best_NTP_candidate.hasLowerWander()) { return; } + uint8_t mac[6] = { 0 }; + + if (!_best_NTP_candidate.getMac(mac)) { return; } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-Now: Send NTP query to: "); + log += formatMAC(mac); + addLog(LOG_LEVEL_INFO, log); + } + + _best_NTP_candidate.markSendTime(); + ESPEasy_Now_NTP_query query; + size_t len = sizeof(ESPEasy_Now_NTP_query); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); + msg.addBinaryData(reinterpret_cast(&query), len); + msg.send(mac); +} + +void ESPEasy_now_handler_t::sendNTPbroadcast() +{ + ESPEasy_Now_NTP_query query; + query.createBroadcastNTP(); + size_t len = sizeof(ESPEasy_Now_NTP_query); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); + msg.addBinaryData(reinterpret_cast(&query), len); + msg.send(query._mac); +} + bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) { if (!use_EspEasy_now) { return false; } @@ -199,6 +233,9 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) case ESPEasy_now_hdr::message_t::Announcement: handled = handle_DiscoveryAnnounce(message); break; + case ESPEasy_now_hdr::message_t::NTP_Query: + handled = handle_NTPquery(message); + break; case ESPEasy_now_hdr::message_t::MQTTControllerMessage: handled = handle_MQTTControllerMessage(message); break; @@ -215,13 +252,20 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m size_t payload_pos = 0; message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); - if (!received.validate()) return false; + + if (!received.validate()) { return false; } Nodes.addNode(received); + // Test to see if the discovery announce could be a good candidate for next NTP query. + uint8_t mac[6] = { 0 }; + message.getMac(mac); + _best_NTP_candidate.find_best_NTP( + mac, + static_cast(received.timeSource), + received.lastUpdated); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - uint8_t mac[6] = { 0 }; - message.getMac(mac); + String log; size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); log = F("ESPEasy Now discovery: "); @@ -233,6 +277,35 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m return true; } +bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message) +{ + ESPEasy_Now_NTP_query query; + + // NTP query messages have a single binary blob, starting at 0 + size_t payload_pos = 0; + + message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_NTP_query), payload_pos); + + if (query._timeSource == timeSource_t::No_time_source) { + // Received a query, must generate an answer for it. + + // first fetch the MAC address to reply to + if (!message.getMac(query._mac)) { return false; } + + // Fill the reply + query.createReply(message.getFirstPacketTimestamp()); + + size_t len = sizeof(ESPEasy_Now_NTP_query); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); + msg.addBinaryData(reinterpret_cast(&query), len); + msg.send(query._mac); + return true; + } + + // Received a reply on our own query + return _best_NTP_candidate.processReply(query, message.getFirstPacketTimestamp()); +} + bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message) { # ifdef USES_MQTT diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index b6b2db9410..b8e9ca29f8 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -8,6 +8,7 @@ # include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_merger.h" +# include "../DataStructs/ESPEasy_Now_NTP_query.h" # include "../Globals/CPlugins.h" @@ -26,6 +27,10 @@ class ESPEasy_now_handler_t { // This may be picked up by others void sendDiscoveryAnnounce(byte channel = 0); + void sendNTPquery(); + + void sendNTPbroadcast(); + bool sendToMQTT(controllerIndex_t controllerIndex, const String & topic, const String & payload); @@ -37,7 +42,12 @@ class ESPEasy_now_handler_t { bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message); + bool handle_NTPquery(const ESPEasy_now_merger& message); + bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message); + + ESPEasy_Now_NTP_query _best_NTP_candidate; + }; diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 78ec5a3f57..3a9f2aade8 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -6,6 +6,7 @@ #include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" +#include "../Globals/ESPEasy_now_handler.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" #include "../Globals/TimeZone.h" @@ -17,12 +18,39 @@ #include +String getString(timeSource_t timeSource) +{ + switch (timeSource) { + case timeSource_t::GPS_PPS_time_source: return F("GPS PPS"); + case timeSource_t::GPS_time_source: return F("GPS"); + case timeSource_t::NTP_time_source: return F("NTP"); + case timeSource_t::Manual_set: return F("Manual"); + case timeSource_t::ESP_now_peer: return F("ESPEasy-NOW peer"); + case timeSource_t::Restore_RTC_time_source: return F("RTC at boot"); + case timeSource_t::No_time_source: return F("No time set"); + } + return F("Unknown"); +} + +bool isExternalTimeSource(timeSource_t timeSource) +{ + switch (timeSource) { + case timeSource_t::GPS_PPS_time_source: + case timeSource_t::GPS_time_source: + case timeSource_t::NTP_time_source: + case timeSource_t::Manual_set: + return true; + default: + return false; + } +} + ESPEasy_time::ESPEasy_time() { - memset(&tm, 0, sizeof(tm)); - memset(&tsRise, 0, sizeof(tm)); - memset(&tsSet, 0, sizeof(tm)); + memset(&tm, 0, sizeof(tm)); + memset(&tsRise, 0, sizeof(tm)); + memset(&tsSet, 0, sizeof(tm)); memset(&sunRise, 0, sizeof(tm)); - memset(&sunSet, 0, sizeof(tm)); + memset(&sunSet, 0, sizeof(tm)); } struct tm ESPEasy_time::addSeconds(const struct tm& ts, int seconds, bool toLocalTime) const { @@ -38,7 +66,6 @@ struct tm ESPEasy_time::addSeconds(const struct tm& ts, int seconds, bool toLoca return result; } - void ESPEasy_time::breakTime(unsigned long timeInput, struct tm& tm) { uint8_t year; uint8_t month, monthLength; @@ -91,21 +118,26 @@ void ESPEasy_time::breakTime(unsigned long timeInput, struct tm& tm) { tm.tm_mday = time + 1; // day of month } - void ESPEasy_time::restoreLastKnownUnixTime(unsigned long lastSysTime, byte deepSleepState) { static bool firstCall = true; - if (firstCall && lastSysTime != 0 && deepSleepState != 1) { - firstCall = false; - timeSource = Restore_RTC_time_source; - externalTimeSource = static_cast(lastSysTime); + + if (firstCall && (lastSysTime != 0) && (deepSleepState != 1)) { + firstCall = false; + timeSource = timeSource_t::Restore_RTC_time_source; + externalUnixTime_d = static_cast(lastSysTime); + // Do not add the current uptime as offset. This will be done when calling now() + lastSyncTime = 0; + initTime(); } } void ESPEasy_time::setExternalTimeSource(double time, timeSource_t source) { - timeSource = source; - externalTimeSource = time; + timeSource = source; + externalUnixTime_d = time; + lastSyncTime = millis(); + nextSyncTime = 0; } uint32_t ESPEasy_time::getUnixTime() const @@ -132,26 +164,38 @@ unsigned long ESPEasy_time::now() { double unixTime_d = -1.0; if (externalTimeSource > 0.0f) { - unixTime_d = externalTimeSource; - externalTimeSource = -1.0; + unixTime_d = externalUnixTime_d; + + // Correct for the delay between the last received external time and applying it + unixTime_d += (timePassedSince(lastSyncTime) / 1000.0); + externalUnixTime_d = -1.0; } - if ((unixTime_d > 0.0f) || getNtpTime(unixTime_d)) { + // Try NTP if the time source is not external. + bool updatedTime = (unixTime_d > 0.0); + if (!isExternalTimeSource(timeSource)) { + if (getNtpTime(unixTime_d)) { + updatedTime = true; + } + } + if (updatedTime) { prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) timeSynced = true; if (loglevelActiveFor(LOG_LEVEL_INFO)) { double time_offset = unixTime_d - sysTime; - String log = F("Time set to "); - log += String(unixTime_d,3); + String log = F("Time set to "); + log += String(unixTime_d, 3); - if (-86400 < time_offset && time_offset < 86400) { + if ((-86400 < time_offset) && (time_offset < 86400)) { // Only useful to show adjustment if it is less than a day. log += F(" Time adjusted by "); log += String(time_offset * 1000.0f); log += F(" msec. Wander: "); log += String((time_offset * 1000.0f) / syncInterval); log += F(" msec/second"); + log += F(" Source: "); + log += getString(timeSource); } addLog(LOG_LEVEL_INFO, log) } @@ -160,6 +204,11 @@ unsigned long ESPEasy_time::now() { time_zone.applyTimeZone(unixTime_d); nextSyncTime = (uint32_t)unixTime_d + syncInterval; + if (isExternalTimeSource(timeSource)) { + #ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.sendNTPbroadcast(); + #endif + } } } RTC.lastSysTime = static_cast(sysTime); @@ -168,6 +217,7 @@ unsigned long ESPEasy_time::now() { if (timeSynced) { calcSunRiseAndSet(); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("Local time: "); log += getDateTimeString('-', ':', ' '); @@ -191,7 +241,6 @@ unsigned long ESPEasy_time::now() { return (unsigned long)localSystime; } - bool ESPEasy_time::reportNewMinute() { now(); @@ -208,8 +257,6 @@ bool ESPEasy_time::reportNewMinute() return true; } - - bool ESPEasy_time::systemTimePresent() const { switch (timeSource) { case No_time_source: @@ -223,8 +270,6 @@ bool ESPEasy_time::systemTimePresent() const { return nextSyncTime > 0 || Settings.UseNTP || externalTimeSource > 0.0f; } - - bool ESPEasy_time::getNtpTime(double& unixTime_d) { if (!Settings.UseNTP || !NetworkConnected(10)) { @@ -250,7 +295,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) // When pool host fails, retry can be much sooner nextSyncTime = sysTime + 5; - useNTPpool = true; + useNTPpool = true; } log += " ("; @@ -280,10 +325,10 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) while (udp.parsePacket() > 0) { // discard any previously received packets } memset(packetBuffer, 0, NTP_PACKET_SIZE); - packetBuffer[0] = 0b11100011; // LI, Version, Mode - packetBuffer[1] = 0; // Stratum, or type of clock - packetBuffer[2] = 6; // Polling Interval - packetBuffer[3] = 0xEC; // Peer Clock Precision + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; @@ -307,7 +352,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer if ((packetBuffer[0] & 0b11000000) == 0b11000000) { - // Leap-Indicator: unknown (clock unsynchronized) + // Leap-Indicator: unknown (clock unsynchronized) // See: https://github.com/letscontrolit/ESPEasy/issues/2886#issuecomment-586656384 if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("NTP : NTP host ("); @@ -315,13 +360,14 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) log += ") unsynchronized"; addLog(LOG_LEVEL_ERROR, log); } + if (!useNTPpool) { // Does not make sense to try it very often if a single host is used which is not synchronized. nextSyncTime = sysTime + 120; } udp.stop(); return false; - } + } // For more detailed info on improving accuracy, see: // https://github.com/lettier/ntpclient/issues/4#issuecomment-360703503 @@ -335,6 +381,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) secsSince1900 |= (unsigned long)packetBuffer[41] << 16; secsSince1900 |= (unsigned long)packetBuffer[42] << 8; secsSince1900 |= (unsigned long)packetBuffer[43]; + if (secsSince1900 == 0) { // No time stamp received @@ -360,6 +407,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) unixTime_d += (static_cast(txTm_f) / 4294967295.0f); long total_delay = timePassedSince(beginWait); + lastSyncTime = millis(); // compensate for the delay by adding half the total delay // N.B. unixTime_d is in seconds and delay in msec. @@ -383,11 +431,12 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) addLog(LOG_LEVEL_INFO, log); } udp.stop(); - timeSource = NTP_time_source; + timeSource = timeSource_t::NTP_time_source; return true; } delay(10); } + // Timeout. if (!useNTPpool) { // Retry again in a minute. @@ -401,11 +450,9 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) return false; } - /********************************************************************************************\ Date/Time string formatters \*********************************************************************************************/ - String ESPEasy_time::getDateString(char delimiter) const { return getDateString(tm, delimiter); @@ -430,7 +477,6 @@ String ESPEasy_time::getTimeString_ampm(char delimiter, bool show_seconds /*=tru return getTimeString(tm, delimiter, true, show_seconds); } - // returns the current Time separated by the given delimiter // time format example with ':' delimiter: 23:59:59 (HH:MM:SS) String ESPEasy_time::getTimeString(const struct tm& ts, char delimiter, bool am_pm, bool show_seconds) @@ -483,13 +529,11 @@ String ESPEasy_time::getDateTimeString(const struct tm& ts, char dateDelimiter, return ret; } - /********************************************************************************************\ Get current time/date \*********************************************************************************************/ - int ESPEasy_time::year(unsigned long t) - { +{ struct tm tmp; breakTime(t, tmp); @@ -504,25 +548,21 @@ int ESPEasy_time::weekday(unsigned long t) return tmp.tm_wday; } -String ESPEasy_time::weekday_str(int wday) +String ESPEasy_time::weekday_str(int wday) { - const String weekDays = F("SunMonTueWedThuFriSat"); - return weekDays.substring(wday * 3, wday * 3 + 3); + const String weekDays = F("SunMonTueWedThuFriSat"); + + return weekDays.substring(wday * 3, wday * 3 + 3); } -String ESPEasy_time::weekday_str() const +String ESPEasy_time::weekday_str() const { - return weekday_str(weekday()-1); + return weekday_str(weekday() - 1); } - - - - /********************************************************************************************\ Sunrise/Sunset calculations \*********************************************************************************************/ - int ESPEasy_time::getSecOffset(const String& format) { int position_minus = format.indexOf('-'); int position_plus = format.indexOf('+'); @@ -552,7 +592,6 @@ int ESPEasy_time::getSecOffset(const String& format) { return value; } - String ESPEasy_time::getSunriseTimeString(char delimiter) const { return getTimeString(sunRise, delimiter, false, false); } @@ -575,7 +614,6 @@ String ESPEasy_time::getSunsetTimeString(char delimiter, int secOffset) const { return getTimeString(getSunSet(secOffset), delimiter, false, false); } - float ESPEasy_time::sunDeclination(int doy) { // Declination of the sun in radians // Formula 2008 by Arnold(at)Barmettler.com, fit to 20 years of average declinations (2008-2027) @@ -634,7 +672,7 @@ void ESPEasy_time::calcSunRiseAndSet() { tsRise = addSeconds(tsRise, secOffset_longitude, false); breakTime(time_zone.toLocal(makeTime(tsRise)), sunRise); - breakTime(time_zone.toLocal(makeTime(tsSet)), sunSet); + breakTime(time_zone.toLocal(makeTime(tsSet)), sunSet); } struct tm ESPEasy_time::getSunRise(int secOffset) const { @@ -644,5 +682,3 @@ struct tm ESPEasy_time::getSunRise(int secOffset) const { struct tm ESPEasy_time::getSunSet(int secOffset) const { return addSeconds(tsSet, secOffset, true); } - - diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 5a129ea9d8..6a439b7718 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -6,188 +6,218 @@ #include "../../ESPEasyTimeTypes.h" -class ESPEasy_time { -public: - -ESPEasy_time(); - -struct tm addSeconds(const struct tm& ts, int seconds, bool toLocalTime) const; -static void breakTime(unsigned long timeInput, struct tm& tm); - - -// Restore the last known system time -// This may be useful to get some idea of what time it is. -// This way the unit can do things based on local time even when NTP servers may not respond. -// Do not use this when booting from deep sleep. -// Only call this once during boot. -void restoreLastKnownUnixTime(unsigned long lastSysTime, byte deepSleepState); - -void setExternalTimeSource(double time, timeSource_t source); - -uint32_t getUnixTime() const; - -void initTime(); - -// Update and get the current systime -unsigned long now(); - -// Update time and return whether the minute has changed since last check. -bool reportNewMinute(); - -bool systemTimePresent() const; - -bool getNtpTime(double& unixTime_d); - - +// Time Source type, sort by priority. +// Enum values are sent via NodeStruct, so only add new ones and don't change existing values +// typical time wander of an ESP module is 0.04 msec/sec, or roughly 3.5 seconds per 24h. +enum class timeSource_t : uint8_t { + // External time source (considered more reliable) + GPS_PPS_time_source = 5, // 1 - 10 msec accuracy + GPS_time_source = 10, // 10 - 100 msec accuracy + NTP_time_source = 15, // 20 - 100 msec accuracy + + // Manual override has higher priority because it is some kind of external sync + Manual_set = 20, // Unknown accuracy + + // Sources which may drift over time due to lack of external synchronization. + ESP_now_peer = 40, // < 5 msec accuracy between nodes, but time on the whole network may drift + + Restore_RTC_time_source = 50, // > 1 sec difference per reboot + No_time_source = 255 // No time set +}; -/********************************************************************************************\ - Date/Time string formatters - \*********************************************************************************************/ +String getString(timeSource_t timeSource); +bool isExternalTimeSource(timeSource_t timeSource); +class ESPEasy_time { public: -// Format the current Date separated by the given delimiter -// Default date format example: 20161231 (YYYYMMDD) -String getDateString(char delimiter = '\0') const; - -// Format given Date separated by the given delimiter -// date format example with '-' delimiter: 2016-12-31 (YYYY-MM-DD) -static String getDateString(const struct tm& ts, char delimiter); - -// Formats the current Time -// Default time format example: 235959 (HHMMSS) -String getTimeString(char delimiter = '\0', bool show_seconds=true) const; - -String getTimeString_ampm(char delimiter = '\0', bool show_seconds=true) const; - -// returns the current Time separated by the given delimiter -// time format example with ':' delimiter: 23:59:59 (HH:MM:SS) -static String getTimeString(const struct tm& ts, char delimiter, bool am_pm, bool show_seconds); - + ESPEasy_time(); + struct tm addSeconds(const struct tm& ts, + int seconds, + bool toLocalTime) const; + static void breakTime(unsigned long timeInput, + struct tm & tm); -String getDateTimeString(char dateDelimiter = '-', char timeDelimiter = ':', char dateTimeDelimiter = ' ') const; -String getDateTimeString_ampm(char dateDelimiter = '-', char timeDelimiter = ':', char dateTimeDelimiter = ' ') const; + // Restore the last known system time + // This may be useful to get some idea of what time it is. + // This way the unit can do things based on local time even when NTP servers may not respond. + // Do not use this when booting from deep sleep. + // Only call this once during boot. + void restoreLastKnownUnixTime(unsigned long lastSysTime, + byte deepSleepState); -// returns the current Date and Time separated by the given delimiter -// if called like this: getDateTimeString('\0', '\0', '\0'); -// it will give back this: 20161231235959 (YYYYMMDDHHMMSS) -static String getDateTimeString(const struct tm& ts, char dateDelimiter = '-', char timeDelimiter = ':', char dateTimeDelimiter = ' ', bool am_pm = false); + void setExternalTimeSource(double time, + timeSource_t source); + uint32_t getUnixTime() const; -/********************************************************************************************\ - Get current time/date - \*********************************************************************************************/ + void initTime(); -// Get the year given a Unix time stamp -static int year(unsigned long t); + // Update and get the current systime + unsigned long now(); -// Get the weekday, given a Unix time stamp -static int weekday(unsigned long t); - -// Convert a weekday number (Sun = 1 ... Sat = 7) to a 3 letter string -static String weekday_str(int wday); - - -// Get current year. -int year() const -{ - return 1970 + tm.tm_year; -} - -// Get current month -byte month() const -{ - return tm.tm_mon; -} - -// Get current day of the month -byte day() const -{ - return tm.tm_mday; -} - -// Get current hour -byte hour() const -{ - return tm.tm_hour; -} - -// Get current minute -byte minute() const -{ - return tm.tm_min; -} - -// Get current second -byte second() const -{ - return tm.tm_sec; -} - -// day of week, sunday is day 1 -int weekday() const -{ - return tm.tm_wday; -} - -String weekday_str() const; + // Update time and return whether the minute has changed since last check. + bool reportNewMinute(); + bool systemTimePresent() const; + bool getNtpTime(double& unixTime_d); + /********************************************************************************************\ + Date/Time string formatters + \*********************************************************************************************/ +public: -/********************************************************************************************\ - Sunrise/Sunset calculations - \*********************************************************************************************/ + // Format the current Date separated by the given delimiter + // Default date format example: 20161231 (YYYYMMDD) + String getDateString(char delimiter = '\0') const; + + // Format given Date separated by the given delimiter + // date format example with '-' delimiter: 2016-12-31 (YYYY-MM-DD) + static String getDateString(const struct tm& ts, + char delimiter); + + // Formats the current Time + // Default time format example: 235959 (HHMMSS) + String getTimeString(char delimiter = '\0', + bool show_seconds = true) const; + + String getTimeString_ampm(char delimiter = '\0', + bool show_seconds = true) const; + + // returns the current Time separated by the given delimiter + // time format example with ':' delimiter: 23:59:59 (HH:MM:SS) + static String getTimeString(const struct tm& ts, + char delimiter, + bool am_pm, + bool show_seconds); + + + String getDateTimeString(char dateDelimiter = '-', + char timeDelimiter = ':', + char dateTimeDelimiter = ' ') const; + String getDateTimeString_ampm(char dateDelimiter = '-', + char timeDelimiter = ':', + char dateTimeDelimiter = ' ') const; + + // returns the current Date and Time separated by the given delimiter + // if called like this: getDateTimeString('\0', '\0', '\0'); + // it will give back this: 20161231235959 (YYYYMMDDHHMMSS) + static String getDateTimeString(const struct tm& ts, + char dateDelimiter = '-', + char timeDelimiter = ':', + char dateTimeDelimiter = ' ', + bool am_pm = false); + + + /********************************************************************************************\ + Get current time/date + \*********************************************************************************************/ + + // Get the year given a Unix time stamp + static int year(unsigned long t); + + // Get the weekday, given a Unix time stamp + static int weekday(unsigned long t); + + // Convert a weekday number (Sun = 1 ... Sat = 7) to a 3 letter string + static String weekday_str(int wday); + + + // Get current year. + int year() const + { + return 1970 + tm.tm_year; + } + + // Get current month + byte month() const + { + return tm.tm_mon; + } + + // Get current day of the month + byte day() const + { + return tm.tm_mday; + } + + // Get current hour + byte hour() const + { + return tm.tm_hour; + } + + // Get current minute + byte minute() const + { + return tm.tm_min; + } + + // Get current second + byte second() const + { + return tm.tm_sec; + } + + // day of week, sunday is day 1 + int weekday() const + { + return tm.tm_wday; + } + + String weekday_str() const; + + + /********************************************************************************************\ + Sunrise/Sunset calculations + \*********************************************************************************************/ public: -// Compute the offset in seconds of the substring +/-[smh] -static int getSecOffset(const String& format) ; -String getSunriseTimeString(char delimiter) const; -String getSunsetTimeString(char delimiter) const; -String getSunriseTimeString(char delimiter, int secOffset) const; -String getSunsetTimeString(char delimiter, int secOffset) const; - + // Compute the offset in seconds of the substring +/-[smh] + static int getSecOffset(const String& format); + String getSunriseTimeString(char delimiter) const; + String getSunsetTimeString(char delimiter) const; + String getSunriseTimeString(char delimiter, + int secOffset) const; + String getSunsetTimeString(char delimiter, + int secOffset) const; private: -static float sunDeclination(int doy); -static float diurnalArc(float dec, float lat); -static float equationOfTime(int doy); -static int dayOfYear(int year, int month, int day); - -void calcSunRiseAndSet(); -struct tm getSunRise(int secOffset) const; -struct tm getSunSet(int secOffset) const; - - - - - + static float sunDeclination(int doy); + static float diurnalArc(float dec, + float lat); + static float equationOfTime(int doy); + static int dayOfYear(int year, + int month, + int day); + void calcSunRiseAndSet(); + struct tm getSunRise(int secOffset) const; + struct tm getSunSet(int secOffset) const; public: -struct tm tm; -uint32_t syncInterval = 3600; // time sync will be attempted after this many seconds -double sysTime = 0.0; // Use high resolution double to get better sync between nodes when using NTP -uint32_t prevMillis = 0; -uint32_t nextSyncTime = 0; -double externalTimeSource = -1.0; // Used to set time from a source other than NTP. -struct tm tsRise, tsSet; -struct tm sunRise; -struct tm sunSet; -timeSource_t timeSource = No_time_source; - -byte PrevMinutes = 0; - - - + struct tm tm; + uint32_t syncInterval = 3600; // time sync will be attempted after this many seconds + double sysTime = 0.0; // Use high resolution double to get better sync between nodes when using NTP + uint32_t prevMillis = 0; + uint32_t nextSyncTime = 0; + uint32_t lastSyncTime = 0; + double externalUnixTime_d = -1.0; // Used to set time from a source other than NTP. + struct tm tsRise, tsSet; + struct tm sunRise; + struct tm sunSet; + timeSource_t timeSource = timeSource_t::No_time_source; + + byte PrevMinutes = 0; }; -#endif // HELPERS_ESPEASY_TIME_H \ No newline at end of file +#endif // HELPERS_ESPEASY_TIME_H From 840077f959988adfc094f0b3cced4c0a78db5e29 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 18 May 2020 12:20:10 +0200 Subject: [PATCH 023/404] [ESPEasy-Now] Show time source in system info --- src/StringProvider.ino | 2 ++ src/StringProviderTypes.h | 1 + src/WebServer_JSON.ino | 1 + src/WebServer_RootPage.ino | 1 + src/WebServer_SysInfoPage.ino | 1 + src/src/Helpers/ESPEasy_time.cpp | 4 ++-- src/src/Helpers/ESPEasy_time.h | 2 +- 7 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/StringProvider.ino b/src/StringProvider.ino index 27c51c988a..f73bd4284a 100644 --- a/src/StringProvider.ino +++ b/src/StringProvider.ino @@ -24,6 +24,7 @@ String getLabel(LabelType::Enum label) { case LabelType::HOST_NAME: return F("Hostname"); case LabelType::LOCAL_TIME: return F("Local Time"); + case LabelType::TIME_SOURCE: return F("Time Source"); case LabelType::UPTIME: return F("Uptime"); case LabelType::LOAD_PCT: return F("Load"); case LabelType::LOOP_COUNT: return F("Load LC"); @@ -161,6 +162,7 @@ String getValue(LabelType::Enum label) { case LabelType::LOCAL_TIME: return node_time.getDateTimeString('-',':',' '); + case LabelType::TIME_SOURCE: return toString(node_time.timeSource); case LabelType::UPTIME: return String(wdcounter / 2); case LabelType::LOAD_PCT: return String(getCPUload()); case LabelType::LOOP_COUNT: return String(getLoopCountPerSec()); diff --git a/src/StringProviderTypes.h b/src/StringProviderTypes.h index a97ea1d913..893fb0a01c 100644 --- a/src/StringProviderTypes.h +++ b/src/StringProviderTypes.h @@ -13,6 +13,7 @@ enum Enum : short { HOST_NAME, LOCAL_TIME, + TIME_SOURCE, UPTIME, LOAD_PCT, // 15.10 LOOP_COUNT, // 400 diff --git a/src/WebServer_JSON.ino b/src/WebServer_JSON.ino index 4240b7a02c..1e65518862 100644 --- a/src/WebServer_JSON.ino +++ b/src/WebServer_JSON.ino @@ -127,6 +127,7 @@ void handle_json() stream_next_json_object_value(LabelType::PLUGIN_COUNT); stream_next_json_object_value(LabelType::PLUGIN_DESCRIPTION); stream_next_json_object_value(LabelType::LOCAL_TIME); + stream_next_json_object_value(LabelType::TIME_SOURCE); stream_next_json_object_value(LabelType::UNIT_NR); stream_next_json_object_value(LabelType::UNIT_NAME); stream_next_json_object_value(LabelType::UPTIME); diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 36a1ab2171..0a217ab738 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -66,6 +66,7 @@ void handle_root() { else { addHtml(F("No system time source")); } + addRowLabelValue(LabelType::TIME_SOURCE); addRowLabel(getLabel(LabelType::UPTIME)); { diff --git a/src/WebServer_SysInfoPage.ino b/src/WebServer_SysInfoPage.ino index d28df5a6f8..e3bf70e760 100644 --- a/src/WebServer_SysInfoPage.ino +++ b/src/WebServer_SysInfoPage.ino @@ -257,6 +257,7 @@ void handle_sysinfo_basicInfo() { if (node_time.systemTimePresent()) { addRowLabelValue(LabelType::LOCAL_TIME); + addRowLabelValue(LabelType::TIME_SOURCE); } addRowLabel(getLabel(LabelType::UPTIME)); diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 3a9f2aade8..2f7155c9c9 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -18,7 +18,7 @@ #include -String getString(timeSource_t timeSource) +String toString(timeSource_t timeSource) { switch (timeSource) { case timeSource_t::GPS_PPS_time_source: return F("GPS PPS"); @@ -195,7 +195,7 @@ unsigned long ESPEasy_time::now() { log += String((time_offset * 1000.0f) / syncInterval); log += F(" msec/second"); log += F(" Source: "); - log += getString(timeSource); + log += toString(timeSource); } addLog(LOG_LEVEL_INFO, log) } diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 6a439b7718..c943401f97 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -25,7 +25,7 @@ enum class timeSource_t : uint8_t { No_time_source = 255 // No time set }; -String getString(timeSource_t timeSource); +String toString(timeSource_t timeSource); bool isExternalTimeSource(timeSource_t timeSource); class ESPEasy_time { From bcab3efed8f2b5becb1ce14db7d81fa12cb7816e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 18 May 2020 16:09:26 +0200 Subject: [PATCH 024/404] [ESPEasy-Now] Add controller duplicate checker to ask peers before send Some plugins may receive the same data, when close to each other. These duplicates must be detected before sending them to the controller. So data sent to the controllers is paused for a short while to check if another node already processed the same data. --- src/Controller.ino | 23 ++ src/ESPEasy_fdwdecl.h | 1 + src/_P094_CULReader.ino | 6 +- src/src/DataStructs/DeviceStruct.cpp | 3 +- src/src/DataStructs/DeviceStruct.h | 3 +- .../ESPEasy_Now_DuplicateCheck.cpp | 9 + .../DataStructs/ESPEasy_Now_DuplicateCheck.h | 24 ++ src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/DataStructs/ESPEasy_now_merger.h | 2 +- .../SendData_DuplicateChecker_data.cpp | 22 ++ .../SendData_DuplicateChecker_data.h | 20 ++ .../SendData_DuplicateChecker_struct.cpp | 98 +++++++ .../SendData_DuplicateChecker_struct.h | 44 +++ src/src/Globals/Plugins.cpp | 9 + src/src/Globals/Plugins.h | 2 + src/src/Globals/SendData_DuplicateChecker.cpp | 3 + src/src/Globals/SendData_DuplicateChecker.h | 8 + src/src/Helpers/ESPEasy_now_handler.cpp | 261 ++++++++++++------ src/src/Helpers/ESPEasy_now_handler.h | 17 +- 19 files changed, 465 insertions(+), 91 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h create mode 100644 src/src/DataStructs/SendData_DuplicateChecker_data.cpp create mode 100644 src/src/DataStructs/SendData_DuplicateChecker_data.h create mode 100644 src/src/DataStructs/SendData_DuplicateChecker_struct.cpp create mode 100644 src/src/DataStructs/SendData_DuplicateChecker_struct.h create mode 100644 src/src/Globals/SendData_DuplicateChecker.cpp create mode 100644 src/src/Globals/SendData_DuplicateChecker.h diff --git a/src/Controller.ino b/src/Controller.ino index d2cf7033ef..459df731ff 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -16,6 +16,8 @@ #include "src/Globals/Plugins.h" #include "src/Globals/Protocol.h" #include "src/Globals/ESPEasy_now_handler.h" +#include "src/Globals/SendData_DuplicateChecker.h" +#include "_CPlugin_Helper.h" #include "src/Helpers/ESPEasy_now.h" #include "src/Helpers/PortStatus.h" @@ -78,6 +80,27 @@ void sendData(struct EventStruct *event) STOP_TIMER(SEND_DATA_STATS); } + +// ******************************************************************************** +// Send to controllers, via a duplicate check +// Some plugins may receive the same data among nodes, so check first if +// another node may already have sent it. +// The compare_key is computed by the sender plugin, with plugin specific knowledge +// to make sure the key describes enough to detect duplicates. +// ******************************************************************************** +void sendData_checkDuplicates(struct EventStruct *event, const String& compare_key) +{ + uint32_t key = SendData_DuplicateChecker.add(event, compare_key); + if (key != SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY) { + // Must send out request to other nodes to see if any other has already processed it. + uint8_t broadcastMac[6]; + ESPEasy_now_handler.sendSendData_DuplicateCheck( + key, + ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck, + broadcastMac); + } +} + bool validUserVar(struct EventStruct *event) { switch (event->getSensorType()) { case Sensor_VType::SENSOR_TYPE_LONG: return true; diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index a4a63202be..a8cef68500 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -84,6 +84,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char void flushAndDisconnectAllClients(); int calc_CRC16(const char *ptr, int count); +uint32_t calc_CRC32(const uint8_t *data, size_t length); // Used in src/Commands/* void process_serialWriteBuffer(); diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 4dd3b5349a..84ffad632c 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -66,6 +66,7 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { Device[deviceCount].SendDataOption = true; Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = false; + Device[deviceCount].DuplicateDetection = true; break; } @@ -208,7 +209,10 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { log += event->String2; addLog(LOG_LEVEL_INFO, log); } - sendData(event); + // Filter length options: + // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit sending meters, which normaly is a fault) + // - 38 char, The exact message, because we have 2 byte from the value payload + sendData_checkDuplicates(event, event->String2.substring(0, 22)); } } } diff --git a/src/src/DataStructs/DeviceStruct.cpp b/src/src/DataStructs/DeviceStruct.cpp index cd533ad5a7..7a4eeee461 100644 --- a/src/src/DataStructs/DeviceStruct.cpp +++ b/src/src/DataStructs/DeviceStruct.cpp @@ -5,7 +5,8 @@ OutputDataType(Output_Data_type_t::Default), PullUpOption(false), InverseLogicOption(false), FormulaOption(false), Custom(false), SendDataOption(false), GlobalSyncOption(false), - TimerOption(false), TimerOptional(false), DecimalsOnly(false) {} + TimerOption(false), TimerOptional(false), DecimalsOnly(false), + DuplicateDetection(false) {} bool DeviceStruct::connectedToGPIOpins() const { switch(Type) { diff --git a/src/src/DataStructs/DeviceStruct.h b/src/src/DataStructs/DeviceStruct.h index 505ea4449a..395928a27a 100644 --- a/src/src/DataStructs/DeviceStruct.h +++ b/src/src/DataStructs/DeviceStruct.h @@ -57,7 +57,7 @@ enum class Output_Data_type_t : byte { * DeviceStruct * Description of a plugin \*********************************************************************************************/ -struct DeviceStruct +struct __attribute__((__packed__)) DeviceStruct { DeviceStruct(); @@ -81,6 +81,7 @@ struct DeviceStruct bool TimerOption : 1; // Allow to set the "Interval" timer for the plugin. bool TimerOptional : 1; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay) bool DecimalsOnly : 1; // Allow to set the number of decimals (otherwise treated a 0 decimals) + bool DuplicateDetection : 1; // Some (typically receiving) plugins may receive the same data on multiple nodes. Such a plugin must help detect message duplicates. }; typedef std::vector DeviceVector; diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp new file mode 100644 index 0000000000..d52c126347 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp @@ -0,0 +1,9 @@ +#include "ESPEasy_Now_DuplicateCheck.h" + +ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck() + : _key(0), _type(ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck) {} + +ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck(uint32_t key, + message_t message_type) + : _key(key), _type(message_type) {} + diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h new file mode 100644 index 0000000000..8878fbf866 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h @@ -0,0 +1,24 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H +#define DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H + +#include + +class ESPEasy_Now_DuplicateCheck { +public: + + enum class message_t : uint8_t { + KeyToCheck = 0, + AlreadyProcessed = 1 + }; + + ESPEasy_Now_DuplicateCheck(); + + ESPEasy_Now_DuplicateCheck(uint32_t key, + message_t message_type); + + const uint32_t _key; + const message_t _type; +}; + + +#endif // DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 94f1cb66b2..e92cf1876b 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -22,6 +22,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { Announcement, MQTTControllerMessage, NTP_Query, + SendData_DuplicateCheck, ChecksumError = 255 }; diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 561e08e8a1..870bff9a23 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -59,7 +59,7 @@ class ESPEasy_now_merger { size_t& payload_pos_in_packet) const; unsigned long _firstPacketTimestamp = 0; - std::map_queue; + std::map _queue; uint8_t _nr_packets = 255; }; diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp new file mode 100644 index 0000000000..0c8109b1b0 --- /dev/null +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp @@ -0,0 +1,22 @@ +#include "SendData_DuplicateChecker_data.h" + + +#include "../Helpers/ESPEasy_time_calc.h" +#include "../../ESPEasy_fdwdecl.h" + +#define TIMEOUT_ASK_FOR_DUPLICATE 100 + +SendData_DuplicateChecker_data::SendData_DuplicateChecker_data(EventStruct *event) { + if (event != nullptr) { + _event = *event; + } +} + +bool SendData_DuplicateChecker_data::doSend() +{ + if (timePassedSince(_timestamp) > TIMEOUT_ASK_FOR_DUPLICATE) { + sendData(&_event); + return true; + } + return false; +} diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.h b/src/src/DataStructs/SendData_DuplicateChecker_data.h new file mode 100644 index 0000000000..4ed2d44445 --- /dev/null +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.h @@ -0,0 +1,20 @@ +#ifndef DATASTRUCTS_SENDDATA_DUPLICATECHECKER_DATA_H +#define DATASTRUCTS_SENDDATA_DUPLICATECHECKER_DATA_H + +#include "ESPEasy_EventStruct.h" + +class SendData_DuplicateChecker_data { +public: + + SendData_DuplicateChecker_data(struct EventStruct *event); + + bool doSend(); + +private: + + EventStruct _event; + unsigned long _timestamp = millis(); +}; + + +#endif // DATASTRUCTS_SENDDATA_DUPLICATECHECKER_DATA_H diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp new file mode 100644 index 0000000000..69030e51b4 --- /dev/null +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -0,0 +1,98 @@ +#include "SendData_DuplicateChecker_struct.h" + +#include "../Globals/Plugins.h" +#include "../Helpers/ESPEasy_time_calc.h" +#include "../../ESPEasy_fdwdecl.h" + + +#define HISTORIC_ELEMENT_LIFETIME 120000 // 2 minutes + +const uint32_t SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY = 0; + +uint32_t create_compare_key(taskIndex_t taskIndex, const String& compare_key) +{ + pluginID_t id = getPluginID_from_TaskIndex(taskIndex); + + if (id == INVALID_PLUGIN_ID) { + return SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY; + } + uint32_t key = calc_CRC32(reinterpret_cast(compare_key.c_str()), compare_key.length()); + key += id; + + // consider the 0 as invalid key, so never return 0 on a valid key + if (key == SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY) { + ++key; + } + return key; +} + +uint32_t SendData_DuplicateChecker_struct::add(struct EventStruct *event, const String& compare_key) +{ + uint32_t key = create_compare_key(event->TaskIndex, compare_key); + + if (key != DUPLICATE_CHECKER_INVALID_KEY) { + if (historicKey(key)) { + // Item already exists in the queue, no need to ask around + return DUPLICATE_CHECKER_INVALID_KEY; + } + + _queue.emplace(std::make_pair(key, SendData_DuplicateChecker_data(event))); + _historic[key] = millis(); + } + return key; +} + +bool SendData_DuplicateChecker_struct::historicKey(uint32_t key) +{ + // Consider invalid key always as historic key so it will never be processed. + if (key == DUPLICATE_CHECKER_INVALID_KEY) { return true; } + auto it = _historic.find(key); + + if (it == _historic.end()) + { + // Someone asked about it, so mark it here + _historic[key] = millis(); + return false; + } + + // Apparently we've seen another instance of that message, renew the last seen timestamp + it->second = millis(); + return true; +} + +void SendData_DuplicateChecker_struct::remove(uint32_t key) +{ + auto it = _queue.find(key); + + if (it != _queue.end()) { + _queue.erase(it); + } +} + +void SendData_DuplicateChecker_struct::loop() +{ + purge_old_historic(); + + for (auto it = _queue.begin(); it != _queue.end();) { + if (it->second.doSend()) { + it = _queue.erase(it); + + // Processed one, others will be processed later + return; + } else { + ++it; + } + } +} + +void SendData_DuplicateChecker_struct::purge_old_historic() +{ + for (auto it = _historic.begin(); it != _historic.end();) + { + if (timePassedSince(it->second) > HISTORIC_ELEMENT_LIFETIME) { + it = _historic.erase(it); + } else { + ++it; + } + } +} diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.h b/src/src/DataStructs/SendData_DuplicateChecker_struct.h new file mode 100644 index 0000000000..cf7c3bc26a --- /dev/null +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.h @@ -0,0 +1,44 @@ +#ifndef DATASTRUCTS_SENDDATA_DUPLICATECHECKER_STRUCT_H +#define DATASTRUCTS_SENDDATA_DUPLICATECHECKER_STRUCT_H + + +#include "SendData_DuplicateChecker_data.h" + +#include + +// This duplicate checker keeps track of keys of previous messages for some time. +// If a message has been seen before, it will not be processed. +// New messages will be asked to peers. +// If a peer already has the message processed, then it has to reply within the timeout. +// Messages queried for by a peer will also be added to the historic list of seen messages. +class SendData_DuplicateChecker_struct { +public: + + static const uint32_t DUPLICATE_CHECKER_INVALID_KEY; + + // Add event to the queue and return key to ask around. + uint32_t add(struct EventStruct *event, + const String & compare_key); + + // Check to see if we already know about some key. + // If not yet seen, add it to our historic list since someone else is already processing it + bool historicKey(uint32_t key); + + // Another node already reported to have handled the key + void remove(uint32_t key); + + // Send out items in the queue not marked by other nodes as already seen. + void loop(); + +private: + + void purge_old_historic(); + + // Map of key + event + std::map_queue; + + // Map of key + timestamp last seen. + std::map_historic; +}; + +#endif // DATASTRUCTS_SENDDATA_DUPLICATECHECKER_STRUCT_H diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index ff0866bbb1..3429a49f0b 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -89,6 +89,15 @@ deviceIndex_t getDeviceIndex_from_TaskIndex(taskIndex_t taskIndex) { return INVALID_DEVICE_INDEX; } +pluginID_t getPluginID_from_TaskIndex(taskIndex_t taskIndex) { + deviceIndex_t deviceIndex = getDeviceIndex_from_TaskIndex(taskIndex); + + if (deviceIndex == INVALID_DEVICE_INDEX) { + return INVALID_PLUGIN_ID; + } + return DeviceIndex_to_Plugin_id[deviceIndex]; +} + deviceIndex_t getDeviceIndex(pluginID_t pluginID) { if (pluginID != INVALID_PLUGIN_ID) { diff --git a/src/src/Globals/Plugins.h b/src/src/Globals/Plugins.h index 802f42edea..e75b2d6f4c 100644 --- a/src/src/Globals/Plugins.h +++ b/src/src/Globals/Plugins.h @@ -90,6 +90,8 @@ bool supportedPluginID(pluginID_t pluginID); deviceIndex_t getDeviceIndex_from_TaskIndex(taskIndex_t taskIndex); +pluginID_t getPluginID_from_TaskIndex(taskIndex_t taskIndex); + /********************************************************************************************\ Find Device Index given a plugin ID diff --git a/src/src/Globals/SendData_DuplicateChecker.cpp b/src/src/Globals/SendData_DuplicateChecker.cpp new file mode 100644 index 0000000000..69ede6960c --- /dev/null +++ b/src/src/Globals/SendData_DuplicateChecker.cpp @@ -0,0 +1,3 @@ +#include "SendData_DuplicateChecker.h" + +SendData_DuplicateChecker_struct SendData_DuplicateChecker; \ No newline at end of file diff --git a/src/src/Globals/SendData_DuplicateChecker.h b/src/src/Globals/SendData_DuplicateChecker.h new file mode 100644 index 0000000000..fb770079a2 --- /dev/null +++ b/src/src/Globals/SendData_DuplicateChecker.h @@ -0,0 +1,8 @@ +#ifndef GLOBALS_SENDDATA_DUPLICATECHECKER_H +#define GLOBALS_SENDDATA_DUPLICATECHECKER_H + +#include "../DataStructs/SendData_DuplicateChecker_struct.h" + +extern SendData_DuplicateChecker_struct SendData_DuplicateChecker; + +#endif // GLOBALS_SENDDATA_DUPLICATECHECKER_H \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index aa2d6c6834..f81d9265e8 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -3,6 +3,7 @@ #ifdef USES_ESPEASY_NOW # include "ESPEasy_time_calc.h" +# include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" @@ -10,6 +11,7 @@ # include "../Globals/ESPEasy_time.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" +# include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" # include "../../ESPEasy_fdwdecl.h" # include "../../ESPEasy_Log.h" @@ -133,6 +135,39 @@ bool ESPEasy_now_handler_t::loop() return somethingProcessed; } +bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) +{ + addLog(LOG_LEVEL_INFO, message.getLogString()); + bool handled = false; + + switch (message.getFirstHeader().message_type) + { + case ESPEasy_now_hdr::message_t::NotSet: + case ESPEasy_now_hdr::message_t::ChecksumError: + break; + case ESPEasy_now_hdr::message_t::Acknowledgement: + break; + case ESPEasy_now_hdr::message_t::Announcement: + handled = handle_DiscoveryAnnounce(message); + break; + case ESPEasy_now_hdr::message_t::NTP_Query: + handled = handle_NTPquery(message); + break; + case ESPEasy_now_hdr::message_t::MQTTControllerMessage: + handled = handle_MQTTControllerMessage(message); + break; + case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: + handled = handle_SendData_DuplicateCheck(message); + break; + } + + return handled; +} + +// ************************************************************* +// * Discovery Announcement +// ************************************************************* + void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) { NodeStruct thisNode; @@ -144,6 +179,43 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) msg.sendToBroadcast(); } +bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) +{ + NodeStruct received; + + // Discovery messages have a single binary blob, starting at 0 + size_t payload_pos = 0; + + message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); + + if (!received.validate()) { return false; } + Nodes.addNode(received); + + // Test to see if the discovery announce could be a good candidate for next NTP query. + uint8_t mac[6] = { 0 }; + message.getMac(mac); + _best_NTP_candidate.find_best_NTP( + mac, + static_cast(received.timeSource), + received.lastUpdated); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + size_t payloadSize = message.getPayloadSize(); + log.reserve(payloadSize + 40); + log = F("ESPEasy Now discovery: "); + log += message.getLogString(); + log += '\n'; + log += received.getSummary(); + addLog(LOG_LEVEL_INFO, log); + } + return true; +} + +// ************************************************************* +// * NTP Query +// ************************************************************* + void ESPEasy_now_handler_t::sendNTPquery() { if (!_best_NTP_candidate.hasLowerWander()) { return; } @@ -168,6 +240,7 @@ void ESPEasy_now_handler_t::sendNTPquery() void ESPEasy_now_handler_t::sendNTPbroadcast() { ESPEasy_Now_NTP_query query; + query.createBroadcastNTP(); size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); @@ -175,6 +248,39 @@ void ESPEasy_now_handler_t::sendNTPbroadcast() msg.send(query._mac); } +bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message) +{ + ESPEasy_Now_NTP_query query; + + // NTP query messages have a single binary blob, starting at 0 + size_t payload_pos = 0; + + message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_NTP_query), payload_pos); + + if (query._timeSource == timeSource_t::No_time_source) { + // Received a query, must generate an answer for it. + + // first fetch the MAC address to reply to + if (!message.getMac(query._mac)) { return false; } + + // Fill the reply + query.createReply(message.getFirstPacketTimestamp()); + + size_t len = sizeof(ESPEasy_Now_NTP_query); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); + msg.addBinaryData(reinterpret_cast(&query), len); + msg.send(query._mac); + return true; + } + + // Received a reply on our own query + return _best_NTP_candidate.processReply(query, message.getFirstPacketTimestamp()); +} + +// ************************************************************* +// * MQTT controller forwarder +// ************************************************************* + bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) { if (!use_EspEasy_now) { return false; } @@ -218,113 +324,102 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return processed; } -bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message) { - addLog(LOG_LEVEL_INFO, message.getLogString()); - bool handled = false; + # ifdef USES_MQTT - switch (message.getFirstHeader().message_type) - { - case ESPEasy_now_hdr::message_t::NotSet: - case ESPEasy_now_hdr::message_t::ChecksumError: - break; - case ESPEasy_now_hdr::message_t::Acknowledgement: - break; - case ESPEasy_now_hdr::message_t::Announcement: - handled = handle_DiscoveryAnnounce(message); - break; - case ESPEasy_now_hdr::message_t::NTP_Query: - handled = handle_NTPquery(message); - break; - case ESPEasy_now_hdr::message_t::MQTTControllerMessage: - handled = handle_MQTTControllerMessage(message); - break; + // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + + if (validControllerIndex(controllerIndex)) { + size_t pos = 0; + String topic = message.getString(pos); + String payload = message.getString(pos); + + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + return MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); } - return handled; + # endif // ifdef USES_MQTT + return false; } -bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) -{ - NodeStruct received; +// ************************************************************* +// * Controller Message Duplicate Check +// ************************************************************* - // Discovery messages have a single binary blob, starting at 0 - size_t payload_pos = 0; +void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t key, + ESPEasy_Now_DuplicateCheck::message_t message_type, + uint8_t mac[6]) +{ + ESPEasy_Now_DuplicateCheck check(key, message_type); + size_t len = sizeof(ESPEasy_Now_DuplicateCheck); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::SendData_DuplicateCheck, len); - message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); + msg.addBinaryData(reinterpret_cast(&check), len); - if (!received.validate()) { return false; } - Nodes.addNode(received); - - // Test to see if the discovery announce could be a good candidate for next NTP query. - uint8_t mac[6] = { 0 }; - message.getMac(mac); - _best_NTP_candidate.find_best_NTP( - mac, - static_cast(received.timeSource), - received.lastUpdated); + switch (message_type) { + case ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck: + msg.sendToBroadcast(); + break; + case ESPEasy_Now_DuplicateCheck::message_t::AlreadyProcessed: + msg.send(mac); + break; + } - if (loglevelActiveFor(LOG_LEVEL_INFO)) { + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log; - size_t payloadSize = message.getPayloadSize(); - log.reserve(payloadSize + 40); - log = F("ESPEasy Now discovery: "); - log += message.getLogString(); - log += '\n'; - log += received.getSummary(); - addLog(LOG_LEVEL_INFO, log); + log = F("ESPEasy_now dup check: "); + + switch (message_type) { + case ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck: + log += F("Broadcast check key "); + log += key; + break; + case ESPEasy_Now_DuplicateCheck::message_t::AlreadyProcessed: + log += F("Processed key "); + log += key; + log += ' '; + log += formatMAC(mac); + break; + } + addLog(LOG_LEVEL_DEBUG, log); } - return true; } -bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message) { - ESPEasy_Now_NTP_query query; - - // NTP query messages have a single binary blob, starting at 0 + ESPEasy_Now_DuplicateCheck check; size_t payload_pos = 0; - message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_NTP_query), payload_pos); - - if (query._timeSource == timeSource_t::No_time_source) { - // Received a query, must generate an answer for it. + message.getBinaryData(reinterpret_cast(&check), sizeof(ESPEasy_Now_DuplicateCheck), payload_pos); - // first fetch the MAC address to reply to - if (!message.getMac(query._mac)) { return false; } + switch (check._type) { + case ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck: - // Fill the reply - query.createReply(message.getFirstPacketTimestamp()); + // This is a query from another node. + // Check if it has already been processed by some node. + if (SendData_DuplicateChecker.historicKey(check._key)) { + // Must reply back to that node we already have seen it + uint8_t mac[6]; - size_t len = sizeof(ESPEasy_Now_NTP_query); - ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); - msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(query._mac); - return true; - } - - // Received a reply on our own query - return _best_NTP_candidate.processReply(query, message.getFirstPacketTimestamp()); -} - -bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message) -{ - # ifdef USES_MQTT - - // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + if (message.getMac(mac)) { + sendSendData_DuplicateCheck(check._key, + ESPEasy_Now_DuplicateCheck::message_t::AlreadyProcessed, + mac); + } + } + return true; - controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + case ESPEasy_Now_DuplicateCheck::message_t::AlreadyProcessed: - if (validControllerIndex(controllerIndex)) { - size_t pos = 0; - String topic = message.getString(pos); - String payload = message.getString(pos); + // This is a rejection indicating some other node already has the data processed + SendData_DuplicateChecker.remove(check._key); - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - return MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + return true; } - - # endif // ifdef USES_MQTT return false; } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index b8e9ca29f8..61b90abf03 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -6,6 +6,7 @@ #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_now_hdr.h" +# include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" @@ -23,6 +24,12 @@ class ESPEasy_now_handler_t { bool loop(); +private: + + bool processMessage(const ESPEasy_now_merger& message); + +public: + // Send out the discovery announcement via broadcast. // This may be picked up by others void sendDiscoveryAnnounce(byte channel = 0); @@ -35,10 +42,11 @@ class ESPEasy_now_handler_t { const String & topic, const String & payload); -private: - - bool processMessage(const ESPEasy_now_merger& message); + void sendSendData_DuplicateCheck(uint32_t key, + ESPEasy_Now_DuplicateCheck::message_t message_type, + uint8_t mac[6]); +private: bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message); @@ -46,8 +54,9 @@ class ESPEasy_now_handler_t { bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message); - ESPEasy_Now_NTP_query _best_NTP_candidate; + bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message); + ESPEasy_Now_NTP_query _best_NTP_candidate; }; From a7b7c6cea7eeaabdb716b0936267ac2ba4f6865d Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 19 May 2020 00:13:51 +0200 Subject: [PATCH 025/404] [ESPEasy-Now] Call the de-duplication loop() from 10/sec call --- src/Controller.ino | 4 ++++ src/ESPEasy.ino | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Controller.ino b/src/Controller.ino index 459df731ff..9de6f079fd 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -90,6 +90,7 @@ void sendData(struct EventStruct *event) // ******************************************************************************** void sendData_checkDuplicates(struct EventStruct *event, const String& compare_key) { +#ifdef USES_ESPEASY_NOW uint32_t key = SendData_DuplicateChecker.add(event, compare_key); if (key != SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY) { // Must send out request to other nodes to see if any other has already processed it. @@ -99,6 +100,9 @@ void sendData_checkDuplicates(struct EventStruct *event, const String& compare_k ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck, broadcastMac); } +#else + sendData(event); +#endif } bool validUserVar(struct EventStruct *event) { diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 711f039930..1dae976d12 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -124,6 +124,7 @@ #include "src/Globals/RTC.h" #include "src/Globals/RamTracker.h" #include "src/Globals/SecuritySettings.h" +#include "src/Globals/SendData_DuplicateChecker.h" #include "src/Globals/Services.h" #include "src/Globals/Settings.h" #include "src/Globals/Statistics.h" From c19ef979fdc6835dad270a19e837f296aac01eec Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 19 May 2020 13:29:09 +0200 Subject: [PATCH 026/404] [ESPEasy-Now] Shorten TTL for historic de-dup keys Maintaining 10 minutes of keys is too long for a busy system. It will run out of memory very soon. Reduced to 10 seconds. Probably need to make it dynamic --- src/src/DataStructs/SendData_DuplicateChecker_struct.cpp | 4 +++- src/src/DataStructs/TimingStats.cpp | 1 + src/src/DataStructs/TimingStats.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 69030e51b4..4c11813525 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -3,9 +3,10 @@ #include "../Globals/Plugins.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../../ESPEasy_fdwdecl.h" +#include "../../ESPEasy_Log.h" -#define HISTORIC_ELEMENT_LIFETIME 120000 // 2 minutes +#define HISTORIC_ELEMENT_LIFETIME 10000 // 10 seconds const uint32_t SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY = 0; @@ -65,6 +66,7 @@ void SendData_DuplicateChecker_struct::remove(uint32_t key) auto it = _queue.find(key); if (it != _queue.end()) { + addLog(LOG_LEVEL_DEBUG, F("ESPEasy-Now message not sent as processed elsewhere")); _queue.erase(it); } } diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index dbbb8f006d..873327a454 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -234,6 +234,7 @@ String getMiscStatsName(int stat) { case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy Now send Message Success"); case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy Now send Message Fail"); case ESPEASY_NOW_SEND_PCKT: return F("ESPEasy Now send Packet"); + case ESPEASY_NOW_DEDUP_LOOP: return F("ESPEasy Now DuplicateCheck loop"); case C001_DELAY_QUEUE: case C002_DELAY_QUEUE: case C003_DELAY_QUEUE: diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index ffbc0a818d..edcdfab90b 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -80,6 +80,7 @@ # define ESPEASY_NOW_SEND_MSG_SUC 59 # define ESPEASY_NOW_SEND_MSG_FAIL 60 # define ESPEASY_NOW_SEND_PCKT 61 +# define ESPEASY_NOW_DEDUP_LOOP 62 class TimingStats { From 419f69d09b96ca560a950d8e4d63652a7c01a412 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 22 May 2020 14:51:25 +0200 Subject: [PATCH 027/404] [ESPEasy-Now] Move ESPEasyNow handler loop() to global 10/s call --- src/ESPEasy.ino | 1 + src/_P098_ESPEasyNowReceiver.ino | 3 +++ src/src/Globals/Services.h | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 1dae976d12..994e13ea41 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -112,6 +112,7 @@ #include "src/Globals/CPlugins.h" #include "src/Globals/Device.h" +#include "src/Globals/ESPEasy_now_handler.h" #include "src/Globals/ESPEasyWiFiEvent.h" #include "src/Globals/ESPEasy_Scheduler.h" #include "src/Globals/EventQueue.h" diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 8434864e17..614dec1402 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -87,9 +87,12 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) case PLUGIN_FIFTY_PER_SECOND: { + /* if (ESPEasy_now_handler.loop()) { // Some packet was handled, check if it is something for this plugin } + // Moved to run10TimesPerSecond() + */ break; } diff --git a/src/src/Globals/Services.h b/src/src/Globals/Services.h index d4cca9e66f..968725d42f 100644 --- a/src/src/Globals/Services.h +++ b/src/src/Globals/Services.h @@ -20,10 +20,10 @@ #include #include - #include extern ESP8266WebServer web_server; #ifndef NO_HTTP_UPDATER + #include extern ESP8266HTTPUpdateServer httpUpdater; #endif @@ -35,10 +35,10 @@ #include #include - #include extern WebServer web_server; #ifndef NO_HTTP_UPDATER + #include extern ESP32HTTPUpdateServer httpUpdater; #endif From 89c0bcfc877235827e0aa2dd3eb491d533a13c89 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 27 May 2020 22:49:55 +0200 Subject: [PATCH 028/404] [ESPEasy-Now] Prepare auto discovery + command "espeasynowdisable" Use `espeasynowdisable` to disable ESPEasyNow for 5 minutes. This will ease the OTA update process in busy environments. --- platformio_core_defs.ini | 3 +- src/ESPEasyWiFiEvent.cpp | 19 +--- src/ESPEasyWifi.cpp | 59 ++++++++-- src/Networking.ino | 4 +- src/StringProvider.ino | 10 ++ src/StringProviderTypes.h | 4 + src/WebServer_AdvancedConfigPage.ino | 8 ++ src/WebServer_ConfigPage.ino | 10 +- src/WebServer_JSON.ino | 3 + src/WebServer_Markup_Forms.ino | 13 +-- src/WebServer_RootPage.ino | 2 +- src/WebServer_SysInfoPage.ino | 3 + src/WebServer_WiFiScanner.ino | 3 + src/_P098_ESPEasyNowReceiver.ino | 2 - src/src/Commands/ESPEasy_Now_cmd.cpp | 26 +++++ src/src/Commands/ESPEasy_Now_cmd.h | 16 +++ src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 31 ++--- src/src/DataStructs/ESPEasy_Now_NTP_query.h | 5 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 12 +- src/src/DataStructs/ESPEasy_Now_packet.h | 5 +- src/src/DataStructs/ESPEasy_Now_peer.cpp | 85 ++++++++++++++ src/src/DataStructs/ESPEasy_Now_peer.h | 38 +++++++ src/src/DataStructs/ESPEasy_now_merger.cpp | 17 ++- src/src/DataStructs/ESPEasy_now_merger.h | 13 ++- src/src/DataStructs/ESPEasy_now_splitter.cpp | 42 ++++--- src/src/DataStructs/ESPEasy_now_splitter.h | 13 ++- src/src/DataStructs/MAC_address.cpp | 70 ++++++++++++ src/src/DataStructs/MAC_address.h | 51 +++++++++ src/src/DataStructs/NodeStruct.cpp | 81 +++++++++++-- src/src/DataStructs/NodeStruct.h | 35 ++++-- src/src/DataStructs/NodesHandler.cpp | 70 +++++++----- src/src/DataStructs/NodesHandler.h | 23 ++-- src/src/DataStructs/SettingsStruct.cpp | 10 ++ src/src/DataStructs/SettingsStruct.h | 3 + src/src/Globals/ESPEasyWiFiEvent.cpp | 4 +- src/src/Globals/ESPEasyWiFiEvent.h | 5 +- src/src/Globals/ESPEasy_Now_peers.cpp | 7 ++ src/src/Globals/ESPEasy_Now_peers.h | 15 +++ src/src/Globals/ESPEasy_now_state.cpp | 2 +- src/src/Globals/ESPEasy_now_state.h | 3 +- src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 107 ++++++++++++++++-- src/src/Helpers/ESPEasy_now_handler.h | 10 +- 43 files changed, 758 insertions(+), 186 deletions(-) create mode 100644 src/src/Commands/ESPEasy_Now_cmd.cpp create mode 100644 src/src/Commands/ESPEasy_Now_cmd.h create mode 100644 src/src/DataStructs/ESPEasy_Now_peer.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_peer.h create mode 100644 src/src/DataStructs/MAC_address.cpp create mode 100644 src/src/DataStructs/MAC_address.h create mode 100644 src/src/Globals/ESPEasy_Now_peers.cpp create mode 100644 src/src/Globals/ESPEasy_Now_peers.h diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 8e7ab8df62..513e91f44a 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -148,4 +148,5 @@ platform = espressif32@2.0.0 [core_esp32_stage] -platform = https://github.com/platformio/platform-espressif32.git#feature/stage +platform = https://github.com/platformio/platform-espressif32.git +platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git \ No newline at end of file diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index 98aa9a7049..6f9511612a 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -98,16 +98,11 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { break; case SYSTEM_EVENT_AP_STACONNECTED: - for (byte i = 0; i < 6; ++i) { - lastMacConnectedAPmode[i] = info.sta_connected.mac[i]; - } + lastMacConnectedAPmode.set(info.sta_connected.mac); processedConnectAPmode = false; break; case SYSTEM_EVENT_AP_STADISCONNECTED: - - for (byte i = 0; i < 6; ++i) { - lastMacConnectedAPmode[i] = info.sta_disconnected.mac[i]; - } + lastMacConnectedAPmode.set(info.sta_disconnected.mac); processedDisconnectAPmode = false; break; case SYSTEM_EVENT_SCAN_DONE: @@ -212,16 +207,12 @@ void ICACHE_RAM_ATTR onDHCPTimeout() { } void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { - for (byte i = 0; i < 6; ++i) { - lastMacConnectedAPmode[i] = event.mac[i]; - } + lastMacConnectedAPmode.set(event.mac); processedConnectAPmode = false; } -void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { - for (byte i = 0; i < 6; ++i) { - lastMacDisconnectedAPmode[i] = event.mac[i]; - } +void onDisonnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { + lastMacDisconnectedAPmode.set(event.mac); processedDisconnectAPmode = false; } diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 0f3c59b8fc..795ce62985 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -251,9 +251,16 @@ bool prepareWiFi() { // Reset to default power mode requires a reboot since setting it to WIFI_LIGHT_SLEEP will cause a crash. WiFi.setSleepMode(WIFI_NONE_SLEEP); } + #endif // if defined(ESP8266) + + #if defined(ESP32) + WiFi.setHostname(hostname); + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + #endif // if defined(ESP32) + #ifdef USES_ESPEASY_NOW - if (plugin_EspEasy_now_enabled) { + if (Settings.UseESPEasyNow()) { setAP(true); WiFi.softAP("ESPNOW", nullptr, 1); WiFi.softAPdisconnect(false); @@ -262,13 +269,7 @@ bool prepareWiFi() { #endif - #endif // if defined(ESP8266) - #if defined(ESP32) - WiFi.setHostname(hostname); - WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); - #endif // if defined(ESP32) - - if (RTC.lastWiFiChannel == 0 && wifi_connect_attempt <= 1) { + if (RTC.lastWiFiChannel != 0 && wifi_connect_attempt <= 1) { WifiScan(false, true); } setConnectionSpeed(); @@ -430,15 +431,46 @@ void WifiScan(bool async, bool quick) { if (quick) { #ifdef ESP8266 // Only scan a single channel if the RTC.lastWiFiChannel is known to speed up connection time. - WiFi.scanNetworks(async, show_hidden, RTC.lastWiFiChannel); + channel = RTC.lastWiFiChannel; #else - WiFi.scanNetworks(async, show_hidden); + // ESP32 RTC is not yet supported in ESPEasy #endif - } else { - WiFi.scanNetworks(async, show_hidden); } + WifiScan_channel(channel, async); } +// ******************************************************************************** +// Scan WiFi network async, one channel at a time +// ******************************************************************************** +void WifiScan_channel(uint8_t channel, bool async) { + if (WiFi.scanComplete() == -1) { + // Scan still busy + return; + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log = F("WIFI : Start network scan"); + if (channel != 0) { + log += F(" channel "); + log += channel; + } + addLog(LOG_LEVEL_INFO, log); + } + bool show_hidden = true; + processedScanDone = false; + lastGetScanMoment = millis(); + #ifdef ESP8266 + WiFi.scanNetworks(async, show_hidden, channel); + #else + bool passive = false; + uint32_t max_ms_per_chan = 300; + // FIXME TD-er: The current installed ESP32 core does not yet support channel as parameter + WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan); + //WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan, channel); + #endif +} + + // ******************************************************************************** // Scan all Wifi Access Points // ******************************************************************************** @@ -468,6 +500,9 @@ void WifiScan() } } serialPrintln(""); +#ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.addPeerFromWiFiScan(); +#endif } // ******************************************************************************** diff --git a/src/Networking.ino b/src/Networking.ino index b52a9f002f..2dfe65c51b 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -233,9 +233,9 @@ void checkUDP() String log; log.reserve(64); log = F("UDP : "); - log += formatMAC(received.mac); + log += received.STA_MAC().toString(); log += ','; - log += formatIP(received.ip); + log += received.IP().toString(); log += ','; log += received.unit; addLog(LOG_LEVEL_DEBUG_MORE, log); diff --git a/src/StringProvider.ino b/src/StringProvider.ino index f73bd4284a..1c9612241a 100644 --- a/src/StringProvider.ino +++ b/src/StringProvider.ino @@ -6,6 +6,7 @@ #endif #include "src/Globals/ESPEasy_Scheduler.h" +#include "src/Globals/ESPEasy_now_state.h" #include "src/Helpers/CompiletimeDefines.h" #include "src/Helpers/Memory.h" @@ -88,6 +89,10 @@ String getLabel(LabelType::Enum label) { case LabelType::FORCE_WIFI_NOSLEEP: return F("Force WiFi No Sleep"); case LabelType::PERIODICAL_GRAT_ARP: return F("Periodical send Gratuitous ARP"); case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); + #ifdef USES_ESPEASY_NOW + case LabelType::USE_ESPEASY_NOW: return F("Use ESPEasy-Now"); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable ESPEasy-Now"); + #endif case LabelType::BUILD_DESC: return F("Build"); case LabelType::GIT_BUILD: return F("Git Build"); @@ -228,6 +233,11 @@ String getValue(LabelType::Enum label) { case LabelType::RESTART_WIFI_LOST_CONN: return jsonBool(Settings.WiFiRestart_connection_lost()); case LabelType::FORCE_WIFI_NOSLEEP: return jsonBool(Settings.WifiNoneSleep()); case LabelType::PERIODICAL_GRAT_ARP: return jsonBool(Settings.gratuitousARP()); + #ifdef USES_ESPEASY_NOW + case LabelType::USE_ESPEASY_NOW: return jsonBool(Settings.UseESPEasyNow()); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); + #endif + case LabelType::CONNECTION_FAIL_THRESH: return String(Settings.ConnectionFailuresThreshold); case LabelType::BUILD_DESC: return String(BUILD); diff --git a/src/StringProviderTypes.h b/src/StringProviderTypes.h index 893fb0a01c..02921fc8cc 100644 --- a/src/StringProviderTypes.h +++ b/src/StringProviderTypes.h @@ -76,6 +76,10 @@ enum Enum : short { FORCE_WIFI_NOSLEEP, PERIODICAL_GRAT_ARP, CONNECTION_FAIL_THRESH, + #ifdef USES_ESPEASY_NOW + USE_ESPEASY_NOW, + TEMP_DISABLE_ESPEASY_NOW, + #endif BUILD_DESC, GIT_BUILD, diff --git a/src/WebServer_AdvancedConfigPage.ino b/src/WebServer_AdvancedConfigPage.ino index dacf511826..481e9141b1 100644 --- a/src/WebServer_AdvancedConfigPage.ino +++ b/src/WebServer_AdvancedConfigPage.ino @@ -81,6 +81,10 @@ void handle_advanced() { Settings.gratuitousARP(isFormItemChecked(getInternalLabel(LabelType::PERIODICAL_GRAT_ARP))); #endif // ifdef SUPPORT_ARP +#ifdef USES_ESPEASY_NOW + Settings.UseESPEasyNow(isFormItemChecked(getInternalLabel(LabelType::USE_ESPEASY_NOW))); +#endif + addHtmlError(SaveSettings()); if (node_time.systemTimePresent()) { @@ -202,6 +206,10 @@ void handle_advanced() { #endif // ifdef SUPPORT_ARP addFormCheckBox(LabelType::CPU_ECO_MODE, Settings.EcoPowerMode()); addFormNote(F("Node may miss receiving packets with Eco mode enabled")); +#ifdef USES_ESPEASY_NOW + addFormCheckBox(LabelType::USE_ESPEASY_NOW, Settings.UseESPEasyNow()); +#endif + addFormSeparator(2); html_TR_TD(); diff --git a/src/WebServer_ConfigPage.ino b/src/WebServer_ConfigPage.ino index f132c1e38b..32ffc19a15 100644 --- a/src/WebServer_ConfigPage.ino +++ b/src/WebServer_ConfigPage.ino @@ -3,6 +3,8 @@ #include "src/Helpers/DeepSleep.h" +#include "src/DataStructs/MAC_address.h" + // ******************************************************************************** // Web Interface config page // ******************************************************************************** @@ -107,15 +109,15 @@ void handle_config() { if (peer_mac.length() == 0) { peer_mac = F("00:00:00:00:00:00"); } - byte mac[6] = {0}; - if (str2mac(peer_mac.c_str(), mac)) { - memcpy(SecuritySettings.EspEasyNowPeerMAC[peer], mac, 6); + MAC_address mac; + if (mac.set(peer_mac.c_str())) { + mac.get(SecuritySettings.EspEasyNowPeerMAC[peer]); } /* String log = F("MAC decoding "); log += peer_mac; log += F(" => "); - log += formatMAC(mac); + log += mac.toString(); addLog(LOG_LEVEL_INFO, log); */ } diff --git a/src/WebServer_JSON.ino b/src/WebServer_JSON.ino index 1e65518862..f87e128524 100644 --- a/src/WebServer_JSON.ino +++ b/src/WebServer_JSON.ino @@ -179,6 +179,9 @@ void handle_json() #ifdef SUPPORT_ARP stream_next_json_object_value(LabelType::PERIODICAL_GRAT_ARP); #endif // ifdef SUPPORT_ARP +#ifdef USES_ESPEASY_NOW + stream_next_json_object_value(LabelType::USE_ESPEASY_NOW); +#endif stream_next_json_object_value(LabelType::CONNECTION_FAIL_THRESH); stream_last_json_object_value(LabelType::WIFI_RSSI); // TODO: PKR: Add ETH Objects diff --git a/src/WebServer_Markup_Forms.ino b/src/WebServer_Markup_Forms.ino index 71142222e3..47c440247c 100644 --- a/src/WebServer_Markup_Forms.ino +++ b/src/WebServer_Markup_Forms.ino @@ -168,15 +168,8 @@ void addFormIPBox(const String& label, const String& id, const byte ip[4]) // ******************************************************************************** // Add a MAC Box form // ******************************************************************************** -void addFormMACBox(const String& label, const String& id, const byte mac[6]) +void addFormMACBox(const String& label, const String& id, const MAC_address mac) { - bool empty_MAC = true; - for (int i = 0; i < 6; ++i) { - if (mac[i] != 0) { - empty_MAC = false; - } - } - addRowLabel_tr_id(label, id); String html; @@ -186,8 +179,8 @@ void addFormMACBox(const String& label, const String& id, const byte mac[6]) html += id; html += F("' value='"); - if (!empty_MAC) { - html += formatMAC(mac); + if (!mac.all_zero()) { + html += mac.toString(); } html += "'>"; addHtml(html); diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 0a217ab738..1c6ab959af 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -198,7 +198,7 @@ void handle_root() { html.reserve(64); html += F("http://"); - html += it->second.ip.toString(); + html += it->second.IP().toString(); uint16_t port = it->second.webgui_portnumber; if (port !=0 && port != 80) { html += ':'; diff --git a/src/WebServer_SysInfoPage.ino b/src/WebServer_SysInfoPage.ino index e3bf70e760..57562717c1 100644 --- a/src/WebServer_SysInfoPage.ino +++ b/src/WebServer_SysInfoPage.ino @@ -454,6 +454,9 @@ void handle_sysinfo_WiFiSettings() { addRowLabelValue(LabelType::PERIODICAL_GRAT_ARP); # endif // ifdef SUPPORT_ARP addRowLabelValue(LabelType::CONNECTION_FAIL_THRESH); +#ifdef USES_ESPEASY_NOW + addRowLabelValue(LabelType::USE_ESPEASY_NOW); +#endif } void handle_sysinfo_Firmware() { diff --git a/src/WebServer_WiFiScanner.ino b/src/WebServer_WiFiScanner.ino index f32c50866d..8cfa8f926a 100644 --- a/src/WebServer_WiFiScanner.ino +++ b/src/WebServer_WiFiScanner.ino @@ -92,6 +92,9 @@ void handle_wifiscanner() { addHtml(formatScanResult(i, "", rssi)); html_TD(); getWiFi_RSSI_icon(rssi, 45); + #ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.addPeerFromWiFiScan(i); + #endif } } diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 614dec1402..56e41dd79e 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -73,14 +73,12 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) // Do not set the sensor type, or else it will be set for all instances of the Dummy plugin. // sensorTypeHelper_setSensorType(event, 0); - plugin_EspEasy_now_enabled = true; success = true; break; } case PLUGIN_EXIT: { - plugin_EspEasy_now_enabled = false; success = true; break; } diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp new file mode 100644 index 0000000000..0c76d44c06 --- /dev/null +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -0,0 +1,26 @@ +#include "ESPEasy_Now_cmd.h" + + +#include "../Globals/ESPEasy_now_state.h" + +#ifdef USES_ESPEASY_NOW + +#include "../Commands/Common.h" +#include "../../ESPEasy_fdwdecl.h" +#include "../../ESPEasy_common.h" + + +String Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line) +{ + temp_disable_EspEasy_now_timer = millis() + (5*60*1000); + return return_command_success(); +} + +String Command_ESPEasy_Now_Enable(struct EventStruct *event, const char *Line) +{ + // Do not set to 0, but to some moment that will be considered passed when checked the next time. + temp_disable_EspEasy_now_timer = millis(); + return return_command_success(); +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Commands/ESPEasy_Now_cmd.h b/src/src/Commands/ESPEasy_Now_cmd.h new file mode 100644 index 0000000000..9f35f2a671 --- /dev/null +++ b/src/src/Commands/ESPEasy_Now_cmd.h @@ -0,0 +1,16 @@ +#ifndef COMMANDS_ESPEASY_NOW_CMD_H +#define COMMANDS_ESPEASY_NOW_CMD_H + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +class String; + +String Command_ESPEasy_Now_Disable(struct EventStruct *event, + const char *Line); +String Command_ESPEasy_Now_Enable(struct EventStruct *event, + const char *Line); + +#endif // ifdef USES_ESPEASY_NOW + +#endif // COMMANDS_ESPEASY_NOW_CMD_H diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index aa185a0437..c9f453fcaf 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -22,13 +22,11 @@ ESPEasy_Now_NTP_query::ESPEasy_Now_NTP_query() reset(true); } -bool ESPEasy_Now_NTP_query::getMac(uint8_t mac[6]) const +bool ESPEasy_Now_NTP_query::getMac(MAC_address& mac) const { if (_timeSource == timeSource_t::No_time_source) { return false; } - for (byte i = 0; i < 6; ++i) { - mac[i] = _mac[i]; - } + mac.set(_mac); return true; } @@ -84,7 +82,7 @@ unsigned long ESPEasy_Now_NTP_query::computeExpectedWander(timeSource_t timeSou return expectedWander_ms; } -void ESPEasy_Now_NTP_query::find_best_NTP(const uint8_t mac[6], +void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, timeSource_t timeSource, unsigned long timePassedSinceLastTimeSync) { @@ -103,32 +101,19 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const uint8_t mac[6], computeExpectedWander(timeSource, timePassedSinceLastTimeSync); // First check if it matches the current best candidate. - bool matches_current_best = true; - - for (byte i = 0; i < 6 && matches_current_best; ++i) { - matches_current_best = (_mac[i] == mac[i]); - } - + bool matches_current_best = mac == _mac; if (matches_current_best) { // Update expected wander based on current time since last sync updated = true; } else { if (_expectedWander_ms > expectedWander_ms) { // We found a good new candidate - bool matches_prev_fail = true; - - for (byte i = 0; i < 6 && matches_prev_fail; ++i) { - matches_prev_fail = (_mac_prev_fail[i] == mac[i]); - } - + bool matches_prev_fail = mac == _mac_prev_fail; if (matches_prev_fail) { // No need to retry. return; } - - for (byte i = 0; i < 6; ++i) { - _mac[i] = mac[i]; - } + mac.get(_mac); updated = true; } } @@ -138,7 +123,7 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const uint8_t mac[6], String log; log.reserve(64); log = F("ESPEasy Now: Best NTP peer: "); - log += formatMAC(_mac); + log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; log += F(" ms -> "); @@ -224,7 +209,7 @@ void ESPEasy_Now_NTP_query::createReply(unsigned long queryReceiveTimestamp) String log; log.reserve(64); log = F("ESPEasy Now: Create NTP reply to: "); - log += formatMAC(_mac); + log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; log += F(" ms"); diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index be408b6676..84abc26805 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -7,6 +7,7 @@ #ifdef USES_ESPEASY_NOW # include "../Helpers/ESPEasy_time.h" +#include "MAC_address.h" class ESPEasy_Now_NTP_query { @@ -14,9 +15,9 @@ class ESPEasy_Now_NTP_query { ESPEasy_Now_NTP_query(); - bool getMac(uint8_t mac[6]) const; + bool getMac(MAC_address& mac) const; - void find_best_NTP(const uint8_t mac[6], + void find_best_NTP(const MAC_address& mac, timeSource_t timeSource, unsigned long timePassedSinceLastTimeSync); diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index af07575e12..b8b4d172d9 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -12,10 +12,10 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t pay setHeader(header); } -ESPEasy_Now_packet::ESPEasy_Now_packet(const uint8_t mac[6], const uint8_t *buf, size_t packetSize) +ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *buf, size_t packetSize) { setSize(packetSize); - memcpy(_mac, mac, 6); + mac.get(_mac); memcpy(&_buf[0], buf, packetSize); } @@ -84,9 +84,9 @@ size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) return addBinaryData(reinterpret_cast(string.c_str()), length, payload_pos); } -void ESPEasy_Now_packet::setMac(uint8_t mac[6]) +void ESPEasy_Now_packet::setMac(const MAC_address& mac) { - memcpy(_mac, mac, 6); + memcpy(_mac, mac.mac, 6); } void ESPEasy_Now_packet::setBroadcast() @@ -154,8 +154,8 @@ String ESPEasy_Now_packet::getLogString() const ESPEasy_now_hdr header = getHeader(); String log; - log.reserve(30); - log += formatMAC(_mac); + log.reserve(40); + log += MAC_address(_mac).toString(); log += F(" payload: "); log += getPayloadSize(); log += F(" ("); diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 276dded146..3c4328ff83 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -6,6 +6,7 @@ #include "../Globals/ESPEasy_now_state.h" #ifdef USES_ESPEASY_NOW +#include "MAC_address.h" # include "ESPEasy_now_hdr.h" # include @@ -18,7 +19,7 @@ class ESPEasy_Now_packet { size_t payloadSize); // Constructor for receiving a packet - ESPEasy_Now_packet(const uint8_t mac[6], + ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *buf, size_t packetSize); @@ -34,7 +35,7 @@ class ESPEasy_Now_packet { void setHeader(ESPEasy_now_hdr header); - void setMac(uint8_t mac[6]); + void setMac(const MAC_address& mac); void setBroadcast(); diff --git a/src/src/DataStructs/ESPEasy_Now_peer.cpp b/src/src/DataStructs/ESPEasy_Now_peer.cpp new file mode 100644 index 0000000000..cd4bb2e674 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_peer.cpp @@ -0,0 +1,85 @@ +#include "ESPEasy_Now_peer.h" + +#ifdef USES_ESPEASY_NOW + +ESPEasy_Now_peer::ESPEasy_Now_peer() +{ + _peerInfo.channel = 0; +} + +ESPEasy_Now_peer::ESPEasy_Now_peer(uint8_t mac[6], uint8_t channel, int8_t rssi) + : _rssi(rssi) +{ + setMac(mac); + _peerInfo.channel = channel; +} + +void ESPEasy_Now_peer::setMac(uint8_t mac[6]) +{ + for (byte i = 0; i < 6; ++i) { + _peerInfo.mac[i] = mac[i]; + } +} + +bool ESPEasy_Now_peer::equalMac(const ESPEasy_Now_peer& other) const +{ + for (byte i = 0; i < 6; ++i) { + if (_peerInfo.mac[i] != other._peerInfo.mac[i]) { + return false; + } + } + return true; +} + +bool ESPEasy_Now_peer::update(const ESPEasy_Now_peer& other) +{ + if (equalMac(other)) { + if (other._rssi < 0) { + _rssi = other._rssi; + } + + if (other._distance != 255) { + _distance = other._distance; + } + _peerInfo.channel = other._peerInfo.channel; + + if (other._confirmedESPEasyNowPeer) { + _confirmedESPEasyNowPeer = true; + } + return true; + } + return false; +} + +bool ESPEasy_Now_peer::operator<(const ESPEasy_Now_peer& other) const +{ + if (_distance != other._distance) { + return _distance < other._distance; + } + + if (_confirmedESPEasyNowPeer != other._confirmedESPEasyNowPeer) { + // One is confirmed, so prefer that one. + return _confirmedESPEasyNowPeer; + } + + if (_rssi != other._rssi) { + if (_rssi >= 0) { + // This one has no set RSSI, so the other one is better + return false; + } + + if (other._rssi >= 0) { + // This other has no set RSSI, so the this one is better + return true; + } + return _rssi > other._rssi; + } + return true; +} + +bool ESPEasy_Now_peer::operator==(const ESPEasy_Now_peer& other) const +{ + return equalMac(other); +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_peer.h b/src/src/DataStructs/ESPEasy_Now_peer.h new file mode 100644 index 0000000000..ca6e4f6463 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_peer.h @@ -0,0 +1,38 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_PEER_H +#define DATASTRUCTS_ESPEASY_NOW_PEER_H + +#include + +#include "../Globals/ESPEasy_now_state.h" + +#ifdef USES_ESPEASY_NOW + +class __attribute__((__packed__)) ESPEasy_Now_peer { +public: + + ESPEasy_Now_peer(); + ESPEasy_Now_peer(uint8_t mac[6], + uint8_t channel, + int8_t rssi); + + void setMac(uint8_t mac[6]); + + bool equalMac(const ESPEasy_Now_peer &other) const; + + bool update(const ESPEasy_Now_peer &other); + + // Compare peers. + // Return true when this peer has better RSSI and/or is a confirmed ESPEasy-Now peer + bool operator<(const ESPEasy_Now_peer &other) const; + + // A peer is equal, when it has the same MAC. + bool operator==(const ESPEasy_Now_peer &other) const; + + WifiEspNowPeerInfo _peerInfo; + int8_t _rssi = 0; + uint8_t _distance = 255; + bool _confirmedESPEasyNowPeer = false; +}; +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCTS_ESPEASY_NOW_PEER_H diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 9ef003b271..9b622e5e43 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -10,10 +10,10 @@ ESPEasy_now_merger::ESPEasy_now_merger() { } void ESPEasy_now_merger::addPacket( - uint8_t packet_nr, - const uint8_t mac[6], - const uint8_t *buf, - size_t packetSize) + uint8_t packet_nr, + const MAC_address& mac, + const uint8_t *buf, + size_t packetSize) { _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet(mac, buf, packetSize))); _firstPacketTimestamp = millis(); @@ -67,13 +67,18 @@ bool ESPEasy_now_merger::getMac(uint8_t *mac) const return true; } +bool ESPEasy_now_merger::getMac(MAC_address& mac) const +{ + return getMac(mac.mac); +} + String ESPEasy_now_merger::getLogString() const { - uint8_t mac[6] = { 0 }; + MAC_address mac; getMac(mac); String log; - log += formatMAC(mac); + log += mac.toString(); log += F(" payload: "); log += getPayloadSize(); log += F(" ("); diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 870bff9a23..91833c0c58 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -5,6 +5,8 @@ #ifdef USES_ESPEASY_NOW +# include "MAC_address.h" + // Class to process all incoming messages from a single sender. // One or more packets form a complete message. @@ -18,10 +20,10 @@ class ESPEasy_now_merger { ESPEasy_now_merger(); void addPacket( - uint8_t packet_nr, - const uint8_t mac[6], - const uint8_t *buf, - size_t packetSize); + uint8_t packet_nr, + const MAC_address& mac, + const uint8_t *buf, + size_t packetSize); // Check if all parts of the packet have been received bool messageComplete() const; @@ -47,6 +49,7 @@ class ESPEasy_now_merger { ESPEasy_now_hdr getFirstHeader() const; bool getMac(uint8_t *mac) const; + bool getMac(MAC_address& mac) const; String getLogString() const; @@ -59,7 +62,7 @@ class ESPEasy_now_merger { size_t& payload_pos_in_packet) const; unsigned long _firstPacketTimestamp = 0; - std::map _queue; + std::map_queue; uint8_t _nr_packets = 255; }; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index d86ac4923d..a454d38e0a 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -4,6 +4,7 @@ # include "../../ESPEasy_Log.h" # include "../DataStructs/TimingStats.h" +# include "../Globals/Nodes.h" # include "../Helpers/ESPEasy_time_calc.h" static uint8_t ESPEasy_now_message_count = 1; @@ -72,22 +73,23 @@ bool ESPEasy_now_splitter::sendToBroadcast() for (int i = 0; i < 6; ++i) { mac[i] = 0xFF; } - return send(mac); + return send(mac, 0); } -bool ESPEasy_now_splitter::send(uint8_t mac[6]) +bool ESPEasy_now_splitter::send(const MAC_address& mac, + int channel) { prepareForSend(mac); const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - if (!send(_queue[i])) { return false; } + if (!send(_queue[i], channel)) { return false; } } return true; } -WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) +WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t timeout, int channel) { START_TIMER; prepareForSend(mac); @@ -97,7 +99,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - send(_queue[i]); + send(_queue[i], channel); sendStatus = waitForSendStatus(timeout); if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -142,19 +144,33 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(uint8_t mac[6], size_t timeout) return sendStatus; } -bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet) +bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) { START_TIMER; - bool has_peer = WifiEspNow.hasPeer(packet._mac); - if (!has_peer) { - WifiEspNow.addPeer(packet._mac); + if (!WifiEspNow.hasPeer(packet._mac)) { + // Only have a single temp peer added, so we don't run out of slots for peers. + static MAC_address last_tmp_mac; + + if (last_tmp_mac != packet._mac) { + if (!last_tmp_mac.all_zero()) { + WifiEspNow.removePeer(last_tmp_mac.mac); + } + last_tmp_mac.set(packet._mac); + } + + // Check to see if we know its channel + if (channel == 0) { + const NodeStruct *nodeInfo = Nodes.getNodeByMac(packet._mac); + + if (nodeInfo != nullptr) { + channel = nodeInfo->channel; + } + } + WifiEspNow.addPeer(packet._mac, channel); } bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); - if (!has_peer) { - WifiEspNow.removePeer(packet._mac); - } STOP_TIMER(ESPEASY_NOW_SEND_PCKT); delay(0); @@ -172,7 +188,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) con return sendStatus; } -void ESPEasy_now_splitter::prepareForSend(uint8_t mac[6]) +void ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) { size_t nr_packets = _queue.size(); diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 0a64ad0558..a6194f64ab 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -17,10 +17,12 @@ class ESPEasy_now_splitter { size_t addString(const String& string); bool sendToBroadcast(); - bool send(uint8_t mac[6]); + bool send(const MAC_address& mac, + int channel = 0); - WifiEspNowSendStatus send(uint8_t mac[6], - size_t timeout); + WifiEspNowSendStatus send(const MAC_address& mac, + size_t timeout, + int channel); private: @@ -29,9 +31,10 @@ class ESPEasy_now_splitter { size_t getPayloadPos() const; - bool send(const ESPEasy_Now_packet& packet); + bool send(const ESPEasy_Now_packet& packet, + int channel); - void prepareForSend(uint8_t mac[6]); + void prepareForSend(const MAC_address& mac); WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; diff --git a/src/src/DataStructs/MAC_address.cpp b/src/src/DataStructs/MAC_address.cpp new file mode 100644 index 0000000000..85659fb99b --- /dev/null +++ b/src/src/DataStructs/MAC_address.cpp @@ -0,0 +1,70 @@ +#include "MAC_address.h" + +#include "../../ESPEasy_common.h" + +MAC_address::MAC_address() +{} + +MAC_address::MAC_address(const uint8_t new_mac[6]) +{ + memcpy(mac, new_mac, 6); +} + +bool MAC_address::set(const char *string) +{ + unsigned u[6]; + int c = sscanf(string, "%x:%x:%x:%x:%x:%x", u, u + 1, u + 2, u + 3, u + 4, u + 5); + + if (c != 6) { + return false; + } + + for (int i = 0; i < 6; ++i) { + mac[i] = static_cast(u[i]); + } + return true; +} + +void MAC_address::set(const uint8_t other[6]) +{ + memcpy(mac, other, 6); +} + +void MAC_address::get(uint8_t mac_out[6]) const +{ + memcpy(mac_out, mac, 6); +} + +bool MAC_address::all_zero() const +{ + for (int i = 0; i < 6; ++i) { + if (mac[i] != 0) { + return false; + } + } + return true; +} + +String MAC_address::toString() const +{ + char str[20] = { 0 }; + + toString(str); + return String(str); +} + +void MAC_address::toString(char (& strMAC)[20]) const +{ + sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + ZERO_TERMINATE(strMAC); +} + +bool MAC_address::mac_addr_cmp(const uint8_t other[6]) const +{ + for (int i = 0; i < 6; ++i) { + if (mac[i] != other[i]) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/src/src/DataStructs/MAC_address.h b/src/src/DataStructs/MAC_address.h new file mode 100644 index 0000000000..736d436fd9 --- /dev/null +++ b/src/src/DataStructs/MAC_address.h @@ -0,0 +1,51 @@ +#ifndef DATASTRUCTS_MAC_ADDRESS_H +#define DATASTRUCTS_MAC_ADDRESS_H + +#include +#include + +class __attribute__((__packed__)) MAC_address { +public: + + MAC_address(); + + MAC_address(const uint8_t new_mac[6]); + + bool operator==(const MAC_address& other) const { + return mac_addr_cmp(other.mac); + } + + bool operator!=(const MAC_address& other) const { + return !mac_addr_cmp(other.mac); + } + + bool operator==(const uint8_t other[6]) const { + return mac_addr_cmp(other); + } + + bool operator!=(const uint8_t other[6]) const { + return !mac_addr_cmp(other); + } + + // Parse string with MAC address. + // Returns false if the given string has no valid formatted mac address. + bool set(const char *string); + + void set(const uint8_t other[6]); + + void get(uint8_t mac_out[6]) const; + + bool all_zero() const; + + String toString() const; + + void toString(char (& strMAC)[20]) const; + + uint8_t mac[6] = { 0 }; + +private: + + bool mac_addr_cmp(const uint8_t other[6]) const; +}; + +#endif // DATASTRUCTS_MAC_ADDRESS_H diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 4d5a19c589..002f268563 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -17,18 +17,16 @@ String getNodeTypeDisplayString(byte nodeType) { return ""; } - NodeStruct::NodeStruct() : +NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0), build(0), age(0), nodeType(0), webgui_portnumber(0) - { - for (byte i = 0; i < 4; ++i) { ip[i] = 0; } - } +{} bool NodeStruct::validate() { if (build < 20107) { // webserverPort introduced in 20107 - webserverPort = 80; - load = 0; - distance = 255; + webgui_portnumber = 80; + load = 0; + distance = 255; } // FIXME TD-er: Must make some sanity checks to see if it is a valid message @@ -36,7 +34,7 @@ bool NodeStruct::validate() { } void NodeStruct::setLocalData() { - WiFi.macAddress(mac); + WiFi.macAddress(sta_mac); WiFi.softAPmacAddress(ap_mac); { IPAddress localIP = WiFi.localIP(); @@ -45,13 +43,14 @@ void NodeStruct::setLocalData() { ip[i] = localIP[i]; } } + channel = WiFi.channel(); unit = Settings.Unit; build = Settings.Build; memcpy(nodeName, Settings.Name, 25); nodeType = NODE_TYPE_ID; - // webserverPort = Settings.WebserverPort; // PR #3053 + webgui_portnumber = Settings.WebserverPort; int load_int = getCPUload() * 2.55; if (load_int > 255) { @@ -102,6 +101,10 @@ IPAddress NodeStruct::IP() const { return IPAddress(ip[0], ip[1], ip[2], ip[3]); } +MAC_address NodeStruct::STA_MAC() const { + return MAC_address(sta_mac); +} + unsigned long NodeStruct::getAge() const { return timePassedSince(lastUpdated); } @@ -125,3 +128,63 @@ String NodeStruct::getSummary() const { res += distance; return res; } + +bool NodeStruct::setESPEasyNow_mac(const MAC_address& received_mac) +{ + if (received_mac == sta_mac) { + ESPEasyNowPeer = 1; + useAP_ESPEasyNow = 0; + return true; + } + + if (received_mac == ap_mac) { + ESPEasyNowPeer = 1; + useAP_ESPEasyNow = 1; + return true; + } + return false; +} + +int8_t NodeStruct::getRSSI() const +{ + if (scaled_rssi == 0) { + return 0; // Not set + } + + if (scaled_rssi == 0x3F) { + return 31; // Error state + } + + // scaled_rssi = 1 ... 62 + // output = -38 ... -99 + int8_t rssi = scaled_rssi + 37; + return rssi * -1; +} + +void NodeStruct::setRSSI(int8_t rssi) +{ + if (rssi == 0) { + // Not set + scaled_rssi = 0; + return; + } + + if (rssi > 0) { + // Error state + scaled_rssi = 0x3F; + return; + } + rssi *= -1; + rssi -= 37; + + if (rssi < 1) { + scaled_rssi = 1; + return; + } + + if (rssi >= 0x3F) { + scaled_rssi = 0x3F - 1; + return; + } + scaled_rssi = rssi; +} diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index f08d098240..b4b2263dc6 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../Helpers/ESPEasy_time.h" +#include "MAC_address.h" #include #include @@ -33,12 +34,20 @@ struct __attribute__((__packed__)) NodeStruct IPAddress IP() const; + MAC_address STA_MAC() const; + unsigned long getAge() const; float getLoad() const; String getSummary() const; + bool setESPEasyNow_mac(const MAC_address& received_mac); + + int8_t getRSSI() const; + + void setRSSI(int8_t rssi); + // Do not change the order of this data, as it is being sent via P2P UDP. // 6 byte mac (STA interface) @@ -55,17 +64,21 @@ struct __attribute__((__packed__)) NodeStruct // 1 byte administrative distance - uint8_t mac[6] = { 0 }; // STA mode MAC - uint8_t ip[4] = { 0 }; - byte unit = 0; - uint16_t build = 0; - byte nodeName[25] = { 0 }; - byte nodeType = 0; - uint16_t webserverPort = 80; - uint8_t ap_mac[6] = { 0 }; // AP mode MAC - uint8_t load = 127; // Default to average load - uint8_t distance = 255; // Administrative distance for routing - uint8_t timeSource = static_cast(timeSource_t::No_time_source); + uint8_t sta_mac[6] = { 0 }; // STA mode MAC + uint8_t ip[4] = { 0 }; + byte unit = 0; + uint16_t build = 0; + byte nodeName[25] = { 0 }; + byte nodeType = 0; + uint16_t webgui_portnumber = 80; + uint8_t ap_mac[6] = { 0 }; // AP mode MAC + uint8_t load = 127; // Default to average load + uint8_t distance = 255; // Administrative distance for routing + uint8_t timeSource = static_cast(timeSource_t::No_time_source); + uint8_t channel = 0; // The WiFi channel used + uint8_t ESPEasyNowPeer : 1; // Signalling if the node is an ESPEasy-Now peer + uint8_t useAP_ESPEasyNow : 1; // ESPEasy-Now can either use STA or AP for communications. + uint8_t scaled_rssi : 6; // "shortened" RSSI value // When sending system info, this value contains the time since last time sync. // When kept as node info, this is the last time stamp the node info was updated. diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 69dda4dd84..426aa63755 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,27 +1,8 @@ #include "NodesHandler.h" - -static bool mac_equal(const uint8_t *mac1, const uint8_t *mac2) -{ - for (byte i = 0; i < 6; ++i) { - if (mac1[i] != mac2[i]) { return false; } - } - return true; -} - -static bool mac_empty(const uint8_t *mac) -{ - for (byte i = 0; i < 6; ++i) { - if (mac[i] != 0) { - return false; - } - } - return true; -} - void NodesHandler::addNode(const NodeStruct& node) { - _nodes[node.unit] = node; + _nodes[node.unit] = node; _nodes[node.unit].lastUpdated = millis(); } @@ -32,8 +13,7 @@ bool NodesHandler::hasNode(uint8_t unit_nr) const bool NodesHandler::hasNode(const uint8_t *mac) const { - bool dummy; - return getNodeByMac(mac, dummy) != nullptr; + return getNodeByMac(mac) != nullptr; } const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const @@ -46,21 +26,48 @@ const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const return &(it->second); } -const NodeStruct * NodesHandler::getNodeByMac(const uint8_t *mac, bool& match_STA) const +NodeStruct * NodesHandler::getNodeByMac(const MAC_address& mac) { - if (mac_empty(mac)) { + if (mac.all_zero()) { return nullptr; } delay(0); + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { - - if (mac_equal(mac, it->second.mac)) { + if (mac == it->second.sta_mac) { + return &(it->second); + } + + if (mac == it->second.ap_mac) { + return &(it->second); + } + } + return nullptr; +} + +const NodeStruct * NodesHandler::getNodeByMac(const MAC_address& mac) const +{ + bool match_STA; + + return getNodeByMac(mac, match_STA); +} + +const NodeStruct * NodesHandler::getNodeByMac(const MAC_address& mac, bool& match_STA) const +{ + if (mac.all_zero()) { + return nullptr; + } + delay(0); + + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) + { + if (mac == it->second.sta_mac) { match_STA = true; return &(it->second); } - if (mac_equal(mac, it->second.ap_mac)) { + if (mac == it->second.ap_mac) { match_STA = false; return &(it->second); } @@ -85,17 +92,20 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& { max_age = 0; bool nodeRemoved = false; - for (auto it = _nodes.begin(); it != _nodes.end(); ) { + + for (auto it = _nodes.begin(); it != _nodes.end();) { unsigned long age = it->second.getAge(); + if (age > max_age_allowed) { - it = _nodes.erase(it); + it = _nodes.erase(it); nodeRemoved = true; } else { ++it; + if (age > max_age) { max_age = age; } } } return nodeRemoved; -} \ No newline at end of file +} diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 04e4130f47..1ef7e3021b 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -3,33 +3,38 @@ #include "NodeStruct.h" +#include "MAC_address.h" + class NodesHandler { public: - void addNode(const NodeStruct& node); - bool hasNode(uint8_t unit_nr) const; + void addNode(const NodeStruct& node); - bool hasNode(const uint8_t* mac) const; + bool hasNode(uint8_t unit_nr) const; - const NodeStruct* getNode(uint8_t unit_nr) const; + bool hasNode(const uint8_t *mac) const; - const NodeStruct* getNodeByMac(const uint8_t* mac, bool& match_STA) const; + const NodeStruct * getNode(uint8_t unit_nr) const; - NodesMap::const_iterator begin() const; + NodeStruct * getNodeByMac(const MAC_address& mac); + const NodeStruct * getNodeByMac(const MAC_address& mac) const; + const NodeStruct * getNodeByMac(const MAC_address& mac, + bool & match_STA) const; + NodesMap::const_iterator begin() const; NodesMap::const_iterator end() const; NodesMap::const_iterator find(uint8_t unit_nr) const; // Remove nodes in list older than max_age_allowed (msec) // Returns oldest age, max_age (msec) not removed from the list. // Return true if a node has been removed. - bool refreshNodeList(unsigned long max_age_allowed, unsigned long& max_age); + bool refreshNodeList(unsigned long max_age_allowed, + unsigned long& max_age); private: NodesMap _nodes; - }; -#endif // DATASTRUCTS_NODESHANDLER_H \ No newline at end of file +#endif // DATASTRUCTS_NODESHANDLER_H diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index fa33452ade..046a4f96cb 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -114,6 +114,16 @@ void SettingsStruct_tmpl::SendToHttp_ack(bool value) { bitWrite(VariousBits1, 10, value); } +template +bool SettingsStruct_tmpl::UseESPEasyNow() const { + return bitRead(VariousBits1, 11); +} + +template +void SettingsStruct_tmpl::UseESPEasyNow(bool value) { + bitWrite(VariousBits1, 11, value); +} + template void SettingsStruct_tmpl::validate() { if (UDPPort > 65535) { UDPPort = 0; } diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 6ab4dbc216..5dda846905 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -82,6 +82,9 @@ class SettingsStruct_tmpl bool SendToHttp_ack() const; void SendToHttp_ack(bool value); + bool UseESPEasyNow() const; + void UseESPEasyNow(bool value); + void validate(); bool networkSettingsEmpty() const; diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index 722f067970..9efef40dfb 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -41,8 +41,8 @@ LongTermTimer::Duration lastConnectedDuration_us = 0ll; LongTermTimer timerAPoff; // Timer to check whether the AP mode should be disabled (0 = disabled) LongTermTimer timerAPstart; // Timer to start AP mode, started when no valid network is detected. bool intent_to_reboot = false; -uint8_t lastMacConnectedAPmode[6] = { 0 }; -uint8_t lastMacDisconnectedAPmode[6] = { 0 }; +MAC_address lastMacConnectedAPmode; +MAC_address lastMacDisconnectedAPmode; // Semaphore like bools for processing data gathered from WiFi events. diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index 8828fcdb95..2a840ff1b3 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -5,6 +5,7 @@ #include #include +#include "../DataStructs/MAC_address.h" #include "../Helpers/LongTermTimer.h" // WifiStatus @@ -100,8 +101,8 @@ extern LongTermTimer timerAPoff; // Timer to check whether the AP mode should extern LongTermTimer timerAPstart; // Timer to start AP mode, started when no valid network is detected. extern bool intent_to_reboot; -extern uint8_t lastMacConnectedAPmode[6]; -extern uint8_t lastMacDisconnectedAPmode[6]; +extern MAC_address lastMacConnectedAPmode; +extern MAC_address lastMacDisconnectedAPmode; // Semaphore like bools for processing data gathered from WiFi events. diff --git a/src/src/Globals/ESPEasy_Now_peers.cpp b/src/src/Globals/ESPEasy_Now_peers.cpp new file mode 100644 index 0000000000..05dd94edef --- /dev/null +++ b/src/src/Globals/ESPEasy_Now_peers.cpp @@ -0,0 +1,7 @@ +#include "ESPEasy_Now_peers.h" + +#ifdef USES_ESPEASY_NOW + +std::list ESPEasy_Now_peers; + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/ESPEasy_Now_peers.h b/src/src/Globals/ESPEasy_Now_peers.h new file mode 100644 index 0000000000..1711e83875 --- /dev/null +++ b/src/src/Globals/ESPEasy_Now_peers.h @@ -0,0 +1,15 @@ +#ifndef GLOBALS_ESPEASY_NOW_PEERS_H +#define GLOBALS_ESPEASY_NOW_PEERS_H + +#include "../DataStructs/ESPEasy_Now_peer.h" + +#ifdef USES_ESPEASY_NOW + +# include + +extern std::list ESPEasy_Now_peers; + + +#endif // ifdef USES_ESPEASY_NOW + +#endif // GLOBALS_ESPEASY_NOW_PEERS_H diff --git a/src/src/Globals/ESPEasy_now_state.cpp b/src/src/Globals/ESPEasy_now_state.cpp index f87575fb4b..74673eeb26 100644 --- a/src/src/Globals/ESPEasy_now_state.cpp +++ b/src/src/Globals/ESPEasy_now_state.cpp @@ -6,6 +6,6 @@ bool use_EspEasy_now = false; bool plugin_EspEasy_now_active = false; -bool plugin_EspEasy_now_enabled = false; +unsigned long temp_disable_EspEasy_now_timer = 0; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/ESPEasy_now_state.h b/src/src/Globals/ESPEasy_now_state.h index 095e399c57..b1c8f31e98 100644 --- a/src/src/Globals/ESPEasy_now_state.h +++ b/src/src/Globals/ESPEasy_now_state.h @@ -9,8 +9,7 @@ extern bool use_EspEasy_now; extern bool plugin_EspEasy_now_active; -extern bool plugin_EspEasy_now_enabled; - +extern unsigned long temp_disable_EspEasy_now_timer; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index cdf4499215..b196af9de2 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -85,7 +85,7 @@ void run_compiletime_checks() { #ifdef USES_NOTIFIER check_size(); #endif - check_size(); + check_size(); check_size(); check_size(); check_size(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f81d9265e8..8c9991dcd0 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -8,6 +8,7 @@ # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" # include "../DataStructs/TimingStats.h" +# include "../Globals/ESPEasy_Now_peers.h" # include "../Globals/ESPEasy_time.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" @@ -64,6 +65,8 @@ bool ESPEasy_now_handler_t::begin() { if (!WifiEspNow.begin()) { return false; } + if (!Settings.UseESPEasyNow()) { return false; } + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { if (SecuritySettings.peerMacSet(peer)) { if (!WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer])) { @@ -71,7 +74,7 @@ bool ESPEasy_now_handler_t::begin() String log; log.reserve(48); log = F("ESPEasy_Now: Failed to add peer "); - log += formatMAC(SecuritySettings.EspEasyNowPeerMAC[peer]); + log += MAC_address(SecuritySettings.EspEasyNowPeerMAC[peer]).toString(); addLog(LOG_LEVEL_ERROR, log); } } @@ -84,6 +87,7 @@ bool ESPEasy_now_handler_t::begin() sendDiscoveryAnnounce(); use_EspEasy_now = true; + addLog(LOG_LEVEL_INFO, F("ESPEasy-Now enabled")); return true; } @@ -91,10 +95,31 @@ void ESPEasy_now_handler_t::end() { use_EspEasy_now = false; WifiEspNow.end(); + addLog(LOG_LEVEL_INFO, F("ESPEasy-Now disabled")); } bool ESPEasy_now_handler_t::loop() { + if (temp_disable_EspEasy_now_timer != 0) { + if (timeOutReached(temp_disable_EspEasy_now_timer)) { + if (begin()) { + temp_disable_EspEasy_now_timer = 0; + } + } else { + if (use_EspEasy_now) { + end(); + } + return false; + } + } else { + if (Settings.UseESPEasyNow() != use_EspEasy_now) { + if (!use_EspEasy_now) { + begin(); + } else { + end(); + } + } + } bool somethingProcessed = false; if (!ESPEasy_now_in_queue.empty()) { @@ -135,6 +160,40 @@ bool ESPEasy_now_handler_t::loop() return somethingProcessed; } +void ESPEasy_now_handler_t::addPeerFromWiFiScan() +{ + const int8_t scanCompleteStatus = WiFi.scanComplete(); + for (int8_t i = 0; i < scanCompleteStatus; ++i) { + addPeerFromWiFiScan(i); + } +} + +void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) +{ + int8_t scanCompleteStatus = WiFi.scanComplete(); + + switch (scanCompleteStatus) { + case 0: // Nothing (yet) found + return; + case -1: // WIFI_SCAN_RUNNING + return; + case -2: // WIFI_SCAN_FAILED + return; + } + + if (scanIndex > scanCompleteStatus) { return; } + MAC_address peer_mac = WiFi.BSSID(scanIndex); + auto nodeInfo = Nodes.getNodeByMac(peer_mac); + + if (nodeInfo != nullptr) { + nodeInfo->setRSSI(WiFi.RSSI(scanIndex)); + nodeInfo->channel = WiFi.channel(scanIndex); + } else { + // Must trigger a discovery request from the node. + sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + } +} + bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) { addLog(LOG_LEVEL_INFO, message.getLogString()); @@ -168,7 +227,17 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) // * Discovery Announcement // ************************************************************* -void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) +void ESPEasy_now_handler_t::sendDiscoveryAnnounce() +{ + MAC_address broadcast; + + for (int i = 0; i < 6; ++i) { + broadcast.mac[i] = 0xFF; + } + sendDiscoveryAnnounce(broadcast); +} + +void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int channel) { NodeStruct thisNode; @@ -176,7 +245,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(byte channel) size_t len = sizeof(NodeStruct); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); msg.addBinaryData(reinterpret_cast(&thisNode), len); - msg.sendToBroadcast(); + msg.send(mac, channel); } bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) @@ -189,11 +258,25 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m message.getBinaryData(reinterpret_cast(&received), sizeof(NodeStruct), payload_pos); if (!received.validate()) { return false; } + + MAC_address mac; + message.getMac(mac); + + if (!received.setESPEasyNow_mac(mac)) { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log; + log = F("ESPEasy Now: Received discovery message from MAC not stated in message: "); + log += mac.toString(); + addLog(LOG_LEVEL_ERROR, log); + } + return false; + } + + bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; + Nodes.addNode(received); // Test to see if the discovery announce could be a good candidate for next NTP query. - uint8_t mac[6] = { 0 }; - message.getMac(mac); _best_NTP_candidate.find_best_NTP( mac, static_cast(received.timeSource), @@ -209,6 +292,10 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); } + + if (isNewNode) { + sendDiscoveryAnnounce(mac); + } return true; } @@ -219,13 +306,13 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m void ESPEasy_now_handler_t::sendNTPquery() { if (!_best_NTP_candidate.hasLowerWander()) { return; } - uint8_t mac[6] = { 0 }; + MAC_address mac; if (!_best_NTP_candidate.getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy-Now: Send NTP query to: "); - log += formatMAC(mac); + log += mac.toString(); addLog(LOG_LEVEL_INFO, log); } @@ -234,7 +321,7 @@ void ESPEasy_now_handler_t::sendNTPquery() size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(mac); + msg.send(mac.mac); } void ESPEasy_now_handler_t::sendNTPbroadcast() @@ -308,7 +395,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const // FIXME TD-er: This must be optimized to keep the last working index. // Or else it may take quite a while to send each message if (SecuritySettings.peerMacSet(peer)) { - WifiEspNowSendStatus sendStatus = msg.send(SecuritySettings.EspEasyNowPeerMAC[peer], millis() + ControllerSettings.ClientTimeout); + WifiEspNowSendStatus sendStatus = msg.send(SecuritySettings.EspEasyNowPeerMAC[peer], millis() + ControllerSettings.ClientTimeout, 0); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -382,7 +469,7 @@ void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t log += F("Processed key "); log += key; log += ' '; - log += formatMAC(mac); + log += MAC_address(mac).toString(); break; } addLog(LOG_LEVEL_DEBUG, log); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 61b90abf03..d7f7c6e2cd 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -8,8 +8,10 @@ # include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_Now_peer.h" # include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" +# include "../DataStructs/MAC_address.h" # include "../Globals/CPlugins.h" @@ -24,6 +26,11 @@ class ESPEasy_now_handler_t { bool loop(); + void addPeerFromWiFiScan(); + void addPeerFromWiFiScan(uint8_t scanIndex); + + void addPeer(const ESPEasy_Now_peer& peer); + private: bool processMessage(const ESPEasy_now_merger& message); @@ -32,7 +39,8 @@ class ESPEasy_now_handler_t { // Send out the discovery announcement via broadcast. // This may be picked up by others - void sendDiscoveryAnnounce(byte channel = 0); + void sendDiscoveryAnnounce(); + void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); void sendNTPquery(); From 32da2191343bdd7f750910fb0d5c56ee473070cd Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 28 May 2020 02:25:52 +0200 Subject: [PATCH 029/404] [ESPEasy-Now] Use Peer auto discovery for MQTT relay --- src/Networking.ino | 10 +-- src/src/DataStructs/ESPEasy_Now_peer.cpp | 85 ------------------------ src/src/DataStructs/ESPEasy_Now_peer.h | 38 ----------- src/src/DataStructs/NodeStruct.cpp | 33 +++++++++ src/src/DataStructs/NodeStruct.h | 10 +++ src/src/DataStructs/NodesHandler.cpp | 52 +++++++++++++++ src/src/DataStructs/NodesHandler.h | 13 +++- src/src/Globals/ESPEasy_Now_peers.cpp | 7 -- src/src/Globals/ESPEasy_Now_peers.h | 15 ----- src/src/Helpers/ESPEasy_now_handler.cpp | 34 +++++++--- src/src/Helpers/ESPEasy_now_handler.h | 5 +- 11 files changed, 139 insertions(+), 163 deletions(-) delete mode 100644 src/src/DataStructs/ESPEasy_Now_peer.cpp delete mode 100644 src/src/DataStructs/ESPEasy_Now_peer.h delete mode 100644 src/src/Globals/ESPEasy_Now_peers.cpp delete mode 100644 src/src/Globals/ESPEasy_Now_peers.h diff --git a/src/Networking.ino b/src/Networking.ino index 2dfe65c51b..ec7a4f050b 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -372,15 +372,17 @@ void sendSysInfoUDP(byte repeats) addLog(LOG_LEVEL_DEBUG_MORE, F("UDP : Send Sysinfo message")); #endif // ifndef BUILD_NO_DEBUG - NodeStruct thisNode; - thisNode.setLocalData(); - Nodes.addNode(thisNode); + const NodeStruct * thisNode = Nodes.getThisNode(); + if (thisNode == nullptr) { + // Should not happen + return; + } // Prepare UDP packet to send byte data[80]; data[0] = 255; data[1] = 1; - memcpy(&data[2], &thisNode, sizeof(NodeStruct)); + memcpy(&data[2], thisNode, sizeof(NodeStruct)); for (byte counter = 0; counter < repeats; counter++) { uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; diff --git a/src/src/DataStructs/ESPEasy_Now_peer.cpp b/src/src/DataStructs/ESPEasy_Now_peer.cpp deleted file mode 100644 index cd4bb2e674..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_peer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "ESPEasy_Now_peer.h" - -#ifdef USES_ESPEASY_NOW - -ESPEasy_Now_peer::ESPEasy_Now_peer() -{ - _peerInfo.channel = 0; -} - -ESPEasy_Now_peer::ESPEasy_Now_peer(uint8_t mac[6], uint8_t channel, int8_t rssi) - : _rssi(rssi) -{ - setMac(mac); - _peerInfo.channel = channel; -} - -void ESPEasy_Now_peer::setMac(uint8_t mac[6]) -{ - for (byte i = 0; i < 6; ++i) { - _peerInfo.mac[i] = mac[i]; - } -} - -bool ESPEasy_Now_peer::equalMac(const ESPEasy_Now_peer& other) const -{ - for (byte i = 0; i < 6; ++i) { - if (_peerInfo.mac[i] != other._peerInfo.mac[i]) { - return false; - } - } - return true; -} - -bool ESPEasy_Now_peer::update(const ESPEasy_Now_peer& other) -{ - if (equalMac(other)) { - if (other._rssi < 0) { - _rssi = other._rssi; - } - - if (other._distance != 255) { - _distance = other._distance; - } - _peerInfo.channel = other._peerInfo.channel; - - if (other._confirmedESPEasyNowPeer) { - _confirmedESPEasyNowPeer = true; - } - return true; - } - return false; -} - -bool ESPEasy_Now_peer::operator<(const ESPEasy_Now_peer& other) const -{ - if (_distance != other._distance) { - return _distance < other._distance; - } - - if (_confirmedESPEasyNowPeer != other._confirmedESPEasyNowPeer) { - // One is confirmed, so prefer that one. - return _confirmedESPEasyNowPeer; - } - - if (_rssi != other._rssi) { - if (_rssi >= 0) { - // This one has no set RSSI, so the other one is better - return false; - } - - if (other._rssi >= 0) { - // This other has no set RSSI, so the this one is better - return true; - } - return _rssi > other._rssi; - } - return true; -} - -bool ESPEasy_Now_peer::operator==(const ESPEasy_Now_peer& other) const -{ - return equalMac(other); -} - -#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_peer.h b/src/src/DataStructs/ESPEasy_Now_peer.h deleted file mode 100644 index ca6e4f6463..0000000000 --- a/src/src/DataStructs/ESPEasy_Now_peer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_PEER_H -#define DATASTRUCTS_ESPEASY_NOW_PEER_H - -#include - -#include "../Globals/ESPEasy_now_state.h" - -#ifdef USES_ESPEASY_NOW - -class __attribute__((__packed__)) ESPEasy_Now_peer { -public: - - ESPEasy_Now_peer(); - ESPEasy_Now_peer(uint8_t mac[6], - uint8_t channel, - int8_t rssi); - - void setMac(uint8_t mac[6]); - - bool equalMac(const ESPEasy_Now_peer &other) const; - - bool update(const ESPEasy_Now_peer &other); - - // Compare peers. - // Return true when this peer has better RSSI and/or is a confirmed ESPEasy-Now peer - bool operator<(const ESPEasy_Now_peer &other) const; - - // A peer is equal, when it has the same MAC. - bool operator==(const ESPEasy_Now_peer &other) const; - - WifiEspNowPeerInfo _peerInfo; - int8_t _rssi = 0; - uint8_t _distance = 255; - bool _confirmedESPEasyNowPeer = false; -}; -#endif // ifdef USES_ESPEASY_NOW - -#endif // DATASTRUCTS_ESPEASY_NOW_PEER_H diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 002f268563..927107a08e 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -33,6 +33,32 @@ bool NodeStruct::validate() { return true; } +bool NodeStruct::operator<(const NodeStruct &other) const { + if (ESPEasyNowPeer != other.ESPEasyNowPeer) { + // One is confirmed, so prefer that one. + return ESPEasyNowPeer; + } + + if (distance != other.distance) { + return distance < other.distance; + } + + if (getRSSI() != other.getRSSI()) { + if (getRSSI() >= 0) { + // This one has no set RSSI, so the other one is better + return false; + } + + if (other.getRSSI() >= 0) { + // This other has no set RSSI, so the this one is better + return true; + } + return getRSSI() > other.getRSSI(); + } + return true; +} + + void NodeStruct::setLocalData() { WiFi.macAddress(sta_mac); WiFi.softAPmacAddress(ap_mac); @@ -105,6 +131,13 @@ MAC_address NodeStruct::STA_MAC() const { return MAC_address(sta_mac); } +MAC_address NodeStruct::ESPEasy_Now_MAC() const { + if (useAP_ESPEasyNow) { + return MAC_address(ap_mac); + } + return MAC_address(sta_mac); +} + unsigned long NodeStruct::getAge() const { return timePassedSince(lastUpdated); } diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index b4b2263dc6..e849772cac 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -26,6 +26,14 @@ struct __attribute__((__packed__)) NodeStruct bool validate(); + // Compare nodes. + // Return true when this node has better credentials to be used as ESPEasy-Now neighbor + // - Shorter distance to a network connected gateway node. + // - confirmed ESPEasy-Now peer + // - better RSSI + // - lower load (TODO TD-er) + bool operator<(const NodeStruct &other) const; + void setLocalData(); String getNodeTypeDisplayString() const; @@ -36,6 +44,8 @@ struct __attribute__((__packed__)) NodeStruct MAC_address STA_MAC() const; + MAC_address ESPEasy_Now_MAC() const; + unsigned long getAge() const; float getLoad() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 426aa63755..77a2f80402 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,5 +1,8 @@ #include "NodesHandler.h" +#include "../../ESPEasy-Globals.h" + + void NodesHandler::addNode(const NodeStruct& node) { _nodes[node.unit] = node; @@ -75,6 +78,55 @@ const NodeStruct * NodesHandler::getNodeByMac(const MAC_address& mac, bool& matc return nullptr; } +const NodeStruct * NodesHandler::getPreferredNode() const { + MAC_address dummy; + return getPreferredNode_notMatching(dummy); +} + +const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching) const { + MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + const NodeStruct *thisNode = getNodeByMac(this_mac); + const NodeStruct *reject = getNodeByMac(not_matching); + + const NodeStruct *res = nullptr; + + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) + { + if ((&(it->second) != reject) && (&(it->second) != thisNode)) { + if (res == nullptr) { + res = &(it->second); + } else { + if (it->second < *res) { + res = &(it->second); + } + } + } + } + return res; +} + +void NodesHandler::updateThisNode() { + NodeStruct thisNode; + + thisNode.setLocalData(); + const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); + + if (preferred != nullptr) { + if (preferred->distance < 255) { + thisNode.distance = preferred->distance + 1; + } + } + addNode(thisNode); +} + +const NodeStruct * NodesHandler::getThisNode() { + updateThisNode(); + MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + return getNodeByMac(this_mac.mac); +} + NodesMap::const_iterator NodesHandler::begin() const { return _nodes.begin(); } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 1ef7e3021b..662e5f4d4c 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -28,8 +28,17 @@ class NodesHandler { // Remove nodes in list older than max_age_allowed (msec) // Returns oldest age, max_age (msec) not removed from the list. // Return true if a node has been removed. - bool refreshNodeList(unsigned long max_age_allowed, - unsigned long& max_age); + bool refreshNodeList(unsigned long max_age_allowed, + unsigned long& max_age); + + + const NodeStruct* getPreferredNode() const; + const NodeStruct* getPreferredNode_notMatching(const MAC_address& not_matching) const; + + // Update the node referring to this unit with the most recent info. + void updateThisNode(); + + const NodeStruct * getThisNode(); private: diff --git a/src/src/Globals/ESPEasy_Now_peers.cpp b/src/src/Globals/ESPEasy_Now_peers.cpp deleted file mode 100644 index 05dd94edef..0000000000 --- a/src/src/Globals/ESPEasy_Now_peers.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "ESPEasy_Now_peers.h" - -#ifdef USES_ESPEASY_NOW - -std::list ESPEasy_Now_peers; - -#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/ESPEasy_Now_peers.h b/src/src/Globals/ESPEasy_Now_peers.h deleted file mode 100644 index 1711e83875..0000000000 --- a/src/src/Globals/ESPEasy_Now_peers.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef GLOBALS_ESPEASY_NOW_PEERS_H -#define GLOBALS_ESPEASY_NOW_PEERS_H - -#include "../DataStructs/ESPEasy_Now_peer.h" - -#ifdef USES_ESPEASY_NOW - -# include - -extern std::list ESPEasy_Now_peers; - - -#endif // ifdef USES_ESPEASY_NOW - -#endif // GLOBALS_ESPEASY_NOW_PEERS_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 8c9991dcd0..0d72abe8b1 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -8,7 +8,6 @@ # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" # include "../DataStructs/TimingStats.h" -# include "../Globals/ESPEasy_Now_peers.h" # include "../Globals/ESPEasy_time.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" @@ -239,12 +238,14 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce() void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int channel) { - NodeStruct thisNode; - - thisNode.setLocalData(); + const NodeStruct * thisNode = Nodes.getThisNode(); + if (thisNode == nullptr) { + // Should not happen + return; + } size_t len = sizeof(NodeStruct); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); - msg.addBinaryData(reinterpret_cast(&thisNode), len); + msg.addBinaryData(reinterpret_cast(thisNode), len); msg.send(mac, channel); } @@ -407,6 +408,23 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const } } } + if (!processed) { + const NodeStruct* preferred = Nodes.getPreferredNode(); + if (preferred != nullptr) { + MAC_address mac = preferred->ESPEasy_Now_MAC(); + WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + ControllerSettings.ClientTimeout, preferred->channel); + + switch (sendStatus) { + case WifiEspNowSendStatus::OK: + { + processed = true; + break; + } + default: break; + } + + } + } } return processed; } @@ -439,7 +457,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, - uint8_t mac[6]) + const MAC_address& mac) { ESPEasy_Now_DuplicateCheck check(key, message_type); size_t len = sizeof(ESPEasy_Now_DuplicateCheck); @@ -469,7 +487,7 @@ void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t log += F("Processed key "); log += key; log += ' '; - log += MAC_address(mac).toString(); + log += mac.toString(); break; } addLog(LOG_LEVEL_DEBUG, log); @@ -490,7 +508,7 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer // Check if it has already been processed by some node. if (SendData_DuplicateChecker.historicKey(check._key)) { // Must reply back to that node we already have seen it - uint8_t mac[6]; + MAC_address mac; if (message.getMac(mac)) { sendSendData_DuplicateCheck(check._key, diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index d7f7c6e2cd..cee5d9fa27 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -8,7 +8,6 @@ # include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" -# include "../DataStructs/ESPEasy_Now_peer.h" # include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" # include "../DataStructs/MAC_address.h" @@ -29,8 +28,6 @@ class ESPEasy_now_handler_t { void addPeerFromWiFiScan(); void addPeerFromWiFiScan(uint8_t scanIndex); - void addPeer(const ESPEasy_Now_peer& peer); - private: bool processMessage(const ESPEasy_now_merger& message); @@ -52,7 +49,7 @@ class ESPEasy_now_handler_t { void sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, - uint8_t mac[6]); + const MAC_address& mac); private: From b9bf3b70cc9fbb1d6017030a539592ec023f8e6c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 30 May 2020 15:42:49 +0200 Subject: [PATCH 030/404] [Test] Add generated count output for sysinfo and CUL reader for debug In order to test for missing messages when sending data to controllers. The sysinfo and CUL reader plugin can generate a counter value which gets incremented on every call to PLUGIN_READ. For the sysinfo plugin, this can also be used to output upto 4 'count' messages with the same value on each call to PLUGIN_READ. The generated output of the CUL reader plugin will generate a string output starting with the counter, followed by N times the last decimal of the counter. The total length of the generated string is as long as set in the task config. --- src/_P026_Sysinfo.ino | 12 +++++++- src/_P094_CULReader.ino | 35 +++++++++++++++++++--- src/src/PluginStructs/P094_data_struct.cpp | 4 +++ src/src/PluginStructs/P094_data_struct.h | 4 +++ 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/_P026_Sysinfo.ino b/src/_P026_Sysinfo.ino index f4e41c0bd8..18c7990fd1 100644 --- a/src/_P026_Sysinfo.ino +++ b/src/_P026_Sysinfo.ino @@ -17,7 +17,7 @@ #define P026_SENSOR_TYPE_INDEX (P026_QUERY1_CONFIG_POS + VARS_PER_TASK) #define P026_NR_OUTPUT_VALUES getValueCountFromSensorType(static_cast(PCONFIG(P026_SENSOR_TYPE_INDEX))) -#define P026_NR_OUTPUT_OPTIONS 12 +#define P026_NR_OUTPUT_OPTIONS 13 String Plugin_026_valuename(byte value_nr, bool displayString) { switch (value_nr) { @@ -33,12 +33,16 @@ String Plugin_026_valuename(byte value_nr, bool displayString) { case 9: return displayString ? F("Web activity") : F("web"); case 10: return displayString ? F("Free Stack") : F("freestack"); case 11: return displayString ? F("None") : F(""); + case 12: return displayString ? F("Test Counter") : F("testcount"); default: break; } return ""; } +// Used for testing, just increment every time the task's PLUGIN_READ is called +static uint32_t p026_read_count = 0; + boolean Plugin_026(byte function, struct EventStruct *event, String& string) { boolean success = false; @@ -159,6 +163,7 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string) } addLog(LOG_LEVEL_INFO, log); } + ++p026_read_count; success = true; break; } @@ -255,6 +260,11 @@ float P026_get_value(int type) value = getCurrentFreeStack(); break; } + case 12: + { + value = p026_read_count; + break; + } } return value; } diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 84ffad632c..e0adc6c552 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -23,6 +23,9 @@ #define P094_BAUDRATE PCONFIG_LONG(0) #define P094_BAUDRATE_LABEL PCONFIG_LABEL(0) +#define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) +#define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) + #define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. #define P094_NR_OUTPUT_OPTIONS 1 @@ -117,6 +120,7 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { case PLUGIN_SET_DEFAULTS: { P094_BAUDRATE = P094_DEFAULT_BAUDRATE; + P094_DEBUG_SENTENCE_LENGTH = 0; success = true; break; @@ -144,12 +148,15 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { addFormSubHeader(F("Statistics")); P094_html_show_stats(event); + addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); + success = true; break; } case PLUGIN_WEBFORM_SAVE: { P094_BAUDRATE = getFormItemInt(P094_BAUDRATE_LABEL); + P094_DEBUG_SENTENCE_LENGTH = getFormItemInt(P094_DEBUG_SENTENCE_LABEL); P094_data_struct *P094_data = static_cast(getPluginTaskData(event->TaskIndex)); @@ -212,7 +219,8 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { // Filter length options: // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit sending meters, which normaly is a fault) // - 38 char, The exact message, because we have 2 byte from the value payload - sendData_checkDuplicates(event, event->String2.substring(0, 22)); + //sendData_checkDuplicates(event, event->String2.substring(0, 22)); + sendData(event); } } } @@ -222,10 +230,29 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { } case PLUGIN_READ: { - P094_data_struct *P094_data = - static_cast(getPluginTaskData(event->TaskIndex)); + if (P094_DEBUG_SENTENCE_LENGTH > 0) { + P094_data_struct *P094_data = + static_cast(getPluginTaskData(event->TaskIndex)); - if ((nullptr != P094_data)) {} + if ((nullptr != P094_data)) { + const uint32_t debug_count = P094_data->getDebugCounter(); + event->String2.reserve(P094_DEBUG_SENTENCE_LENGTH); + event->String2 = String(debug_count); + event->String2 += '_'; + const char c = '0' + debug_count % 10; + for (long i = event->String2.length(); i < P094_DEBUG_SENTENCE_LENGTH; ++i) { + event->String2 += c; + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("CUL Reader: Sending: "); + log += event->String2.substring(0, 20); + log += F("..."); + addLog(LOG_LEVEL_INFO, log); + } +// sendData_checkDuplicates(event, event->String2.substring(0, 22)); + sendData(event); + } + } break; } diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 982a51eca8..ff7285a0e0 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -453,4 +453,8 @@ size_t P094_data_struct::P094_Get_filter_base_index(size_t filterLine) { return filterLine * P094_ITEMS_PER_FILTER + P094_FIRST_FILTER_POS; } +uint32_t P094_data_struct::getDebugCounter() { + return debug_counter++; +} + #endif // USES_P094 diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index ce86f05c87..392aee2ab9 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -117,6 +117,9 @@ struct P094_data_struct : public PluginTaskData_base { static size_t P094_Get_filter_base_index(size_t filterLine); + // Get (and increment) debug counter + uint32_t getDebugCounter(); + private: bool max_length_reached() const; @@ -128,6 +131,7 @@ struct P094_data_struct : public PluginTaskData_base { uint32_t sentences_received_error = 0; uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; + uint32_t debug_counter = 0; bool valueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS]; P094_Filter_Value_Type valueType_index[P094_NR_FILTERS]; From 09ca802849a98ccdbf84f26a7cb4a9f3a985c586 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 30 May 2020 15:44:48 +0200 Subject: [PATCH 031/404] [ESPEasy-Now] Fix computed distance in announce packet The distance was not set for the node with access to the 'outside world'. This could lead to a storm of messages. --- src/src/DataStructs/NodeStruct.cpp | 40 --------------- src/src/DataStructs/NodesHandler.cpp | 75 +++++++++++++++++++++++++--- src/src/DataStructs/NodesHandler.h | 3 ++ 3 files changed, 71 insertions(+), 47 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 927107a08e..b15ef202e9 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -58,46 +58,6 @@ bool NodeStruct::operator<(const NodeStruct &other) const { return true; } - -void NodeStruct::setLocalData() { - WiFi.macAddress(sta_mac); - WiFi.softAPmacAddress(ap_mac); - { - IPAddress localIP = WiFi.localIP(); - - for (byte i = 0; i < 4; ++i) { - ip[i] = localIP[i]; - } - } - channel = WiFi.channel(); - - unit = Settings.Unit; - build = Settings.Build; - memcpy(nodeName, Settings.Name, 25); - nodeType = NODE_TYPE_ID; - - webgui_portnumber = Settings.WebserverPort; - int load_int = getCPUload() * 2.55; - - if (load_int > 255) { - load = 255; - } else { - load = load_int; - } - timeSource = static_cast(node_time.timeSource); - - switch (node_time.timeSource) { - case timeSource_t::No_time_source: - lastUpdated = (1 << 30); - break; - default: - { - lastUpdated = timePassedSince(node_time.lastSyncTime); - break; - } - } -} - String NodeStruct::getNodeTypeDisplayString() const { switch (nodeType) { diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 77a2f80402..8f2b99d47b 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,7 +1,8 @@ #include "NodesHandler.h" #include "../../ESPEasy-Globals.h" - +#include "../Helpers/ESPEasy_time_calc.h" +#include "../Globals/MQTT.h" void NodesHandler::addNode(const NodeStruct& node) { @@ -80,14 +81,16 @@ const NodeStruct * NodesHandler::getNodeByMac(const MAC_address& mac, bool& matc const NodeStruct * NodesHandler::getPreferredNode() const { MAC_address dummy; + return getPreferredNode_notMatching(dummy); } const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching) const { MAC_address this_mac; + WiFi.macAddress(this_mac.mac); const NodeStruct *thisNode = getNodeByMac(this_mac); - const NodeStruct *reject = getNodeByMac(not_matching); + const NodeStruct *reject = getNodeByMac(not_matching); const NodeStruct *res = nullptr; @@ -109,12 +112,54 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& void NodesHandler::updateThisNode() { NodeStruct thisNode; - thisNode.setLocalData(); - const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); + // Set local data + WiFi.macAddress(thisNode.sta_mac); + WiFi.softAPmacAddress(thisNode.ap_mac); + { + IPAddress localIP = WiFi.localIP(); + + for (byte i = 0; i < 4; ++i) { + thisNode.ip[i] = localIP[i]; + } + } + thisNode.channel = WiFi.channel(); + + thisNode.unit = Settings.Unit; + thisNode.build = Settings.Build; + memcpy(thisNode.nodeName, Settings.Name, 25); + thisNode.nodeType = NODE_TYPE_ID; + + thisNode.webgui_portnumber = Settings.WebserverPort; + int load_int = getCPUload() * 2.55; + + if (load_int > 255) { + thisNode.load = 255; + } else { + thisNode.load = load_int; + } + thisNode.timeSource = static_cast(node_time.timeSource); + + switch (node_time.timeSource) { + case timeSource_t::No_time_source: + thisNode.lastUpdated = (1 << 30); + break; + default: + { + thisNode.lastUpdated = timePassedSince(node_time.lastSyncTime); + break; + } + } - if (preferred != nullptr) { - if (preferred->distance < 255) { - thisNode.distance = preferred->distance + 1; + if (isEndpoint()) { + thisNode.distance = 0; + } else { + thisNode.distance = 255; + const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); + + if (preferred != nullptr) { + if (preferred->distance < 255) { + thisNode.distance = preferred->distance + 1; + } } } addNode(thisNode); @@ -161,3 +206,19 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& } return nodeRemoved; } + +// FIXME TD-er: should be a check per controller to see if it will accept messages +bool NodesHandler::isEndpoint() const +{ + // FIXME TD-er: Must check controller to see if it needs wifi (e.g. LoRa or cache controller do not need it) + #ifdef USES_MQTT + controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); + if (validControllerIndex(enabledMqttController)) { + return MQTTclient_connected; + } + #endif + + if (!WiFiConnected()) return false; + + return false; +} \ No newline at end of file diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 662e5f4d4c..2b37f9df28 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -40,8 +40,11 @@ class NodesHandler { const NodeStruct * getThisNode(); + private: + bool isEndpoint() const; + NodesMap _nodes; }; From 275d45c4ea207b4ae0e53f20b79e7a334556365a Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 3 Jun 2020 22:07:49 +0200 Subject: [PATCH 032/404] [ESPEasy-Now] Add work-around for forcing wifi STA channel when not connected A quick hack to force the WiFi STA channel to be the same as the other peer node you try to connect to. TODO: Must find a good reproducible way to force WiFi STA on a channel if it is not connected to an AP. --- src/WebServer_RootPage.ino | 25 ++- src/src/DataStructs/ESPEasy_now_splitter.cpp | 4 +- src/src/DataStructs/NodeStruct.cpp | 59 ++++--- src/src/DataStructs/NodeStruct.h | 7 +- src/src/DataStructs/NodesHandler.cpp | 7 +- src/src/DataStructs/NodesHandler.h | 6 + src/src/Globals/ESPEasyWiFiEvent.cpp | 1 + src/src/Globals/ESPEasyWiFiEvent.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 159 +++++++++++++++++-- src/src/Helpers/ESPEasy_now_handler.h | 8 + 10 files changed, 236 insertions(+), 41 deletions(-) diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 1c6ab959af..6fac604ce6 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -160,10 +160,13 @@ void handle_root() { html_table_header("IP", 160); // Should fit "255.255.255.255" html_table_header("Load"); html_table_header("Age (s)"); + #ifdef USES_ESPEASY_NOW + html_table_header("Dist"); + #endif for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.ip[0] != 0) + if (it->second.valid()) { bool isThisUnit = it->first == Settings.Unit; @@ -192,8 +195,9 @@ void handle_root() { html_TD(); addHtml(it->second.getNodeTypeDisplayString()); html_TD(); - html_add_wide_button_prefix(); + if (it->second.ip[0] != 0) { + html_add_wide_button_prefix(); String html; html.reserve(64); @@ -208,11 +212,26 @@ void handle_root() { html += it->second.IP().toString(); html += ""; addHtml(html); + } else if (it->second.ESPEasyNowPeer) { + addHtml(F("ESPEasy-Now ")); + addHtml(it->second.ESPEasy_Now_MAC().toString()); + addHtml(F(" (ch: ")); + addHtml(String(it->second.channel)); + addHtml(F(")")); } html_TD(); - addHtml(String(it->second.getLoad())); + const float load = it->second.getLoad(); + if (load > 0.1) { + addHtml(String(it->second.getLoad())); + } html_TD(); addHtml(String(it->second.getAge()/1000)); // time in seconds + #ifdef USES_ESPEASY_NOW + html_TD(); + if (it->second.distance != 255) { + addHtml(String(it->second.distance)); + } + #endif } } diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index a454d38e0a..15aff41561 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -167,7 +167,9 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) channel = nodeInfo->channel; } } - WifiEspNow.addPeer(packet._mac, channel); + // FIXME TD-er: Not sure why, but setting the channel does not work well. +// WifiEspNow.addPeer(packet._mac, channel); + WifiEspNow.addPeer(packet._mac, 0); } bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index b15ef202e9..b0bdc1fd49 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -3,24 +3,18 @@ #include "../Globals/Settings.h" #include "../../ESPEasy-Globals.h" #include "../../ESPEasyTimeTypes.h" - -String getNodeTypeDisplayString(byte nodeType) { - switch (nodeType) - { - case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); - case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); - case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); - case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); - case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); - case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); - } - return ""; -} +#include "../Globals/SecuritySettings.h" +#include "../Helpers/ESPEasy_time_calc.h" NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0), build(0), age(0), nodeType(0), webgui_portnumber(0) {} +bool NodeStruct::valid() const { + // FIXME TD-er: Must make some sanity checks to see if it is a valid message + return true; +} + bool NodeStruct::validate() { if (build < 20107) { // webserverPort introduced in 20107 @@ -30,7 +24,7 @@ bool NodeStruct::validate() { } // FIXME TD-er: Must make some sanity checks to see if it is a valid message - return true; + return valid(); } bool NodeStruct::operator<(const NodeStruct &other) const { @@ -39,21 +33,29 @@ bool NodeStruct::operator<(const NodeStruct &other) const { return ESPEasyNowPeer; } + const bool markedAsPriority = markedAsPriorityPeer(); + if (markedAsPriority != other.markedAsPriorityPeer()) { + return markedAsPriority; + } + if (distance != other.distance) { return distance < other.distance; } + + const int8_t thisRssi = getRSSI(); + const int8_t otherRssi = other.getRSSI(); - if (getRSSI() != other.getRSSI()) { - if (getRSSI() >= 0) { + if (thisRssi != otherRssi) { + if (thisRssi >= 0) { // This one has no set RSSI, so the other one is better return false; } - if (other.getRSSI() >= 0) { + if (otherRssi >= 0) { // This other has no set RSSI, so the this one is better return true; } - return getRSSI() > other.getRSSI(); + return thisRssi > otherRssi; } return true; } @@ -117,6 +119,10 @@ String NodeStruct::getSummary() const { res += '"'; res += F(" load: "); res += String(getLoad(), 1); + res += F(" RSSI: "); + res += getRSSI(); + res += F(" ch: "); + res += channel; res += F(" dst: "); res += distance; return res; @@ -181,3 +187,20 @@ void NodeStruct::setRSSI(int8_t rssi) } scaled_rssi = rssi; } + +bool NodeStruct::markedAsPriorityPeer() const +{ + for (int i = 0; i < ESPEASY_NOW_PEER_MAX; ++i) { + if (SecuritySettings.peerMacSet(i)) { + if (match(SecuritySettings.EspEasyNowPeerMAC[i])) { + return true; + } + } + } + return false; +} + +bool NodeStruct::match(const MAC_address& mac) const +{ + return (mac == sta_mac || mac == ap_mac); +} \ No newline at end of file diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index e849772cac..569951fce6 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -23,7 +23,8 @@ String getNodeTypeDisplayString(byte nodeType); struct __attribute__((__packed__)) NodeStruct { NodeStruct(); - + + bool valid() const; bool validate(); // Compare nodes. @@ -58,6 +59,10 @@ struct __attribute__((__packed__)) NodeStruct void setRSSI(int8_t rssi); + bool markedAsPriorityPeer() const; + + bool match(const MAC_address& mac) const; + // Do not change the order of this data, as it is being sent via P2P UDP. // 6 byte mac (STA interface) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 8f2b99d47b..67cd82f30a 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -151,17 +151,18 @@ void NodesHandler::updateThisNode() { } if (isEndpoint()) { - thisNode.distance = 0; + _distance = 0; } else { - thisNode.distance = 255; + _distance = 255; const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); if (preferred != nullptr) { if (preferred->distance < 255) { - thisNode.distance = preferred->distance + 1; + _distance = preferred->distance + 1; } } } + thisNode.distance = _distance; addNode(thisNode); } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 2b37f9df28..893a444b10 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -40,11 +40,17 @@ class NodesHandler { const NodeStruct * getThisNode(); + uint8_t getDistance() const { + return _distance; + } + private: bool isEndpoint() const; + uint8_t _distance = 255; // Cached value + NodesMap _nodes; }; diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index 9efef40dfb..17392ab0cf 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -30,6 +30,7 @@ int wifi_reconnects = -1; // First connection attempt is not a re String last_ssid; bool bssid_changed = false; bool channel_changed = false; +bool espeasy_now_only = false; WiFiDisconnectReason lastDisconnectReason = WIFI_DISCONNECT_REASON_UNSPECIFIED; LongTermTimer lastConnectMoment; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index 2a840ff1b3..a8bb7df67d 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -89,6 +89,7 @@ extern int wifi_reconnects; // First connection attempt is not a reconnect. extern String last_ssid; extern bool bssid_changed; extern bool channel_changed; +extern bool espeasy_now_only; extern WiFiDisconnectReason lastDisconnectReason; extern LongTermTimer lastConnectMoment; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 0d72abe8b1..c31bebba08 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -19,6 +19,11 @@ # include +#define ESPEASY_NOW_ACTIVVITY_TIMEOUT 60000 // 1 minute + +#define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" +#define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" + static uint64_t mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messageType, uint8_t message_count) { uint64_t key = message_count; @@ -62,30 +67,67 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t bool ESPEasy_now_handler_t::begin() { - if (!WifiEspNow.begin()) { return false; } - if (!Settings.UseESPEasyNow()) { return false; } + if (use_EspEasy_now) { + return true; + } + + _last_used = millis(); + int channel = WiFi.channel(); + + const NodeStruct* preferred = Nodes.getPreferredNode(); + if (preferred != nullptr) { + channel = preferred->channel; + } + + const String ssid = F(ESPEASY_NOW_TMP_SSID); + const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); + + if (espeasy_now_only) { + WifiScan(false, false); + addPeerFromWiFiScan(); + + const uint8_t* bssid = nullptr; + bool connect = false; + WiFi.begin(ssid.c_str(), passphrase.c_str(), channel); + } + setAP(true); + + WiFi.softAP(ssid.c_str(), passphrase.c_str(), channel); +// WiFi.softAPdisconnect(false); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-Now: begin on channel "); + log += channel; + addLog(LOG_LEVEL_INFO, log); + } + + if (!WifiEspNow.begin()) { + addLog(LOG_LEVEL_ERROR, F("ESPEasy-Now: Failed to initialize ESPEasy-Now")); + return false; + } + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { if (SecuritySettings.peerMacSet(peer)) { - if (!WifiEspNow.addPeer(SecuritySettings.EspEasyNowPeerMAC[peer])) { - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log; - log.reserve(48); - log = F("ESPEasy_Now: Failed to add peer "); - log += MAC_address(SecuritySettings.EspEasyNowPeerMAC[peer]).toString(); - addLog(LOG_LEVEL_ERROR, log); - } - } + add_peer(SecuritySettings.EspEasyNowPeerMAC[peer], 0); + } + } + + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { + if (it->second.ESPEasyNowPeer) { + add_peer(it->second.ESPEasy_Now_MAC(), it->second.channel); } } + // FIXME TD-er: Must check in settings if enabled WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); sendDiscoveryAnnounce(); use_EspEasy_now = true; + _last_used = 0; addLog(LOG_LEVEL_INFO, F("ESPEasy-Now enabled")); return true; } @@ -156,9 +198,29 @@ bool ESPEasy_now_handler_t::loop() } } } + if (_send_failed_count > 30 /*|| !active()*/) { + _send_failed_count = 0; + espeasy_now_only = true; + // Start scanning the next channel to see if we may end up with a new found node +// WifiScan(false, false); +// addPeerFromWiFiScan(); +// _last_used = millis(); + begin(); + } return somethingProcessed; } +bool ESPEasy_now_handler_t::active() const +{ + if (!use_EspEasy_now) { + return false; + } + if (_last_used == 0) { + return false; + } + return (timePassedSince(_last_used) < ESPEASY_NOW_ACTIVVITY_TIMEOUT); +} + void ESPEasy_now_handler_t::addPeerFromWiFiScan() { const int8_t scanCompleteStatus = WiFi.scanComplete(); @@ -188,8 +250,28 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) nodeInfo->setRSSI(WiFi.RSSI(scanIndex)); nodeInfo->channel = WiFi.channel(scanIndex); } else { - // Must trigger a discovery request from the node. - sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + // FIXME TD-er: For now we assume the other node uses AP for ESPEasy-now + NodeStruct tmpNodeInfo; + tmpNodeInfo.setRSSI(WiFi.RSSI(scanIndex)); + tmpNodeInfo.channel = WiFi.channel(scanIndex); + peer_mac.get(tmpNodeInfo.ap_mac); + tmpNodeInfo.setESPEasyNow_mac(peer_mac); + + if (tmpNodeInfo.markedAsPriorityPeer()) { + Nodes.addNode(tmpNodeInfo); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-Now: Found node via WiFi scan: "); + log += peer_mac.toString(); + log += F(" "); + log += tmpNodeInfo.getRSSI(); + log += F(" dBm ch: "); + log += tmpNodeInfo.channel; + addLog(LOG_LEVEL_INFO, log); + } + // Must trigger a discovery request from the node. + // FIXME TD-er: Disable auto discovery for now + // sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + } } } @@ -218,6 +300,9 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) handled = handle_SendData_DuplicateCheck(message); break; } + if (handled) { + _last_used = millis(); + } return handled; } @@ -273,7 +358,8 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m return false; } - bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; +// FIXME TD-er: Disable auto discovery for now +// bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; Nodes.addNode(received); @@ -294,9 +380,12 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m addLog(LOG_LEVEL_INFO, log); } + // FIXME TD-er: Disable auto discovery for now +/* if (isNewNode) { sendDiscoveryAnnounce(mac); } +*/ return true; } @@ -373,6 +462,13 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const { if (!use_EspEasy_now) { return false; } + const uint8_t distance = Nodes.getDistance(); + if (distance == 0 || distance == 255) { + // No need to send via ESPEasy_Now. + // We're either connected (distance == 0) + // or have no neighbor that can forward the message (distance == 255) + return false; + } MakeControllerSettings(ControllerSettings); LoadControllerSettings(controllerIndex, ControllerSettings); @@ -392,6 +488,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const msg.addString(topic); msg.addString(payload); +/* for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX && !processed; ++peer) { // FIXME TD-er: This must be optimized to keep the last working index. // Or else it may take quite a while to send each message @@ -404,15 +501,22 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const processed = true; break; } + case WifiEspNowSendStatus::NONE: + case WifiEspNowSendStatus::FAIL: + { + ++_send_failed_count; + break; + } default: break; } } } + */ if (!processed) { const NodeStruct* preferred = Nodes.getPreferredNode(); if (preferred != nullptr) { MAC_address mac = preferred->ESPEasy_Now_MAC(); - WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + ControllerSettings.ClientTimeout, preferred->channel); + WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2* ControllerSettings.ClientTimeout, preferred->channel); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -420,6 +524,12 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const processed = true; break; } + case WifiEspNowSendStatus::NONE: + case WifiEspNowSendStatus::FAIL: + { + ++_send_failed_count; + break; + } default: break; } @@ -528,4 +638,23 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer return false; } +bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const +{ + MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + // Don't add yourself as a peer + if (this_mac == mac) return false; + if (!WifiEspNow.addPeer(mac.mac, channel)) { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log; + log.reserve(48); + log = F("ESPEasy_Now: Failed to add peer "); + log += MAC_address(mac).toString(); + addLog(LOG_LEVEL_ERROR, log); + } + return false; + } + return true; +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index cee5d9fa27..37f98cbed8 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -25,6 +25,8 @@ class ESPEasy_now_handler_t { bool loop(); + bool active() const; + void addPeerFromWiFiScan(); void addPeerFromWiFiScan(uint8_t scanIndex); @@ -61,7 +63,13 @@ class ESPEasy_now_handler_t { bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message); + bool add_peer(const MAC_address& mac, int channel) const; + ESPEasy_Now_NTP_query _best_NTP_candidate; + + unsigned long _last_used = 0; + + uint8_t _send_failed_count = 0; }; From 17b7258aa43b1e8dd8641f797cd532a97b88faec Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 4 Jun 2020 03:20:47 +0200 Subject: [PATCH 033/404] [ESPEasy-Now] Clean up espeasy-now only code --- src/ESPEasyWiFi_credentials.cpp | 79 +++++++++++++++++++++++-- src/ESPEasyWifi_ProcessEvent.cpp | 36 +++++------ src/WebServer_RootPage.ino | 22 ++++--- src/src/DataStructs/NodeStruct.cpp | 9 +++ src/src/Helpers/ESPEasy_now_handler.cpp | 24 +++++--- 5 files changed, 134 insertions(+), 36 deletions(-) diff --git a/src/ESPEasyWiFi_credentials.cpp b/src/ESPEasyWiFi_credentials.cpp index aea8a2c5a0..276cc977f7 100644 --- a/src/ESPEasyWiFi_credentials.cpp +++ b/src/ESPEasyWiFi_credentials.cpp @@ -5,24 +5,92 @@ // ******************************************************************************** // Manage WiFi credentials // ******************************************************************************** + +#include "src/Globals/ESPEasy_now_state.h" +#include "src/Globals/SecuritySettings.h" +#include "src/Globals/RTC.h" +#include "src/Globals/ESPEasyWiFiEvent.h" + +#ifdef USES_ESPEASY_NOW +#define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" +#define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" +#endif + +bool validWiFiSettingsIndex(uint8_t index) { + return index <= 2; +} + +#ifdef USES_ESPEASY_NOW +bool isESPEasy_now_only(uint8_t index) { + return index == 2; +} +#endif + const char* getLastWiFiSettingsSSID() { - return RTC.lastWiFiSettingsIndex == 0 ? SecuritySettings.WifiSSID : SecuritySettings.WifiSSID2; + switch (RTC.lastWiFiSettingsIndex) { + case 0: + return SecuritySettings.WifiSSID; + case 1: + return SecuritySettings.WifiSSID2; + +#ifdef USES_ESPEASY_NOW + case 2: + return ESPEASY_NOW_TMP_SSID; +#endif + default: + break; + } + return nullptr; } const char* getLastWiFiSettingsPassphrase() { - return RTC.lastWiFiSettingsIndex == 0 ? SecuritySettings.WifiKey : SecuritySettings.WifiKey2; + switch (RTC.lastWiFiSettingsIndex) { + case 0: + return SecuritySettings.WifiKey; + case 1: + return SecuritySettings.WifiKey2; + +#ifdef USES_ESPEASY_NOW + case 2: + return ESPEASY_NOW_TMP_PASSPHRASE; +#endif + default: + break; + } + return nullptr; } bool selectNextWiFiSettings() { uint8_t tmp = RTC.lastWiFiSettingsIndex; - - RTC.lastWiFiSettingsIndex = (RTC.lastWiFiSettingsIndex + 1) % 2; + RTC.lastWiFiSettingsIndex += 1; + if (!validWiFiSettingsIndex(RTC.lastWiFiSettingsIndex)) { + RTC.lastWiFiSettingsIndex = 0; + } if (!wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase())) { // other settings are not correct, switch back. RTC.lastWiFiSettingsIndex = tmp; return false; // Nothing changed. } +#ifdef USES_ESPEASY_NOW + if (espeasy_now_only != isESPEasy_now_only(RTC.lastWiFiSettingsIndex)) { + if (!espeasy_now_only) { + espeasy_now_only = true; + ESPEasy_now_handler.end(); + addLog(LOG_LEVEL_INFO, F("ESPEasy-Now only mode")); + } + if (espeasy_now_only) { + if (!ESPEasy_now_handler.begin()) { + espeasy_now_only = false; + } + } + } + if (espeasy_now_only && use_EspEasy_now) { + if (!ESPEasy_now_handler.active()) { + espeasy_now_only = false; + } + } +#endif return true; } @@ -34,6 +102,9 @@ bool selectValidWiFiSettings() { } bool wifiSettingsValid(const char *ssid, const char *pass) { + if (ssid == nullptr || pass == nullptr) { + return false; + } if ((ssid[0] == 0) || (strcasecmp(ssid, "ssid") == 0)) { return false; } diff --git a/src/ESPEasyWifi_ProcessEvent.cpp b/src/ESPEasyWifi_ProcessEvent.cpp index 02bf85d1d6..0d4f1b94b6 100644 --- a/src/ESPEasyWifi_ProcessEvent.cpp +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -411,26 +411,28 @@ void processScanDone() { const uint8_t startWiFiSettings = RTC.lastWiFiSettingsIndex; bool done = false; while (!done) { - String ssid_to_check = getLastWiFiSettingsSSID(); - for (int i = 0; i < scanCompleteStatus; ++i) { - if (WiFi.SSID(i) == ssid_to_check) { - int32_t rssi = WiFi.RSSI(i); - - if (bestRssi < rssi) { - bestRssi = rssi; - bestScanID = i; - bestWiFiSettings = RTC.lastWiFiSettingsIndex; + if (getLastWiFiSettingsSSID() != nullptr) { + String ssid_to_check = getLastWiFiSettingsSSID(); + for (int i = 0; i < scanCompleteStatus; ++i) { + if (WiFi.SSID(i) == ssid_to_check) { + int32_t rssi = WiFi.RSSI(i); + + if (bestRssi < rssi) { + bestRssi = rssi; + bestScanID = i; + bestWiFiSettings = RTC.lastWiFiSettingsIndex; + } } } - } - // Select the next WiFi settings. - // RTC.lastWiFiSettingsIndex may be updated. - if (!selectNextWiFiSettings()) { - done = true; - } - if (startWiFiSettings == RTC.lastWiFiSettingsIndex) { - done = true; + // Select the next WiFi settings. + // RTC.lastWiFiSettingsIndex may be updated. + if (!selectNextWiFiSettings()) { + done = true; + } + if (startWiFiSettings == RTC.lastWiFiSettingsIndex) { + done = true; + } } } diff --git a/src/WebServer_RootPage.ino b/src/WebServer_RootPage.ino index 6fac604ce6..11461e3ec7 100644 --- a/src/WebServer_RootPage.ino +++ b/src/WebServer_RootPage.ino @@ -162,6 +162,7 @@ void handle_root() { html_table_header("Age (s)"); #ifdef USES_ESPEASY_NOW html_table_header("Dist"); + html_table_header("Peer Info", 160); #endif for (auto it = Nodes.begin(); it != Nodes.end(); ++it) @@ -212,13 +213,7 @@ void handle_root() { html += it->second.IP().toString(); html += ""; addHtml(html); - } else if (it->second.ESPEasyNowPeer) { - addHtml(F("ESPEasy-Now ")); - addHtml(it->second.ESPEasy_Now_MAC().toString()); - addHtml(F(" (ch: ")); - addHtml(String(it->second.channel)); - addHtml(F(")")); - } + } html_TD(); const float load = it->second.getLoad(); if (load > 0.1) { @@ -231,6 +226,19 @@ void handle_root() { if (it->second.distance != 255) { addHtml(String(it->second.distance)); } + html_TD(); + if (it->second.ESPEasyNowPeer) { + addHtml(F("ESPEasy-Now ")); + addHtml(it->second.ESPEasy_Now_MAC().toString()); + addHtml(F(" (ch: ")); + addHtml(String(it->second.channel)); + int8_t rssi = it->second.getRSSI(); + if (rssi < 0) { + addHtml(F(" ")); + addHtml(String(rssi)); + } + addHtml(F(")")); + } #endif } } diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index b0bdc1fd49..1f4445cce8 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -19,8 +19,17 @@ bool NodeStruct::validate() { if (build < 20107) { // webserverPort introduced in 20107 webgui_portnumber = 80; + for (byte i = 0; i < 6; ++i) { + ap_mac[i] = 0; + } load = 0; distance = 255; + timeSource = static_cast(timeSource_t::No_time_source); + channel = 0; + ESPEasyNowPeer = 0; + useAP_ESPEasyNow = 0; + setRSSI(0); + lastUpdated = 0; } // FIXME TD-er: Must make some sanity checks to see if it is a valid message diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index c31bebba08..9607c093d8 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -75,27 +75,35 @@ bool ESPEasy_now_handler_t::begin() _last_used = millis(); int channel = WiFi.channel(); + MAC_address bssid; + + if (espeasy_now_only) { + WifiScan(false, false); + addPeerFromWiFiScan(); + } const NodeStruct* preferred = Nodes.getPreferredNode(); if (preferred != nullptr) { channel = preferred->channel; + bssid.set(preferred->ap_mac); } const String ssid = F(ESPEASY_NOW_TMP_SSID); const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); if (espeasy_now_only) { - WifiScan(false, false); - addPeerFromWiFiScan(); - - const uint8_t* bssid = nullptr; - bool connect = false; - WiFi.begin(ssid.c_str(), passphrase.c_str(), channel); + if (bssid.all_zero()) { + WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel); + } else { + WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel, bssid.mac); + } } setAP(true); - WiFi.softAP(ssid.c_str(), passphrase.c_str(), channel); -// WiFi.softAPdisconnect(false); + int ssid_hidden = 1; + int max_connection = 6; + WiFi.softAP(ssid.c_str(), passphrase.c_str(), channel, ssid_hidden, max_connection); +// WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy-Now: begin on channel "); From ab554bbac22e8a04d37060c99be6019b58ee2686 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 6 Jun 2020 12:28:10 +0200 Subject: [PATCH 034/404] [ESPEasy-Now] Prepare for quick auto discovery based on probe event --- src/ESPEasyWiFiEvent.cpp | 5 +++++ src/ESPEasyWiFiEvent.h | 2 ++ src/ESPEasyWifi.cpp | 1 + src/ESPEasyWifi_ProcessEvent.cpp | 23 +++++++++++++++++++++++ src/src/DataStructs/MAC_address.h | 24 ++++++++++++++++++++++++ src/src/DataStructs/NodesHandler.cpp | 4 +++- src/src/Globals/ESPEasyWiFiEvent.cpp | 4 ++++ src/src/Globals/ESPEasyWiFiEvent.h | 4 ++++ 8 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index 6f9511612a..684f6cdf5e 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -216,4 +216,9 @@ void onDisonnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { processedDisconnectAPmode = false; } +void onProbeRequestAPmode(const WiFiEventSoftAPModeProbeRequestReceived& event) { + APModeProbeRequestReceived_list.push_back(event); + processedProbeRequestAPmode = false; +} + #endif // ifdef ESP8266 diff --git a/src/ESPEasyWiFiEvent.h b/src/ESPEasyWiFiEvent.h index 1bc9724bf8..5161cb4f21 100644 --- a/src/ESPEasyWiFiEvent.h +++ b/src/ESPEasyWiFiEvent.h @@ -58,6 +58,8 @@ void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event); void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event); +void onProbeRequestAPmode(const WiFiEventSoftAPModeProbeRequestReceived& event); + #endif // ifdef ESP32 diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 795ce62985..52b773deaf 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -350,6 +350,7 @@ void resetWiFi() { processedDHCPTimeout = true; processedConnectAPmode = true; processedDisconnectAPmode = true; + processedProbeRequestAPmode = true; processedScanDone = true; wifiConnectAttemptNeeded = true; WifiDisconnect(); diff --git a/src/ESPEasyWifi_ProcessEvent.cpp b/src/ESPEasyWifi_ProcessEvent.cpp index 0d4f1b94b6..d3959b31e9 100644 --- a/src/ESPEasyWifi_ProcessEvent.cpp +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -122,6 +122,8 @@ void handle_unprocessedWiFiEvents() if (!processedConnectAPmode) { processConnectAPmode(); } + if (!processedProbeRequestAPmode) { processProbeRequestAPmode(); } + if (timerAPoff.isSet()) { processDisableAPmode(); } if (!processedScanDone) { processScanDone(); } @@ -335,6 +337,27 @@ void processDisconnectAPmode() { } } +void processProbeRequestAPmode() { + if (processedProbeRequestAPmode) { return; } + + const MAC_address mac(APModeProbeRequestReceived_list.front().mac); + const int rssi = APModeProbeRequestReceived_list.front().rssi; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("AP Mode: Probe Request: "); + log += mac.toString(); + log += F(" ("); + log += rssi; + log += F(" dBm)"); + addLog(LOG_LEVEL_INFO, log); + } + + // FIXME TD-er: Must create an answer for ESPEasy-now node discovery + + APModeProbeRequestReceived_list.pop_front(); + processedProbeRequestAPmode = APModeProbeRequestReceived_list.size() == 0; +} + // Client connects to AP on this node void processConnectAPmode() { if (processedConnectAPmode) { return; } diff --git a/src/src/DataStructs/MAC_address.h b/src/src/DataStructs/MAC_address.h index 736d436fd9..e05533cc3f 100644 --- a/src/src/DataStructs/MAC_address.h +++ b/src/src/DataStructs/MAC_address.h @@ -41,6 +41,30 @@ class __attribute__((__packed__)) MAC_address { void toString(char (& strMAC)[20]) const; + // An universally administered address (UAA) is uniquely assigned to a device by its manufacturer. + // The first three octets (in transmission order) identify the organization that issued + // the identifier and are known as the organizationally unique identifier (OUI) + bool isUniversal() const { + return (mac[0] & 2) == 0; + } + + // A locally administered address (LAA) is assigned to a device by a network administrator, overriding the burned-in address. + bool isLocal() const { + return !isUniversal(); + } + + // Unicast frames are meant to be received by a single network device. + // See: https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast + bool isUnicast() const { + return (mac[0] & 1) == 0; + } + + // Multicast frames are meant to be received by multiple network devices + // See: https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast + bool isMulticast() const { + return !isUnicast(); + } + uint8_t mac[6] = { 0 }; private: diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 67cd82f30a..f200db2f36 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -215,7 +215,9 @@ bool NodesHandler::isEndpoint() const #ifdef USES_MQTT controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(enabledMqttController)) { - return MQTTclient_connected; + // FIXME TD-er: Must call updateMQTTclient_connected() and see what effect + // the MQTTclient_connected state has when using ESPEasy-now. + return MQTTclient.connected(); } #endif diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index 17392ab0cf..75703fe4be 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -16,6 +16,9 @@ WiFiEventHandler stationGotIpHandler; WiFiEventHandler stationModeDHCPTimeoutHandler; WiFiEventHandler APModeStationConnectedHandler; WiFiEventHandler APModeStationDisconnectedHandler; +WiFiEventHandler APModeProbeRequestReceivedHandler; + +std::list APModeProbeRequestReceived_list; #endif // ifdef ESP8266 @@ -53,6 +56,7 @@ volatile bool processedGotIP = true; volatile bool processedDHCPTimeout = true; volatile bool processedConnectAPmode = true; volatile bool processedDisconnectAPmode = true; +volatile bool processedProbeRequestAPmode = true; volatile bool processedScanDone = true; bool wifiConnectAttemptNeeded = true; bool wifiConnectInProgress = false; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index a8bb7df67d..8f75c98b44 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "../DataStructs/MAC_address.h" #include "../Helpers/LongTermTimer.h" @@ -75,6 +76,8 @@ extern WiFiEventHandler stationGotIpHandler; extern WiFiEventHandler stationModeDHCPTimeoutHandler; extern WiFiEventHandler APModeStationConnectedHandler; extern WiFiEventHandler APModeStationDisconnectedHandler; +extern WiFiEventHandler APModeProbeRequestReceivedHandler; +extern std::list APModeProbeRequestReceived_list; #endif // ifdef ESP8266 @@ -113,6 +116,7 @@ extern volatile bool processedGotIP; extern volatile bool processedDHCPTimeout; extern volatile bool processedConnectAPmode; extern volatile bool processedDisconnectAPmode; +extern volatile bool processedProbeRequestAPmode; extern volatile bool processedScanDone; extern bool wifiConnectAttemptNeeded; extern bool wifiConnectInProgress; From d1a865d4f4d229df31ebd2a50487fba181f47aed Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 8 Jun 2020 14:04:49 +0200 Subject: [PATCH 035/404] Fix merge issue with EventValueSource::Enum source --- src/src/Commands/InternalCommands.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 2a45456652..5353eb5527 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -14,6 +14,7 @@ #include "../Commands/Common.h" #include "../Commands/Controller.h" #include "../Commands/Diagnostic.h" +#include "../Commands/ESPEasy_Now_cmd.h" #include "../Commands/HTTP.h" #include "../Commands/i2c.h" @@ -191,6 +192,8 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch COMMAND_CASE("erasesdkwifi", Command_WiFi_Erase, 0); // WiFi.h COMMAND_CASE( "event", Command_Rules_Events, -1); // Rule.h COMMAND_CASE("executerules", Command_Rules_Execute, -1); // Rule.h + COMMAND_CASE("espeasynowdisable", Command_ESPEasy_Now_Disable, 0); // ESPEasy_Now_cmd.h + COMMAND_CASE( "espeasynowenable", Command_ESPEasy_Now_Enable, 0); // ESPEasy_Now_cmd.h break; } case 'g': { From abf255cc2db3de34c5b8156e1314fbb123387e08 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 10 Jun 2020 15:30:30 +0200 Subject: [PATCH 036/404] [Controller] Check if controller host/IP is set before MQTT connect --- src/src/DataStructs/ControllerSettingsStruct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index b3f6b32ec5..a68355520c 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -137,7 +137,7 @@ struct ControllerSettingsStruct bool enableESPEasyNowFallback() const; void enableESPEasyNowFallback(bool value); - boolean UseDNS; + bool UseDNS; byte IP[4]; unsigned int Port; char HostName[65]; From 3abe65bc623d700ea7b89c4df3eae5043f0899ce Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 10 Jun 2020 15:33:02 +0200 Subject: [PATCH 037/404] [ESPEasy-Now] Retry sending separate packets for multi-part ESPEasy-now --- src/src/DataStructs/ESPEasy_now_splitter.cpp | 54 +++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 15aff41561..acf64ff2f2 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -99,34 +99,40 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - send(_queue[i], channel); - sendStatus = waitForSendStatus(timeout); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - - switch (sendStatus) { - case WifiEspNowSendStatus::NONE: - { - log = F("ESPEasy Now: TIMEOUT to: "); - break; - } - case WifiEspNowSendStatus::FAIL: - { - log = F("ESPEasy Now: Sent FAILED to: "); - break; - } - case WifiEspNowSendStatus::OK: - { - log = F("ESPEasy Now: Sent to: "); - break; + uint8_t retry = 2; + while (retry > 0) { + --retry; + send(_queue[i], channel); + sendStatus = waitForSendStatus(timeout); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + + switch (sendStatus) { + case WifiEspNowSendStatus::NONE: + { + log = F("ESPEasy Now: TIMEOUT to: "); + break; + } + case WifiEspNowSendStatus::FAIL: + { + log = F("ESPEasy Now: Sent FAILED to: "); + if (retry != 0) { + delay(10); + } + break; + } + case WifiEspNowSendStatus::OK: + { + log = F("ESPEasy Now: Sent to: "); + retry = 0; + break; + } } + log += _queue[i].getLogString(); + addLog(LOG_LEVEL_INFO, log); } - log += _queue[i].getLogString(); - addLog(LOG_LEVEL_INFO, log); } - switch (sendStatus) { case WifiEspNowSendStatus::NONE: case WifiEspNowSendStatus::FAIL: From f8c008a19c5c1b99bd0b14e9aabb87392b59b9c9 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 10 Jun 2020 15:33:35 +0200 Subject: [PATCH 038/404] [ESPEasy-Now] Send out discovery announce immediately when being probed --- src/ESPEasyWifi_ProcessEvent.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ESPEasyWifi_ProcessEvent.cpp b/src/ESPEasyWifi_ProcessEvent.cpp index d3959b31e9..8b9c79b822 100644 --- a/src/ESPEasyWifi_ProcessEvent.cpp +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -314,6 +314,7 @@ void processGotIP() { wifiSetup = false; SaveSettings(); } + refreshNodeList(); logConnectionStatus(); if ((bitRead(wifiStatus, ESPEASY_WIFI_CONNECTED) || WiFi.isConnected()) && hasIPaddr()) { @@ -353,6 +354,9 @@ void processProbeRequestAPmode() { } // FIXME TD-er: Must create an answer for ESPEasy-now node discovery + #ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.sendDiscoveryAnnounce(); + #endif APModeProbeRequestReceived_list.pop_front(); processedProbeRequestAPmode = APModeProbeRequestReceived_list.size() == 0; From ae93c4d81055cdc828062444d1e3045cf2cfb009 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 11 Jun 2020 13:21:57 +0200 Subject: [PATCH 039/404] [ESPEasy-Now] MQTT queue management to optimize forwarding flow Keep track of the MQTT queue of the receiving end of the MQTT forwarding. This allows to more efficiently forward the relatively large messages throughout a longer chain of ESPEasy-now nodes. --- .../ESPEasy_Now_MQTT_queue_check_packet.cpp | 18 ++ .../ESPEasy_Now_MQTT_queue_check_packet.h | 33 ++ src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 290 ++++++++++++------ src/src/Helpers/ESPEasy_now_handler.h | 18 +- 5 files changed, 261 insertions(+), 99 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp new file mode 100644 index 0000000000..f0629d6f8c --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp @@ -0,0 +1,18 @@ +#include "ESPEasy_Now_MQTT_queue_check_packet.h" + + + +void ESPEasy_Now_MQTT_queue_check_packet::markSendTime() { + _millis_out = millis(); + state = QueueState::Unset; +} + +void ESPEasy_Now_MQTT_queue_check_packet::setState(bool isFull) +{ + state = isFull ? QueueState::Full : QueueState::Empty; +} + +bool ESPEasy_Now_MQTT_queue_check_packet::isSet() const +{ + return state != QueueState::Unset; +} \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h new file mode 100644 index 0000000000..b0a8fb6579 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h @@ -0,0 +1,33 @@ +#ifndef DATASTRUCT_ESPEASY_NOW_MQTT_QUEUE_CHECK_PACKET_H +#define DATASTRUCT_ESPEASY_NOW_MQTT_QUEUE_CHECK_PACKET_H + +#include + +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + +class ESPEasy_Now_MQTT_queue_check_packet { +public: + + enum class QueueState : uint8_t { + Unset, + Empty, + Full + }; + + ESPEasy_Now_MQTT_queue_check_packet() {} + + void setState(bool isFull); + + bool isSet() const; + + void markSendTime(); + + unsigned long _millis_out = millis(); + QueueState state = QueueState::Unset; + +}; + +#endif // ifdef USES_ESPEASY_NOW + +#endif // DATASTRUCT_ESPEASY_NOW_MQTT_QUEUE_CHECK_PACKET_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index e92cf1876b..00499f9d76 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -23,6 +23,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { MQTTControllerMessage, NTP_Query, SendData_DuplicateCheck, + MQTTCheckControllerQueue, ChecksumError = 255 }; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 9607c093d8..9eaffb0914 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -19,10 +19,10 @@ # include -#define ESPEASY_NOW_ACTIVVITY_TIMEOUT 60000 // 1 minute +# define ESPEASY_NOW_ACTIVVITY_TIMEOUT 60000 // 1 minute -#define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" -#define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" +# define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" +# define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" static uint64_t mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messageType, uint8_t message_count) { @@ -69,7 +69,7 @@ bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } - if (use_EspEasy_now) { + if (use_EspEasy_now) { return true; } @@ -82,13 +82,14 @@ bool ESPEasy_now_handler_t::begin() addPeerFromWiFiScan(); } - const NodeStruct* preferred = Nodes.getPreferredNode(); + const NodeStruct *preferred = Nodes.getPreferredNode(); + if (preferred != nullptr) { channel = preferred->channel; bssid.set(preferred->ap_mac); } - const String ssid = F(ESPEASY_NOW_TMP_SSID); + const String ssid = F(ESPEASY_NOW_TMP_SSID); const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); if (espeasy_now_only) { @@ -100,10 +101,11 @@ bool ESPEasy_now_handler_t::begin() } setAP(true); - int ssid_hidden = 1; + int ssid_hidden = 1; int max_connection = 6; WiFi.softAP(ssid.c_str(), passphrase.c_str(), channel, ssid_hidden, max_connection); -// WiFi.softAPdisconnect(false); + + // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy-Now: begin on channel "); @@ -111,9 +113,9 @@ bool ESPEasy_now_handler_t::begin() addLog(LOG_LEVEL_INFO, log); } - if (!WifiEspNow.begin()) { + if (!WifiEspNow.begin()) { addLog(LOG_LEVEL_ERROR, F("ESPEasy-Now: Failed to initialize ESPEasy-Now")); - return false; + return false; } for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { @@ -135,7 +137,7 @@ bool ESPEasy_now_handler_t::begin() sendDiscoveryAnnounce(); use_EspEasy_now = true; - _last_used = 0; + _last_used = 0; addLog(LOG_LEVEL_INFO, F("ESPEasy-Now enabled")); return true; } @@ -190,7 +192,9 @@ bool ESPEasy_now_handler_t::loop() } } else { // Process it - somethingProcessed = processMessage(it->second); + bool mustKeep = !removeMessage; + somethingProcessed = processMessage(it->second, mustKeep); + removeMessage = !mustKeep; STOP_TIMER(HANDLE_ESPEASY_NOW_LOOP); } @@ -206,13 +210,15 @@ bool ESPEasy_now_handler_t::loop() } } } + if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; - espeasy_now_only = true; + espeasy_now_only = true; + // Start scanning the next channel to see if we may end up with a new found node -// WifiScan(false, false); -// addPeerFromWiFiScan(); -// _last_used = millis(); + // WifiScan(false, false); + // addPeerFromWiFiScan(); + // _last_used = millis(); begin(); } return somethingProcessed; @@ -223,15 +229,17 @@ bool ESPEasy_now_handler_t::active() const if (!use_EspEasy_now) { return false; } + if (_last_used == 0) { return false; } - return (timePassedSince(_last_used) < ESPEASY_NOW_ACTIVVITY_TIMEOUT); + return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVVITY_TIMEOUT; } void ESPEasy_now_handler_t::addPeerFromWiFiScan() { const int8_t scanCompleteStatus = WiFi.scanComplete(); + for (int8_t i = 0; i < scanCompleteStatus; ++i) { addPeerFromWiFiScan(i); } @@ -267,6 +275,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) if (tmpNodeInfo.markedAsPriorityPeer()) { Nodes.addNode(tmpNodeInfo); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("ESPEasy-Now: Found node via WiFi scan: "); log += peer_mac.toString(); @@ -276,17 +285,19 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) log += tmpNodeInfo.channel; addLog(LOG_LEVEL_INFO, log); } + // Must trigger a discovery request from the node. // FIXME TD-er: Disable auto discovery for now - // sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + // sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); } } } -bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { addLog(LOG_LEVEL_INFO, message.getLogString()); bool handled = false; + mustKeep = true; switch (message.getFirstHeader().message_type) { @@ -296,18 +307,22 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message) case ESPEasy_now_hdr::message_t::Acknowledgement: break; case ESPEasy_now_hdr::message_t::Announcement: - handled = handle_DiscoveryAnnounce(message); + handled = handle_DiscoveryAnnounce(message, mustKeep); break; case ESPEasy_now_hdr::message_t::NTP_Query: - handled = handle_NTPquery(message); + handled = handle_NTPquery(message, mustKeep); break; case ESPEasy_now_hdr::message_t::MQTTControllerMessage: - handled = handle_MQTTControllerMessage(message); + handled = handle_MQTTControllerMessage(message, mustKeep); + break; + case ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue: + handled = handle_MQTTCheckControllerQueue(message, mustKeep); break; case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: - handled = handle_SendData_DuplicateCheck(message); + handled = handle_SendData_DuplicateCheck(message, mustKeep); break; } + if (handled) { _last_used = millis(); } @@ -331,7 +346,8 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce() void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int channel) { - const NodeStruct * thisNode = Nodes.getThisNode(); + const NodeStruct *thisNode = Nodes.getThisNode(); + if (thisNode == nullptr) { // Should not happen return; @@ -342,8 +358,9 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch msg.send(mac, channel); } -bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep) { + mustKeep = false; NodeStruct received; // Discovery messages have a single binary blob, starting at 0 @@ -366,8 +383,8 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m return false; } -// FIXME TD-er: Disable auto discovery for now -// bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; + // FIXME TD-er: Disable auto discovery for now + // bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; Nodes.addNode(received); @@ -389,11 +406,12 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m } // FIXME TD-er: Disable auto discovery for now -/* - if (isNewNode) { - sendDiscoveryAnnounce(mac); - } -*/ + + /* + if (isNewNode) { + sendDiscoveryAnnounce(mac); + } + */ return true; } @@ -433,8 +451,9 @@ void ESPEasy_now_handler_t::sendNTPbroadcast() msg.send(query._mac); } -bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, bool& mustKeep) { + mustKeep = false; ESPEasy_Now_NTP_query query; // NTP query messages have a single binary blob, starting at 0 @@ -471,7 +490,8 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (!use_EspEasy_now) { return false; } const uint8_t distance = Nodes.getDistance(); - if (distance == 0 || distance == 255) { + + if ((distance == 0) || (distance == 255)) { // No need to send via ESPEasy_Now. // We're either connected (distance == 0) // or have no neighbor that can forward the message (distance == 255) @@ -484,70 +504,55 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const bool processed = false; if (ControllerSettings.enableESPEasyNowFallback() /*&& !WiFiConnected(10) */) { - // each string has null termination - const size_t topic_length = topic.length() + 1; - const size_t payload_length = payload.length() + 1; - - // Todo: Add cpluginID_t cpluginID; to the message - size_t len = topic_length + payload_length; - - ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTControllerMessage, len); - - msg.addString(topic); - msg.addString(payload); - -/* - for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX && !processed; ++peer) { - // FIXME TD-er: This must be optimized to keep the last working index. - // Or else it may take quite a while to send each message - if (SecuritySettings.peerMacSet(peer)) { - WifiEspNowSendStatus sendStatus = msg.send(SecuritySettings.EspEasyNowPeerMAC[peer], millis() + ControllerSettings.ClientTimeout, 0); - - switch (sendStatus) { - case WifiEspNowSendStatus::OK: - { - processed = true; - break; - } - case WifiEspNowSendStatus::NONE: - case WifiEspNowSendStatus::FAIL: - { - ++_send_failed_count; - break; - } - default: break; - } + const NodeStruct *preferred = Nodes.getPreferredNode(); + + if (preferred != nullptr) { + + switch (_preferredNodeMQTTqueueState.state) { + case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: + case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: + sendMQTTCheckControllerQueue(controllerIndex); + return false; + case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Empty: + break; } - } - */ - if (!processed) { - const NodeStruct* preferred = Nodes.getPreferredNode(); - if (preferred != nullptr) { - MAC_address mac = preferred->ESPEasy_Now_MAC(); - WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2* ControllerSettings.ClientTimeout, preferred->channel); - - switch (sendStatus) { - case WifiEspNowSendStatus::OK: - { - processed = true; - break; - } - case WifiEspNowSendStatus::NONE: - case WifiEspNowSendStatus::FAIL: - { - ++_send_failed_count; - break; - } - default: break; - } + + // each string has null termination + const size_t topic_length = topic.length() + 1; + const size_t payload_length = payload.length() + 1; + + // Todo: Add cpluginID_t cpluginID; to the message + size_t len = topic_length + payload_length; + + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTControllerMessage, len); + + msg.addString(topic); + msg.addString(payload); + + MAC_address mac = preferred->ESPEasy_Now_MAC(); + WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * ControllerSettings.ClientTimeout, preferred->channel); + + switch (sendStatus) { + case WifiEspNowSendStatus::OK: + { + processed = true; + break; + } + case WifiEspNowSendStatus::NONE: + case WifiEspNowSendStatus::FAIL: + { + ++_send_failed_count; + break; + } + default: break; } } } return processed; } -bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message, bool& mustKeep) { # ifdef USES_MQTT @@ -562,7 +567,100 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge MakeControllerSettings(ControllerSettings); LoadControllerSettings(controllerIndex, ControllerSettings); - return MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + + MAC_address mac; + if (message.getMac(mac)) { + ESPEasy_Now_MQTT_queue_check_packet query; + query.setState(MQTT_queueFull(controllerIndex)); + sendMQTTCheckControllerQueue(mac, 0, query.state); + } + + mustKeep = !success; + return success; + } + + # endif // ifdef USES_MQTT + mustKeep = false; + return false; +} + +// ************************************************************* +// * Check MQTT queue state of preferred node +// ************************************************************* +bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex) +{ + if (!use_EspEasy_now) { return false; } + + const uint8_t distance = Nodes.getDistance(); + + if ((distance == 0) || (distance == 255)) { + // No need to send via ESPEasy_Now. + // We're either connected (distance == 0) + // or have no neighbor that can forward the message (distance == 255) + return false; + } + const NodeStruct *preferred = Nodes.getPreferredNode(); + + if (preferred != nullptr) { + return sendMQTTCheckControllerQueue(preferred->ESPEasy_Now_MAC(), preferred->channel); + } + return false; +} + +bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address& mac, int channel, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) { + ESPEasy_Now_MQTT_queue_check_packet query; + query.state = state; + size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); + msg.addBinaryData(reinterpret_cast(&query), len); + size_t timeout = 10; + WifiEspNowSendStatus sendStatus = msg.send(mac, timeout, channel); + switch (sendStatus) { + case WifiEspNowSendStatus::OK: + { + return true; + } + case WifiEspNowSendStatus::NONE: + case WifiEspNowSendStatus::FAIL: + { + break; + } + default: break; + } + return false; +} + + +bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, bool& mustKeep) +{ + mustKeep = false; + # ifdef USES_MQTT + + ESPEasy_Now_MQTT_queue_check_packet query; + size_t payload_pos = 0; + message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_NTP_query), payload_pos); + + controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); + + if (validControllerIndex(controllerIndex)) { + if (query.isSet()) { + // Got an answer from our query + _preferredNodeMQTTqueueState = query; + return true; + } else { + MAC_address mac; + if (message.getMac(mac)) { + // We have to give our own queue state and reply + query.setState(MQTT_queueFull(controllerIndex)); + + size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); + msg.addBinaryData(reinterpret_cast(&query), len); + msg.send(mac); + return true; + } + } } # endif // ifdef USES_MQTT @@ -575,7 +673,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, - const MAC_address& mac) + const MAC_address & mac) { ESPEasy_Now_DuplicateCheck check(key, message_type); size_t len = sizeof(ESPEasy_Now_DuplicateCheck); @@ -612,8 +710,9 @@ void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t } } -bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message) +bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message, bool& mustKeep) { + mustKeep = false; ESPEasy_Now_DuplicateCheck check; size_t payload_pos = 0; @@ -649,9 +748,12 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const { MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + // Don't add yourself as a peer - if (this_mac == mac) return false; + if (this_mac == mac) { return false; } + if (!WifiEspNow.addPeer(mac.mac, channel)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 37f98cbed8..a8bf881fc0 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -10,6 +10,7 @@ # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" +# include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" # include "../DataStructs/MAC_address.h" # include "../Globals/CPlugins.h" @@ -32,7 +33,7 @@ class ESPEasy_now_handler_t { private: - bool processMessage(const ESPEasy_now_merger& message); + bool processMessage(const ESPEasy_now_merger& message, bool& mustKeep); public: @@ -49,19 +50,24 @@ class ESPEasy_now_handler_t { const String & topic, const String & payload); + bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); + bool sendMQTTCheckControllerQueue(const MAC_address& mac, int channel, ESPEasy_Now_MQTT_queue_check_packet::QueueState state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); + void sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, const MAC_address& mac); private: - bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message); + bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep); + + bool handle_NTPquery(const ESPEasy_now_merger& message, bool& mustKeep); - bool handle_NTPquery(const ESPEasy_now_merger& message); + bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message, bool& mustKeep); - bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message); + bool handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, bool& mustKeep); - bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message); + bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message, bool& mustKeep); bool add_peer(const MAC_address& mac, int channel) const; @@ -70,6 +76,8 @@ class ESPEasy_now_handler_t { unsigned long _last_used = 0; uint8_t _send_failed_count = 0; + + ESPEasy_Now_MQTT_queue_check_packet _preferredNodeMQTTqueueState; }; From 18739853df901eb0cc2fd5ecbd8b8ac46e2859b2 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 12 Jun 2020 01:12:35 +0200 Subject: [PATCH 040/404] [ESPEasy-Now] Reduce memory usage processing received messages --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 13 +++++ src/src/DataStructs/ESPEasy_Now_packet.h | 6 ++ src/src/DataStructs/ESPEasy_now_merger.cpp | 65 ++++++++++++++++++++-- src/src/DataStructs/ESPEasy_now_merger.h | 5 ++ src/src/Helpers/ESPEasy_now_handler.cpp | 34 ++++++++--- 5 files changed, 109 insertions(+), 14 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index b8b4d172d9..a0d2aa8569 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -149,6 +149,19 @@ String ESPEasy_Now_packet::getString(size_t& payload_pos) const return res; } +const char* ESPEasy_Now_packet::get_c_str(size_t& payload_pos, size_t& str_length) const +{ + size_t bytes_left = getPayloadSize(); + + if (payload_pos > bytes_left) { return nullptr; } + bytes_left -= payload_pos; + size_t buf_pos = sizeof(ESPEasy_now_hdr) + payload_pos; + str_length = strnlen(reinterpret_cast(&_buf[buf_pos]), bytes_left); + payload_pos += str_length; + return reinterpret_cast(&_buf[buf_pos]); +} + + String ESPEasy_Now_packet::getLogString() const { ESPEasy_now_hdr header = getHeader(); diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 3c4328ff83..b363bf1ebd 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -56,6 +56,12 @@ class ESPEasy_Now_packet { // payload_pos will contain the new position to start for a next string String getString(size_t& payload_pos) const; + // Get a pointer to the start of the string starting from position pos in the buffer. + // The char pointer will be guaranteed null terminated. + // payload_pos will contain the new position to start for a next string + // @param str_length will contain the length of the found string + const char* get_c_str(size_t& payload_pos, size_t& str_length) const; + // Get pointer to the begin of the payload const uint8_t * begin() const; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 9b622e5e43..14074e8a34 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -15,6 +15,12 @@ void ESPEasy_now_merger::addPacket( const uint8_t *buf, size_t packetSize) { + const uint16_t maxFreeBlock = ESP.getMaxFreeBlockSize(); + if (2 * packetSize > maxFreeBlock) { + // Not enough free memory to process the block. + return; + } + _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet(mac, buf, packetSize))); _firstPacketTimestamp = millis(); } @@ -101,19 +107,68 @@ size_t ESPEasy_now_merger::getPayloadSize() const } String ESPEasy_now_merger::getString(size_t& payload_pos) const +{ + String res; + getString(res, payload_pos); + return res; +} + +bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const +{ + size_t stringLength = 0; + { + // Compute the expected string size, so we don't have to perform re-allocations + size_t tmp_payload_pos = payload_pos; + stringLength = str_len(tmp_payload_pos); + if (stringLength == 0) { + return false; + } + string.reserve(stringLength); + } + + size_t bufsize = 128; + if (stringLength < bufsize) { + bufsize = stringLength; + } + std::vector buf; + buf.resize(bufsize); + + bool done = false; + + // We do fetch more data from the message than the string size, so copy payload_pos first + size_t tmp_payload_pos = payload_pos; + + while (!done) { + size_t received = getBinaryData(&buf[0], bufsize, tmp_payload_pos); + + for (size_t buf_pos = 0; buf_pos < received && !done; ++buf_pos) { + char c = static_cast(buf[buf_pos]); + + if (c == 0) { + done = true; + } else { + string += c; + } + } + + if (received < bufsize) { done = true; } + } + payload_pos += string.length() + 1; // Store the position of the null termination + return true; +} + +size_t ESPEasy_now_merger::str_len(size_t& payload_pos) const { const size_t bufsize = 128; std::vector buf; buf.resize(bufsize); - String res; - res.reserve(bufsize * 2); - bool done = false; // We do fetch more data from the message than the string size, so copy payload_pos first size_t tmp_payload_pos = payload_pos; + size_t res = 0; while (!done) { size_t received = getBinaryData(&buf[0], bufsize, tmp_payload_pos); @@ -124,13 +179,13 @@ String ESPEasy_now_merger::getString(size_t& payload_pos) const if (c == 0) { done = true; } else { - res += c; + ++res; } } if (received < bufsize) { done = true; } } - payload_pos += res.length() + 1; // Store the position of the null termination + payload_pos += res + 1; // Store the position of the null termination return res; } diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 91833c0c58..a547cbc3d9 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -41,6 +41,11 @@ class ESPEasy_now_merger { // Return a string starting from position pos in the buffer. // payload_pos will contain the new position to start for a next string String getString(size_t& payload_pos) const; + bool getString(String& string, size_t& payload_pos) const; + + // Compute the length of a string starting from position pos in the buffer. + // payload_pos will contain the new position to start for a next string + size_t str_len(size_t& payload_pos) const; size_t getBinaryData(uint8_t *data, size_t length, diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 9eaffb0914..95235b227c 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -498,12 +498,19 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return false; } - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); + unsigned int ClientTimeout; + bool enableESPEasyNowFallback; + { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); + ClientTimeout = ControllerSettings.ClientTimeout; + } bool processed = false; - if (ControllerSettings.enableESPEasyNowFallback() /*&& !WiFiConnected(10) */) { + if (enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { const NodeStruct *preferred = Nodes.getPreferredNode(); if (preferred != nullptr) { @@ -531,7 +538,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const msg.addString(payload); MAC_address mac = preferred->ESPEasy_Now_MAC(); - WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * ControllerSettings.ClientTimeout, preferred->channel); + WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * ClientTimeout, preferred->channel); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -561,13 +568,22 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(controllerIndex)) { + bool mqtt_retainFlag; + { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); + } + size_t pos = 0; - String topic = message.getString(pos); - String payload = message.getString(pos); + String topic; + String payload; - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), ControllerSettings.mqtt_retainFlag()); + message.getString(topic, pos); + message.getString(payload, pos); + + bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), mqtt_retainFlag); MAC_address mac; if (message.getMac(mac)) { From 1f44f060809ec4232e45532f003b4f2185a97a24 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 17 Jun 2020 09:29:16 +0200 Subject: [PATCH 041/404] [ESPEasy-Now] Cache controller settings to save RAM --- src/src/Helpers/ESPEasy_now_handler.cpp | 82 ++++++++++++++++--------- src/src/Helpers/ESPEasy_now_handler.h | 8 +++ 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 95235b227c..786dc3bf12 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -76,6 +76,7 @@ bool ESPEasy_now_handler_t::begin() _last_used = millis(); int channel = WiFi.channel(); MAC_address bssid; + _controllerIndex = INVALID_CONTROLLER_INDEX; if (espeasy_now_only) { WifiScan(false, false); @@ -144,7 +145,8 @@ bool ESPEasy_now_handler_t::begin() void ESPEasy_now_handler_t::end() { - use_EspEasy_now = false; + _controllerIndex = INVALID_CONTROLLER_INDEX; + use_EspEasy_now = false; WifiEspNow.end(); addLog(LOG_LEVEL_INFO, F("ESPEasy-Now disabled")); } @@ -498,30 +500,23 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return false; } - unsigned int ClientTimeout; - bool enableESPEasyNowFallback; - { - // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); - ClientTimeout = ControllerSettings.ClientTimeout; + if (validControllerIndex(controllerIndex)) { + load_ControllerSettingsCache(controllerIndex); } bool processed = false; - if (enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { + if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { const NodeStruct *preferred = Nodes.getPreferredNode(); if (preferred != nullptr) { - switch (_preferredNodeMQTTqueueState.state) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: sendMQTTCheckControllerQueue(controllerIndex); return false; case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Empty: - break; + break; } @@ -538,7 +533,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const msg.addString(payload); MAC_address mac = preferred->ESPEasy_Now_MAC(); - WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * ClientTimeout, preferred->channel); + WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * _ClientTimeout, preferred->channel); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -568,27 +563,26 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(controllerIndex)) { - bool mqtt_retainFlag; - { - // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); - } - - size_t pos = 0; + load_ControllerSettingsCache(controllerIndex); + size_t pos = 0; String topic; String payload; - message.getString(topic, pos); + message.getString(topic, pos); message.getString(payload, pos); - bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), mqtt_retainFlag); + bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), _mqtt_retainFlag); MAC_address mac; + if (message.getMac(mac)) { ESPEasy_Now_MQTT_queue_check_packet query; - query.setState(MQTT_queueFull(controllerIndex)); + const bool queue_full = MQTT_queueFull(controllerIndex); + query.setState(queue_full); + + if (loglevelActiveFor(LOG_LEVEL_INFO) && queue_full) { + addLog(LOG_LEVEL_INFO, F("ESPEasy Now: After MQTT message received: Full")); + } sendMQTTCheckControllerQueue(mac, 0, query.state); } @@ -624,14 +618,18 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(controllerIndex_t contr return false; } -bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address& mac, int channel, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) { +bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address & mac, + int channel, + ESPEasy_Now_MQTT_queue_check_packet::QueueState state) { ESPEasy_Now_MQTT_queue_check_packet query; + query.state = state; size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); msg.addBinaryData(reinterpret_cast(&query), len); - size_t timeout = 10; + size_t timeout = 10; WifiEspNowSendStatus sendStatus = msg.send(mac, timeout, channel); + switch (sendStatus) { case WifiEspNowSendStatus::OK: { @@ -647,7 +645,6 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address& mac, return false; } - bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, bool& mustKeep) { mustKeep = false; @@ -655,7 +652,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me ESPEasy_Now_MQTT_queue_check_packet query; size_t payload_pos = 0; - message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_NTP_query), payload_pos); + message.getBinaryData(reinterpret_cast(&query), sizeof(ESPEasy_Now_MQTT_queue_check_packet), payload_pos); controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); @@ -663,13 +660,24 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me if (query.isSet()) { // Got an answer from our query _preferredNodeMQTTqueueState = query; + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + String log; + log = F("ESPEasy Now: Received Queue state: "); + log += _preferredNodeMQTTqueueState.isFull() ? F("Full") : F("not Full"); + addLog(LOG_LEVEL_DEBUG_MORE, log); + } + # endif // ifndef BUILD_NO_DEBUG return true; } else { MAC_address mac; - if (message.getMac(mac)) { + + if (message.getMac(mac)) { // We have to give our own queue state and reply query.setState(MQTT_queueFull(controllerIndex)); + // addLog(LOG_LEVEL_INFO, F("ESPEasy Now: reply to queue state query")); size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); msg.addBinaryData(reinterpret_cast(&query), len); @@ -783,4 +791,18 @@ bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const return true; } +void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t controllerIndex) +{ + if (validControllerIndex(controllerIndex) && controllerIndex != _controllerIndex) + { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(controllerIndex, ControllerSettings); + _enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); + _ClientTimeout = ControllerSettings.ClientTimeout; + _mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); + _controllerIndex = controllerIndex; + } +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index a8bf881fc0..0354927660 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -71,6 +71,8 @@ class ESPEasy_now_handler_t { bool add_peer(const MAC_address& mac, int channel) const; + void load_ControllerSettingsCache(controllerIndex_t controllerIndex); + ESPEasy_Now_NTP_query _best_NTP_candidate; unsigned long _last_used = 0; @@ -78,6 +80,12 @@ class ESPEasy_now_handler_t { uint8_t _send_failed_count = 0; ESPEasy_Now_MQTT_queue_check_packet _preferredNodeMQTTqueueState; + + unsigned int _ClientTimeout = 0; + controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; + bool _enableESPEasyNowFallback = false; + bool _mqtt_retainFlag = false; + }; From aef257dda4ed81f5c94945425ff05d02d47a6f4f Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 17 Jun 2020 09:32:04 +0200 Subject: [PATCH 042/404] [ESPEasy-Now] Fix packet timeout + check MQTT controller queue full --- src/ESPEasyWiFi_credentials.cpp | 6 +-- src/src/Commands/InternalCommands.cpp | 2 + .../ESPEasy_Now_DuplicateCheck.cpp | 5 +-- .../DataStructs/ESPEasy_Now_DuplicateCheck.h | 6 +-- .../ESPEasy_Now_MQTT_queue_check_packet.cpp | 12 +++++- .../ESPEasy_Now_MQTT_queue_check_packet.h | 7 ++-- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 6 ++- src/src/DataStructs/ESPEasy_Now_NTP_query.h | 6 +-- src/src/DataStructs/ESPEasy_now_merger.cpp | 14 +++++-- src/src/DataStructs/ESPEasy_now_merger.h | 3 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 39 +++++++++++++------ src/src/DataStructs/ESPEasy_now_splitter.h | 6 +-- 12 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/ESPEasyWiFi_credentials.cpp b/src/ESPEasyWiFi_credentials.cpp index 276cc977f7..d2a98a818c 100644 --- a/src/ESPEasyWiFi_credentials.cpp +++ b/src/ESPEasyWiFi_credentials.cpp @@ -21,8 +21,8 @@ bool validWiFiSettingsIndex(uint8_t index) { } #ifdef USES_ESPEASY_NOW -bool isESPEasy_now_only(uint8_t index) { - return index == 2; +bool isESPEasy_now_only() { + return RTC.lastWiFiSettingsIndex == 2; } #endif @@ -73,7 +73,7 @@ bool selectNextWiFiSettings() { return false; // Nothing changed. } #ifdef USES_ESPEASY_NOW - if (espeasy_now_only != isESPEasy_now_only(RTC.lastWiFiSettingsIndex)) { + if (espeasy_now_only != isESPEasy_now_only()) { if (!espeasy_now_only) { espeasy_now_only = true; ESPEasy_now_handler.end(); diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 5353eb5527..b6fb312e94 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -192,8 +192,10 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch COMMAND_CASE("erasesdkwifi", Command_WiFi_Erase, 0); // WiFi.h COMMAND_CASE( "event", Command_Rules_Events, -1); // Rule.h COMMAND_CASE("executerules", Command_Rules_Execute, -1); // Rule.h +#ifdef USES_ESPEASY_NOW COMMAND_CASE("espeasynowdisable", Command_ESPEasy_Now_Disable, 0); // ESPEasy_Now_cmd.h COMMAND_CASE( "espeasynowenable", Command_ESPEasy_Now_Enable, 0); // ESPEasy_Now_cmd.h +#endif break; } case 'g': { diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp index d52c126347..9ddb61890d 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp @@ -3,7 +3,6 @@ ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck() : _key(0), _type(ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck) {} -ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck(uint32_t key, - message_t message_type) +ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck(uint32_t key, + message_t message_type) : _key(key), _type(message_type) {} - diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h index 8878fbf866..52b4302d96 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h @@ -7,13 +7,13 @@ class ESPEasy_Now_DuplicateCheck { public: enum class message_t : uint8_t { - KeyToCheck = 0, + KeyToCheck = 0, AlreadyProcessed = 1 }; ESPEasy_Now_DuplicateCheck(); - - ESPEasy_Now_DuplicateCheck(uint32_t key, + + ESPEasy_Now_DuplicateCheck(uint32_t key, message_t message_type); const uint32_t _key; diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp index f0629d6f8c..74e627135d 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp @@ -1,10 +1,11 @@ #include "ESPEasy_Now_MQTT_queue_check_packet.h" +#ifdef USES_ESPEASY_NOW void ESPEasy_Now_MQTT_queue_check_packet::markSendTime() { _millis_out = millis(); - state = QueueState::Unset; + state = QueueState::Unset; } void ESPEasy_Now_MQTT_queue_check_packet::setState(bool isFull) @@ -12,7 +13,14 @@ void ESPEasy_Now_MQTT_queue_check_packet::setState(bool isFull) state = isFull ? QueueState::Full : QueueState::Empty; } +bool ESPEasy_Now_MQTT_queue_check_packet::isFull() const +{ + return state != QueueState::Empty; +} + bool ESPEasy_Now_MQTT_queue_check_packet::isSet() const { return state != QueueState::Unset; -} \ No newline at end of file +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h index b0a8fb6579..9677745814 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h @@ -19,13 +19,14 @@ class ESPEasy_Now_MQTT_queue_check_packet { void setState(bool isFull); + bool isFull() const; + bool isSet() const; - void markSendTime(); + void markSendTime(); unsigned long _millis_out = millis(); - QueueState state = QueueState::Unset; - + QueueState state = QueueState::Unset; }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index c9f453fcaf..c5bb7f068d 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -83,8 +83,8 @@ unsigned long ESPEasy_Now_NTP_query::computeExpectedWander(timeSource_t timeSou } void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, - timeSource_t timeSource, - unsigned long timePassedSinceLastTimeSync) + timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync) { if (_millis_out != 0) { if (timePassedSince(_millis_out) > MAX_DELAY_FOR_REPLY) { @@ -102,6 +102,7 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, // First check if it matches the current best candidate. bool matches_current_best = mac == _mac; + if (matches_current_best) { // Update expected wander based on current time since last sync updated = true; @@ -109,6 +110,7 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, if (_expectedWander_ms > expectedWander_ms) { // We found a good new candidate bool matches_prev_fail = mac == _mac_prev_fail; + if (matches_prev_fail) { // No need to retry. return; diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index 84abc26805..f44b6c46a4 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -7,7 +7,7 @@ #ifdef USES_ESPEASY_NOW # include "../Helpers/ESPEasy_time.h" -#include "MAC_address.h" +# include "MAC_address.h" class ESPEasy_Now_NTP_query { @@ -18,8 +18,8 @@ class ESPEasy_Now_NTP_query { bool getMac(MAC_address& mac) const; void find_best_NTP(const MAC_address& mac, - timeSource_t timeSource, - unsigned long timePassedSinceLastTimeSync); + timeSource_t timeSource, + unsigned long timePassedSinceLastTimeSync); void reset(bool success); diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 14074e8a34..b62851c5ea 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -5,6 +5,8 @@ # include "../Helpers/ESPEasy_time_calc.h" # include "../../ESPEasy_fdwdecl.h" +# define ESPEASY_NOW_MESSAGE_TIMEOUT 5000 + ESPEasy_now_merger::ESPEasy_now_merger() { _firstPacketTimestamp = millis(); } @@ -16,8 +18,11 @@ void ESPEasy_now_merger::addPacket( size_t packetSize) { const uint16_t maxFreeBlock = ESP.getMaxFreeBlockSize(); + if (2 * packetSize > maxFreeBlock) { // Not enough free memory to process the block. + // Since this message will never be complete, set the timer to an expired value. + _firstPacketTimestamp -= ESPEASY_NOW_MESSAGE_TIMEOUT; return; } @@ -32,7 +37,7 @@ bool ESPEasy_now_merger::messageComplete() const bool ESPEasy_now_merger::expired() const { - return timePassedSince(_firstPacketTimestamp) > 5000; + return timePassedSince(_firstPacketTimestamp) > ESPEASY_NOW_MESSAGE_TIMEOUT; } uint8_t ESPEasy_now_merger::receivedCount(uint8_t& nr_packets) const @@ -109,17 +114,19 @@ size_t ESPEasy_now_merger::getPayloadSize() const String ESPEasy_now_merger::getString(size_t& payload_pos) const { String res; + getString(res, payload_pos); return res; } -bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const +bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const { size_t stringLength = 0; { // Compute the expected string size, so we don't have to perform re-allocations size_t tmp_payload_pos = payload_pos; stringLength = str_len(tmp_payload_pos); + if (stringLength == 0) { return false; } @@ -127,6 +134,7 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const } size_t bufsize = 128; + if (stringLength < bufsize) { bufsize = stringLength; } @@ -168,7 +176,7 @@ size_t ESPEasy_now_merger::str_len(size_t& payload_pos) const // We do fetch more data from the message than the string size, so copy payload_pos first size_t tmp_payload_pos = payload_pos; - size_t res = 0; + size_t res = 0; while (!done) { size_t received = getBinaryData(&buf[0], bufsize, tmp_payload_pos); diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index a547cbc3d9..709d107d3e 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -41,7 +41,8 @@ class ESPEasy_now_merger { // Return a string starting from position pos in the buffer. // payload_pos will contain the new position to start for a next string String getString(size_t& payload_pos) const; - bool getString(String& string, size_t& payload_pos) const; + bool getString(String& string, + size_t& payload_pos) const; // Compute the length of a string starting from position pos in the buffer. // payload_pos will contain the new position to start for a next string diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index acf64ff2f2..ef1c8c6787 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -77,7 +77,7 @@ bool ESPEasy_now_splitter::sendToBroadcast() } bool ESPEasy_now_splitter::send(const MAC_address& mac, - int channel) + int channel) { prepareForSend(mac); @@ -99,12 +99,19 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - uint8_t retry = 2; + uint8_t retry = 2; + while (retry > 0) { --retry; send(_queue[i], channel); sendStatus = waitForSendStatus(timeout); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { + + if (sendStatus == WifiEspNowSendStatus::OK) { + retry = 0; + } + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log; switch (sendStatus) { @@ -116,20 +123,21 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t case WifiEspNowSendStatus::FAIL: { log = F("ESPEasy Now: Sent FAILED to: "); - if (retry != 0) { - delay(10); - } break; } case WifiEspNowSendStatus::OK: { log = F("ESPEasy Now: Sent to: "); - retry = 0; break; } } log += _queue[i].getLogString(); - addLog(LOG_LEVEL_INFO, log); + addLog(LOG_LEVEL_DEBUG, log); + } + # endif // ifndef BUILD_NO_DEBUG + + if (retry != 0) { + delay(10); } } @@ -173,9 +181,11 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) channel = nodeInfo->channel; } } + // FIXME TD-er: Not sure why, but setting the channel does not work well. -// WifiEspNow.addPeer(packet._mac, channel); - WifiEspNow.addPeer(packet._mac, 0); + WifiEspNow.addPeer(packet._mac, channel); + + // WifiEspNow.addPeer(packet._mac, 0); } bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); @@ -189,7 +199,14 @@ WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) con { WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; - while (!timeOutReached(timeout) && sendStatus == WifiEspNowSendStatus::NONE) { + if (timeout < 20) { + // ESP-now keeps sending for 20 msec using lower transfer rated every 2nd attempt. + timeout = 20; + } + + size_t timer = millis() + timeout; + + while (!timeOutReached(timer) && sendStatus == WifiEspNowSendStatus::NONE) { sendStatus = WifiEspNow.getSendStatus(); delay(1); } diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index a6194f64ab..3b9e479560 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -18,11 +18,11 @@ class ESPEasy_now_splitter { bool sendToBroadcast(); bool send(const MAC_address& mac, - int channel = 0); + int channel = 0); WifiEspNowSendStatus send(const MAC_address& mac, size_t timeout, - int channel); + int channel); private: @@ -32,7 +32,7 @@ class ESPEasy_now_splitter { size_t getPayloadPos() const; bool send(const ESPEasy_Now_packet& packet, - int channel); + int channel); void prepareForSend(const MAC_address& mac); From 9d1978353c336c1100ed4a5dcf3f9951deb98b3e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 19 Jun 2020 01:00:32 +0200 Subject: [PATCH 043/404] [ESPEasy-Now] Fix recreate mesh after reboot --- src/ESPEasy.ino | 7 ++++ src/src/DataStructs/NodeStruct.cpp | 53 +++++++++++++++++-------- src/src/DataStructs/NodesHandler.cpp | 20 +++++++++- src/src/DataStructs/NodesHandler.h | 8 ++++ src/src/Helpers/ESPEasy_now_handler.cpp | 41 ++++++++++++++----- 5 files changed, 103 insertions(+), 26 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 994e13ea41..2658e99882 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -405,6 +405,13 @@ void setup() rulesProcessing(event); // TD-er: Process events in the setup() now. } +#ifdef USES_ESPEASY_NOW + if (isESPEasy_now_only() || Settings.UseESPEasyNow()) { + RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. + RTC.lastWiFiChannel = 0; // Force slow connect + } +#endif + NetworkConnectRelaxed(); setWebserverRunning(true); diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 1f4445cce8..d6a5a47594 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -6,6 +6,8 @@ #include "../Globals/SecuritySettings.h" #include "../Helpers/ESPEasy_time_calc.h" +#define NODE_STRUCT_AGE_TIMEOUT 120000 // 2 minutes + NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0), build(0), age(0), nodeType(0), webgui_portnumber(0) {} @@ -37,9 +39,10 @@ bool NodeStruct::validate() { } bool NodeStruct::operator<(const NodeStruct &other) const { - if (ESPEasyNowPeer != other.ESPEasyNowPeer) { - // One is confirmed, so prefer that one. - return ESPEasyNowPeer; + const bool thisExpired = getAge() > NODE_STRUCT_AGE_TIMEOUT; + const bool otherExpired = other.getAge() > NODE_STRUCT_AGE_TIMEOUT; + if (thisExpired != otherExpired) { + return !thisExpired; } const bool markedAsPriority = markedAsPriorityPeer(); @@ -47,26 +50,44 @@ bool NodeStruct::operator<(const NodeStruct &other) const { return markedAsPriority; } - if (distance != other.distance) { - return distance < other.distance; + if (ESPEasyNowPeer != other.ESPEasyNowPeer) { + // One is confirmed, so prefer that one. + return ESPEasyNowPeer; } - + const int8_t thisRssi = getRSSI(); const int8_t otherRssi = other.getRSSI(); - if (thisRssi != otherRssi) { - if (thisRssi >= 0) { - // This one has no set RSSI, so the other one is better - return false; - } + int score_this = getLoad(); + int score_other = other.getLoad(); - if (otherRssi >= 0) { - // This other has no set RSSI, so the this one is better - return true; + if (distance != other.distance) { + if (getAge() < NODE_STRUCT_AGE_TIMEOUT && other.getAge() < NODE_STRUCT_AGE_TIMEOUT) { + // Distance is not the same, so take distance into account. + return distance < other.distance; +/* + int distance_penalty = distance - other.distance; + distance_penalty = distance_penalty * distance_penalty * 10; + if (distance > other.distance) { + score_this += distance_penalty; + } else { + score_other += distance_penalty; + } +*/ } - return thisRssi > otherRssi; } - return true; + + if (thisRssi >= 0 || otherRssi >= 0) { + // One or both have no RSSI, so cannot use RSSI in computing score + } else { + // RSSI value is negative, so subtract the value + // RSSI range from -38 ... 99 + // Shift RSSI and add a weighing factor to make sure + // A load of 100% with RSSI of -40 is preferred over a load of 20% with an RSSI of -80. + score_this -= (thisRssi + 38) * 2; + score_other -= (otherRssi + 38) * 2; + } + return score_this > score_other; } String NodeStruct::getNodeTypeDisplayString() const { diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index f200db2f36..9fa39881fc 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -6,6 +6,15 @@ void NodesHandler::addNode(const NodeStruct& node) { + // Erase any existing node with matching MAC address + for (auto it = _nodes.begin(); it != _nodes.end(); ) + { + if (node.match(it->second.sta_mac) || node.match(it->second.ap_mac)) { + it = _nodes.erase(it); + } else { + ++it; + } + } _nodes[node.unit] = node; _nodes[node.unit].lastUpdated = millis(); } @@ -162,6 +171,9 @@ void NodesHandler::updateThisNode() { } } } + if (_distance < 255) { + _lastTimeValidDistance = millis(); + } thisNode.distance = _distance; addNode(thisNode); } @@ -224,4 +236,10 @@ bool NodesHandler::isEndpoint() const if (!WiFiConnected()) return false; return false; -} \ No newline at end of file +} + +bool NodesHandler::lastTimeValidDistanceExpired() const +{ +// if (_lastTimeValidDistance == 0) return false; + return timePassedSince(_lastTimeValidDistance) > 120000; // 2 minutes +} diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 893a444b10..8baf63623c 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -44,11 +44,19 @@ class NodesHandler { return _distance; } + bool lastTimeValidDistanceExpired() const; + + unsigned long get_lastTimeValidDistance() const { + return _lastTimeValidDistance; + } + private: bool isEndpoint() const; + unsigned long _lastTimeValidDistance = 0; + uint8_t _distance = 255; // Cached value NodesMap _nodes; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 786dc3bf12..b99a5b2025 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -19,7 +19,7 @@ # include -# define ESPEASY_NOW_ACTIVVITY_TIMEOUT 60000 // 1 minute +# define ESPEASY_NOW_ACTIVVITY_TIMEOUT 120000 // 2 minutes # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" @@ -138,7 +138,6 @@ bool ESPEasy_now_handler_t::begin() sendDiscoveryAnnounce(); use_EspEasy_now = true; - _last_used = 0; addLog(LOG_LEVEL_INFO, F("ESPEasy-Now enabled")); return true; } @@ -147,6 +146,7 @@ void ESPEasy_now_handler_t::end() { _controllerIndex = INVALID_CONTROLLER_INDEX; use_EspEasy_now = false; + _last_used = 0; WifiEspNow.end(); addLog(LOG_LEVEL_INFO, F("ESPEasy-Now disabled")); } @@ -235,6 +235,9 @@ bool ESPEasy_now_handler_t::active() const if (_last_used == 0) { return false; } + if (Nodes.lastTimeValidDistanceExpired()) { + return false; + } return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVVITY_TIMEOUT; } @@ -300,6 +303,7 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo addLog(LOG_LEVEL_INFO, message.getLogString()); bool handled = false; mustKeep = true; + bool considerActive = false; switch (message.getFirstHeader().message_type) { @@ -316,16 +320,18 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo break; case ESPEasy_now_hdr::message_t::MQTTControllerMessage: handled = handle_MQTTControllerMessage(message, mustKeep); + considerActive = true; break; case ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue: handled = handle_MQTTCheckControllerQueue(message, mustKeep); + considerActive = true; break; case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: handled = handle_SendData_DuplicateCheck(message, mustKeep); break; } - if (handled) { + if (handled && considerActive) { _last_used = millis(); } @@ -365,6 +371,8 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m mustKeep = false; NodeStruct received; + const uint8_t cur_distance = Nodes.getDistance(); + // Discovery messages have a single binary blob, starting at 0 size_t payload_pos = 0; @@ -414,6 +422,12 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m sendDiscoveryAnnounce(mac); } */ + + const uint8_t new_distance = Nodes.getDistance(); + if (new_distance != cur_distance) { + sendDiscoveryAnnounce(); + } + return true; } @@ -564,14 +578,23 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge if (validControllerIndex(controllerIndex)) { load_ControllerSettingsCache(controllerIndex); - size_t pos = 0; - String topic; - String payload; + bool success = false; + { + size_t pos = 0; + String topic; + String payload; - message.getString(topic, pos); - message.getString(payload, pos); + message.getString(topic, pos); + message.getString(payload, pos); - bool success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), _mqtt_retainFlag); + size_t payloadSize = message.getPayloadSize(); + if ((topic.length() + payload.length() + 2) >= payloadSize) { + success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), _mqtt_retainFlag); + } else { + mustKeep = false; + return success; + } + } MAC_address mac; From b4f0f26409273949a501103e13fdb797e4f753eb Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 20 Jun 2020 18:23:09 +0200 Subject: [PATCH 044/404] [ESPEasy-Now] Add check for invalid messages due to out of memory --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 27 +++++++++++++++++--- src/src/DataStructs/ESPEasy_Now_packet.h | 16 ++++++++---- src/src/DataStructs/ESPEasy_now_hdr.cpp | 2 +- src/src/DataStructs/ESPEasy_now_hdr.h | 2 +- src/src/DataStructs/ESPEasy_now_merger.cpp | 10 ++++++++ src/src/DataStructs/ESPEasy_now_merger.h | 2 ++ src/src/DataStructs/ESPEasy_now_splitter.cpp | 17 +++++++++--- src/src/DataStructs/ESPEasy_now_splitter.h | 2 +- src/src/DataStructs/TimingStats.cpp | 1 + src/src/DataStructs/TimingStats.h | 11 ++++---- src/src/Helpers/ESPEasy_now_handler.cpp | 24 +++++++++++++---- 11 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index a0d2aa8569..116f5e6da4 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -16,17 +16,31 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *bu { setSize(packetSize); mac.get(_mac); + size_t bufsize = _buf.size(); + if (packetSize > bufsize) { + // Cannot store the whole packet, so consider it as invalid. + packetSize = bufsize; + _valid = false; + } memcpy(&_buf[0], buf, packetSize); } void ESPEasy_Now_packet::setSize(size_t packetSize) { if (packetSize > ESPEASY_NOW_MAX_PACKET_SIZE) { - _buf.resize(ESPEASY_NOW_MAX_PACKET_SIZE); + packetSize = ESPEASY_NOW_MAX_PACKET_SIZE; } - else { - _buf.resize(packetSize); + const size_t maxFreeBlock = ESP.getMaxFreeBlockSize(); + if (packetSize > maxFreeBlock) { + packetSize = maxFreeBlock; } + + _buf.resize(packetSize); +} + +bool ESPEasy_Now_packet::valid() const +{ + return _valid && (getSize() >= sizeof(ESPEasy_now_hdr)); } uint16_t ESPEasy_Now_packet::computeChecksum() const @@ -74,7 +88,12 @@ ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) { header.checksum = computeChecksum(); - memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); + if (_buf.size() < sizeof(ESPEasy_now_hdr)) { + // Not even the header will fit, so this is an invalid packet. + _valid = false; + } else { + memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); + } } size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index b363bf1ebd..87b6c1b317 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -6,7 +6,7 @@ #include "../Globals/ESPEasy_now_state.h" #ifdef USES_ESPEASY_NOW -#include "MAC_address.h" +# include "MAC_address.h" # include "ESPEasy_now_hdr.h" # include @@ -20,8 +20,11 @@ class ESPEasy_Now_packet { // Constructor for receiving a packet ESPEasy_Now_packet(const MAC_address& mac, - const uint8_t *buf, - size_t packetSize); + const uint8_t *buf, + size_t packetSize); + + // A packet may become invalid if it was not possible to allocate enough memory for the buffer + bool valid() const; bool checksumValid() const; @@ -54,13 +57,14 @@ class ESPEasy_Now_packet { // Return a string starting from position pos in the buffer. // payload_pos will contain the new position to start for a next string - String getString(size_t& payload_pos) const; + String getString(size_t& payload_pos) const; // Get a pointer to the start of the string starting from position pos in the buffer. // The char pointer will be guaranteed null terminated. // payload_pos will contain the new position to start for a next string // @param str_length will contain the length of the found string - const char* get_c_str(size_t& payload_pos, size_t& str_length) const; + const char* get_c_str(size_t& payload_pos, + size_t& str_length) const; // Get pointer to the begin of the payload const uint8_t * begin() const; @@ -77,6 +81,8 @@ class ESPEasy_Now_packet { std::vector_buf; + bool _valid = true; + void setSize(size_t packetSize); uint16_t computeChecksum() const; diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index f8629f95f9..6f54b071f1 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -17,7 +17,7 @@ ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr& other) packet_nr = other.packet_nr; nr_packets = other.nr_packets; message_count = other.message_count; - notUsed1 = other.notUsed1; + payload_size = other.payload_size; checksum = other.checksum; return *this; } diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 00499f9d76..d9a0873d0f 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -40,7 +40,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { uint8_t packet_nr = 0; // Current message number (start at 0) uint8_t nr_packets = 1; // The highest message number of this sequence uint8_t message_count = 1; // A set of messages all have the same message_count - uint8_t notUsed1 = 0; // reserved + uint8_t payload_size = 0; // Size of the payload uint16_t checksum = 0; // checksum of the packet }; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index b62851c5ea..7c90f47d44 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -40,6 +40,16 @@ bool ESPEasy_now_merger::expired() const return timePassedSince(_firstPacketTimestamp) > ESPEASY_NOW_MESSAGE_TIMEOUT; } +bool ESPEasy_now_merger::valid() const +{ + for (auto it = _queue.begin(); it != _queue.end(); ++it) { + if (!it->second.valid()) { + return false; + } + } + return true; +} + uint8_t ESPEasy_now_merger::receivedCount(uint8_t& nr_packets) const { nr_packets = getFirstHeader().nr_packets; diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 709d107d3e..324faa74a0 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -33,6 +33,8 @@ class ESPEasy_now_merger { // Check of set has expired (not all packets received within timeout) bool expired() const; + bool valid() const; + ESPEasy_Now_packet_map::const_iterator find(uint8_t packet_nr) const; // Get combined size of all packets. diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index ef1c8c6787..2ec2010641 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -79,7 +79,9 @@ bool ESPEasy_now_splitter::sendToBroadcast() bool ESPEasy_now_splitter::send(const MAC_address& mac, int channel) { - prepareForSend(mac); + if (!prepareForSend(mac)) { + return false; + } const size_t nr_packets = _queue.size(); @@ -92,10 +94,11 @@ bool ESPEasy_now_splitter::send(const MAC_address& mac, WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t timeout, int channel) { START_TIMER; - prepareForSend(mac); + if (!prepareForSend(mac)) { + return WifiEspNowSendStatus::FAIL; + } WifiEspNowSendStatus sendStatus = WifiEspNowSendStatus::NONE; - const size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { @@ -213,16 +216,22 @@ WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) con return sendStatus; } -void ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) +bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) { size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { + if (!_queue[i].valid()) { + addLog(LOG_LEVEL_ERROR, F("ESPEasy Now: Could not prepare for send")); + return false; + } ESPEasy_now_hdr header = _queue[i].getHeader(); header.nr_packets = nr_packets; + header.payload_size = _queue[i].getPayloadSize(); _queue[i].setHeader(header); _queue[i].setMac(mac); } + return true; } #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 3b9e479560..71accb876c 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -34,7 +34,7 @@ class ESPEasy_now_splitter { bool send(const ESPEasy_Now_packet& packet, int channel); - void prepareForSend(const MAC_address& mac); + bool prepareForSend(const MAC_address& mac); WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 873327a454..dfbc4d8733 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -230,6 +230,7 @@ String getMiscStatsName(int stat) { case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); case HANDLE_ESPEASY_NOW_LOOP: return F("Handle Received ESPEasy Now message"); case EXPIRED_ESPEASY_NOW_LOOP: return F("ESPEasy Now incomplete expired"); + case INVALID_ESPEASY_NOW_LOOP: return F("ESPEasy Now incomplete invalid"); case RECEIVE_ESPEASY_NOW_LOOP: return F("ESPEasy_now_onReceive()"); case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy Now send Message Success"); case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy Now send Message Fail"); diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index edcdfab90b..46163fbfbe 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -76,11 +76,12 @@ # define HANDLE_SERVING_WEBPAGE 55 # define HANDLE_ESPEASY_NOW_LOOP 56 # define EXPIRED_ESPEASY_NOW_LOOP 57 -# define RECEIVE_ESPEASY_NOW_LOOP 58 -# define ESPEASY_NOW_SEND_MSG_SUC 59 -# define ESPEASY_NOW_SEND_MSG_FAIL 60 -# define ESPEASY_NOW_SEND_PCKT 61 -# define ESPEASY_NOW_DEDUP_LOOP 62 +# define INVALID_ESPEASY_NOW_LOOP 58 +# define RECEIVE_ESPEASY_NOW_LOOP 59 +# define ESPEASY_NOW_SEND_MSG_SUC 60 +# define ESPEASY_NOW_SEND_MSG_FAIL 61 +# define ESPEASY_NOW_SEND_PCKT 62 +# define ESPEASY_NOW_DEDUP_LOOP 63 class TimingStats { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index b99a5b2025..371d37cb04 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -176,17 +176,29 @@ bool ESPEasy_now_handler_t::loop() bool somethingProcessed = false; if (!ESPEasy_now_in_queue.empty()) { - for (auto it = ESPEasy_now_in_queue.begin(); it != ESPEasy_now_in_queue.end();) { + unsigned long timeout = millis() + 50; + for (auto it = ESPEasy_now_in_queue.begin(); !timeOutReached(timeout) && it != ESPEasy_now_in_queue.end();) { bool removeMessage = true; START_TIMER; - if (!it->second.messageComplete()) { - if (it->second.expired()) { - STOP_TIMER(EXPIRED_ESPEASY_NOW_LOOP); + bool valid = it->second.valid(); + if (!valid || !it->second.messageComplete()) { + bool expired = it->second.expired(); + + if (!valid || expired) { + if (expired) { + STOP_TIMER(EXPIRED_ESPEASY_NOW_LOOP); + } else { + STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); + } if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = it->second.getLogString(); - log += F(" Expired!"); + if (expired) { + log += F(" Expired!"); + } else { + log += F(" Invalid!"); + } addLog(LOG_LEVEL_ERROR, log); } } else { @@ -203,10 +215,12 @@ bool ESPEasy_now_handler_t::loop() if (removeMessage) { it = ESPEasy_now_in_queue.erase(it); +/* // FIXME TD-er: For now only process one item and then wait for the next loop. if (somethingProcessed) { return true; } +*/ } else { ++it; } From eff9b34585ef1d08f7f886ae1d69f31fd6854a9c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Mon, 22 Jun 2020 09:23:12 +0200 Subject: [PATCH 045/404] [ESPEasy-Now] More memory efficient MQTT publish --- src/Controller.ino | 28 ++++++++++++++++++++++ src/ESPEasy_fdwdecl.h | 6 +++++ src/src/DataStructs/ESPEasy_now_merger.cpp | 14 +++-------- src/src/Helpers/ESPEasy_now_handler.cpp | 27 +++++++-------------- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index 9de6f079fd..b8cc417df0 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -474,6 +474,34 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { return false; } +#ifdef USES_ESPEASY_NOW + +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained) +{ + bool success = false; + if (!MQTT_queueFull(controller_idx)) + { + success = MQTTDelayHandler.addToQueue(MQTT_queue_element()); + if (success) { + size_t pos = 0; + MQTTDelayHandler.sendQueue.back().controller_idx = controller_idx; + MQTTDelayHandler.sendQueue.back()._retained = retained; + message.getString(MQTTDelayHandler.sendQueue.back()._topic, pos); + message.getString(MQTTDelayHandler.sendQueue.back()._payload, pos); + } + + size_t payloadSize = message.getPayloadSize(); + if ((MQTTDelayHandler.sendQueue.back()._topic.length() + MQTTDelayHandler.sendQueue.back()._payload.length() + 2) < payloadSize) { + success = false; + MQTTDelayHandler.sendQueue.pop_back(); + } + } + scheduleNextMQTTdelayQueue(); + return success; +} + +#endif + bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained) { if (MQTTDelayHandler == nullptr) { diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index a8cef68500..0a42e0f234 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -4,6 +4,7 @@ #include "ESPEasy_common.h" #include "src/DataStructs/SettingsType.h" #include "src/DataStructs/ESPEasy_EventStruct.h" +#include "src/DataStructs/ESPEasy_now_merger.h" #include "src/Globals/CPlugins.h" @@ -79,6 +80,11 @@ void callback(char *c_topic, bool MQTTCheck(controllerIndex_t controller_idx); //bool MQTT_queueFull(controllerIndex_t controller_idx); bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained); +#ifdef USES_ESPEASY_NOW + +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); +#endif + #endif // ifdef USES_MQTT void flushAndDisconnectAllClients(); diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 7c90f47d44..9ac894c834 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -143,13 +143,8 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const string.reserve(stringLength); } - size_t bufsize = 128; - - if (stringLength < bufsize) { - bufsize = stringLength; - } - std::vector buf; - buf.resize(bufsize); + const size_t bufsize = 128; + uint8_t buf[bufsize] = {0}; bool done = false; @@ -178,10 +173,7 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const size_t ESPEasy_now_merger::str_len(size_t& payload_pos) const { const size_t bufsize = 128; - std::vector buf; - - buf.resize(bufsize); - + uint8_t buf[bufsize] = {0}; bool done = false; // We do fetch more data from the message than the string size, so copy payload_pos first diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 371d37cb04..5ba2973ad5 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -2,6 +2,9 @@ #ifdef USES_ESPEASY_NOW +# include "../../ESPEasy_fdwdecl.h" +# include "../../ESPEasy_Log.h" +# include "../../_CPlugin_Helper.h" # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" @@ -13,8 +16,8 @@ # include "../Globals/SecuritySettings.h" # include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" -# include "../../ESPEasy_fdwdecl.h" -# include "../../ESPEasy_Log.h" +# include "../ControllerQueue/MQTT_queue_element.h" + # include @@ -592,22 +595,10 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge if (validControllerIndex(controllerIndex)) { load_ControllerSettingsCache(controllerIndex); - bool success = false; - { - size_t pos = 0; - String topic; - String payload; - - message.getString(topic, pos); - message.getString(payload, pos); - - size_t payloadSize = message.getPayloadSize(); - if ((topic.length() + payload.length() + 2) >= payloadSize) { - success = MQTTpublish(controllerIndex, topic.c_str(), payload.c_str(), _mqtt_retainFlag); - } else { - mustKeep = false; - return success; - } + bool success = MQTTpublish(controllerIndex, message, _mqtt_retainFlag); + if (!success) { + mustKeep = false; + return success; } MAC_address mac; From cc32778067b40eb150f2f49b7750fc8d68662cdf Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 23 Jun 2020 16:25:58 +0200 Subject: [PATCH 046/404] Fix merge issues --- src/Controller.ino | 1 + src/ESPEasy.ino | 1 + src/ESPEasyNetwork.cpp | 19 ++++---- src/ESPEasyWiFi_credentials.cpp | 7 +-- src/ESPEasyWiFi_credentials.h | 5 ++ src/ESPEasyWifi.cpp | 81 +++++++++++++++++++++----------- src/ESPEasyWifi.h | 1 + src/ESPEasyWifi_ProcessEvent.cpp | 24 +++++++++- src/ESPEasyWifi_ProcessEvent.h | 1 + src/Networking.ino | 23 --------- src/_C019.ino | 2 +- 11 files changed, 97 insertions(+), 68 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index b8cc417df0..49539fb4a2 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -476,6 +476,7 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { #ifdef USES_ESPEASY_NOW +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained) { bool success = false; diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 2658e99882..4830ce458a 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -102,6 +102,7 @@ #include "src/DataStructs/ControllerSettingsStruct.h" #include "src/DataStructs/DeviceModel.h" #include "src/DataStructs/ESPEasy_EventStruct.h" +#include "src/DataStructs/NodesHandler.h" #include "src/DataStructs/PortStatusStruct.h" #include "src/DataStructs/ProtocolStruct.h" #include "src/DataStructs/RTCStruct.h" diff --git a/src/ESPEasyNetwork.cpp b/src/ESPEasyNetwork.cpp index 95321cd491..ed92eab293 100644 --- a/src/ESPEasyNetwork.cpp +++ b/src/ESPEasyNetwork.cpp @@ -6,6 +6,7 @@ #include "ESPEasy_Log.h" #include "ESPEasy_fdwdecl.h" +#include "src/DataStructs/MAC_address.h" #include "src/Globals/NetworkState.h" #include "src/Helpers/StringConverter.h" @@ -122,13 +123,11 @@ String NetworkMacAddress() { } } #endif + + MAC_address net_mac; + NetworkMacAddressAsBytes(net_mac.mac); - uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = NetworkMacAddressAsBytes(mac); - char macaddress[20]; - formatMAC(macread, macaddress); - - return String(macaddress); + return net_mac.toString(); } uint8_t * NetworkMacAddressAsBytes(uint8_t* mac) { @@ -180,9 +179,7 @@ String createRFCCompliantHostname(String oldString) { } String WifiSoftAPmacAddress() { - uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = WiFi.softAPmacAddress(mac); - char macaddress[20]; - formatMAC(macread, macaddress); - return String(macaddress); + MAC_address ap_mac; + WiFi.softAPmacAddress(ap_mac.mac); + return ap_mac.toString(); } \ No newline at end of file diff --git a/src/ESPEasyWiFi_credentials.cpp b/src/ESPEasyWiFi_credentials.cpp index d2a98a818c..77cc325597 100644 --- a/src/ESPEasyWiFi_credentials.cpp +++ b/src/ESPEasyWiFi_credentials.cpp @@ -1,15 +1,16 @@ #include "ESPEasyWiFi_credentials.h" -#include "src/Globals/RTC.h" -#include "src/Globals/SecuritySettings.h" + // ******************************************************************************** // Manage WiFi credentials // ******************************************************************************** #include "src/Globals/ESPEasy_now_state.h" +#include "src/Globals/ESPEasy_now_handler.h" #include "src/Globals/SecuritySettings.h" #include "src/Globals/RTC.h" #include "src/Globals/ESPEasyWiFiEvent.h" +#include "ESPEasy_Log.h" #ifdef USES_ESPEASY_NOW #define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" @@ -114,4 +115,4 @@ bool wifiSettingsValid(const char *ssid, const char *pass) { if (strlen(pass) > 64) { return false; } return true; -} +} \ No newline at end of file diff --git a/src/ESPEasyWiFi_credentials.h b/src/ESPEasyWiFi_credentials.h index f608100d93..849e37ca78 100644 --- a/src/ESPEasyWiFi_credentials.h +++ b/src/ESPEasyWiFi_credentials.h @@ -1,6 +1,11 @@ #ifndef ESPEASYWIFI_CREDENTIALS_H #define ESPEASYWIFI_CREDENTIALS_H + +#ifdef USES_ESPEASY_NOW +bool isESPEasy_now_only(); +#endif + const char* getLastWiFiSettingsSSID(); const char* getLastWiFiSettingsPassphrase(); bool selectNextWiFiSettings(); diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 52b773deaf..5d261ed178 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -12,6 +12,7 @@ #include "src/Globals/SecuritySettings.h" #include "src/Helpers/ESPEasy_time_calc.h" #include "src/Helpers/StringConverter.h" +#include "src/Globals/ESPEasy_now_handler.h" // ******************************************************************************** // WiFi state @@ -73,6 +74,7 @@ */ + // ******************************************************************************** // Check WiFi connected status // This is basically the state machine to switch between states: @@ -178,9 +180,6 @@ void WiFiConnectRelaxed() { return; } - // Start connect attempt now, so no longer needed to attempt new connection. - wifiConnectAttemptNeeded = false; - if (!prepareWiFi()) { addLog(LOG_LEVEL_ERROR, F("WIFI : Could not prepare WiFi!")); last_wifi_connect_attempt_moment.clear(); @@ -188,6 +187,16 @@ void WiFiConnectRelaxed() { return; } + // Start connect attempt now, so no longer needed to attempt new connection. + wifiConnectAttemptNeeded = false; + + if (espeasy_now_only) { + if (WifiIsSTA(WiFi.getMode())) { + setSTA(false); + } + return; + } + if (wifiSetupConnect) { // wifiSetupConnect is when run from the setup page. RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. @@ -205,6 +214,21 @@ void WiFiConnectRelaxed() { } const char *ssid = getLastWiFiSettingsSSID(); const char *passphrase = getLastWiFiSettingsPassphrase(); + if (!wifiSettingsValid(ssid, passphrase)) { + addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings")); + } else { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("WIFI : Connecting "); + log += ssid; + log += F(" attempt #"); + log += wifi_connect_attempt; + addLog(LOG_LEVEL_INFO, log); + } + last_wifi_connect_attempt_moment = millis(); + if ((wifi_connect_attempt != 0) && wifi_connect_attempt % 4 == 0 ) { + WifiScan(false, false); + } + wifiConnectInProgress = true; if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WIFI : Connecting "); @@ -217,13 +241,11 @@ void WiFiConnectRelaxed() { last_wifi_connect_attempt_moment.setNow(); wifiConnectInProgress = true; - // First try quick reconnect using last known BSSID and channel. - bool useQuickConnect = RTC.lastBSSID[0] != 0 && RTC.lastWiFiChannel != 0 && wifi_connect_attempt < 3; - - if (useQuickConnect) { - WiFi.begin(ssid, passphrase, RTC.lastWiFiChannel, &RTC.lastBSSID[0]); - } else { - WiFi.begin(ssid, passphrase); + if (useQuickConnect) { + WiFi.begin(ssid, passphrase, RTC.lastWiFiChannel, &RTC.lastBSSID[0]); + } else { + WiFi.begin(ssid, passphrase); + } } ++wifi_connect_attempt; logConnectionStatus(); @@ -240,7 +262,13 @@ bool prepareWiFi() { setAP(true); return false; } - setSTA(true); + if (espeasy_now_only) { + if (WifiIsSTA(WiFi.getMode())) { + setSTA(false); + } + } else { + setSTA(true); + } char hostname[40]; safe_strncpy(hostname, NetworkCreateRFCCompliantHostname().c_str(), sizeof(hostname)); #if defined(ESP8266) @@ -258,20 +286,13 @@ bool prepareWiFi() { WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); #endif // if defined(ESP32) - - #ifdef USES_ESPEASY_NOW - if (Settings.UseESPEasyNow()) { - setAP(true); - WiFi.softAP("ESPNOW", nullptr, 1); - WiFi.softAPdisconnect(false); - WifiEspNow.begin(); - } - #endif - - if (RTC.lastWiFiChannel != 0 && wifi_connect_attempt <= 1) { WifiScan(false, true); } + #ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.begin(); + #endif + setConnectionSpeed(); setupStaticIPconfig(); return true; @@ -401,8 +422,7 @@ void WifiDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW - WifiEspNow.end(); - use_EspEasy_now = false; + ESPEasy_now_handler.end(); #endif #if defined(ESP32) WiFi.disconnect(); @@ -719,6 +739,12 @@ bool wifiConnectTimeoutReached() { bool wifiAPmodeActivelyUsed() { + #ifdef USES_ESPEASY_NOW + if (ESPEasy_now_handler.active()) { + // Prevent WiFi reconnects when ESPEasy now is actively used. + return true; + } + #endif if (!WifiIsAP(WiFi.getMode()) || (!timerAPoff.isSet())) { // AP not active or soon to be disabled in processDisableAPmode() return false; @@ -743,16 +769,13 @@ void setConnectionSpeed() { #ifdef ESP32 /* uint8_t protocol = WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G; // Default to BG - if (!Settings.ForceWiFi_bg_mode() || (wifi_connect_attempt > 10)) { // Set to use BGN protocol |= WIFI_PROTOCOL_11N; } - if (WifiIsSTA(WiFi.getMode())) { esp_wifi_set_protocol(WIFI_IF_STA, protocol); } - if (WifiIsAP(WiFi.getMode())) { esp_wifi_set_protocol(WIFI_IF_AP, protocol); } @@ -937,7 +960,9 @@ void logConnectionStatus() { if (log.length() > 0) { const char *ssid = getLastWiFiSettingsSSID(); - log += ssid; + if (ssid != nullptr) { + log += ssid; + } addLog(LOG_LEVEL_INFO, log); } } diff --git a/src/ESPEasyWifi.h b/src/ESPEasyWifi.h index 7eaac4af47..f46f2eb41b 100644 --- a/src/ESPEasyWifi.h +++ b/src/ESPEasyWifi.h @@ -32,6 +32,7 @@ void setAP(bool enable); String getWifiModeString(WiFiMode_t wifimode); void setWifiMode(WiFiMode_t wifimode); bool WifiIsAP(WiFiMode_t wifimode); +bool WifiIsSTA(WiFiMode_t wifimode); bool useStaticIP(); bool wifiConnectTimeoutReached(); bool wifiAPmodeActivelyUsed(); diff --git a/src/ESPEasyWifi_ProcessEvent.cpp b/src/ESPEasyWifi_ProcessEvent.cpp index 8b9c79b822..f184b4a8ea 100644 --- a/src/ESPEasyWifi_ProcessEvent.cpp +++ b/src/ESPEasyWifi_ProcessEvent.cpp @@ -18,8 +18,11 @@ #include "src/Helpers/Misc.h" #include "src/Helpers/Network.h" #include "src/Helpers/Scheduler.h" +#include "src/DataStructs/NodesHandler.h" #include "src/Helpers/StringConverter.h" +#include "src/Globals/ESPEasy_now_state.h" +#include "src/Globals/ESPEasy_now_handler.h" bool unprocessedWifiEvents() { if (processedConnect && processedDisconnect && processedGotIP && processedDHCPTimeout) @@ -155,6 +158,7 @@ void handle_unprocessedWiFiEvents() // ******************************************************************************** void processDisconnect() { if (processedDisconnect) { return; } + processedDisconnect = true; wifiStatus = ESPEASY_WIFI_DISCONNECTED; delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 @@ -177,6 +181,12 @@ void processDisconnect() { addLog(LOG_LEVEL_INFO, log); } + // FIXME TD-er: Disconnect processing is done in several places. + #ifdef USES_ESPEASY_NOW + if (wifiAPmodeActivelyUsed() || espeasy_now_only) return; + ESPEasy_now_handler.end(); + #endif + if (Settings.WiFiRestart_connection_lost()) { initWiFi(); delay(100); @@ -331,7 +341,7 @@ void processDisconnectAPmode() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { const int nrStationsConnected = WiFi.softAPgetStationNum(); String log = F("AP Mode: Client disconnected: "); - log += formatMAC(lastMacDisconnectedAPmode); + log += lastMacDisconnectedAPmode.toString(); log += F(" Connected devices: "); log += nrStationsConnected; addLog(LOG_LEVEL_INFO, log); @@ -371,7 +381,7 @@ void processConnectAPmode() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("AP Mode: Client connected: "); - log += formatMAC(lastMacConnectedAPmode); + log += lastMacConnectedAPmode.toString(); log += F(" Connected devices: "); log += WiFi.softAPgetStationNum(); addLog(LOG_LEVEL_INFO, log); @@ -390,6 +400,10 @@ void processConnectAPmode() { void processDisableAPmode() { if (!timerAPoff.isSet()) { return; } + #ifdef USES_ESPEASY_NOW + if (Settings.UseESPEasyNow()) { return;} + #endif + if (WifiIsAP(WiFi.getMode())) { // disable AP after timeout and no clients connected. if (timerAPoff.timeoutReached(WIFI_AP_OFF_TIMER_DURATION) && (WiFi.softAPgetStationNum() == 0)) { @@ -430,6 +444,11 @@ void processScanDone() { addLog(LOG_LEVEL_INFO, log); } +#ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.addPeerFromWiFiScan(); + if (espeasy_now_only) { return; } +#endif + int bestScanID = -1; int32_t bestRssi = -1000; uint8_t bestWiFiSettings = RTC.lastWiFiSettingsIndex; @@ -536,6 +555,7 @@ void markWiFi_services_initialized() { } } + #ifdef HAS_ETHERNET void processEthernetConnected() { diff --git a/src/ESPEasyWifi_ProcessEvent.h b/src/ESPEasyWifi_ProcessEvent.h index 668fc6fa96..b64e707269 100644 --- a/src/ESPEasyWifi_ProcessEvent.h +++ b/src/ESPEasyWifi_ProcessEvent.h @@ -9,6 +9,7 @@ void processDisconnect(); void processConnect(); void processGotIP(); void processDisconnectAPmode(); +void processProbeRequestAPmode(); void processConnectAPmode(); void processDisableAPmode(); void processScanDone(); diff --git a/src/Networking.ino b/src/Networking.ino index ec7a4f050b..6d2a6c2aa4 100644 --- a/src/Networking.ino +++ b/src/Networking.ino @@ -385,30 +385,7 @@ void sendSysInfoUDP(byte repeats) memcpy(&data[2], thisNode, sizeof(NodeStruct)); for (byte counter = 0; counter < repeats; counter++) { - uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; - uint8_t *macread = NetworkMacAddressAsBytes(mac); - byte data[80] = {0}; - data[0] = 255; - data[1] = 1; - memcpy(&data[2], &thisNode, sizeof(NodeStruct)); - - for (byte x = 0; x < 6; x++) { - data[x + 2] = macread[x]; - } - - IPAddress ip = NetworkLocalIP(); - - for (byte x = 0; x < 4; x++) { - data[x + 8] = ip[x]; - } - data[12] = Settings.Unit; - data[13] = lowByte(Settings.Build); - data[14] = highByte(Settings.Build); - memcpy((byte *)data + 15, Settings.Name, 25); - data[40] = NODE_TYPE_ID; - data[41] = lowByte(Settings.WebserverPort); - data[42] = highByte(Settings.WebserverPort); statusLED(true); IPAddress broadcastIP(255, 255, 255, 255); diff --git a/src/_C019.ino b/src/_C019.ino index 63f637635c..320b28163d 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -34,7 +34,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesCheckReply = false; Protocol[protocolCount].usesTimeout = false; Protocol[protocolCount].usesSampleSets = false; - Protocol[protocolCount].needsWiFi = false; + Protocol[protocolCount].needsNetwork = false; break; } From a535c940242960932904ab5e0cf3d31ad3225889 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 2 Jul 2020 10:38:43 +0200 Subject: [PATCH 047/404] [WiFi] Remove default parameters of WifiScan to make use more clear --- src/ESPEasyWifi.h | 1 + src/src/Commands/WiFi.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ESPEasyWifi.h b/src/ESPEasyWifi.h index f46f2eb41b..ac9347210e 100644 --- a/src/ESPEasyWifi.h +++ b/src/ESPEasyWifi.h @@ -27,6 +27,7 @@ void initWiFi(); void WifiDisconnect(); void WifiScan(bool async, bool quick); void WifiScan(); +void WifiScan_channel(uint8_t channel, bool async); void setSTA(bool enable); void setAP(bool enable); String getWifiModeString(WiFiMode_t wifimode); diff --git a/src/src/Commands/WiFi.cpp b/src/src/Commands/WiFi.cpp index 1ac3f5d2cc..7d802245ac 100644 --- a/src/src/Commands/WiFi.cpp +++ b/src/src/Commands/WiFi.cpp @@ -1,6 +1,7 @@ #include "../Commands/WiFi.h" #include "../../ESPEasy_common.h" +#include "../../ESPEasyWifi.h" #include "../Commands/Common.h" #include "../Globals/Settings.h" #include "../Helpers/StringConverter.h" From 7ea618dc2d7827db355b93531ff4683930a22d0e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 2 Jul 2020 10:40:41 +0200 Subject: [PATCH 048/404] [WiFi] Allow WiFi reconnect when client connected to AP for more then 5 minutes A connected client to the AP mode of the node could prevent the unit to try to reconnect to WiFi. --- src/ESPEasyWiFiEvent.cpp | 1 + src/ESPEasyWifi.cpp | 8 +++++++- src/src/Globals/ESPEasyWiFiEvent.cpp | 2 ++ src/src/Globals/ESPEasyWiFiEvent.h | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index 684f6cdf5e..432d3817d3 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -208,6 +208,7 @@ void ICACHE_RAM_ATTR onDHCPTimeout() { void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { lastMacConnectedAPmode.set(event.mac); + lastAPmodeStationConnectMoment = millis(); processedConnectAPmode = false; } diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 5d261ed178..73bf66214a 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -749,7 +749,13 @@ bool wifiAPmodeActivelyUsed() // AP not active or soon to be disabled in processDisableAPmode() return false; } - return WiFi.softAPgetStationNum() != 0; + if (WiFi.softAPgetStationNum() != 0) { + if (timePassedSince(lastAPmodeStationConnectMoment) < (5*60*1000)) { + // Client is connected for less then 5 minutes + return true; + } + } + return false; // FIXME TD-er: is effectively checking for AP active enough or must really check for connected clients to prevent automatic wifi // reconnect? diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index 75703fe4be..a158615f09 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -44,7 +44,9 @@ LongTermTimer lastGetScanMoment; LongTermTimer::Duration lastConnectedDuration_us = 0ll; LongTermTimer timerAPoff; // Timer to check whether the AP mode should be disabled (0 = disabled) LongTermTimer timerAPstart; // Timer to start AP mode, started when no valid network is detected. +LongTermTimer lastAPmodeStationConnectMoment; bool intent_to_reboot = false; + MAC_address lastMacConnectedAPmode; MAC_address lastMacDisconnectedAPmode; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index 8f75c98b44..a3ecf23696 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -103,6 +103,7 @@ extern LongTermTimer lastGetScanMoment; extern LongTermTimer::Duration lastConnectedDuration_us; extern LongTermTimer timerAPoff; // Timer to check whether the AP mode should be disabled (0 = disabled) extern LongTermTimer timerAPstart; // Timer to start AP mode, started when no valid network is detected. +extern LongTermTimer lastAPmodeStationConnectMoment; extern bool intent_to_reboot; extern MAC_address lastMacConnectedAPmode; From f08b35e37002c26fbe7a1e9433d3403b0a110d65 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 2 Jul 2020 10:41:29 +0200 Subject: [PATCH 049/404] [ESPEasy-Now] Only update own distance based on current node information --- src/src/DataStructs/NodeStruct.cpp | 11 +++++++---- src/src/DataStructs/NodeStruct.h | 2 ++ src/src/DataStructs/NodesHandler.cpp | 12 ++++++++---- src/src/DataStructs/NodesHandler.h | 3 +-- src/src/Helpers/ESPEasy_now_handler.cpp | 23 +++++++++++++++-------- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index d6a5a47594..dde7f501e2 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -39,9 +39,8 @@ bool NodeStruct::validate() { } bool NodeStruct::operator<(const NodeStruct &other) const { - const bool thisExpired = getAge() > NODE_STRUCT_AGE_TIMEOUT; - const bool otherExpired = other.getAge() > NODE_STRUCT_AGE_TIMEOUT; - if (thisExpired != otherExpired) { + const bool thisExpired = isExpired(); + if (thisExpired != other.isExpired()) { return !thisExpired; } @@ -62,7 +61,7 @@ bool NodeStruct::operator<(const NodeStruct &other) const { int score_other = other.getLoad(); if (distance != other.distance) { - if (getAge() < NODE_STRUCT_AGE_TIMEOUT && other.getAge() < NODE_STRUCT_AGE_TIMEOUT) { + if (!isExpired() && !other.isExpired()) { // Distance is not the same, so take distance into account. return distance < other.distance; /* @@ -134,6 +133,10 @@ unsigned long NodeStruct::getAge() const { return timePassedSince(lastUpdated); } +bool NodeStruct::isExpired() const { + return getAge() > NODE_STRUCT_AGE_TIMEOUT; +} + float NodeStruct::getLoad() const { return load / 2.55; } diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 569951fce6..949dc0b0b5 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -49,6 +49,8 @@ struct __attribute__((__packed__)) NodeStruct unsigned long getAge() const; + bool isExpired() const; + float getLoad() const; String getSummary() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 9fa39881fc..5359e6e43e 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -6,10 +6,13 @@ void NodesHandler::addNode(const NodeStruct& node) { + int8_t rssi = 0; + // Erase any existing node with matching MAC address for (auto it = _nodes.begin(); it != _nodes.end(); ) { if (node.match(it->second.sta_mac) || node.match(it->second.ap_mac)) { + rssi = it->second.getRSSI(); it = _nodes.erase(it); } else { ++it; @@ -17,6 +20,9 @@ void NodesHandler::addNode(const NodeStruct& node) } _nodes[node.unit] = node; _nodes[node.unit].lastUpdated = millis(); + if (node.getRSSI() >= 0) { + _nodes[node.unit].setRSSI(rssi); + } } bool NodesHandler::hasNode(uint8_t unit_nr) const @@ -166,14 +172,12 @@ void NodesHandler::updateThisNode() { const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); if (preferred != nullptr) { - if (preferred->distance < 255) { + if (preferred->distance < 255 && !preferred->isExpired()) { _distance = preferred->distance + 1; + _lastTimeValidDistance = millis(); } } } - if (_distance < 255) { - _lastTimeValidDistance = millis(); - } thisNode.distance = _distance; addNode(thisNode); } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 8baf63623c..cc63ee3b7a 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -50,11 +50,10 @@ class NodesHandler { return _lastTimeValidDistance; } + bool isEndpoint() const; private: - bool isEndpoint() const; - unsigned long _lastTimeValidDistance = 0; uint8_t _distance = 255; // Cached value diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 5ba2973ad5..337d769306 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -4,6 +4,7 @@ # include "../../ESPEasy_fdwdecl.h" # include "../../ESPEasy_Log.h" +# include "../../ESPEasyWifi.h" # include "../../_CPlugin_Helper.h" # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" @@ -22,7 +23,7 @@ # include -# define ESPEASY_NOW_ACTIVVITY_TIMEOUT 120000 // 2 minutes +# define ESPEASY_NOW_ACTIVITY_TIMEOUT 120000 // 2 minutes # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" @@ -86,16 +87,19 @@ bool ESPEasy_now_handler_t::begin() addPeerFromWiFiScan(); } - const NodeStruct *preferred = Nodes.getPreferredNode(); + if (!Nodes.isEndpoint()) { + const NodeStruct *preferred = Nodes.getPreferredNode(); - if (preferred != nullptr) { - channel = preferred->channel; - bssid.set(preferred->ap_mac); + if (preferred != nullptr) { + channel = preferred->channel; + bssid.set(preferred->ap_mac); + } } const String ssid = F(ESPEASY_NOW_TMP_SSID); const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); + setAP(true); if (espeasy_now_only) { if (bssid.all_zero()) { WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel); @@ -103,7 +107,6 @@ bool ESPEasy_now_handler_t::begin() WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel, bssid.mac); } } - setAP(true); int ssid_hidden = 1; int max_connection = 6; @@ -255,7 +258,7 @@ bool ESPEasy_now_handler_t::active() const if (Nodes.lastTimeValidDistanceExpired()) { return false; } - return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVVITY_TIMEOUT; + return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVITY_TIMEOUT; } void ESPEasy_now_handler_t::addPeerFromWiFiScan() @@ -317,7 +320,11 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { - addLog(LOG_LEVEL_INFO, message.getLogString()); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-Now received "); + log += message.getLogString(); + addLog(LOG_LEVEL_INFO, log); + } bool handled = false; mustKeep = true; bool considerActive = false; From 9e3657d14ff856ece0247e8c1b386f02bdb82aac Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 3 Jul 2020 11:45:07 +0200 Subject: [PATCH 050/404] [Build] Fix merge issues --- src/ESPEasy_fdwdecl.h | 2 +- src/_C019.ino | 4 ++ .../ControllerDelayHandlerStruct.h | 3 +- .../ControllerQueue/DelayQueueElements.cpp | 9 ++-- src/src/DataStructs/NodesHandler.cpp | 2 + src/src/Helpers/ESPEasy_now_handler.cpp | 3 ++ src/src/Helpers/PeriodicalActions.cpp | 42 +++++++++++++++++-- src/src/Helpers/Scheduler.cpp | 8 ++-- src/src/PluginStructs/P094_data_struct.cpp | 1 + 9 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index 0a42e0f234..8631b1f5d3 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -78,7 +78,7 @@ void callback(char *c_topic, //void MQTTDisconnect(); //bool MQTTConnect(controllerIndex_t controller_idx); bool MQTTCheck(controllerIndex_t controller_idx); -//bool MQTT_queueFull(controllerIndex_t controller_idx); +bool MQTT_queueFull(controllerIndex_t controller_idx); bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained); #ifdef USES_ESPEASY_NOW diff --git a/src/_C019.ino b/src/_C019.ino index 320b28163d..84b1e1f93e 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -5,6 +5,10 @@ // ####################################################################################################### #include "src/Globals/ESPEasy_now_handler.h" +#include "src/ControllerQueue/C019_queue_element.h" +#include "ESPEasy_plugindefs.h" +#include "ESPEasy_fdwdecl.h" +#include "_CPlugin_Helper.h" #define CPLUGIN_019 diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 0ab70f1e59..74208662f1 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -226,7 +226,8 @@ struct ControllerDelayHandlerStruct { } else { \ LoadControllerSettings(element->controller_idx, ControllerSettings); \ C##NNN####M##_DelayHandler->configureControllerSettings(ControllerSettings); \ - if (!C##NNN####M##_DelayHandler->readyToProcess(*element)) { ready = false; } \ + if (!C##NNN####M##_DelayHandler->readyToProcess(*element) && \ + !ControllerSettings.enableESPEasyNowFallback()) { ready = false; } \ } \ if (ready) { \ START_TIMER; \ diff --git a/src/src/ControllerQueue/DelayQueueElements.cpp b/src/src/ControllerQueue/DelayQueueElements.cpp index 5b013257d2..da6108ce6f 100644 --- a/src/src/ControllerQueue/DelayQueueElements.cpp +++ b/src/src/ControllerQueue/DelayQueueElements.cpp @@ -136,11 +136,10 @@ DEFINE_Cxxx_DELAY_QUEUE_MACRO_CPP(0, 18) #endif // ifdef USES_C018 -/* - #ifdef USES_C019 - DEFINE_Cxxx_DELAY_QUEUE_MACRO_CPP(0, 19) - #endif - */ + +#ifdef USES_C019 + DEFINE_Cxxx_DELAY_QUEUE_MACRO_CPP(0, 19) +#endif /* #ifdef USES_C020 diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 5359e6e43e..440042eeb0 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,7 +1,9 @@ #include "NodesHandler.h" #include "../../ESPEasy-Globals.h" +#include "../../ESPEasyWifi.h" #include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/PeriodicalActions.h" #include "../Globals/MQTT.h" void NodesHandler::addNode(const NodeStruct& node) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 337d769306..42b5ccac31 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -5,6 +5,7 @@ # include "../../ESPEasy_fdwdecl.h" # include "../../ESPEasy_Log.h" # include "../../ESPEasyWifi.h" +# include "../../ESPEasyWiFi_credentials.h" # include "../../_CPlugin_Helper.h" # include "ESPEasy_time_calc.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" @@ -18,6 +19,8 @@ # include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" # include "../ControllerQueue/MQTT_queue_element.h" +# include "../Helpers/PeriodicalActions.h" +# include "../Helpers/ESPEasy_Storage.h" # include diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 53078fddc2..0f91abb7de 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -16,6 +16,8 @@ #include "../Globals/SecuritySettings.h" #include "../Globals/Services.h" #include "../Globals/Statistics.h" +#include "../Globals/ESPEasy_now_handler.h" +#include "../Globals/SendData_DuplicateChecker.h" #include "../Helpers/ESPEasyRTC.h" #include "../Helpers/Hardware.h" #include "../Helpers/Memory.h" @@ -62,6 +64,16 @@ void run10TimesPerSecond() { CPluginCall(CPlugin::Function::CPLUGIN_TEN_PER_SECOND, 0, dummy); STOP_TIMER(CPLUGIN_CALL_10PS); } + #ifdef USES_ESPEASY_NOW + { + if (ESPEasy_now_handler.loop()) { + // FIXME TD-er: Must check if enabled, etc. + } + START_TIMER; + SendData_DuplicateChecker.loop(); + STOP_TIMER(ESPEASY_NOW_DEDUP_LOOP); + } + #endif processNextEvent(); #ifdef USES_C015 @@ -256,11 +268,35 @@ void processMQTTdelayQueue() { if (element == NULL) { return; } - if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) { - if (connectionFailures > 0) { - --connectionFailures; +#ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + String log; + log.reserve(30 + element->_topic.length() + element->_payload.length()); + log += F("processMQTTdelayQueue: "); + log += element->_topic; + log += " "; + log += element->_payload.substring(0,64); + addLog(LOG_LEVEL_DEBUG, log); + } +#endif + + bool processed = false; + + #ifdef USES_ESPEASY_NOW + if (!MQTTclient.connected()) { + processed = ESPEasy_now_handler.sendToMQTT(element->controller_idx, element->_topic, element->_payload); + } + #endif + + if (!processed) { + if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) { + if (connectionFailures > 0) { + --connectionFailures; + } + processed = true; } MQTTDelayHandler->markProcessed(true); + statusLED(true); } else { MQTTDelayHandler->markProcessed(false); #ifndef BUILD_NO_DEBUG diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index 1781fe860f..9cd76cfb21 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -361,11 +361,9 @@ void ESPEasy_Scheduler::process_interval_timer(IntervalTimer_e id, unsigned long break; case IntervalTimer_e::TIMER_C019_DELAY_QUEUE: - /* - #ifdef USES_C019 - process_c019_delay_queue(); - #endif - */ + #ifdef USES_C019 + process_c019_delay_queue(); + #endif break; case IntervalTimer_e::TIMER_C020_DELAY_QUEUE: diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index ff7285a0e0..08942c32d9 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -5,6 +5,7 @@ #include "../Helpers/StringConverter.h" + P094_data_struct::P094_data_struct() : easySerial(nullptr) {} P094_data_struct::~P094_data_struct() { From 2e038159e7ef69b6e95459730ff9d5029a0524c4 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 4 Jul 2020 14:08:47 +0200 Subject: [PATCH 051/404] [WiFi] Reduce wifi reset calls and call full wifi init at reset --- src/ESPEasyWiFiEvent.cpp | 2 +- src/ESPEasyWifi.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index 432d3817d3..81fe7335b5 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -212,7 +212,7 @@ void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { processedConnectAPmode = false; } -void onDisonnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { +void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { lastMacDisconnectedAPmode.set(event.mac); processedDisconnectAPmode = false; } diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 73bf66214a..4bffc9c1c0 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -407,14 +407,16 @@ void initWiFi() #ifdef ESP8266 // WiFi event handlers stationConnectedHandler = WiFi.onStationModeConnected(onConnected); - stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect); - stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP); + stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect); + stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP); stationModeDHCPTimeoutHandler = WiFi.onStationModeDHCPTimeout(onDHCPTimeout); APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode); APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode); + APModeProbeRequestReceivedHandler = WiFi.onSoftAPModeProbeRequestReceived(onProbeRequestAPmode); #endif } + // ******************************************************************************** // Disconnect from Wifi AP // ******************************************************************************** From aa56334c34c941456e2e5f2a8efe88add47aeca1 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 12 Aug 2020 01:24:24 +0200 Subject: [PATCH 052/404] [ESPEasy-now] Fix merge issues. --- src/Controller.ino | 14 +++--- src/ESPEasyTimeTypes.cpp | 31 +++++++++++++ src/ESPEasyTimeTypes.h | 30 ++++++++----- src/_C019.ino | 6 +-- .../DataStructs/ControllerSettingsStruct.cpp | 4 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 + src/src/DataStructs/ESPEasy_now_merger.cpp | 2 + src/src/Globals/ESPEasyWiFiEvent.cpp | 4 ++ src/src/Globals/ESPEasyWiFiEvent.h | 4 ++ src/src/Helpers/ESPEasy_time.cpp | 44 +++++-------------- src/src/Helpers/ESPEasy_time.h | 21 --------- 11 files changed, 85 insertions(+), 77 deletions(-) create mode 100644 src/ESPEasyTimeTypes.cpp diff --git a/src/Controller.ino b/src/Controller.ino index 49539fb4a2..5140a1bfc2 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -482,19 +482,19 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes bool success = false; if (!MQTT_queueFull(controller_idx)) { - success = MQTTDelayHandler.addToQueue(MQTT_queue_element()); + success = MQTTDelayHandler->addToQueue(MQTT_queue_element()); if (success) { size_t pos = 0; - MQTTDelayHandler.sendQueue.back().controller_idx = controller_idx; - MQTTDelayHandler.sendQueue.back()._retained = retained; - message.getString(MQTTDelayHandler.sendQueue.back()._topic, pos); - message.getString(MQTTDelayHandler.sendQueue.back()._payload, pos); + MQTTDelayHandler->sendQueue.back().controller_idx = controller_idx; + MQTTDelayHandler->sendQueue.back()._retained = retained; + message.getString(MQTTDelayHandler->sendQueue.back()._topic, pos); + message.getString(MQTTDelayHandler->sendQueue.back()._payload, pos); } size_t payloadSize = message.getPayloadSize(); - if ((MQTTDelayHandler.sendQueue.back()._topic.length() + MQTTDelayHandler.sendQueue.back()._payload.length() + 2) < payloadSize) { + if ((MQTTDelayHandler->sendQueue.back()._topic.length() + MQTTDelayHandler->sendQueue.back()._payload.length() + 2) < payloadSize) { success = false; - MQTTDelayHandler.sendQueue.pop_back(); + MQTTDelayHandler->sendQueue.pop_back(); } } scheduleNextMQTTdelayQueue(); diff --git a/src/ESPEasyTimeTypes.cpp b/src/ESPEasyTimeTypes.cpp new file mode 100644 index 0000000000..d66be32d25 --- /dev/null +++ b/src/ESPEasyTimeTypes.cpp @@ -0,0 +1,31 @@ +#include "ESPEasyTimeTypes.h" + +#include + + +String toString(timeSource_t timeSource) +{ + switch (timeSource) { + case timeSource_t::GPS_PPS_time_source: return F("GPS PPS"); + case timeSource_t::GPS_time_source: return F("GPS"); + case timeSource_t::NTP_time_source: return F("NTP"); + case timeSource_t::Manual_set: return F("Manual"); + case timeSource_t::ESP_now_peer: return F("ESPEasy-NOW peer"); + case timeSource_t::Restore_RTC_time_source: return F("RTC at boot"); + case timeSource_t::No_time_source: return F("No time set"); + } + return F("Unknown"); +} + +bool isExternalTimeSource(timeSource_t timeSource) +{ + switch (timeSource) { + case timeSource_t::GPS_PPS_time_source: + case timeSource_t::GPS_time_source: + case timeSource_t::NTP_time_source: + case timeSource_t::Manual_set: + return true; + default: + return false; + } +} diff --git a/src/ESPEasyTimeTypes.h b/src/ESPEasyTimeTypes.h index deb330e10f..aff670fc9f 100644 --- a/src/ESPEasyTimeTypes.h +++ b/src/ESPEasyTimeTypes.h @@ -2,19 +2,29 @@ #define ESPEASY_TIMETYPES_H_ #include -#include -#include +class String; -#include "src/DataStructs/TimeChangeRule.h" -#include "src/Globals/Plugins.h" +// Time Source type, sort by priority. +// Enum values are sent via NodeStruct, so only add new ones and don't change existing values +// typical time wander of an ESP module is 0.04 msec/sec, or roughly 3.5 seconds per 24h. +enum class timeSource_t : uint8_t { + // External time source (considered more reliable) + GPS_PPS_time_source = 5, // 1 - 10 msec accuracy + GPS_time_source = 10, // 10 - 100 msec accuracy + NTP_time_source = 15, // 20 - 100 msec accuracy + // Manual override has higher priority because it is some kind of external sync + Manual_set = 20, // Unknown accuracy -enum timeSource_t { - No_time_source, - NTP_time_source, - Restore_RTC_time_source, - GPS_time_source, - Manual_set + // Sources which may drift over time due to lack of external synchronization. + ESP_now_peer = 40, // < 5 msec accuracy between nodes, but time on the whole network may drift + + Restore_RTC_time_source = 50, // > 1 sec difference per reboot + No_time_source = 255 // No time set }; +String toString(timeSource_t timeSource); +bool isExternalTimeSource(timeSource_t timeSource); + + #endif /* ESPEASY_TIMETYPES_H_ */ diff --git a/src/_C019.ino b/src/_C019.ino index 84b1e1f93e..4dc8499db3 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -54,7 +54,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& LoadControllerSettings(event->ControllerIndex, ControllerSettings); // FIXME TD-er: Not sure if MQTT like formatting is the best here. - C019_DelayHandler.configureControllerSettings(ControllerSettings); + C019_DelayHandler->configureControllerSettings(ControllerSettings); break; } @@ -67,8 +67,8 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - success = C019_DelayHandler.addToQueue(C019_queue_element(event)); - scheduleNextDelayQueue(TIMER_C019_DELAY_QUEUE, C019_DelayHandler.getNextScheduleTime()); + success = C019_DelayHandler->addToQueue(C019_queue_element(event)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C019_DELAY_QUEUE, C019_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index d054b89933..1b9ade5881 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -256,10 +256,10 @@ void ControllerSettingsStruct::sendBinary(bool value) bool ControllerSettingsStruct::enableESPEasyNowFallback() const { - return bitRead(MQTT_flags, 7); + return bitRead(VariousFlags, 8); } void ControllerSettingsStruct::enableESPEasyNowFallback(bool value) { - bitWrite(MQTT_flags, 7, value); + bitWrite(VariousFlags, 8, value); } diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 116f5e6da4..0a4d44fff0 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -30,10 +30,12 @@ void ESPEasy_Now_packet::setSize(size_t packetSize) if (packetSize > ESPEASY_NOW_MAX_PACKET_SIZE) { packetSize = ESPEASY_NOW_MAX_PACKET_SIZE; } + #ifdef ESP8266 const size_t maxFreeBlock = ESP.getMaxFreeBlockSize(); if (packetSize > maxFreeBlock) { packetSize = maxFreeBlock; } + #endif _buf.resize(packetSize); } diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 9ac894c834..6a44b79848 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -17,6 +17,7 @@ void ESPEasy_now_merger::addPacket( const uint8_t *buf, size_t packetSize) { + #ifdef ESP8266 const uint16_t maxFreeBlock = ESP.getMaxFreeBlockSize(); if (2 * packetSize > maxFreeBlock) { @@ -25,6 +26,7 @@ void ESPEasy_now_merger::addPacket( _firstPacketTimestamp -= ESPEASY_NOW_MESSAGE_TIMEOUT; return; } + #endif _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet(mac, buf, packetSize))); _firstPacketTimestamp = millis(); diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index a158615f09..61a561ade7 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -21,6 +21,10 @@ WiFiEventHandler APModeProbeRequestReceivedHandler; std::list APModeProbeRequestReceived_list; #endif // ifdef ESP8266 +#ifdef ESP32 +std::list APModeProbeRequestReceived_list; +#endif + // WiFi related data bool wifiSetup = false; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index a3ecf23696..923e708dd8 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -80,6 +80,10 @@ extern WiFiEventHandler APModeProbeRequestReceivedHandler; extern std::list APModeProbeRequestReceived_list; #endif // ifdef ESP8266 +#ifdef ESP32 +extern std::list APModeProbeRequestReceived_list; +#endif + // WiFi related data extern bool wifiSetup; diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 2f7155c9c9..ead0154178 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -3,6 +3,7 @@ #include "../../ESPEasy-Globals.h" #include "../../ESPEasy_Log.h" #include "../../ESPEasy_fdwdecl.h" +#include "../../ESPEasyTimeTypes.h" #include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" @@ -18,33 +19,6 @@ #include -String toString(timeSource_t timeSource) -{ - switch (timeSource) { - case timeSource_t::GPS_PPS_time_source: return F("GPS PPS"); - case timeSource_t::GPS_time_source: return F("GPS"); - case timeSource_t::NTP_time_source: return F("NTP"); - case timeSource_t::Manual_set: return F("Manual"); - case timeSource_t::ESP_now_peer: return F("ESPEasy-NOW peer"); - case timeSource_t::Restore_RTC_time_source: return F("RTC at boot"); - case timeSource_t::No_time_source: return F("No time set"); - } - return F("Unknown"); -} - -bool isExternalTimeSource(timeSource_t timeSource) -{ - switch (timeSource) { - case timeSource_t::GPS_PPS_time_source: - case timeSource_t::GPS_time_source: - case timeSource_t::NTP_time_source: - case timeSource_t::Manual_set: - return true; - default: - return false; - } -} - ESPEasy_time::ESPEasy_time() { memset(&tm, 0, sizeof(tm)); memset(&tsRise, 0, sizeof(tm)); @@ -163,7 +137,7 @@ unsigned long ESPEasy_time::now() { // nextSyncTime & sysTime are in seconds double unixTime_d = -1.0; - if (externalTimeSource > 0.0f) { + if (externalUnixTime_d > 0.0f) { unixTime_d = externalUnixTime_d; // Correct for the delay between the last received external time and applying it @@ -259,15 +233,17 @@ bool ESPEasy_time::reportNewMinute() bool ESPEasy_time::systemTimePresent() const { switch (timeSource) { - case No_time_source: + case timeSource_t::No_time_source: break; - case NTP_time_source: - case Restore_RTC_time_source: - case GPS_time_source: - case Manual_set: + case timeSource_t::NTP_time_source: + case timeSource_t::Restore_RTC_time_source: + case timeSource_t::GPS_time_source: + case timeSource_t::GPS_PPS_time_source: + case timeSource_t::ESP_now_peer: + case timeSource_t::Manual_set: return true; } - return nextSyncTime > 0 || Settings.UseNTP || externalTimeSource > 0.0f; + return nextSyncTime > 0 || Settings.UseNTP || externalUnixTime_d > 0.0f; } bool ESPEasy_time::getNtpTime(double& unixTime_d) diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index c943401f97..c8deb6d34c 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -6,27 +6,6 @@ #include "../../ESPEasyTimeTypes.h" -// Time Source type, sort by priority. -// Enum values are sent via NodeStruct, so only add new ones and don't change existing values -// typical time wander of an ESP module is 0.04 msec/sec, or roughly 3.5 seconds per 24h. -enum class timeSource_t : uint8_t { - // External time source (considered more reliable) - GPS_PPS_time_source = 5, // 1 - 10 msec accuracy - GPS_time_source = 10, // 10 - 100 msec accuracy - NTP_time_source = 15, // 20 - 100 msec accuracy - - // Manual override has higher priority because it is some kind of external sync - Manual_set = 20, // Unknown accuracy - - // Sources which may drift over time due to lack of external synchronization. - ESP_now_peer = 40, // < 5 msec accuracy between nodes, but time on the whole network may drift - - Restore_RTC_time_source = 50, // > 1 sec difference per reboot - No_time_source = 255 // No time set -}; - -String toString(timeSource_t timeSource); -bool isExternalTimeSource(timeSource_t timeSource); class ESPEasy_time { public: From 37bee461a6afc3d73121ee8435797caffb2ffa5c Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 20 Sep 2020 00:44:32 +0200 Subject: [PATCH 053/404] Fix merge issues --- src/ESPEasyWiFiEvent.cpp | 2 +- src/ESPEasyWifi.cpp | 10 +++++++--- src/_P098_ESPEasyNowReceiver.ino | 4 ++-- src/src/Helpers/ESPEasy_checks.cpp | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/ESPEasyWiFiEvent.cpp b/src/ESPEasyWiFiEvent.cpp index 81fe7335b5..87f59861e9 100644 --- a/src/ESPEasyWiFiEvent.cpp +++ b/src/ESPEasyWiFiEvent.cpp @@ -208,7 +208,7 @@ void ICACHE_RAM_ATTR onDHCPTimeout() { void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) { lastMacConnectedAPmode.set(event.mac); - lastAPmodeStationConnectMoment = millis(); + lastAPmodeStationConnectMoment.setNow(); processedConnectAPmode = false; } diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index 4bffc9c1c0..ae7249b08e 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -224,7 +224,7 @@ void WiFiConnectRelaxed() { log += wifi_connect_attempt; addLog(LOG_LEVEL_INFO, log); } - last_wifi_connect_attempt_moment = millis(); + last_wifi_connect_attempt_moment.setNow(); if ((wifi_connect_attempt != 0) && wifi_connect_attempt % 4 == 0 ) { WifiScan(false, false); } @@ -241,6 +241,9 @@ void WiFiConnectRelaxed() { last_wifi_connect_attempt_moment.setNow(); wifiConnectInProgress = true; + // First try quick reconnect using last known BSSID and channel. + bool useQuickConnect = RTC.lastBSSID[0] != 0 && RTC.lastWiFiChannel != 0 && wifi_connect_attempt < 3; + if (useQuickConnect) { WiFi.begin(ssid, passphrase, RTC.lastWiFiChannel, &RTC.lastBSSID[0]); } else { @@ -451,6 +454,7 @@ void WifiScan(bool async, bool quick) { bool show_hidden = true; processedScanDone = false; lastGetScanMoment.setNow(); + uint8_t channel = 0; // Default to scan all channels if (quick) { #ifdef ESP8266 // Only scan a single channel if the RTC.lastWiFiChannel is known to speed up connection time. @@ -481,7 +485,7 @@ void WifiScan_channel(uint8_t channel, bool async) { } bool show_hidden = true; processedScanDone = false; - lastGetScanMoment = millis(); + lastGetScanMoment.setNow(); #ifdef ESP8266 WiFi.scanNetworks(async, show_hidden, channel); #else @@ -752,7 +756,7 @@ bool wifiAPmodeActivelyUsed() return false; } if (WiFi.softAPgetStationNum() != 0) { - if (timePassedSince(lastAPmodeStationConnectMoment) < (5*60*1000)) { + if (!lastAPmodeStationConnectMoment.timeoutReached(5*60*1000)) { // Client is connected for less then 5 minutes return true; } diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 56e41dd79e..cd7db9c9e6 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -31,7 +31,7 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) { Device[++deviceCount].Number = PLUGIN_ID_098; Device[deviceCount].Type = DEVICE_TYPE_DUMMY; - Device[deviceCount].VType = SENSOR_TYPE_STRING; // FIXME TD-er: Must make this the same as the sender. + Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_STRING; // FIXME TD-er: Must make this the same as the sender. Device[deviceCount].Ports = 0; Device[deviceCount].PullUpOption = false; Device[deviceCount].InverseLogicOption = false; @@ -96,7 +96,7 @@ boolean Plugin_098(byte function, struct EventStruct *event, String& string) case PLUGIN_READ: { - event->sensorType = PCONFIG(0); + event->sensorType = static_cast(PCONFIG(0)); success = true; break; } diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index b196af9de2..4f5264c5e7 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -61,7 +61,7 @@ void check_size() { void run_compiletime_checks() { #ifndef LIMIT_BUILD_SIZE check_size(); - check_size(); + check_size(); #ifdef ESP32 const unsigned int SettingsStructSize = (312 + 84 * TASKS_MAX); #endif From d9d8894d55e734a671c48534f908eb8e0b490e92 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 26 Sep 2020 00:22:34 +0200 Subject: [PATCH 054/404] Fix merge issues --- src/Controller.ino | 2 +- src/ESPEasyWifi.cpp | 8 -------- src/ESPEasy_fdwdecl.h | 2 ++ src/_C019.ino | 5 ++--- src/src/DataStructs/NodeStruct.cpp | 5 ++--- src/src/DataStructs/NodeStruct.h | 4 ++-- src/src/Helpers/PeriodicalActions.cpp | 1 + 7 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index 5140a1bfc2..9da95236a4 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -19,7 +19,7 @@ #include "src/Globals/SendData_DuplicateChecker.h" #include "_CPlugin_Helper.h" -#include "src/Helpers/ESPEasy_now.h" +//#include "src/Helpers/ESPEasy_now.h" #include "src/Helpers/PortStatus.h" #include "src/Helpers/Rules_calculate.h" diff --git a/src/ESPEasyWifi.cpp b/src/ESPEasyWifi.cpp index ae7249b08e..ef1eb4861d 100644 --- a/src/ESPEasyWifi.cpp +++ b/src/ESPEasyWifi.cpp @@ -446,14 +446,6 @@ void WifiDisconnect() // Scan WiFi network // ******************************************************************************** void WifiScan(bool async, bool quick) { - if (WiFi.scanComplete() == -1) { - // Scan still busy - return; - } - addLog(LOG_LEVEL_INFO, F("WIFI : Start network scan")); - bool show_hidden = true; - processedScanDone = false; - lastGetScanMoment.setNow(); uint8_t channel = 0; // Default to scan all channels if (quick) { #ifdef ESP8266 diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index 8631b1f5d3..4b02b7ea03 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -85,6 +85,8 @@ bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); #endif +void sendData(struct EventStruct *event); + #endif // ifdef USES_MQTT void flushAndDisconnectAllClients(); diff --git a/src/_C019.ino b/src/_C019.ino index 4dc8499db3..763a3bf879 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -4,11 +4,10 @@ // ################### Controller Plugin 019: ESPEasy-Now ################################################ // ####################################################################################################### -#include "src/Globals/ESPEasy_now_handler.h" -#include "src/ControllerQueue/C019_queue_element.h" -#include "ESPEasy_plugindefs.h" #include "ESPEasy_fdwdecl.h" #include "_CPlugin_Helper.h" +#include "src/ControllerQueue/C019_queue_element.h" +#include "src/Globals/ESPEasy_now_handler.h" #define CPLUGIN_019 diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index dde7f501e2..8e8cde1546 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -1,15 +1,14 @@ #include "NodeStruct.h" -#include "../Globals/Settings.h" #include "../../ESPEasy-Globals.h" #include "../../ESPEasyTimeTypes.h" #include "../Globals/SecuritySettings.h" +#include "../Globals/Settings.h" #include "../Helpers/ESPEasy_time_calc.h" #define NODE_STRUCT_AGE_TIMEOUT 120000 // 2 minutes -NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0), - build(0), age(0), nodeType(0), webgui_portnumber(0) +NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0) {} bool NodeStruct::valid() const { diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 949dc0b0b5..803d835f24 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -4,8 +4,9 @@ #include "../../ESPEasy_common.h" #include "../Helpers/ESPEasy_time.h" #include "MAC_address.h" -#include + #include +#include #define NODE_TYPE_ID_ESP_EASY_STD 1 @@ -15,7 +16,6 @@ #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 #define NODE_TYPE_ID_NANO_EASY_STD 81 -String getNodeTypeDisplayString(byte nodeType); /*********************************************************************************************\ * NodeStruct diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 0f91abb7de..5a101742cc 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -22,6 +22,7 @@ #include "../Helpers/Hardware.h" #include "../Helpers/Memory.h" #include "../Helpers/Misc.h" +#include "../Helpers/Network.h" #include "../Helpers/StringGenerator_System.h" From f591f6e7cb8b503e0734701f94c9bd9c4c4b384f Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 29 Sep 2020 11:13:55 +0200 Subject: [PATCH 055/404] Fix merge issues in NodeStruct --- src/WebServer_DevicesPage.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WebServer_DevicesPage.ino b/src/WebServer_DevicesPage.ino index 6752650625..35609c6eea 100644 --- a/src/WebServer_DevicesPage.ino +++ b/src/WebServer_DevicesPage.ino @@ -680,11 +680,11 @@ void format_originating_node(byte remoteUnit) { addHtml(String(remoteUnit)); if (remoteUnit != 255) { - NodesMap::iterator it = Nodes.find(remoteUnit); + const NodeStruct *node = Nodes.getNode(remoteUnit); - if (it != Nodes.end()) { + if (node != nullptr) { addHtml(F(" - ")); - addHtml(it->second.nodeName); + addHtml(node->getNodeName()); } else { addHtml(F(" - Not Seen recently")); } @@ -886,10 +886,10 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, byte page) addFormNumericBox(F("Remote Unit"), F("RemoteUnit"), remoteUnit, 0, 255); if (remoteUnit != 255) { - auto it = Nodes.find(remoteUnit); + const NodeStruct* node = Nodes.getNode(remoteUnit); - if (it != Nodes.end()) { - addUnit(it->second.getNodeName()); + if (node != nullptr) { + addUnit(node->getNodeName()); } else { addUnit(F("Unknown Unit Name")); } From f0b6443a1bc031f6916be72a11b80cb6f1100633 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 29 Sep 2020 12:27:25 +0200 Subject: [PATCH 056/404] [ESPEasy-Now] Fix forwarding MQTT messages when connected to ethernet --- src/src/Helpers/PeriodicalActions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 5a101742cc..2394c13ad1 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -296,10 +296,11 @@ void processMQTTdelayQueue() { } processed = true; } - MQTTDelayHandler->markProcessed(true); + } + MQTTDelayHandler->markProcessed(processed); + if (processed) { statusLED(true); } else { - MQTTDelayHandler->markProcessed(false); #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { From 295a5f7b1154ff200ad1aa35729d97d7813bc8ec Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 29 Sep 2020 23:50:13 +0200 Subject: [PATCH 057/404] [ESPEasy-now] Allow ESPEasy-now be set as default build setting --- src/src/DataStructs/ESPEasyDefaults.h | 10 ++++++++++ src/src/DataStructs/SettingsStruct.cpp | 1 + 2 files changed, 11 insertions(+) diff --git a/src/src/DataStructs/ESPEasyDefaults.h b/src/src/DataStructs/ESPEasyDefaults.h index e6c8d6614c..b0a3638b06 100644 --- a/src/src/DataStructs/ESPEasyDefaults.h +++ b/src/src/DataStructs/ESPEasyDefaults.h @@ -73,6 +73,11 @@ #define DEFAULT_ADMIN_PASS "" #endif + +#ifndef DEFAULT_APPEND_UNIT_TO_HOSTNAME +#define DEFAULT_APPEND_UNIT_TO_HOSTNAME false +#endif + #ifndef DEFAULT_WIFI_CONNECTION_TIMEOUT #define DEFAULT_WIFI_CONNECTION_TIMEOUT 10000 // minimum timeout in ms for WiFi to be connected. #endif @@ -99,6 +104,10 @@ #define DEFAULT_SEND_TO_HTTP_ACK false // Wait for ack with SendToHttp command. #endif +#ifndef DEFAULT_USE_ESPEASYNOW +#define DEFAULT_USE_ESPEASYNOW false +#endif + // --- Default Controller ------------------------------------------------------------------------------ #ifndef DEFAULT_CONTROLLER #define DEFAULT_CONTROLLER true // true or false enabled or disabled, set 1st controller defaults @@ -286,6 +295,7 @@ #define DEFAULT_SYNC_UDP_PORT 0 // Used for ESPEasy p2p. (IANA registered port: 8266) #endif + /* // --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------ diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index 046a4f96cb..2cf19e93a1 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -288,6 +288,7 @@ void SettingsStruct_tmpl::clearMisc() { gratuitousARP(DEFAULT_GRATUITOUS_ARP); TolerantLastArgParse(DEFAULT_TOLERANT_LAST_ARG_PARSE); SendToHttp_ack(DEFAULT_SEND_TO_HTTP_ACK); + UseESPEasyNow(DEFAULT_USE_ESPEASYNOW); } template From 720edd93b6c7f7884d75842e695ece97f1b6a2b5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 30 Sep 2020 16:09:59 +0200 Subject: [PATCH 058/404] [ESPEasy-now] Fix crash on ESP32 when ESPEasy-now could not be started Plus include the WifiEspNow library to make some changes to it. --- lib/WifiEspNow/.travis.yml | 57 ++ lib/WifiEspNow/COPYING | 842 ++++++++++++++++++ lib/WifiEspNow/README.md | 13 + .../EspNowBroadcast/EspNowBroadcast.ino | 73 ++ .../examples/EspNowUnicast/EspNowUnicast.ino | 50 ++ lib/WifiEspNow/library.properties | 9 + lib/WifiEspNow/src/WifiEspNow.cpp | 156 ++++ lib/WifiEspNow/src/WifiEspNow.h | 132 +++ lib/WifiEspNow/src/WifiEspNowBroadcast.cpp | 168 ++++ lib/WifiEspNow/src/WifiEspNowBroadcast.h | 81 ++ src/src/Helpers/ESPEasy_now_handler.cpp | 7 +- 11 files changed, 1586 insertions(+), 2 deletions(-) create mode 100644 lib/WifiEspNow/.travis.yml create mode 100644 lib/WifiEspNow/COPYING create mode 100644 lib/WifiEspNow/README.md create mode 100644 lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino create mode 100644 lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino create mode 100644 lib/WifiEspNow/library.properties create mode 100644 lib/WifiEspNow/src/WifiEspNow.cpp create mode 100644 lib/WifiEspNow/src/WifiEspNow.h create mode 100644 lib/WifiEspNow/src/WifiEspNowBroadcast.cpp create mode 100644 lib/WifiEspNow/src/WifiEspNowBroadcast.h diff --git a/lib/WifiEspNow/.travis.yml b/lib/WifiEspNow/.travis.yml new file mode 100644 index 0000000000..a61d493091 --- /dev/null +++ b/lib/WifiEspNow/.travis.yml @@ -0,0 +1,57 @@ +language: bash +os: + - linux +env: + matrix: + - PLATFORM=esp8266 \ + HARDWARE=esp8266com/esp8266 \ + COREGIT=https://github.com/esp8266/Arduino.git \ + CORECOMMIT=192aaa42919dc65e5532ea4b60b002c4e19ce0ec \ + BOARD='--board esp8266com:esp8266:nodemcuv2 --pref custom_xtal=nodemcuv2_80 --pref custom_eesz=nodemcuv2_4M1M' + - PLATFORM=esp32 \ + HARDWARE=espressif/esp32 \ + COREGIT=https://github.com/espressif/arduino-esp32.git \ + CORECOMMIT=7df50a97d17b0953ea01cad0355410a66bd8b8b4 \ + BOARD='--board espressif:esp32:heltec_wifi_kit_32 --pref custom_FlashFreq=heltec_wifi_kit_32_80' + +before_install: + - sudo iptables -A INPUT -p udp -m udp --dport 5353 -j DROP # https://github.com/per1234/arduino-ci-script/issues/1 + - sudo apt-get update; sudo apt-get install xvfb + - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16 + - export DISPLAY=:1.0 + +install: + - mkdir -p $HOME/arduino_ide; cd $HOME/arduino_ide + - curl -L http://downloads.arduino.cc/arduino-1.8.9-linux64.tar.xz | tar xJ --strip 1 + - export PATH="$HOME/arduino_ide:$PATH" + - | + mkdir -p $HOME/Arduino/hardware/$HARDWARE + cd $HOME/Arduino/hardware/$HARDWARE + git init + git fetch $COREGIT + git -c advice.detachedHead=false checkout $CORECOMMIT + git submodule update --init + cd tools + python get.py + - mkdir -p $HOME/Arduino/libraries; cd $HOME/Arduino/libraries + +before_script: + - cp -r $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/WifiEspNow + - arduino $BOARD --save-prefs + - arduino --get-pref + +script: + - | + NFAIL=0 + for SKETCH in $(find $TRAVIS_BUILD_DIR -name '*.ino'); do + echo + echo + if [[ -f $(dirname $SKETCH)/skip-$PLATFORM.txt ]]; then + echo -e '\033[0;34m'Skipping $SKETCH '\033[0m' + continue + fi + echo -e '\033[0;36m'Building $SKETCH '\033[0m' + echo + arduino --verify $SKETCH || NFAIL=$((NFAIL+1)) + done + [[ $NFAIL -eq 0 ]] diff --git a/lib/WifiEspNow/COPYING b/lib/WifiEspNow/COPYING new file mode 100644 index 0000000000..eb931ee991 --- /dev/null +++ b/lib/WifiEspNow/COPYING @@ -0,0 +1,842 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + +********************************************************************** + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/WifiEspNow/README.md b/lib/WifiEspNow/README.md new file mode 100644 index 0000000000..d1c47aa931 --- /dev/null +++ b/lib/WifiEspNow/README.md @@ -0,0 +1,13 @@ +# ESP-NOW Arduino library for ESP8266 and ESP32 + +**WifiEspNow** is an Arduino library for ESP-NOW, a connectionless WiFi communication protocol defined by Espressif. +Refer to [ESP-NOW reference](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/esp_now.html) for more information about how ESP-NOW works and its limitations. + +[`WifiEspNow`](src/WifiEspNow.h) is a simple wrapper of ESP-NOW functions in ESP-IDF. +On ESP8266, it supports unicast only. +On ESP32, it supports both unicast and multicast. + +[`WifiEspNowBroadcast`](src/WifiEspNowBroadcast.h) implements *pseudo* broadcast over ESP-NOW. +Each device advertises a specific WiFi SSID, and discovers each other through BSSID scanning. +Then, messages are transmitted separately toward every peer via ESP-NOW unicast. +This is my custom protocol, which differs from `WifiEspNow` multicast. diff --git a/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino b/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino new file mode 100644 index 0000000000..d8fe72ca1b --- /dev/null +++ b/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino @@ -0,0 +1,73 @@ +#include +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif + +static const int BUTTON_PIN = 0; // "flash" button on NodeMCU, Witty Cloud, etc +static const int LED_PIN = 2; // ESP-12F blue LED + +int ledState = HIGH; + +void processRx(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { + Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + for (int i = 0; i < count; ++i) { + Serial.print(static_cast(buf[i])); + } + Serial.println(); + + digitalWrite(LED_PIN, ledState); + ledState = 1 - ledState; +} + +void setup() { + Serial.begin(115200); + Serial.println(); + + WiFi.persistent(false); + bool ok = WifiEspNowBroadcast.begin("ESPNOW", 3); + if (!ok) { + Serial.println("WifiEspNowBroadcast.begin() failed"); + ESP.restart(); + } + + WifiEspNowBroadcast.onReceive(processRx, nullptr); + + pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, ledState); + + Serial.print("MAC address of this node is "); + Serial.println(WiFi.softAPmacAddress()); + Serial.println("Press the button to send a message"); +} + +void sendMessage() { + char msg[60]; + int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", WiFi.softAPmacAddress().c_str(), millis()); + WifiEspNowBroadcast.send(reinterpret_cast(msg), len); + + Serial.println("Sending message"); + Serial.println(msg); + Serial.print("Recipients:"); + const int MAX_PEERS = 20; + WifiEspNowPeerInfo peers[MAX_PEERS]; + int nPeers = std::min(WifiEspNow.listPeers(peers, MAX_PEERS), MAX_PEERS); + for (int i = 0; i < nPeers; ++i) { + Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X", peers[i].mac[0], peers[i].mac[1], peers[i].mac[2], peers[i].mac[3], peers[i].mac[4], peers[i].mac[5]); + } + Serial.println(); +} + +void loop() { + if (digitalRead(BUTTON_PIN) == LOW) { // button is pressed + sendMessage(); + + while (digitalRead(BUTTON_PIN) == LOW) // wait for button release + ; + } + + WifiEspNowBroadcast.loop(); + delay(10); +} diff --git a/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino b/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino new file mode 100644 index 0000000000..b73bd46642 --- /dev/null +++ b/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino @@ -0,0 +1,50 @@ +#include +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif + +static uint8_t PEER[] {0x5E, 0xCF, 0x7F, 0x90, 0xFA, 0xE8}; + +void printReceivedMessage(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { + Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + for (int i = 0; i < count; ++i) { + Serial.print(static_cast(buf[i])); + } + Serial.println(); +} + +void setup() { + Serial.begin(115200); + Serial.println(); + + WiFi.persistent(false); + WiFi.mode(WIFI_AP); + WiFi.softAP("ESPNOW", nullptr, 3); + WiFi.softAPdisconnect(false); + + Serial.print("MAC address of this node is "); + Serial.println(WiFi.softAPmacAddress()); + + bool ok = WifiEspNow.begin(); + if (!ok) { + Serial.println("WifiEspNow.begin() failed"); + ESP.restart(); + } + + WifiEspNow.onReceive(printReceivedMessage, nullptr); + + ok = WifiEspNow.addPeer(PEER); + if (!ok) { + Serial.println("WifiEspNow.addPeer() failed"); + ESP.restart(); + } +} + +void loop() { + char msg[60]; + int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", WiFi.softAPmacAddress().c_str(), millis()); + WifiEspNow.send(PEER, reinterpret_cast(msg), len); + delay(1000); +} diff --git a/lib/WifiEspNow/library.properties b/lib/WifiEspNow/library.properties new file mode 100644 index 0000000000..209140506b --- /dev/null +++ b/lib/WifiEspNow/library.properties @@ -0,0 +1,9 @@ +name=WifiEspNow +version=0.0.20190814 +author=Junxiao Shi +maintainer=Junxiao Shi +sentence=ESP-NOW for ESP8266 and ESP32. +paragraph=This library wraps ESP-NOW functions as an Arduino library. +category=Communication +url=https://yoursunny.com +architectures=esp8266,esp32 \ No newline at end of file diff --git a/lib/WifiEspNow/src/WifiEspNow.cpp b/lib/WifiEspNow/src/WifiEspNow.cpp new file mode 100644 index 0000000000..08628a5844 --- /dev/null +++ b/lib/WifiEspNow/src/WifiEspNow.cpp @@ -0,0 +1,156 @@ +#include "WifiEspNow.h" + +#include + +#if defined(ESP8266) +#include +#include +#elif defined(ESP32) +#include +#else +#error "This library supports ESP8266 and ESP32 only." +#endif + +WifiEspNowClass WifiEspNow; + +WifiEspNowClass::WifiEspNowClass() + : m_rxCb(nullptr) + , m_rxCbArg(nullptr) + , m_begin(false) +{ +} + +bool +WifiEspNowClass::begin() +{ + m_begin = esp_now_init() == 0 && +#ifdef ESP8266 + esp_now_set_self_role(ESP_NOW_ROLE_COMBO) == 0 && +#endif + esp_now_register_recv_cb(reinterpret_cast(WifiEspNowClass::rx)) == 0 && + esp_now_register_send_cb(reinterpret_cast(WifiEspNowClass::tx)) == 0; + return m_begin; +} + +void +WifiEspNowClass::end() +{ + if (m_begin) { + esp_now_deinit(); + m_begin = false; + } +} + +int +WifiEspNowClass::listPeers(WifiEspNowPeerInfo* peers, int maxPeers) const +{ + int n = 0; + if (m_begin) { +#if defined(ESP8266) + for (u8* mac = esp_now_fetch_peer(true); + mac != nullptr; + mac = esp_now_fetch_peer(false)) { + uint8_t channel = static_cast(esp_now_get_peer_channel(mac)); +#elif defined(ESP32) + esp_now_peer_info_t peer; + for (esp_err_t e = esp_now_fetch_peer(true, &peer); + e == ESP_OK; + e = esp_now_fetch_peer(false, &peer)) { + uint8_t* mac = peer.peer_addr; + uint8_t channel = peer.channel; +#endif + if (n < maxPeers) { + memcpy(peers[n].mac, mac, 6); + peers[n].channel = channel; + } + ++n; + } + } + return n; +} + +bool +WifiEspNowClass::hasPeer(const uint8_t mac[6]) const +{ + if (m_begin) { + return esp_now_is_peer_exist(const_cast(mac)); + } + return false; +} + +#if defined(ESP8266) +bool +WifiEspNowClass::addPeer(const uint8_t mac[6], int channel, const uint8_t key[WIFIESPNOW_KEYLEN]) +{ + if (!m_begin) return false; + if (this->hasPeer(mac)) { + if (esp_now_get_peer_channel(const_cast(mac)) == channel) { + return true; + } + this->removePeer(mac); + } + return esp_now_add_peer(const_cast(mac), ESP_NOW_ROLE_SLAVE, static_cast(channel), + const_cast(key), key == nullptr ? 0 : WIFIESPNOW_KEYLEN) == 0; +} +#elif defined(ESP32) +bool +WifiEspNowClass::addPeer(const uint8_t mac[6], int channel, const uint8_t key[WIFIESPNOW_KEYLEN], int netif) +{ + if (!m_begin) return false; + esp_now_peer_info_t pi; + if (esp_now_get_peer(mac, &pi) == ESP_OK) { + if (pi.channel == static_cast(channel)) { + return true; + } + this->removePeer(mac); + } + memset(&pi, 0, sizeof(pi)); + memcpy(pi.peer_addr, mac, ESP_NOW_ETH_ALEN); + pi.channel = static_cast(channel); + pi.ifidx = static_cast(netif); + if (key != nullptr) { + memcpy(pi.lmk, key, ESP_NOW_KEY_LEN); + pi.encrypt = true; + } + return esp_now_add_peer(&pi) == ESP_OK; +} +#endif + +bool +WifiEspNowClass::removePeer(const uint8_t mac[6]) +{ + if (!m_begin) return false; + return esp_now_del_peer(const_cast(mac)) == 0; +} + +void +WifiEspNowClass::onReceive(RxCallback cb, void* cbarg) +{ + m_rxCb = cb; + m_rxCbArg = cbarg; +} + +bool +WifiEspNowClass::send(const uint8_t mac[6], const uint8_t* buf, size_t count) +{ + if (!m_begin) return false; + if (count > WIFIESPNOW_MAXMSGLEN || count == 0) { + return false; + } + WifiEspNow.m_txRes = WifiEspNowSendStatus::NONE; + return esp_now_send(const_cast(mac), const_cast(buf), static_cast(count)) == 0; +} + +void +WifiEspNowClass::rx(const uint8_t* mac, const uint8_t* data, uint8_t len) +{ + if (WifiEspNow.m_rxCb != nullptr) { + (*WifiEspNow.m_rxCb)(mac, data, len, WifiEspNow.m_rxCbArg); + } +} + +void +WifiEspNowClass::tx(const uint8_t* mac, uint8_t status) +{ + WifiEspNow.m_txRes = status == 0 ? WifiEspNowSendStatus::OK : WifiEspNowSendStatus::FAIL; +} diff --git a/lib/WifiEspNow/src/WifiEspNow.h b/lib/WifiEspNow/src/WifiEspNow.h new file mode 100644 index 0000000000..8052898d76 --- /dev/null +++ b/lib/WifiEspNow/src/WifiEspNow.h @@ -0,0 +1,132 @@ +#ifndef WIFIESPNOW_H +#define WIFIESPNOW_H + +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif + +#include +#include + +/** \brief Key length. + */ +static const int WIFIESPNOW_KEYLEN = 16; + +/** \brief Maximum message length. + */ +static const int WIFIESPNOW_MAXMSGLEN = 250; + +struct WifiEspNowPeerInfo { + uint8_t mac[6]; + uint8_t channel; +}; + +/** \brief Result of send operation. + */ +enum class WifiEspNowSendStatus : uint8_t { + NONE = 0, ///< result unknown, send in progress + OK = 1, ///< sent successfully + FAIL = 2, ///< sending failed +}; + +class WifiEspNowClass +{ +public: + WifiEspNowClass(); + + /** \brief Initialize ESP-NOW. + * \return whether success + */ + bool + begin(); + + /** \brief Stop ESP-NOW. + */ + void + end(); + + /** \brief List current peers. + * \param[out] peers buffer for peer information + * \param maxPeers buffer size + * \return total number of peers, \p std::min(retval,maxPeers) is written to \p peers + */ + int + listPeers(WifiEspNowPeerInfo* peers, int maxPeers) const; + + /** \brief Test whether peer exists. + * \param mac peer MAC address + * \return whether peer exists + */ + bool + hasPeer(const uint8_t mac[6]) const; + + /** \brief Add a peer or change peer channel. + * \param mac peer MAC address + * \param channel peer channel, 0 for current channel + * \param key encryption key, nullptr to disable encryption + * \param netif (ESP32 only) WiFi interface + * \return whether success + * \note To change peer key, remove the peer and re-add. + */ +#if defined(ESP8266) + bool + addPeer(const uint8_t mac[6], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); +#elif defined(ESP32) + bool + addPeer(const uint8_t mac[6], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr, int netif = ESP_IF_WIFI_AP); +#endif + + /** \brief Remove a peer. + * \param mac peer MAC address + * \return whether success + */ + bool + removePeer(const uint8_t mac[6]); + + typedef void (*RxCallback)(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg); + + /** \brief Set receive callback. + * \param cb the callback + * \param cbarg an arbitrary argument passed to the callback + * \note Only one callback is allowed; this replaces any previous callback. + */ + void + onReceive(RxCallback cb, void* cbarg); + + /** \brief Send a message. + * \param mac destination MAC address, nullptr for all peers + * \param buf payload + * \param count payload size, must not exceed \p WIFIESPNOW_MAXMSGLEN + * \return whether success (message queued for transmission) + */ + bool + send(const uint8_t mac[6], const uint8_t* buf, size_t count); + + /** \brief Retrieve status of last sent message. + * \return whether success (unicast message received by peer, multicast message sent) + */ + WifiEspNowSendStatus + getSendStatus() const + { + return m_txRes; + } + +private: + static void + rx(const uint8_t* mac, const uint8_t* data, uint8_t len); + + static void + tx(const uint8_t* mac, uint8_t status); + +private: + RxCallback m_rxCb; + void* m_rxCbArg; + WifiEspNowSendStatus m_txRes; + bool m_begin = false; +}; + +extern WifiEspNowClass WifiEspNow; + +#endif // WIFIESPNOW_H diff --git a/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp new file mode 100644 index 0000000000..b013336b8f --- /dev/null +++ b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp @@ -0,0 +1,168 @@ +#include "WifiEspNowBroadcast.h" + +#if defined(ESP8266) +#include +#include +#elif defined(ESP32) +#include +#include +#else +#error "This library supports ESP8266 and ESP32 only." +#endif + +WifiEspNowBroadcastClass WifiEspNowBroadcast; + +WifiEspNowBroadcastClass::WifiEspNowBroadcastClass() + : m_isScanning(false) +{ +} + +bool +WifiEspNowBroadcastClass::begin(const char* ssid, int channel, int scanFreq) +{ + m_ssid = ssid; + m_nextScan = 0; + m_scanFreq = scanFreq; + + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(ssid, nullptr, channel); + + return WifiEspNow.begin(); +} + +void +WifiEspNowBroadcastClass::loop() +{ + if (millis() >= m_nextScan && !m_isScanning && WiFi.scanComplete() != WIFI_SCAN_RUNNING) { + this->scan(); + } +#ifdef ESP32 + if (m_isScanning && WiFi.scanComplete() >= 0) { + this->processScan(); + } +#endif +} + +void +WifiEspNowBroadcastClass::end() +{ + WifiEspNow.end(); + WiFi.softAPdisconnect(); + m_ssid = ""; +} + +bool +WifiEspNowBroadcastClass::send(const uint8_t* buf, size_t count) +{ + return WifiEspNow.send(nullptr, buf, count); +} + +void +WifiEspNowBroadcastClass::scan() +{ + m_isScanning = true; +#if defined(ESP8266) + scan_config sc; +#elif defined(ESP32) + wifi_scan_config_t sc; +#endif + memset(&sc, 0, sizeof(sc)); + sc.ssid = reinterpret_cast(const_cast(m_ssid.c_str())); +#if defined(ESP8266) + wifi_station_scan(&sc, reinterpret_cast(WifiEspNowBroadcastClass::processScan)); +#elif defined(ESP32) + esp_wifi_scan_start(&sc, false); +#endif +} + +#if defined(ESP8266) +void +WifiEspNowBroadcastClass::processScan(void* result, int status) +{ + WifiEspNowBroadcast.processScan2(result, status); +} + +void +WifiEspNowBroadcastClass::processScan2(void* result, int status) + +#define FOREACH_AP(f) \ + do { \ + for (bss_info* it = reinterpret_cast(result); it; it = STAILQ_NEXT(it, next)) { \ + (f)(it->bssid, it->channel); \ + } \ + } while (false) + +#define DELETE_APS \ + do {} while(false) + +#elif defined(ESP32) +void +WifiEspNowBroadcastClass::processScan() + +// ESP32 WiFiScanClass::_scanDone is always invoked after a scan complete event, so we can use +// Arduino's copy of AP records, but we must check SSID, and should not always delete AP records. + +#define FOREACH_AP(f) \ + do { \ + int nNetworks = WiFi.scanComplete(); \ + for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ + if (WiFi.SSID(i) != m_ssid) { \ + continue; \ + } \ + (f)(WiFi.BSSID(i), static_cast(WiFi.channel(i))); \ + } \ + } while (false) + +#define DELETE_APS \ + do { \ + bool hasOtherSsid = false; \ + int nNetworks = WiFi.scanComplete(); \ + for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ + if (WiFi.SSID(i) == m_ssid) { \ + continue; \ + } \ + hasOtherSsid = true; \ + break; \ + } \ + if (!hasOtherSsid) { \ + WiFi.scanDelete(); \ + } \ + } while(false) + +#endif +{ + m_isScanning = false; + m_nextScan = millis() + m_scanFreq; +#ifdef ESP8266 + if (status != 0) { + return; + } +#endif + + const int MAX_PEERS = 20; + WifiEspNowPeerInfo oldPeers[MAX_PEERS]; + int nOldPeers = std::min(WifiEspNow.listPeers(oldPeers, MAX_PEERS), MAX_PEERS); + const uint8_t PEER_FOUND = 0xFF; // assigned to .channel to indicate peer is matched + + FOREACH_AP([&] (const uint8_t* bssid, uint8_t channel) { + for (int i = 0; i < nOldPeers; ++i) { + if (memcmp(bssid, oldPeers[i].mac, 6) != 0) { + continue; + } + oldPeers[i].channel = PEER_FOUND; + break; + } + }); + + for (int i = 0; i < nOldPeers; ++i) { + if (oldPeers[i].channel != PEER_FOUND) { + WifiEspNow.removePeer(oldPeers[i].mac); + } + } + + FOREACH_AP([&] (const uint8_t* bssid, uint8_t channel) { + WifiEspNow.addPeer(bssid, channel); + }); + + DELETE_APS; +} diff --git a/lib/WifiEspNow/src/WifiEspNowBroadcast.h b/lib/WifiEspNow/src/WifiEspNowBroadcast.h new file mode 100644 index 0000000000..496d48f97e --- /dev/null +++ b/lib/WifiEspNow/src/WifiEspNowBroadcast.h @@ -0,0 +1,81 @@ +#ifndef WIFIESPNOW_BROADCAST_H +#define WIFIESPNOW_BROADCAST_H + +#include "WifiEspNow.h" + +#include + +class WifiEspNowBroadcastClass +{ +public: + WifiEspNowBroadcastClass(); + + /** \brief Initialize ESP-NOW with pseudo broadcast. + * \param ssid AP SSID to announce and find peers + * \param channel AP channel, used if there is no STA connection + * \param scanFreq how often to scan for peers, in millis + * \return whether success + * + * In pseudo broadcast mode, every node announces itself as a group member by advertising a + * certain AP SSID. A node periodically scans other BSSIDs announcing the same SSID, and adds + * them as ESP-NOW peers. Messages are sent to all knows peers. + * + * Pseudo broadcast does not depend on ESP-NOW API to support broadcast. + */ + bool + begin(const char* ssid, int channel = 1, int scanFreq = 15000); + + /** \brief Refresh peers if scanning is due. + */ + void + loop(); + + /** \brief Stop ESP-NOW. + */ + void + end(); + + /** \brief Set receive callback. + * \param cb the callback + * \param cbarg an arbitrary argument passed to the callback + * \note Only one callback is allowed; this replaces any previous callback. + */ + void + onReceive(WifiEspNowClass::RxCallback cb, void* cbarg) + { + WifiEspNow.onReceive(cb, cbarg); + } + + /** \brief Broadcast a message. + * \param buf payload + * \param count payload size, must not exceed \p WIFIESPNOW_MAXMSGLEN + * \return whether success (message queued for transmission) + */ + bool + send(const uint8_t* buf, size_t count); + +private: + void + scan(); + +#if defined(ESP8266) + static void + processScan(void* result, int status); + + void + processScan2(void* result, int status); +#elif defined(ESP32) + void + processScan(); +#endif + +private: + String m_ssid; + int m_scanFreq; + unsigned long m_nextScan; + bool m_isScanning; +}; + +extern WifiEspNowBroadcastClass WifiEspNowBroadcast; + +#endif // WIFIESPNOW_BROADCAST_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 42b5ccac31..5c0b323dc4 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -155,8 +155,11 @@ void ESPEasy_now_handler_t::end() { _controllerIndex = INVALID_CONTROLLER_INDEX; use_EspEasy_now = false; - _last_used = 0; - WifiEspNow.end(); + if (_last_used != 0) { + // Only call WifiEspNow.end() if it was started. + WifiEspNow.end(); + _last_used = 0; + } addLog(LOG_LEVEL_INFO, F("ESPEasy-Now disabled")); } From 57af5e44e0df803bfd3b48064ec1e2fe3e9dde8a Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 30 Sep 2020 16:10:54 +0200 Subject: [PATCH 059/404] [ESPeasy p2p] Use network IP instead of WiFi IP for ESP32 + Ethernet --- src/src/DataStructs/NodesHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 440042eeb0..b95f1b7922 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -133,7 +133,7 @@ void NodesHandler::updateThisNode() { WiFi.macAddress(thisNode.sta_mac); WiFi.softAPmacAddress(thisNode.ap_mac); { - IPAddress localIP = WiFi.localIP(); + IPAddress localIP = NetworkLocalIP(); for (byte i = 0; i < 4; ++i) { thisNode.ip[i] = localIP[i]; From 4b7420b918326e902c2673a952a77e2140e3b994 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 30 Sep 2020 16:45:40 +0200 Subject: [PATCH 060/404] [ESP32] Make WebServer.ino compile on ESP32 stage code. --- src/WebServer.ino | 95 ++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/WebServer.ino b/src/WebServer.ino index d74eea7f15..753e73fc5e 100644 --- a/src/WebServer.ino +++ b/src/WebServer.ino @@ -174,108 +174,111 @@ void WebServerInit() webserver_init = true; // Prepare webserver pages + + // FIXME TD-er: The added String() wrapper is needed for the latest ESP32 core lib. + // See: https://github.com/espressif/arduino-esp32/issues/4374 #ifdef WEBSERVER_ROOT - web_server.on("/", handle_root); + web_server.on(String(F("/")), handle_root); #endif #ifdef WEBSERVER_ADVANCED - web_server.on(F("/advanced"), handle_advanced); + web_server.on(String(F("/advanced")), handle_advanced); #endif #ifdef WEBSERVER_CONFIG - web_server.on(F("/config"), handle_config); + web_server.on(String(F("/config")), handle_config); #endif #ifdef WEBSERVER_CONTROL - web_server.on(F("/control"), handle_control); + web_server.on(String(F("/control")), handle_control); #endif #ifdef WEBSERVER_CONTROLLERS - web_server.on(F("/controllers"), handle_controllers); + web_server.on(String(F("/controllers")), handle_controllers); #endif #ifdef WEBSERVER_DEVICES - web_server.on(F("/devices"), handle_devices); + web_server.on(String(F("/devices")), handle_devices); #endif #ifdef WEBSERVER_DOWNLOAD - web_server.on(F("/download"), handle_download); + web_server.on(String(F("/download")), handle_download); #endif #ifdef USES_C016 // web_server.on(F("/dumpcache"), handle_dumpcache); // C016 specific entrie - web_server.on(F("/cache_json"), handle_cache_json); // C016 specific entrie - web_server.on(F("/cache_csv"), handle_cache_csv); // C016 specific entrie + web_server.on(String(F("/cache_json")), handle_cache_json); // C016 specific entrie + web_server.on(String(F("/cache_csv")), handle_cache_csv); // C016 specific entrie #endif // USES_C016 #ifdef WEBSERVER_FACTORY_RESET - web_server.on(F("/factoryreset"), handle_factoryreset); + web_server.on(String(F("/factoryreset")), handle_factoryreset); #endif #ifdef USE_SETTINGS_ARCHIVE - web_server.on(F("/settingsarchive"), handle_settingsarchive); + web_server.on(String(F("/settingsarchive")), handle_settingsarchive); #endif - web_server.on(F("/favicon.ico"), handle_favicon); + web_server.on(String(F("/favicon.ico")), handle_favicon); #ifdef WEBSERVER_FILELIST - web_server.on(F("/filelist"), handle_filelist); + web_server.on(String(F("/filelist")), handle_filelist); #endif #ifdef WEBSERVER_HARDWARE - web_server.on(F("/hardware"), handle_hardware); + web_server.on(String(F("/hardware")), handle_hardware); #endif #ifdef WEBSERVER_I2C_SCANNER - web_server.on(F("/i2cscanner"), handle_i2cscanner); + web_server.on(String(F("/i2cscanner")), handle_i2cscanner); #endif - web_server.on(F("/json"), handle_json); // Also part of WEBSERVER_NEW_UI - web_server.on(F("/csv"), handle_csvval); - web_server.on(F("/log"), handle_log); - web_server.on(F("/login"), handle_login); - web_server.on(F("/logjson"), handle_log_JSON); // Also part of WEBSERVER_NEW_UI + web_server.on(String(F("/json")), handle_json); // Also part of WEBSERVER_NEW_UI + web_server.on(String(F("/csv")), handle_csvval); + web_server.on(String(F("/log")), handle_log); + web_server.on(String(F("/login")), handle_login); + web_server.on(String(F("/logjson")), handle_log_JSON); // Also part of WEBSERVER_NEW_UI #ifdef USES_NOTIFIER - web_server.on(F("/notifications"), handle_notifications); + web_server.on(String(F("/notifications")), handle_notifications); #endif #ifdef WEBSERVER_PINSTATES - web_server.on(F("/pinstates"), handle_pinstates); + web_server.on(String(F("/pinstates")), handle_pinstates); #endif #ifdef WEBSERVER_RULES - web_server.on(F("/rules"), handle_rules_new); - web_server.on(F("/rules/"), Goto_Rules_Root); - web_server.on(F("/rules/add"), []() + web_server.on(String(F("/rules")), handle_rules_new); + web_server.on(String(F("/rules/")), Goto_Rules_Root); + web_server.on(String(F("/rules/add")), []() { handle_rules_edit(web_server.uri(), true); }); - web_server.on(F("/rules/backup"), handle_rules_backup); - web_server.on(F("/rules/delete"), handle_rules_delete); + web_server.on(String(F("/rules/backup")), handle_rules_backup); + web_server.on(String(F("/rules/delete")), handle_rules_delete); #endif // WEBSERVER_RULES #ifdef FEATURE_SD - web_server.on(F("/SDfilelist"), handle_SDfilelist); + web_server.on(String(F("/SDfilelist")), handle_SDfilelist); #endif // ifdef FEATURE_SD #ifdef WEBSERVER_SETUP - web_server.on(F("/setup"), handle_setup); + web_server.on(String(F("/setup")), handle_setup); #endif #ifdef WEBSERVER_SYSINFO - web_server.on(F("/sysinfo"), handle_sysinfo); + web_server.on(String(F("/sysinfo")), handle_sysinfo); #endif #ifdef WEBSERVER_SYSVARS - web_server.on(F("/sysvars"), handle_sysvars); + web_server.on(String(F("/sysvars")), handle_sysvars); #endif // WEBSERVER_SYSVARS #ifdef WEBSERVER_TIMINGSTATS - web_server.on(F("/timingstats"), handle_timingstats); + web_server.on(String(F("/timingstats")), handle_timingstats); #endif // WEBSERVER_TIMINGSTATS #ifdef WEBSERVER_TOOLS - web_server.on(F("/tools"), handle_tools); + web_server.on(String(F("/tools")), handle_tools); #endif #ifdef WEBSERVER_UPLOAD - web_server.on(F("/upload"), HTTP_GET, handle_upload); - web_server.on(F("/upload"), HTTP_POST, handle_upload_post, handleFileUpload); + web_server.on(String(F("/upload")), HTTP_GET, handle_upload); + web_server.on(String(F("/upload")), HTTP_POST, handle_upload_post, handleFileUpload); #endif #ifdef WEBSERVER_WIFI_SCANNER - web_server.on(F("/wifiscanner"), handle_wifiscanner); + web_server.on(String(F("/wifiscanner")), handle_wifiscanner); #endif #ifdef WEBSERVER_NEW_UI - web_server.on(F("/buildinfo"), handle_buildinfo); // Also part of WEBSERVER_NEW_UI - web_server.on(F("/factoryreset_json"), handle_factoryreset_json); - web_server.on(F("/filelist_json"), handle_filelist_json); - web_server.on(F("/i2cscanner_json"), handle_i2cscanner_json); - web_server.on(F("/node_list_json"), handle_nodes_list_json); - web_server.on(F("/pinstates_json"), handle_pinstates_json); - web_server.on(F("/sysinfo_json"), handle_sysinfo_json); - web_server.on(F("/timingstats_json"), handle_timingstats_json); - web_server.on(F("/upload_json"), HTTP_POST, handle_upload_json, handleFileUpload); - web_server.on(F("/wifiscanner_json"), handle_wifiscanner_json); + web_server.on(String(F("/buildinfo")), handle_buildinfo); // Also part of WEBSERVER_NEW_UI + web_server.on(String(F("/factoryreset_json")), handle_factoryreset_json); + web_server.on(String(F("/filelist_json")), handle_filelist_json); + web_server.on(String(F("/i2cscanner_json")), handle_i2cscanner_json); + web_server.on(String(F("/node_list_json")), handle_nodes_list_json); + web_server.on(String(F("/pinstates_json")), handle_pinstates_json); + web_server.on(String(F("/sysinfo_json")), handle_sysinfo_json); + web_server.on(String(F("/timingstats_json")), handle_timingstats_json); + web_server.on(String(F("/upload_json")), HTTP_POST, handle_upload_json, handleFileUpload); + web_server.on(String(F("/wifiscanner_json")), handle_wifiscanner_json); #endif // WEBSERVER_NEW_UI web_server.onNotFound(handleNotFound); From 907c7b1c42e499299784b45af3dc1c6bcad5373a Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 5 Oct 2020 11:14:13 +0200 Subject: [PATCH 061/404] [ESPEasy-Now] Add p2p packet to send data between nodes via controller --- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 86 ++++++++++++++++++++ src/src/DataStructs/ESPEasy_Now_p2p_data.h | 79 ++++++++++++++++++ src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 53 ++++++++++++ src/src/Helpers/ESPEasy_now_handler.h | 9 +- 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 src/src/DataStructs/ESPEasy_Now_p2p_data.cpp create mode 100644 src/src/DataStructs/ESPEasy_Now_p2p_data.h diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp new file mode 100644 index 0000000000..6697d3f480 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -0,0 +1,86 @@ +#include "ESPEasy_Now_p2p_data.h" + +#include + + +ESPEasy_Now_p2p_data::~ESPEasy_Now_p2p_data() { + if (data != nullptr) { + delete data; + data = nullptr; + } +} + +bool ESPEasy_Now_p2p_data::addFloat(float value) { + return addBinaryData((byte *)(&value), sizeof(float)); +} + +bool ESPEasy_Now_p2p_data::getFloat(float& value, size_t& offset) const { + if ((offset + sizeof(float)) >= dataSize) { + return false; + } + memcpy((byte *)(&value), &data[offset], sizeof(float)); + offset += sizeof(float); + return true; +} + +size_t ESPEasy_Now_p2p_data::getTotalSize() const { + return dataOffset + dataSize; +} + +bool ESPEasy_Now_p2p_data::addBinaryData(uint8_t *binaryData, size_t size) { + size_t oldSize; + + if (allocate(size, oldSize)) { + memcpy(&data[oldSize], binaryData, size); + return true; + } + return false; +} + +const uint8_t * ESPEasy_Now_p2p_data::getBinaryData(size_t offset, size_t& size) const { + if (offset >= dataSize) { + return nullptr; + } + + const size_t available = dataSize - offset; + + if (size < available) { + size = available; + } + return &data[offset]; +} + +uint8_t * ESPEasy_Now_p2p_data::prepareBinaryData(size_t& size) { + size_t oldSize; + + if (data != nullptr) { + delete data; + data = nullptr; + dataSize = 0; + } + + if (!allocate(size, oldSize)) { + return nullptr; + } + size = dataSize; + return data; +} + +bool ESPEasy_Now_p2p_data::allocate(size_t size, size_t& oldSize) { + oldSize = dataSize; + const size_t newSize = oldSize + size; + + uint8_t *tmp_ptr = new (std::nothrow) uint8_t[newSize]; + + if (tmp_ptr == nullptr) { + return false; + } + + if (data != nullptr) { + memcpy(tmp_ptr, data, oldSize); + delete data; + } + data = tmp_ptr; + dataSize = newSize; + return true; +} diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h new file mode 100644 index 0000000000..8d5dcc61eb --- /dev/null +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -0,0 +1,79 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_P2P_DATA_H +#define DATASTRUCTS_ESPEASY_NOW_P2P_DATA_H + +#include + +#include "ESPEasyLimits.h" +#include "../Globals/Plugins.h" + +#define ESPEASY_NOW_P2P_DATA_VERSION 1 + +enum class ESPEasy_Now_p2p_data_type : uint8_t { + NotSet = 0, + PluginDescription = 1, + PluginData = 2 +}; + +struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { + + ~ESPEasy_Now_p2p_data(); + + // Add float at the end of the binary data + // @param value The float to store + // @retval True when successful. Only fails if no data could be allocated + bool addFloat(float value); + + // Get a float, starting at @offset in the data array + // @param value The value to be read + // @param offset The offset in the data array to start. Will be incremented with sizeof(float) + // @retval True when the offset was in the range of the data. + bool getFloat(float & value, + size_t& offset) const; + + // Return the size of the header + data + size_t getTotalSize() const; + + bool addBinaryData(uint8_t *binaryData, + size_t size); + + // Get a pointer to the data starting at offset + // @param offset is the offset in the data array to start (will not be updated) + // @param size is the expected size of the data. Value may be lower if there is less data available than requested. + // @retval Pointer to the data, if available. nullptr if offset is not valid. + const uint8_t* getBinaryData(size_t offset, + size_t& size) const; + + // Clear and resize data array to size. + // @retval pointer to the first element of the data array + uint8_t* prepareBinaryData(size_t& size); + +private: + + // Allocate extra data at the end of the data array + // @param size The extra size in bytes to allocate + // @retval The old size of the data array. + bool allocate(size_t size, + size_t& oldSize); + +public: + + ESPEasy_Now_p2p_data_type dataType = ESPEasy_Now_p2p_data_type::NotSet; + uint16_t dataSize = 0; + + // The sizeof(data) is intended use of sizeof to return the size of a pointer + const uint8_t dataOffset = sizeof(ESPEasy_Now_p2p_data) - sizeof(data); + taskIndex_t sourceTaskIndex = INVALID_TASK_INDEX; + taskIndex_t destTaskIndex = INVALID_TASK_INDEX; + uint16_t plugin_id = INVALID_PLUGIN_ID; // FIXME TD-er: Must change to pluginID_t as soon as that's changed to 16 + // bit + uint16_t sourceUnit = 0; + uint16_t destUnit = 0; + +private: + + // Must use a pointer here instead of a struct, or else this object cannot be made packed. + uint8_t *data = nullptr; +}; + + +#endif // DATASTRUCTS_ESPEASY_NOW_P2P_DATA_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index d9a0873d0f..ba014b04b2 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -24,6 +24,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { NTP_Query, SendData_DuplicateCheck, MQTTCheckControllerQueue, + P2P_data, ChecksumError = 255 }; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 5c0b323dc4..4001d2d2e4 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -359,6 +359,10 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: handled = handle_SendData_DuplicateCheck(message, mustKeep); break; + case ESPEasy_now_hdr::message_t::P2P_data: + handled = handle_ESPEasyNow_p2p(message, mustKeep); + considerActive = true; + break; } if (handled && considerActive) { @@ -846,4 +850,53 @@ void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t contr } } + + +// ************************************************************* +// * ESPEasyNow p2p +// ************************************************************* +bool ESPEasy_now_handler_t::sendESPEasyNow_p2p(controllerIndex_t controllerIndex, const MAC_address& mac, const ESPEasy_Now_p2p_data& data) { + if (!use_EspEasy_now) { return false; } + + size_t size = data.getTotalSize(); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::P2P_data, size); + // Add the first part of the data object, without the data array. + msg.addBinaryData(reinterpret_cast(&data), data.dataOffset); + + // Fetch the data array information, will also update size. + const uint8_t* data_ptr = data.getBinaryData(0, size); + msg.addBinaryData(data_ptr, size); + + return msg.send(mac); +} + +bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, bool& mustKeep) { + mustKeep = false; + ESPEasy_Now_p2p_data data; + size_t payload_pos = 0; + size_t payload_size = message.getPayloadSize(); + size_t headerSize = data.dataOffset; + if (headerSize > payload_size) { + // This can only happen when the receiving end has a larger ESPEasy_Now_p2p_data struct + headerSize = payload_size; + } + message.getBinaryData(reinterpret_cast(&data), headerSize, payload_pos); + // dataOffset may have changed to match the offset used by the sender. + payload_pos = data.dataOffset; + + size_t binaryData_size = payload_size - payload_pos; + uint8_t* binaryData_ptr = data.prepareBinaryData(binaryData_size); + if (binaryData_ptr == nullptr) { + return false; + } + if (message.getBinaryData(binaryData_ptr, binaryData_size, payload_pos) != binaryData_size) { + // Did not receive all data + return false; + } + + // TODO TD-er: Call C019 controller with event containing this data object as a pointer. + + return true; +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 0354927660..36202c40ff 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -11,6 +11,7 @@ # include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" # include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" +# include "../DataStructs/ESPEasy_Now_p2p_data.h" # include "../DataStructs/MAC_address.h" # include "../Globals/CPlugins.h" @@ -51,12 +52,16 @@ class ESPEasy_now_handler_t { const String & payload); bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); - bool sendMQTTCheckControllerQueue(const MAC_address& mac, int channel, ESPEasy_Now_MQTT_queue_check_packet::QueueState state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); + bool sendMQTTCheckControllerQueue(const MAC_address& mac, + int channel, + ESPEasy_Now_MQTT_queue_check_packet::QueueState state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); void sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, const MAC_address& mac); + bool sendESPEasyNow_p2p(controllerIndex_t controllerIndex, const MAC_address& mac, const ESPEasy_Now_p2p_data& data); + private: bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep); @@ -69,6 +74,8 @@ class ESPEasy_now_handler_t { bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, bool& mustKeep); + bool add_peer(const MAC_address& mac, int channel) const; void load_ControllerSettingsCache(controllerIndex_t controllerIndex); From 6ac6bbb0d7301a41644c898110891420f39fa005 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 5 Oct 2020 13:33:04 +0200 Subject: [PATCH 062/404] [ESPEasy-Now] Implement sending ESPEasy-now p2p plugin data message --- src/_C019.ino | 54 +++++++++++++++++-- .../ControllerQueue/C019_queue_element.cpp | 15 ++++-- src/src/ControllerQueue/C019_queue_element.h | 4 +- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 36 +++++++++++++ src/src/DataStructs/ESPEasy_Now_p2p_data.h | 12 ++++- src/src/Globals/CPlugins.cpp | 15 +++--- src/src/Helpers/ESPEasy_now_handler.cpp | 12 ++++- 7 files changed, 127 insertions(+), 21 deletions(-) diff --git a/src/_C019.ino b/src/_C019.ino index 763a3bf879..594299edd3 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -67,15 +67,25 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { success = C019_DelayHandler->addToQueue(C019_queue_element(event)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C019_DELAY_QUEUE, C019_DelayHandler->getNextScheduleTime()); break; } case CPlugin::Function::CPLUGIN_PROTOCOL_RECV: { - // FIXME TD-er: WHen should this be scheduled? - // protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(event->ControllerIndex); - // schedule_controller_event_timer(ProtocolIndex, CPlugin::Function::CPLUGIN_PROTOCOL_RECV, event); + controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_019); + + if (!validControllerIndex(ControllerID)) { + // Controller is not enabled. + break; + } else { + if ((event->Data != nullptr) && (event->Par1 == sizeof(ESPEasy_Now_p2p_data))) { + ESPEasy_Now_p2p_data *data = reinterpret_cast(event->Data); + + if (data->validate()) {} + } + } break; } @@ -107,9 +117,43 @@ bool do_process_c019_delay_queue(int controller_number, const C019_queue_element // *INDENT-ON* bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings) { - bool success = true; + ESPEasy_Now_p2p_data data; - return success; + data.dataType = ESPEasy_Now_p2p_data_type::PluginData; + data.sourceTaskIndex = element.event.TaskIndex; + data.plugin_id = getPluginID_from_TaskIndex(data.sourceTaskIndex); + data.sourceUnit = Settings.Unit; + data.sensorType = element.event.sensorType; + data.valueCount = getValueCountForTask(data.sourceTaskIndex); + + for (byte i = 0; i < data.valueCount; ++i) + { + switch (data.sensorType) { + case Sensor_VType::SENSOR_TYPE_LONG: + data.addString(String((unsigned long)UserVar[element.event.BaseVarIndex] + + ((unsigned long)UserVar[element.event.BaseVarIndex + 1] << 16))); + break; + case Sensor_VType::SENSOR_TYPE_STRING: + data.addString(element.event.String2); + break; + + default: + data.addFloat(UserVar[element.event.BaseVarIndex + i]); + break; + } + } + + if (element.packed.length() > 0) { + data.addString(element.packed); + } + + MAC_address broadcast; + + for (int i = 0; i < 6; ++i) { + broadcast.mac[i] = 0xFF; + } + + return ESPEasy_now_handler.sendESPEasyNow_p2p(controller_number, broadcast, data); } #endif // ifdef USES_C019 diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index f4f7898713..b14fb2c3a0 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -11,17 +11,22 @@ String getPackedFromPlugin(struct EventStruct *event, C019_queue_element::C019_queue_element() {} -C019_queue_element::C019_queue_element(struct EventStruct *event) : - controller_idx(event->ControllerIndex) +C019_queue_element::C019_queue_element(struct EventStruct *event_p) : + controller_idx(event_p->ControllerIndex), + event(*event_p) { - #ifdef USES_PACKED_RAW_DATA - packed = getPackedFromPlugin(event, 0); + #ifdef USES_PACKED_RAW_DATA + packed = getPackedFromPlugin(event_p, 0); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("C019 queue element: "); log += packed; addLog(LOG_LEVEL_INFO, log); } - #endif // USES_PACKED_RAW_DATA + #endif // USES_PACKED_RAW_DATA + + // Extra check to make sure sensorType is correct. + event.sensorType = event.getSensorType(); } size_t C019_queue_element::getSize() const { diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index b2eb519df6..73afae57e0 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -2,12 +2,11 @@ #define CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" +#include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataStructs/ESPEasyLimits.h" #include "../Globals/CPlugins.h" -struct EventStruct; - // #ifdef USES_C019 /*********************************************************************************************\ @@ -27,6 +26,7 @@ class C019_queue_element { String packed; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; + EventStruct event; }; // #endif //USES_C019 diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 6697d3f480..4dafb93f6e 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -10,6 +10,21 @@ ESPEasy_Now_p2p_data::~ESPEasy_Now_p2p_data() { } } +bool ESPEasy_Now_p2p_data::validate() const { + if (data != nullptr) { + if (dataSize == 0) { return false; } + } + + if (dataOffset == 0) { return false; } + + if (!validTaskIndex(destTaskIndex)) { return false; } + + if (!validPluginID(plugin_id)) { return false; } + + // TODO TD-er: Must add more sanity checks here. + return true; +} + bool ESPEasy_Now_p2p_data::addFloat(float value) { return addBinaryData((byte *)(&value), sizeof(float)); } @@ -23,6 +38,27 @@ bool ESPEasy_Now_p2p_data::getFloat(float& value, size_t& offset) const { return true; } +bool ESPEasy_Now_p2p_data::addString(const String& value) { + return addBinaryData((byte *)(value.c_str()), value.length() + 1); // Include null termination +} + +bool ESPEasy_Now_p2p_data::getString(String& value, size_t& offset) const { + int maxStrLen = dataSize - offset; + + if (maxStrLen < 2) { + return false; + } + const size_t str_len = strnlen(reinterpret_cast(&data[offset]), maxStrLen); + + value.reserve(str_len); + + for (int i = 0; i < str_len; ++i) { + value += data[offset]; + ++offset; + } + return true; +} + size_t ESPEasy_Now_p2p_data::getTotalSize() const { return dataOffset + dataSize; } diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h index 8d5dcc61eb..d8d9d87db2 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.h +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -4,6 +4,7 @@ #include #include "ESPEasyLimits.h" +#include "../DataStructs/DeviceStruct.h" #include "../Globals/Plugins.h" #define ESPEASY_NOW_P2P_DATA_VERSION 1 @@ -18,6 +19,8 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { ~ESPEasy_Now_p2p_data(); + bool validate() const; + // Add float at the end of the binary data // @param value The float to store // @retval True when successful. Only fails if no data could be allocated @@ -30,6 +33,11 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { bool getFloat(float & value, size_t& offset) const; + bool addString(const String& value); + + bool getString(String & value, + size_t& offset) const; + // Return the size of the header + data size_t getTotalSize() const; @@ -58,7 +66,7 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { public: ESPEasy_Now_p2p_data_type dataType = ESPEasy_Now_p2p_data_type::NotSet; - uint16_t dataSize = 0; + uint16_t dataSize = 0; // The sizeof(data) is intended use of sizeof to return the size of a pointer const uint8_t dataOffset = sizeof(ESPEasy_Now_p2p_data) - sizeof(data); @@ -68,6 +76,8 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { // bit uint16_t sourceUnit = 0; uint16_t destUnit = 0; + Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; + uint8_t valueCount = 0; private: diff --git a/src/src/Globals/CPlugins.cpp b/src/src/Globals/CPlugins.cpp index 1a8e053f47..7ba9a37ac6 100644 --- a/src/src/Globals/CPlugins.cpp +++ b/src/src/Globals/CPlugins.cpp @@ -99,14 +99,15 @@ bool CPluginCall(CPlugin::Function Function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_SHOW_HOST_CONFIG: { controllerIndex_t controllerindex = event->ControllerIndex; - - if (Settings.ControllerEnabled[controllerindex] && supportedCPluginID(Settings.Protocol[controllerindex])) - { - if (Function == CPlugin::Function::CPLUGIN_PROTOCOL_SEND) { - checkDeviceVTypeForTask(event); + if (validControllerIndex(controllerindex)) { + if (Settings.ControllerEnabled[controllerindex] && supportedCPluginID(Settings.Protocol[controllerindex])) + { + if (Function == CPlugin::Function::CPLUGIN_PROTOCOL_SEND) { + checkDeviceVTypeForTask(event); + } + protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); + CPluginCall(ProtocolIndex, Function, event, str); } - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); - CPluginCall(ProtocolIndex, Function, event, str); } break; } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4001d2d2e4..e461bbc435 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -872,6 +872,11 @@ bool ESPEasy_now_handler_t::sendESPEasyNow_p2p(controllerIndex_t controllerIndex bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, bool& mustKeep) { mustKeep = false; + controllerIndex_t controller_index = findFirstEnabledControllerWithId(19); // CPLUGIN_ID_019 + if (!validControllerIndex(controller_index)) { + return false; + } + ESPEasy_Now_p2p_data data; size_t payload_pos = 0; size_t payload_size = message.getPayloadSize(); @@ -894,7 +899,12 @@ bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& mess return false; } - // TODO TD-er: Call C019 controller with event containing this data object as a pointer. + // Call C019 controller with event containing this data object as a pointer. + EventStruct event; + event.ControllerIndex = controller_index; + event.Par1 = sizeof(ESPEasy_Now_p2p_data); + event.Data = reinterpret_cast(&data); + CPluginCall(CPlugin::Function::CPLUGIN_PROTOCOL_RECV, &event); return true; } From 24d5eb43aff5f9d07befb1ce6cfe3c735fa25a95 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 5 Oct 2020 17:53:33 +0200 Subject: [PATCH 063/404] [ESPEasy-Now] Implement sending/receiving p2p messages --- src/_C019.ino | 46 ++++++++++++++------ src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 8 ++-- src/src/DataStructs/ESPEasy_Now_p2p_data.h | 3 +- src/src/Helpers/ESPEasy_now_handler.cpp | 22 ++++++++-- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/_C019.ino b/src/_C019.ino index 594299edd3..15c70ffe3d 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -29,7 +29,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesPassword = true; Protocol[protocolCount].usesExtCreds = false; Protocol[protocolCount].defaultPort = 0; - Protocol[protocolCount].usesID = false; + Protocol[protocolCount].usesID = true; Protocol[protocolCount].Custom = false; Protocol[protocolCount].usesHost = false; Protocol[protocolCount].usesPort = false; @@ -49,11 +49,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_INIT: { - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - - // FIXME TD-er: Not sure if MQTT like formatting is the best here. - C019_DelayHandler->configureControllerSettings(ControllerSettings); + success = init_c019_delay_queue(event->ControllerIndex); break; } @@ -79,13 +75,33 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& if (!validControllerIndex(ControllerID)) { // Controller is not enabled. break; - } else { - if ((event->Data != nullptr) && (event->Par1 == sizeof(ESPEasy_Now_p2p_data))) { - ESPEasy_Now_p2p_data *data = reinterpret_cast(event->Data); + } + + if ((event->Data == nullptr) || (event->Par1 != sizeof(ESPEasy_Now_p2p_data))) { + break; + } + ESPEasy_Now_p2p_data *data = reinterpret_cast(event->Data); - if (data->validate()) {} + if (!data->validate()) { +// break; + } + + String log = F("ESPEasy_Now PluginData: "); + log += data->plugin_id; + log += F(" sourceUnit: "); + log += data->sourceUnit; + addLog(LOG_LEVEL_INFO, log); + + switch (data->dataType) { + case ESPEasy_Now_p2p_data_type::PluginData: + { + break; } + default: + break; } + + break; } @@ -119,12 +135,15 @@ bool do_process_c019_delay_queue(int controller_number, const C019_queue_element bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings) { ESPEasy_Now_p2p_data data; + const taskIndex_t taskIndex = element.event.TaskIndex; + data.dataType = ESPEasy_Now_p2p_data_type::PluginData; - data.sourceTaskIndex = element.event.TaskIndex; - data.plugin_id = getPluginID_from_TaskIndex(data.sourceTaskIndex); + data.sourceTaskIndex = taskIndex; + data.plugin_id = getPluginID_from_TaskIndex(taskIndex); data.sourceUnit = Settings.Unit; + data.idx = Settings.TaskDeviceID[element.controller_idx][taskIndex]; data.sensorType = element.event.sensorType; - data.valueCount = getValueCountForTask(data.sourceTaskIndex); + data.valueCount = getValueCountForTask(taskIndex); for (byte i = 0; i < data.valueCount; ++i) { @@ -149,6 +168,7 @@ bool do_process_c019_delay_queue(int controller_number, const C019_queue_element MAC_address broadcast; + // FIXME TD-er: Must add a way to reach further than WiFi reach for (int i = 0; i < 6; ++i) { broadcast.mac[i] = 0xFF; } diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 4dafb93f6e..23ee75ad08 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -17,7 +17,7 @@ bool ESPEasy_Now_p2p_data::validate() const { if (dataOffset == 0) { return false; } - if (!validTaskIndex(destTaskIndex)) { return false; } + if (!validTaskIndex(sourceTaskIndex)) { return false; } if (!validPluginID(plugin_id)) { return false; } @@ -52,7 +52,7 @@ bool ESPEasy_Now_p2p_data::getString(String& value, size_t& offset) const { value.reserve(str_len); - for (int i = 0; i < str_len; ++i) { + for (size_t i = 0; i < str_len; ++i) { value += data[offset]; ++offset; } @@ -80,7 +80,7 @@ const uint8_t * ESPEasy_Now_p2p_data::getBinaryData(size_t offset, size_t& size) const size_t available = dataSize - offset; - if (size < available) { + if (size > available) { size = available; } return &data[offset]; @@ -88,11 +88,11 @@ const uint8_t * ESPEasy_Now_p2p_data::getBinaryData(size_t offset, size_t& size) uint8_t * ESPEasy_Now_p2p_data::prepareBinaryData(size_t& size) { size_t oldSize; + dataSize = 0; if (data != nullptr) { delete data; data = nullptr; - dataSize = 0; } if (!allocate(size, oldSize)) { diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h index d8d9d87db2..25f799ce81 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.h +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -69,13 +69,14 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { uint16_t dataSize = 0; // The sizeof(data) is intended use of sizeof to return the size of a pointer - const uint8_t dataOffset = sizeof(ESPEasy_Now_p2p_data) - sizeof(data); + const uint8_t dataOffset = sizeof(ESPEasy_Now_p2p_data) - sizeof(uint8_t *); taskIndex_t sourceTaskIndex = INVALID_TASK_INDEX; taskIndex_t destTaskIndex = INVALID_TASK_INDEX; uint16_t plugin_id = INVALID_PLUGIN_ID; // FIXME TD-er: Must change to pluginID_t as soon as that's changed to 16 // bit uint16_t sourceUnit = 0; uint16_t destUnit = 0; + uint16_t idx = 0; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; uint8_t valueCount = 0; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index e461bbc435..6dea10c1c2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -874,6 +874,7 @@ bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& mess mustKeep = false; controllerIndex_t controller_index = findFirstEnabledControllerWithId(19); // CPLUGIN_ID_019 if (!validControllerIndex(controller_index)) { + addLog(LOG_LEVEL_ERROR, F("Controller C019 not enabled")); return false; } @@ -889,14 +890,27 @@ bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& mess // dataOffset may have changed to match the offset used by the sender. payload_pos = data.dataOffset; - size_t binaryData_size = payload_size - payload_pos; + size_t binaryData_size = payload_size - headerSize; uint8_t* binaryData_ptr = data.prepareBinaryData(binaryData_size); if (binaryData_ptr == nullptr) { - return false; + addLog(LOG_LEVEL_ERROR, F("handle_ESPEasyNow_p2p: Cannot allocate data")); + // Cannot allocate memory to process message, so return true to make sure it gets deleted. + return true; } - if (message.getBinaryData(binaryData_ptr, binaryData_size, payload_pos) != binaryData_size) { + + size_t received_size = message.getBinaryData(binaryData_ptr, binaryData_size, payload_pos); + if (received_size != binaryData_size) { // Did not receive all data - return false; + String log = F("handle_ESPEasyNow_p2p: Did not receive all data "); + log += received_size; + log += '/'; + log += binaryData_size; + log += F(" dataSize: "); + log += data.dataSize; + log += F(" payload_pos: "); + log += data.dataOffset; + addLog(LOG_LEVEL_ERROR, log); +// return false; } // Call C019 controller with event containing this data object as a pointer. From fe9e0aadcce35c3526d99e8ff3b8563566589224 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Oct 2020 13:05:44 +0200 Subject: [PATCH 064/404] [ESPEasy-now] Split processing functions for p2p data to .cpp/.h files --- src/_C019.ino | 34 ++------------ src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 7 +-- src/src/DataStructs/ESPEasy_Now_p2p_data.h | 2 + .../Controller/C019_ESPEasyNow_helper.cpp | 47 +++++++++++++++++++ .../Controller/C019_ESPEasyNow_helper.h | 13 +++++ 5 files changed, 67 insertions(+), 36 deletions(-) create mode 100644 src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp create mode 100644 src/src/Helpers/Controller/C019_ESPEasyNow_helper.h diff --git a/src/_C019.ino b/src/_C019.ino index 15c70ffe3d..e3163cb72f 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -9,6 +9,8 @@ #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" +#include "src/Helpers/Controller/C019_ESPEasyNow_helper.h" + #define CPLUGIN_019 #define CPLUGIN_ID_019 19 @@ -70,37 +72,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_RECV: { - controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_019); - - if (!validControllerIndex(ControllerID)) { - // Controller is not enabled. - break; - } - - if ((event->Data == nullptr) || (event->Par1 != sizeof(ESPEasy_Now_p2p_data))) { - break; - } - ESPEasy_Now_p2p_data *data = reinterpret_cast(event->Data); - - if (!data->validate()) { -// break; - } - - String log = F("ESPEasy_Now PluginData: "); - log += data->plugin_id; - log += F(" sourceUnit: "); - log += data->sourceUnit; - addLog(LOG_LEVEL_INFO, log); - - switch (data->dataType) { - case ESPEasy_Now_p2p_data_type::PluginData: - { - break; - } - default: - break; - } - + C019_ESPEasyNow_helper::process_receive(event); break; } diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 23ee75ad08..96275fdd39 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -89,11 +89,7 @@ const uint8_t * ESPEasy_Now_p2p_data::getBinaryData(size_t offset, size_t& size) uint8_t * ESPEasy_Now_p2p_data::prepareBinaryData(size_t& size) { size_t oldSize; dataSize = 0; - - if (data != nullptr) { - delete data; - data = nullptr; - } + data = nullptr; if (!allocate(size, oldSize)) { return nullptr; @@ -111,6 +107,7 @@ bool ESPEasy_Now_p2p_data::allocate(size_t size, size_t& oldSize) { if (tmp_ptr == nullptr) { return false; } + memset(tmp_ptr, 0, newSize); if (data != nullptr) { memcpy(tmp_ptr, data, oldSize); diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h index 25f799ce81..4b291049db 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.h +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -52,6 +52,8 @@ struct __attribute__((__packed__)) ESPEasy_Now_p2p_data { size_t& size) const; // Clear and resize data array to size. + // This function is meant to be used only on the receiving end to reconstruct the data array. + // Meaning the pointer will just be cleared, no call to delete the pointer. // @retval pointer to the first element of the data array uint8_t* prepareBinaryData(size_t& size); diff --git a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp new file mode 100644 index 0000000000..fa018cb2d1 --- /dev/null +++ b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp @@ -0,0 +1,47 @@ +#include "C019_ESPEasyNow_helper.h" + +#include "../../DataStructs/ESPEasy_EventStruct.h" +#include "../../Globals/CPlugins.h" +#include "../../../ESPEasy_Log.h" + + +bool C019_ESPEasyNow_helper::process_receive(struct EventStruct *event) { + controllerIndex_t ControllerID = findFirstEnabledControllerWithId(19 /* CPLUGIN_ID_019 */ ); + + if (!validControllerIndex(ControllerID)) { + // Controller is not enabled. + return false; + } + + if ((event->Data == nullptr) || (event->Par1 != sizeof(ESPEasy_Now_p2p_data))) { + return false; + } + ESPEasy_Now_p2p_data *data = reinterpret_cast(event->Data); + + if (!data->validate()) { + // return false; + } + + String log = F("ESPEasy_Now PluginData: "); + + log += data->plugin_id; + log += F(" sourceUnit: "); + log += data->sourceUnit; + addLog(LOG_LEVEL_INFO, log); + + switch (data->dataType) { + case ESPEasy_Now_p2p_data_type::PluginData: + { + C019_ESPEasyNow_helper::process_received_PluginData(*data); + break; + } + default: + break; + } + + return true; +} + +void C019_ESPEasyNow_helper::process_received_PluginData(const ESPEasy_Now_p2p_data& data) { + +} diff --git a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.h b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.h new file mode 100644 index 0000000000..7a29b92ade --- /dev/null +++ b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.h @@ -0,0 +1,13 @@ +#ifndef HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H +#define HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H + +#include "../../DataStructs/ESPEasy_Now_p2p_data.h" + +struct C019_ESPEasyNow_helper { + static bool process_receive(struct EventStruct *event); + + static void process_received_PluginData(const ESPEasy_Now_p2p_data& data); +}; + + +#endif // HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H From e63cc9273d44fd63cb61655009a08551a13aeb09 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 22 Oct 2020 12:03:47 +0200 Subject: [PATCH 065/404] Fix build issue due to missing ESPEasyNow source in switch statement --- src/src/DataStructs/EventValueSource.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/DataStructs/EventValueSource.h b/src/src/DataStructs/EventValueSource.h index 2ae6eff790..23ce67b115 100644 --- a/src/src/DataStructs/EventValueSource.h +++ b/src/src/DataStructs/EventValueSource.h @@ -40,6 +40,7 @@ struct EventValueSource { return true; case EventValueSource::Enum::VALUE_SOURCE_HTTP: case EventValueSource::Enum::VALUE_SOURCE_MQTT: + case EventValueSource::Enum::VALUE_SOURCE_ESPEASY_NOW: return group == EventValueSourceGroup::Enum::ALL; } return false; From 26f6d615af9b0a3bbfb614b76c288f2ffffcdfbd Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 22 Oct 2020 23:21:57 +0200 Subject: [PATCH 066/404] Fix merge issues --- src/ESPEasyWiFi_credentials.cpp | 2 +- src/_C019.ino | 3 +- src/_P098_ESPEasyNowReceiver.ino | 2 +- src/_P101_WakeOnLan.ino | 3 +- .../ControllerQueue/C019_queue_element.cpp | 2 +- src/src/ControllerQueue/C019_queue_element.h | 2 +- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 2 +- src/src/DataStructs/ESPEasy_Now_p2p_data.h | 2 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 1 + src/src/DataStructs/ESPEasy_now_splitter.cpp | 2 +- src/src/DataStructs/NodeStruct.cpp | 1 - src/src/DataStructs/NodesHandler.cpp | 6 +- .../SendData_DuplicateChecker_data.cpp | 2 +- .../SendData_DuplicateChecker_struct.cpp | 4 +- .../DataTypes/ESPEasyTimeSource.cpp} | 2 +- src/src/ESPEasyCore/Controller.cpp | 55 +++++++++++++++++++ src/src/ESPEasyCore/Controller.h | 15 +++++ .../Controller/C019_ESPEasyNow_helper.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 17 +++--- src/src/Helpers/Networking.cpp | 1 + src/src/Helpers/PeriodicalActions.cpp | 1 + src/src/Helpers/StringProvider.cpp | 23 +++++++- src/src/Helpers/StringProvider.h | 6 ++ src/src/WebServer/ConfigPage.cpp | 1 + src/src/WebServer/Markup_Forms.h | 6 ++ src/src/WebServer/WiFiScanner.cpp | 1 + 26 files changed, 140 insertions(+), 24 deletions(-) rename src/{ESPEasyTimeTypes.cpp => src/DataTypes/ESPEasyTimeSource.cpp} (96%) diff --git a/src/ESPEasyWiFi_credentials.cpp b/src/ESPEasyWiFi_credentials.cpp index 77cc325597..5248a63577 100644 --- a/src/ESPEasyWiFi_credentials.cpp +++ b/src/ESPEasyWiFi_credentials.cpp @@ -5,12 +5,12 @@ // Manage WiFi credentials // ******************************************************************************** +#include "src/ESPEasyCore/ESPEasy_Log.h" #include "src/Globals/ESPEasy_now_state.h" #include "src/Globals/ESPEasy_now_handler.h" #include "src/Globals/SecuritySettings.h" #include "src/Globals/RTC.h" #include "src/Globals/ESPEasyWiFiEvent.h" -#include "ESPEasy_Log.h" #ifdef USES_ESPEASY_NOW #define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" diff --git a/src/_C019.ino b/src/_C019.ino index e3163cb72f..027ccd66ce 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -5,10 +5,9 @@ // ####################################################################################################### #include "ESPEasy_fdwdecl.h" -#include "_CPlugin_Helper.h" #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" - +#include "src/Helpers/_CPlugin_Helper.h" #include "src/Helpers/Controller/C019_ESPEasyNow_helper.h" diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index cd7db9c9e6..067f69ebec 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -1,10 +1,10 @@ +#include "_Plugin_Helper.h" #ifdef USES_P098 // ####################################################################################################### // #################################### Plugin 098: ESPEasy-Now Receiver ################################# // ####################################################################################################### -#include "_Plugin_Helper.h" #include "src/Globals/ESPEasy_now_handler.h" diff --git a/src/_P101_WakeOnLan.ino b/src/_P101_WakeOnLan.ino index 98c9ad5441..d7825841af 100644 --- a/src/_P101_WakeOnLan.ino +++ b/src/_P101_WakeOnLan.ino @@ -1,3 +1,4 @@ +#include "_Plugin_Helper.h" #ifdef USES_P101 // ####################################################################################################### @@ -48,7 +49,7 @@ // // ************************************************************************************************ -#include "_Plugin_Helper.h" + #include // Plugin defines diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index b14fb2c3a0..2be0029ccf 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -1,7 +1,7 @@ #include "../ControllerQueue/C019_queue_element.h" #include "../DataStructs/ESPEasy_EventStruct.h" -#include "../../ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasy_Log.h" #ifdef USES_PACKED_RAW_DATA diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 73afae57e0..307c8d738f 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -2,8 +2,8 @@ #define CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" +#include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/ESPEasy_EventStruct.h" -#include "../DataStructs/ESPEasyLimits.h" #include "../Globals/CPlugins.h" diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index c5bb7f068d..4ac657a62c 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -12,9 +12,9 @@ # define MINIMUM_TIME_BETWEEN_UPDATES (1800 * 1000) // Half an hour +# include "../ESPEasyCore/ESPEasy_Log.h" # include "../Globals/ESPEasy_time.h" # include "../Helpers/ESPEasy_time_calc.h" -# include "../../ESPEasy_Log.h" # include "../../ESPEasy_fdwdecl.h" ESPEasy_Now_NTP_query::ESPEasy_Now_NTP_query() diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h index 4b291049db..e74b1eeb20 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.h +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -3,7 +3,7 @@ #include -#include "ESPEasyLimits.h" +#include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../Globals/Plugins.h" diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 0a4d44fff0..e27d75559d 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -3,6 +3,7 @@ #ifdef USES_ESPEASY_NOW # include "../../ESPEasy_fdwdecl.h" +# include "../Helpers/CRC_functions.h" # define ESPEASY_NOW_MAX_PACKET_SIZE 200 diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 2ec2010641..1b8e532885 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -2,7 +2,7 @@ #ifdef USES_ESPEASY_NOW -# include "../../ESPEasy_Log.h" +# include "../ESPEasyCore/ESPEasy_Log.h" # include "../DataStructs/TimingStats.h" # include "../Globals/Nodes.h" # include "../Helpers/ESPEasy_time_calc.h" diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 8e8cde1546..c853153280 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -1,7 +1,6 @@ #include "NodeStruct.h" #include "../../ESPEasy-Globals.h" -#include "../../ESPEasyTimeTypes.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" #include "../Helpers/ESPEasy_time_calc.h" diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index b95f1b7922..01f3e2ace0 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,10 +1,14 @@ #include "NodesHandler.h" #include "../../ESPEasy-Globals.h" -#include "../../ESPEasyWifi.h" +#include "../../ESPEasy_fdwdecl.h" +#include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyWifi.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/PeriodicalActions.h" +#include "../Globals/ESPEasy_time.h" #include "../Globals/MQTT.h" +#include "../Globals/Settings.h" void NodesHandler::addNode(const NodeStruct& node) { diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp index 0c8109b1b0..016c7484a2 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp @@ -1,6 +1,6 @@ #include "SendData_DuplicateChecker_data.h" - +#include "../ESPEasyCore/Controller.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../../ESPEasy_fdwdecl.h" diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 4c11813525..97dd3f2882 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -1,9 +1,11 @@ #include "SendData_DuplicateChecker_struct.h" +#include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/Plugins.h" +#include "../Helpers/CRC_functions.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../../ESPEasy_fdwdecl.h" -#include "../../ESPEasy_Log.h" + #define HISTORIC_ELEMENT_LIFETIME 10000 // 10 seconds diff --git a/src/ESPEasyTimeTypes.cpp b/src/src/DataTypes/ESPEasyTimeSource.cpp similarity index 96% rename from src/ESPEasyTimeTypes.cpp rename to src/src/DataTypes/ESPEasyTimeSource.cpp index d66be32d25..7f62f3c669 100644 --- a/src/ESPEasyTimeTypes.cpp +++ b/src/src/DataTypes/ESPEasyTimeSource.cpp @@ -1,4 +1,4 @@ -#include "ESPEasyTimeTypes.h" +#include "ESPEasyTimeSource.h" #include diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 62372ffbe6..aab38159ee 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -19,6 +19,8 @@ #include "../Globals/Device.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" +#include "../Globals/ESPEasy_now_handler.h" +#include "../Globals/SendData_DuplicateChecker.h" #include "../Globals/MQTT.h" #include "../Globals/Plugins.h" #include "../Globals/Protocol.h" @@ -85,6 +87,31 @@ void sendData(struct EventStruct *event) STOP_TIMER(SEND_DATA_STATS); } + +// ******************************************************************************** +// Send to controllers, via a duplicate check +// Some plugins may receive the same data among nodes, so check first if +// another node may already have sent it. +// The compare_key is computed by the sender plugin, with plugin specific knowledge +// to make sure the key describes enough to detect duplicates. +// ******************************************************************************** +void sendData_checkDuplicates(struct EventStruct *event, const String& compare_key) +{ +#ifdef USES_ESPEASY_NOW + uint32_t key = SendData_DuplicateChecker.add(event, compare_key); + if (key != SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY) { + // Must send out request to other nodes to see if any other has already processed it. + uint8_t broadcastMac[6]; + ESPEasy_now_handler.sendSendData_DuplicateCheck( + key, + ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck, + broadcastMac); + } +#else + sendData(event); +#endif +} + bool validUserVar(struct EventStruct *event) { switch (event->getSensorType()) { case Sensor_VType::SENSOR_TYPE_LONG: return true; @@ -455,6 +482,34 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { return false; } +#ifdef USES_ESPEASY_NOW + +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained) +{ + bool success = false; + if (!MQTT_queueFull(controller_idx)) + { + success = MQTTDelayHandler->addToQueue(MQTT_queue_element()); + if (success) { + size_t pos = 0; + MQTTDelayHandler->sendQueue.back().controller_idx = controller_idx; + MQTTDelayHandler->sendQueue.back()._retained = retained; + message.getString(MQTTDelayHandler->sendQueue.back()._topic, pos); + message.getString(MQTTDelayHandler->sendQueue.back()._payload, pos); + } + + size_t payloadSize = message.getPayloadSize(); + if ((MQTTDelayHandler->sendQueue.back()._topic.length() + MQTTDelayHandler->sendQueue.back()._payload.length() + 2) < payloadSize) { + success = false; + MQTTDelayHandler->sendQueue.pop_back(); + } + } + scheduleNextMQTTdelayQueue(); + return success; +} + +#endif + bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained) { if (MQTTDelayHandler == nullptr) { diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 37a1b706b1..797e788776 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include "../DataTypes/EventValueSource.h" +#include "../DataStructs/ESPEasy_now_merger.h" #include "../Globals/CPlugins.h" // ******************************************************************************** @@ -13,6 +14,16 @@ void sendData(struct EventStruct *event); bool validUserVar(struct EventStruct *event); +// ******************************************************************************** +// Send to controllers, via a duplicate check +// Some plugins may receive the same data among nodes, so check first if +// another node may already have sent it. +// The compare_key is computed by the sender plugin, with plugin specific knowledge +// to make sure the key describes enough to detect duplicates. +// ******************************************************************************** +void sendData_checkDuplicates(struct EventStruct *event, const String& compare_key); + + #ifdef USES_MQTT /*********************************************************************************************\ * Handle incoming MQTT messages @@ -59,6 +70,10 @@ void SendStatus(EventValueSource::Enum source, const String& status); #ifdef USES_MQTT bool MQTT_queueFull(controllerIndex_t controller_idx); +#ifdef USES_ESPEASY_NOW +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); +#endif + bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained); diff --git a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp index fa018cb2d1..c5e60b94a5 100644 --- a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp +++ b/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp @@ -1,8 +1,8 @@ #include "C019_ESPEasyNow_helper.h" #include "../../DataStructs/ESPEasy_EventStruct.h" +#include "../../ESPEasyCore/ESPEasy_Log.h" #include "../../Globals/CPlugins.h" -#include "../../../ESPEasy_Log.h" bool C019_ESPEasyNow_helper::process_receive(struct EventStruct *event) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 6dea10c1c2..dabbd87367 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -2,25 +2,28 @@ #ifdef USES_ESPEASY_NOW -# include "../../ESPEasy_fdwdecl.h" -# include "../../ESPEasy_Log.h" -# include "../../ESPEasyWifi.h" # include "../../ESPEasyWiFi_credentials.h" -# include "../../_CPlugin_Helper.h" -# include "ESPEasy_time_calc.h" +# include "../../ESPEasy_fdwdecl.h" +# include "../ControllerQueue/MQTT_queue_element.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_packet.h" # include "../DataStructs/ESPEasy_now_splitter.h" # include "../DataStructs/NodeStruct.h" # include "../DataStructs/TimingStats.h" +# include "../ESPEasyCore/Controller.h" +# include "../ESPEasyCore/ESPEasyWifi.h" +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/ESPEasy_time.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" # include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" -# include "../ControllerQueue/MQTT_queue_element.h" -# include "../Helpers/PeriodicalActions.h" +# include "../Helpers/CRC_functions.h" # include "../Helpers/ESPEasy_Storage.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/PeriodicalActions.h" +# include "../Helpers/_CPlugin_Helper.h" # include diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 77d84587b1..b6999640bf 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -8,6 +8,7 @@ #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" +#include "../Globals/ESPEasy_now_handler.h" #include "../Globals/NetworkState.h" #include "../Globals/Nodes.h" #include "../Globals/Settings.h" diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 2107ea777a..9ea123da3b 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -33,6 +33,7 @@ #include "../Helpers/Hardware.h" #include "../Helpers/Memory.h" #include "../Helpers/Misc.h" +#include "../Helpers/Network.h" #include "../Helpers/Networking.h" #include "../Helpers/StringGenerator_System.h" #include "../Helpers/StringProvider.h" diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index eeeea8d8ee..7812c46ec6 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -11,6 +11,7 @@ #include "../Globals/ESPEasy_Scheduler.h" #include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" #include "../Globals/Settings.h" @@ -36,6 +37,7 @@ String getLabel(LabelType::Enum label) { case LabelType::HOST_NAME: return F("Hostname"); case LabelType::LOCAL_TIME: return F("Local Time"); + case LabelType::TIME_SOURCE: return F("Time Source"); case LabelType::UPTIME: return F("Uptime"); case LabelType::LOAD_PCT: return F("Load"); case LabelType::LOOP_COUNT: return F("Load LC"); @@ -100,6 +102,12 @@ String getLabel(LabelType::Enum label) { case LabelType::PERIODICAL_GRAT_ARP: return F("Periodical send Gratuitous ARP"); case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); + #ifdef USES_ESPEASY_NOW + case LabelType::USE_ESPEASY_NOW: return F("Use ESPEasy-Now"); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable ESPEasy-Now"); + #endif + + case LabelType::BUILD_DESC: return F("Build"); case LabelType::GIT_BUILD: return F("Git Build"); case LabelType::SYSTEM_LIBRARIES: return F("System Libraries"); @@ -170,6 +178,7 @@ String getValue(LabelType::Enum label) { case LabelType::LOCAL_TIME: return node_time.getDateTimeString('-', ':', ' '); + case LabelType::TIME_SOURCE: return toString(node_time.timeSource); case LabelType::UPTIME: return String(wdcounter / 2); case LabelType::LOAD_PCT: return String(getCPUload()); case LabelType::LOOP_COUNT: return String(getLoopCountPerSec()); @@ -240,8 +249,20 @@ String getValue(LabelType::Enum label) { case LabelType::PERIODICAL_GRAT_ARP: return jsonBool(Settings.gratuitousARP()); case LabelType::CONNECTION_FAIL_THRESH: return String(Settings.ConnectionFailuresThreshold); + #ifdef USES_ESPEASY_NOW + case LabelType::USE_ESPEASY_NOW: return jsonBool(Settings.UseESPEasyNow()); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); + #endif + case LabelType::BUILD_DESC: return String(BUILD); - case LabelType::GIT_BUILD: return String(F(BUILD_GIT)); + case LabelType::GIT_BUILD: + { + String res = F(BUILD_GIT); + if (res.length() == 0) { + return getValue(LabelType::BUILD_TIME); + } + return res; + } case LabelType::SYSTEM_LIBRARIES: return getSystemLibraryString(); case LabelType::PLUGIN_COUNT: return String(deviceCount + 1); case LabelType::PLUGIN_DESCRIPTION: return getPluginDescriptionString(); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 6ec70eb62d..6a619da4e3 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -14,6 +14,7 @@ struct LabelType { HOST_NAME, LOCAL_TIME, + TIME_SOURCE, UPTIME, LOAD_PCT, // 15.10 LOOP_COUNT, // 400 @@ -77,6 +78,11 @@ struct LabelType { PERIODICAL_GRAT_ARP, CONNECTION_FAIL_THRESH, + #ifdef USES_ESPEASY_NOW + USE_ESPEASY_NOW, + TEMP_DISABLE_ESPEASY_NOW, + #endif + BUILD_DESC, GIT_BUILD, SYSTEM_LIBRARIES, diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index 9906c9e6b8..1f1fd662a9 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -12,6 +12,7 @@ #include "../ESPEasyCore/Controller.h" #include "../Globals/MQTT.h" +#include "../Globals/Nodes.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" diff --git a/src/src/WebServer/Markup_Forms.h b/src/src/WebServer/Markup_Forms.h index ab041d98e4..f8b674b843 100644 --- a/src/src/WebServer/Markup_Forms.h +++ b/src/src/WebServer/Markup_Forms.h @@ -3,6 +3,7 @@ #include "../WebServer/common.h" +#include "../DataStructs/MAC_address.h" #include "../Globals/Plugins.h" @@ -77,6 +78,11 @@ bool getFormPassword(const String& id, String& password); void addFormIPBox(const String& label, const String& id, const byte ip[4]); +// ******************************************************************************** +// Add a MAC address Box form +// ******************************************************************************** +void addFormMACBox(const String& label, const String& id, const MAC_address mac); + // ******************************************************************************** // Add a IP Access Control select dropdown list // ******************************************************************************** diff --git a/src/src/WebServer/WiFiScanner.cpp b/src/src/WebServer/WiFiScanner.cpp index 7a1005a7a1..956fe16c2f 100644 --- a/src/src/WebServer/WiFiScanner.cpp +++ b/src/src/WebServer/WiFiScanner.cpp @@ -6,6 +6,7 @@ #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../Globals/ESPEasy_now_handler.h" #ifdef WEBSERVER_NEW_UI From 8e143030206c315e26439f4065f1b2e745250516 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 27 Oct 2020 22:17:35 +0100 Subject: [PATCH 067/404] Fix merge issue --- src/src/CustomBuild/ESPEasyLimits.h | 6 +++--- src/src/DataTypes/ESPEasyTimeSource.h | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index 7649f0fd37..a9900089bb 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_ESPEASY_LIMITS_H -#define DATASTRUCTS_ESPEASY_LIMITS_H +#ifndef CUSTOMBUILD_ESPEASY_LIMITS_H +#define CUSTOMBUILD_ESPEASY_LIMITS_H #include "../../ESPEasy_common.h" @@ -162,4 +162,4 @@ #define DOMOTICZ_MAX_IDX 999999999 // Looks like it is an unsigned int, so could be up to 4 bln. -#endif // DATASTRUCTS_ESPEASY_LIMITS_H +#endif // CUSTOMBUILD_ESPEASY_LIMITS_H diff --git a/src/src/DataTypes/ESPEasyTimeSource.h b/src/src/DataTypes/ESPEasyTimeSource.h index 775e4b59d2..ef0545c2d5 100644 --- a/src/src/DataTypes/ESPEasyTimeSource.h +++ b/src/src/DataTypes/ESPEasyTimeSource.h @@ -1,12 +1,10 @@ -#ifndef ESPEASY_TIMETYPES_H_ -#define ESPEASY_TIMETYPES_H_ +#ifndef DATATYPES_ESPEASYTIMESOURCE_H +#define DATATYPES_ESPEASYTIMESOURCE_H -#include "../../src/DataStructs/TimeChangeRule.h" -#include "../../src/Globals/Plugins.h" -#include #include +class String; // Time Source type, sort by priority. // Enum values are sent via NodeStruct, so only add new ones and don't change existing values @@ -31,4 +29,4 @@ String toString(timeSource_t timeSource); bool isExternalTimeSource(timeSource_t timeSource); -#endif /* ESPEASY_TIMETYPES_H_ */ +#endif /* DATATYPES_ESPEASYTIMESOURCE_H */ From 847ba2e0d9ae655ee2dedc6528b863f376dd4581 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 24 Nov 2020 23:14:08 +0100 Subject: [PATCH 068/404] [ESPEasy-now] Fix some data corruption due to out-of-memory --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 11 ++++++++--- src/src/DataStructs/ESPEasy_Now_packet.h | 13 +++++++------ src/src/DataStructs/ESPEasy_now_hdr.h | 2 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 9 +++++---- src/src/Helpers/ESPEasy_now_handler.cpp | 5 ++++- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index e27d75559d..c163a3dffd 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -7,12 +7,14 @@ # define ESPEASY_NOW_MAX_PACKET_SIZE 200 + ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { setSize(payloadSize + sizeof(ESPEasy_now_hdr)); setHeader(header); } + ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *buf, size_t packetSize) { setSize(packetSize); @@ -22,6 +24,8 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *bu // Cannot store the whole packet, so consider it as invalid. packetSize = bufsize; _valid = false; + } else { + _valid = true; } memcpy(&_buf[0], buf, packetSize); } @@ -90,13 +94,14 @@ ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const void ESPEasy_Now_packet::setHeader(ESPEasy_now_hdr header) { - header.checksum = computeChecksum(); if (_buf.size() < sizeof(ESPEasy_now_hdr)) { // Not even the header will fit, so this is an invalid packet. _valid = false; - } else { - memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); + return; } + header.checksum = computeChecksum(); + memcpy(&_buf[0], &header, sizeof(ESPEasy_now_hdr)); + _valid = true; } size_t ESPEasy_Now_packet::addString(const String& string, size_t& payload_pos) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 87b6c1b317..5c5da09da6 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -14,14 +14,15 @@ class ESPEasy_Now_packet { public: + // Constructor for sending a packet - ESPEasy_Now_packet(const ESPEasy_now_hdr& header, - size_t payloadSize); + explicit ESPEasy_Now_packet(const ESPEasy_now_hdr& header, + size_t payloadSize); // Constructor for receiving a packet - ESPEasy_Now_packet(const MAC_address& mac, - const uint8_t *buf, - size_t packetSize); + explicit ESPEasy_Now_packet(const MAC_address& mac, + const uint8_t *buf, + size_t packetSize); // A packet may become invalid if it was not possible to allocate enough memory for the buffer bool valid() const; @@ -81,7 +82,7 @@ class ESPEasy_Now_packet { std::vector_buf; - bool _valid = true; + bool _valid = false; void setSize(size_t packetSize); diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index ba014b04b2..7a18e58df2 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -42,7 +42,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { uint8_t nr_packets = 1; // The highest message number of this sequence uint8_t message_count = 1; // A set of messages all have the same message_count uint8_t payload_size = 0; // Size of the payload - uint16_t checksum = 0; // checksum of the packet + uint16_t checksum = 1; // checksum of the packet, initialize to value which cannot match on an empty packet. }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 1b8e532885..84c94f131b 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -58,6 +58,7 @@ void ESPEasy_now_splitter::createNextPacket() // Determine size of next packet size_t message_bytes_left = _totalSize - _bytesStored; + _header.payload_size = message_bytes_left - sizeof(ESPEasy_now_hdr); _queue.emplace_back(_header, message_bytes_left); _payload_pos = 0; @@ -221,15 +222,15 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { - if (!_queue[i].valid()) { - addLog(LOG_LEVEL_ERROR, F("ESPEasy Now: Could not prepare for send")); - return false; - } ESPEasy_now_hdr header = _queue[i].getHeader(); header.nr_packets = nr_packets; header.payload_size = _queue[i].getPayloadSize(); _queue[i].setHeader(header); _queue[i].setMac(mac); + if (!_queue[i].valid()) { + addLog(LOG_LEVEL_ERROR, F("ESPEasy Now: Could not prepare for send")); + return false; + } } return true; } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 1e514aa714..9b5c014225 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -51,14 +51,16 @@ static uint64_t mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messag std::map ESPEasy_now_in_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { + START_TIMER; if (count < sizeof(ESPEasy_now_hdr)) { + STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; // Too small } - START_TIMER; ESPEasy_now_hdr header; memcpy(&header, buf, sizeof(ESPEasy_now_hdr)); if (header.header_version != ESPEASY_NOW_HEADER_VERSION) { + STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; } @@ -68,6 +70,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t const uint16_t checksum = calc_CRC16(reinterpret_cast(payload), payload_length); if (header.checksum != checksum) { + STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; } uint64_t key = mac_to_key(mac, header.message_type, header.message_count); From 49a9d46f8e7fa517d1df7358ae641ab1cbcea0f8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 3 Dec 2020 13:55:02 +0100 Subject: [PATCH 069/404] [PIO] Fix merge issue regarding include path --- src/src/Commands/ESPEasy_Now_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index 0c76d44c06..1856408d1a 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_cmd.h" +#include "../Commands/ESPEasy_Now_cmd.h" #include "../Globals/ESPEasy_now_state.h" From aa0d2f684171d81d544793dd19cc4d57c2a9efce Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 24 Jan 2021 11:24:34 +0100 Subject: [PATCH 070/404] [Build] Fix merge issues --- src/_C005.ino | 6 ------ src/src/DataStructs/SettingsStruct.cpp | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/_C005.ino b/src/_C005.ino index cbf675201e..33bb110cc6 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -142,14 +142,8 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& for (byte x = 0; x < valueCount; x++) { - String pubname = CPlugin_005_pubname; - bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; - statusLED(true); - LoadTaskSettings(event->TaskIndex); - parseControllerVariables(pubname, event, false); - byte valueCount = getValueCountForTask(event->TaskIndex); for (byte x = 0; x < valueCount; x++) { diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index 7bbeda77d9..ac3a904c38 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -128,6 +128,7 @@ void SettingsStruct_tmpl::UseESPEasyNow(bool value) { bitWrite(VariousBits1, 11, value); } +template bool SettingsStruct_tmpl::CombineTaskValues_SingleEvent(taskIndex_t taskIndex) const { if (validTaskIndex(taskIndex)) return bitRead(TaskDeviceSendDataFlags[taskIndex], 0); From 5228f7839c49f074f9d2de88a9eeaa4bc2032086 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 10 Feb 2021 10:36:22 +0100 Subject: [PATCH 071/404] [Build] Fix case sensitive typo in include --- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index df86aa5b66..6147719f91 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -5,7 +5,7 @@ #include "../DataStructs/NodesHandler.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" -#include "../ESPEasyCore/ESPEasyWiFi.h" +#include "../ESPEasyCore/ESPEasyWifi.h" #include "../ESPEasyCore/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" From 6a6d871c1fe2fef1ae83a79c2123e07e7f9890e0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 10 Feb 2021 11:21:50 +0100 Subject: [PATCH 072/404] Fix merge issue (missing return statement) --- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index e993bd041f..cbc956010e 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -150,7 +150,7 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { #ifdef USES_ESPEASY_NOW bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { - RTC.lastWiFiSettingsIndex == 3; + return RTC.lastWiFiSettingsIndex == 3; } #endif From 60dbde6bf0cb52d77a425f00e5960da9cb5e005f Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 10 Feb 2021 11:22:40 +0100 Subject: [PATCH 073/404] [WiFi] Fix crash when trying to reconnect while low on memory --- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 57 ++++++++++++++-------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index cbc956010e..bfd2abac72 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -187,30 +187,47 @@ void WiFi_AP_CandidatesList::addFromRTC() { return; } - WiFi_AP_Candidate tmp(RTC.lastWiFiSettingsIndex, ssid, key); - - tmp.setBSSID(RTC.lastBSSID); - if (!tmp.bssid_set()) return; - - // This is not taken from a scan, so no idea of the used encryption. - // Try to find a matching BSSID to get the encryption. - bool matchfound = false; - for (auto it = candidates.begin(); !matchfound && it != candidates.end(); ++it) { - if (tmp == *it) { - matchfound = true; - tmp = *it; + bool matchfound = false; + bool mustAdd = false; + int32_t channel = 0; + byte enc_type = 0; + { + WiFi_AP_Candidate tmp(RTC.lastWiFiSettingsIndex, ssid, key); + + tmp.setBSSID(RTC.lastBSSID); + if (!tmp.bssid_set()) return; + + // This is not taken from a scan, so no idea of the used encryption. + // Try to find a matching BSSID to get the encryption. + for (auto it = candidates.begin(); !matchfound && it != candidates.end(); ++it) { + if (tmp == *it) { + matchfound = true; + channel = it->channel; + enc_type = it->enc_type; + } } - } - if (!matchfound) { - if (currentCandidate == tmp) { - tmp = currentCandidate; + if (!matchfound) { + if (currentCandidate == tmp) { + matchfound = true; + channel = currentCandidate.channel; + enc_type = currentCandidate.enc_type; + } + } + if (tmp.usable() && tmp.allowQuickConnect()) { + mustAdd = true; } } - tmp.channel = RTC.lastWiFiChannel; - tmp.rssi = -1; // Set to best possible RSSI so it is tried first. - if (tmp.usable() && tmp.allowQuickConnect()) { - candidates.push_front(tmp); + if (mustAdd) { + // TD-er: Recreate the object here. Otherwise removal of the RTC added candidate causes crashes. + candidates.emplace_front(RTC.lastWiFiSettingsIndex, ssid, key); + candidates.front().setBSSID(RTC.lastBSSID); + candidates.front().channel = RTC.lastWiFiChannel; + candidates.front().rssi = -1; // Set to best possible RSSI so it is tried first. + if (matchfound) { + candidates.front().enc_type = enc_type; + candidates.front().channel = channel; + } } } From 48f8c8edbc316060c84908dcc0e1b2f36aad03db Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 11 Feb 2021 18:57:23 +0100 Subject: [PATCH 074/404] [ESPEasy-Now] Fix build warning for ESPEasy_now_hdr --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 6 +++--- src/src/DataStructs/ESPEasy_now_hdr.cpp | 5 +++++ src/src/DataStructs/ESPEasy_now_hdr.h | 2 ++ src/src/Helpers/ESPEasy_now_handler.cpp | 3 +-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index c163a3dffd..b0fa61e2b4 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -83,12 +83,12 @@ size_t ESPEasy_Now_packet::getMaxPayloadSize() ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const { - ESPEasy_now_hdr header; - if (getSize() >= sizeof(ESPEasy_now_hdr)) { - memcpy(&header, &_buf[0], sizeof(ESPEasy_now_hdr)); + ESPEasy_now_hdr header(&_buf[0]); + return header; } + ESPEasy_now_hdr header; return header; } diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index 6f54b071f1..42b9365677 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -7,6 +7,11 @@ ESPEasy_now_hdr::ESPEasy_now_hdr() {} ESPEasy_now_hdr::ESPEasy_now_hdr(ESPEasy_now_hdr::message_t messageType) : message_type(messageType) {} +ESPEasy_now_hdr::ESPEasy_now_hdr(const uint8_t *buf) +{ + memcpy(this, buf, sizeof(ESPEasy_now_hdr)); +} + ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr& other) { if (&other == this) { diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 7a18e58df2..93ea2ffbe4 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -33,6 +33,8 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { ESPEasy_now_hdr(message_t messageType); + ESPEasy_now_hdr(const uint8_t *buf); + ESPEasy_now_hdr& operator=(const ESPEasy_now_hdr& other); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 3f4dd9342d..052bd82497 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -55,8 +55,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; // Too small } - ESPEasy_now_hdr header; - memcpy(&header, buf, sizeof(ESPEasy_now_hdr)); + ESPEasy_now_hdr header(buf); if (header.header_version != ESPEASY_NOW_HEADER_VERSION) { STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); From e6c63b590b42ebed0e45e4ebd7d9880007f670c5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Feb 2021 12:21:11 +0100 Subject: [PATCH 075/404] [ESPEasy-Now] Fix accepting incomplete multi packet messages. --- src/src/DataStructs/ESPEasy_now_merger.cpp | 33 ++++++++++++---------- src/src/DataStructs/ESPEasy_now_merger.h | 5 ++-- src/src/Helpers/ESPEasy_now_handler.cpp | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 6a44b79848..4b7a686f00 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -34,7 +34,7 @@ void ESPEasy_now_merger::addPacket( bool ESPEasy_now_merger::messageComplete() const { - return _queue.size() >= getFirstHeader().nr_packets; + return _queue.size() >= getExpectedNrPackets(); } bool ESPEasy_now_merger::expired() const @@ -52,26 +52,29 @@ bool ESPEasy_now_merger::valid() const return true; } -uint8_t ESPEasy_now_merger::receivedCount(uint8_t& nr_packets) const -{ - nr_packets = getFirstHeader().nr_packets; - return _queue.size(); -} - ESPEasy_Now_packet_map::const_iterator ESPEasy_now_merger::find(uint8_t packet_nr) const { return _queue.find(packet_nr); } -ESPEasy_now_hdr ESPEasy_now_merger::getFirstHeader() const +uint8_t ESPEasy_now_merger::getExpectedNrPackets() const { - ESPEasy_now_hdr header; - auto it = _queue.find(0); + for (auto it = _queue.begin(); it != _queue.end(); ++it) { + if (it->second.valid()) { + return it->second.getHeader().nr_packets; + } + } + return 255; +} - if (it != _queue.end()) { - header = it->second.getHeader(); +ESPEasy_now_hdr::message_t ESPEasy_now_merger::getMessageType() const +{ + for (auto it = _queue.begin(); it != _queue.end(); ++it) { + if (it->second.valid()) { + return it->second.getHeader().message_type; + } } - return header; + return ESPEasy_now_hdr::message_t::NotSet; } unsigned long ESPEasy_now_merger::getFirstPacketTimestamp() const @@ -107,7 +110,7 @@ String ESPEasy_now_merger::getLogString() const log += F(" ("); log += _queue.size(); log += '/'; - log += getFirstHeader().nr_packets; + log += getExpectedNrPackets(); log += ')'; return log; } @@ -206,7 +209,7 @@ size_t ESPEasy_now_merger::getBinaryData(uint8_t *data, size_t length, size_t& p size_t payload_pos_in_packet; uint8_t packet_nr = findPacketWithPayloadPos(payload_pos, payload_pos_in_packet); - if (packet_nr >= getFirstHeader().nr_packets) { + if (packet_nr >= getExpectedNrPackets()) { return 0; } diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 324faa74a0..ca3736faf5 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -28,8 +28,6 @@ class ESPEasy_now_merger { // Check if all parts of the packet have been received bool messageComplete() const; - uint8_t receivedCount(uint8_t& nr_packets) const; - // Check of set has expired (not all packets received within timeout) bool expired() const; @@ -54,7 +52,8 @@ class ESPEasy_now_merger { size_t length, size_t & payload_pos) const; - ESPEasy_now_hdr getFirstHeader() const; + uint8_t getExpectedNrPackets() const; + ESPEasy_now_hdr::message_t getMessageType() const; bool getMac(uint8_t *mac) const; bool getMac(MAC_address& mac) const; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 052bd82497..f3fc079613 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -342,7 +342,7 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo mustKeep = true; bool considerActive = false; - switch (message.getFirstHeader().message_type) + switch (message.getMessageType()) { case ESPEasy_now_hdr::message_t::NotSet: case ESPEasy_now_hdr::message_t::ChecksumError: From 02b657c2479a20ae4eaed135b4ebec2fd5204263 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Feb 2021 15:05:57 +0100 Subject: [PATCH 076/404] [ESPEasy-NOW] Adapt TX power on RSSI + fix nodes list view Nodes not aware of ESPEasy-NOW do not include AP MAC in node struct data, so must not compare this data when trying to remove duplicate nodes. --- src/src/DataStructs/ESPEasy_now_splitter.cpp | 54 ++++++++++++++------ src/src/DataStructs/ESPEasy_now_splitter.h | 2 + src/src/DataStructs/NodesHandler.cpp | 4 +- src/src/WebServer/JSON.cpp | 4 ++ 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 84c94f131b..d07f4f3882 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -3,8 +3,10 @@ #ifdef USES_ESPEASY_NOW # include "../ESPEasyCore/ESPEasy_Log.h" +# include "../ESPEasyCore/ESPEasyWifi.h" # include "../DataStructs/TimingStats.h" # include "../Globals/Nodes.h" +# include "../Globals/Settings.h" # include "../Helpers/ESPEasy_time_calc.h" static uint8_t ESPEasy_now_message_count = 1; @@ -69,12 +71,7 @@ void ESPEasy_now_splitter::createNextPacket() bool ESPEasy_now_splitter::sendToBroadcast() { - uint8_t mac[6]; - - for (int i = 0; i < 6; ++i) { - mac[i] = 0xFF; - } - return send(mac, 0); + return send(getBroadcastMAC(), 0); } bool ESPEasy_now_splitter::send(const MAC_address& mac, @@ -165,6 +162,17 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) { START_TIMER; + int8_t rssi = 0; + const MAC_address mac(packet._mac); + const NodeStruct *nodeInfo = Nodes.getNodeByMac(packet._mac); + if (nodeInfo != nullptr) { + if (mac != getBroadcastMAC()) { + rssi = nodeInfo->getRSSI(); + } + if (channel == 0) { + channel = nodeInfo->channel; + } + } if (!WifiEspNow.hasPeer(packet._mac)) { // Only have a single temp peer added, so we don't run out of slots for peers. @@ -177,20 +185,25 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) last_tmp_mac.set(packet._mac); } - // Check to see if we know its channel - if (channel == 0) { - const NodeStruct *nodeInfo = Nodes.getNodeByMac(packet._mac); - - if (nodeInfo != nullptr) { - channel = nodeInfo->channel; - } - } - // FIXME TD-er: Not sure why, but setting the channel does not work well. WifiEspNow.addPeer(packet._mac, channel); // WifiEspNow.addPeer(packet._mac, 0); } + + { + // Set TX power based on RSSI of other ESPEasy NOW node. + // For broadcast messages power must be max. + float tx_pwr = 0; // Will be set higher based on RSSI when needed. + // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power + if (Settings.UseMaxTXpowerForSending() || rssi == 0) { + // Force highest power here, so assume the worst RSSI + rssi = -90; + tx_pwr = Settings.getWiFi_TX_power(); + } + SetWiFiTXpower(tx_pwr, rssi); + } + bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); STOP_TIMER(ESPEASY_NOW_SEND_PCKT); @@ -235,4 +248,15 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) return true; } +MAC_address ESPEasy_now_splitter::getBroadcastMAC() +{ + static MAC_address ESPEasy_now_broadcast_MAC; + if (ESPEasy_now_broadcast_MAC.mac[0] != 0xFF) { + for (int i = 0; i < 6; ++i) { + ESPEasy_now_broadcast_MAC.mac[i] = 0xFF; + } + } + return ESPEasy_now_broadcast_MAC; +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 71accb876c..0f86e446b4 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -39,6 +39,8 @@ class ESPEasy_now_splitter { WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; + static MAC_address getBroadcastMAC(); + std::vector_queue; ESPEasy_now_hdr _header; size_t _payload_pos = 255; // Position in the last packet where we left of. diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 01f3e2ace0..5a0867b183 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -17,7 +17,9 @@ void NodesHandler::addNode(const NodeStruct& node) // Erase any existing node with matching MAC address for (auto it = _nodes.begin(); it != _nodes.end(); ) { - if (node.match(it->second.sta_mac) || node.match(it->second.ap_mac)) { + const MAC_address sta(it->second.sta_mac); + const MAC_address ap(it->second.ap_mac); + if ((!sta.all_zero() && node.match(sta)) || (!ap.all_zero() && node.match(ap))) { rssi = it->second.getRSSI(); it = _nodes.erase(it); } else { diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 036339c6d8..f6da21ad2c 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -249,6 +249,10 @@ void handle_json() if (it->second.nodeType) { stream_next_json_object_value(F("platform"), it->second.getNodeTypeDisplayString()); } + const int8_t rssi = it->second.getRSSI(); + if (rssi < 0) { + stream_next_json_object_value(F("rssi"), String(rssi)); + } stream_next_json_object_value(F("ip"), it->second.IP().toString()); stream_last_json_object_value(F("age"), String(it->second.getAge() / 1000)); // time in seconds } // if node info exists From 77275eebd3717a501823617a82ca8086dcaea692 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Feb 2021 17:20:02 +0100 Subject: [PATCH 077/404] [ESPEasy-NOW] Use hidden ESPEasy-now AP for stability For stability of ESPEasy-NOW protocol it is better to connect to a virtual AP hosted by some other ESPEasy-NOW node. We don't send data over it, but it prevents some very nasty (undocumented) power management in the closed source wifi libraries of Espressif to kick in and mess up the ESPEasy-NOW layer. --- src/src/DataStructs/NodesHandler.cpp | 34 ++++++++++++++++++++-- src/src/DataStructs/NodesHandler.h | 2 ++ src/src/DataStructs/WiFi_AP_Candidate.cpp | 5 ++++ src/src/Helpers/Networking.cpp | 7 +++++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 8 ++++- src/src/WebServer/RootPage.cpp | 8 ++--- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 5a0867b183..889e4cc54b 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -8,6 +8,7 @@ #include "../Helpers/PeriodicalActions.h" #include "../Globals/ESPEasy_time.h" #include "../Globals/MQTT.h" +#include "../Globals/RTC.h" #include "../Globals/Settings.h" void NodesHandler::addNode(const NodeStruct& node) @@ -139,10 +140,19 @@ void NodesHandler::updateThisNode() { WiFi.macAddress(thisNode.sta_mac); WiFi.softAPmacAddress(thisNode.ap_mac); { - IPAddress localIP = NetworkLocalIP(); + bool addIP = true; + #ifdef USES_ESPEASY_NOW + if (RTC.lastWiFiSettingsIndex == 3) { + // Connected via 'virtual ESPEasy-now AP' + addIP = false; + } + #endif + if (addIP) { + IPAddress localIP = NetworkLocalIP(); - for (byte i = 0; i < 4; ++i) { - thisNode.ip[i] = localIP[i]; + for (byte i = 0; i < 4; ++i) { + thisNode.ip[i] = localIP[i]; + } } } thisNode.channel = WiFi.channel(); @@ -176,6 +186,7 @@ void NodesHandler::updateThisNode() { if (isEndpoint()) { _distance = 0; } else { + const uint8_t lastDistance = _distance; _distance = 255; const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); @@ -183,6 +194,14 @@ void NodesHandler::updateThisNode() { if (preferred->distance < 255 && !preferred->isExpired()) { _distance = preferred->distance + 1; _lastTimeValidDistance = millis(); + if (_distance != lastDistance) { + #ifdef USES_ESPEASY_NOW + if (RTC.lastWiFiSettingsIndex == 3 && WiFiConnected()) { + RTC.clearLastWiFi(); // Force a WiFi scan + WifiDisconnect(); + } + #endif + } } } } @@ -250,6 +269,15 @@ bool NodesHandler::isEndpoint() const return false; } +uint8_t NodesHandler::getESPEasyNOW_channel() const +{ + const NodeStruct *preferred = getPreferredNode(); + if (preferred != nullptr) { + return preferred->channel; + } + return 0; +} + bool NodesHandler::lastTimeValidDistanceExpired() const { // if (_lastTimeValidDistance == 0) return false; diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index cc63ee3b7a..ae443a8875 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -52,6 +52,8 @@ class NodesHandler { bool isEndpoint() const; + uint8_t getESPEasyNOW_channel() const; + private: unsigned long _lastTimeValidDistance = 0; diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index ac4023bd2a..1ed6040669 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -42,6 +42,11 @@ bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { if (other.rssi >= 0) { return true; } + // Prefer non hidden over hidden. + if (isHidden != other.isHidden) { + return !isHidden; + } + // RSSI values are negative, so the larger value is the better one. return rssi > other.rssi; } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 791f061b7c..80d41f8c72 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -385,6 +385,13 @@ void refreshNodeList() const unsigned long max_age_allowed = 10 * 60 * 1000; // 10 minutes Nodes.refreshNodeList(max_age_allowed, max_age); + #ifdef USES_ESPEASY_NOW + const uint8_t channel = Nodes.getESPEasyNOW_channel(); + if (channel != 0) { + WifiScan(true, channel); + } + #endif + if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 7154d8bf3a..f05d4bcc07 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -159,7 +159,13 @@ bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { void WiFi_AP_CandidatesList::add(uint8_t networkItem) { WiFi_AP_Candidate tmp(networkItem); - if (tmp.isHidden && Settings.IncludeHiddenSSID()) { + const bool inclHiddenSSID = + #ifdef USES_ESPEASY_NOW + Settings.UseESPEasyNow() || + #endif + Settings.IncludeHiddenSSID(); + + if (tmp.isHidden && inclHiddenSSID) { candidates.push_back(tmp); return; } diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 4428fcf73d..f56e554cfb 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -266,9 +266,9 @@ void handle_root() { html += ':'; html += String(port); } - html += "'>"; + html += F("'>"); html += it->second.IP().toString(); - html += ""; + html += F(""); addHtml(html); } html_TD(); @@ -291,10 +291,10 @@ void handle_root() { addHtml(String(it->second.channel)); int8_t rssi = it->second.getRSSI(); if (rssi < 0) { - addHtml(F(" ")); + addHtml(' '); addHtml(String(rssi)); } - addHtml(F(")")); + addHtml(')'); } #endif } From ebefab510d345b4fde0a1e13dd89755d92d3a685 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 16 Feb 2021 13:21:11 +0100 Subject: [PATCH 078/404] [ESPEasy-NOW] Connect to known AP as soon as it is seen again Allowing to reconnect to a known AP instead of via ESPEasy-NOW layer as soon as known AP is seen again. --- src/src/DataStructs/NodesHandler.cpp | 7 +++++-- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 5 ++++- src/src/Helpers/Networking.cpp | 3 ++- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 10 +++++++--- src/src/Helpers/WiFi_AP_CandidatesList.h | 6 +++++- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 889e4cc54b..eb63611322 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -10,6 +10,7 @@ #include "../Globals/MQTT.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" +#include "../Globals/WiFi_AP_Candidates.h" void NodesHandler::addNode(const NodeStruct& node) { @@ -142,7 +143,7 @@ void NodesHandler::updateThisNode() { { bool addIP = true; #ifdef USES_ESPEASY_NOW - if (RTC.lastWiFiSettingsIndex == 3) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { // Connected via 'virtual ESPEasy-now AP' addIP = false; } @@ -196,7 +197,9 @@ void NodesHandler::updateThisNode() { _lastTimeValidDistance = millis(); if (_distance != lastDistance) { #ifdef USES_ESPEASY_NOW - if (RTC.lastWiFiSettingsIndex == 3 && WiFiConnected()) { + if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFiConnected()) { + // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP + // Try to reconnect to it. RTC.clearLastWiFi(); // Force a WiFi scan WifiDisconnect(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 6147719f91..e9df09142b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -450,7 +450,10 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); - if (WiFiEventData.espeasy_now_only) { return; } + if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFi_AP_Candidates.addedKnownCandidate() && WiFiConnected()) { + RTC.clearLastWiFi(); // Force a WiFi scan + WifiDisconnect(); + } else if (WiFiEventData.espeasy_now_only) { return; } #endif const WiFi_AP_Candidate bestCandidate = WiFi_AP_Candidates.getBestScanResult(); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index ad443e2099..fd65a508e8 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -385,7 +385,8 @@ void refreshNodeList() const unsigned long max_age_allowed = 10 * 60 * 1000; // 10 minutes Nodes.refreshNodeList(max_age_allowed, max_age); - #ifdef USES_ESPEASY_NOW + #if defined(USES_ESPEASY_NOW) && defined(ESP8266) + // ESP32 does not (yet) allow to scan a single channel so may take too long const uint8_t channel = Nodes.getESPEasyNOW_channel(); if (channel != 0) { WifiScan(true, channel); diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index f05d4bcc07..5d9e6d5ec2 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -16,10 +16,11 @@ WiFi_AP_CandidatesList::WiFi_AP_CandidatesList() { } void WiFi_AP_CandidatesList::load_knownCredentials() { - if (!mustLoadCredentials) { return; } - mustLoadCredentials = false; + if (!_mustLoadCredentials) { return; } + _mustLoadCredentials = false; known.clear(); candidates.clear(); + _addedKnownCandidate = false; addFromRTC(); { @@ -37,7 +38,7 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { } void WiFi_AP_CandidatesList::clearCache() { - mustLoadCredentials = true; + _mustLoadCredentials = true; known.clear(); known_it = known.begin(); } @@ -52,6 +53,7 @@ void WiFi_AP_CandidatesList::force_reload() { void WiFi_AP_CandidatesList::process_WiFiscan(uint8_t scancount) { load_knownCredentials(); candidates.clear(); + _addedKnownCandidate = false; known_it = known.begin(); @@ -147,6 +149,7 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { } } candidates.clear(); + _addedKnownCandidate = false; addFromRTC(); // Store the current one from RTC as the first candidate for a reconnect. } @@ -179,6 +182,7 @@ void WiFi_AP_CandidatesList::add(uint8_t networkItem) { if (tmp.usable()) { candidates.push_back(tmp); + _addedKnownCandidate = true; // Do not return as we may have several AP's with the same SSID and different passwords. } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 867e54044e..da8bb96374 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -38,6 +38,8 @@ struct WiFi_AP_CandidatesList { bool isESPEasy_now_only() const; #endif + bool addedKnownCandidate() const { return _addedKnownCandidate; } + private: // Add item from WiFi scan. @@ -60,7 +62,9 @@ struct WiFi_AP_CandidatesList { WiFi_AP_Candidate currentCandidate; - bool mustLoadCredentials = true; + bool _mustLoadCredentials = true; + + bool _addedKnownCandidate = false; }; #endif // ifndef HELPERS_WIFI_AP_CANDIDATESLIST_H From 689fa5d9992a396c6dd5fabb77142884a41a6a87 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 17 Feb 2021 15:54:16 +0100 Subject: [PATCH 079/404] [ESPEasy-NOW] Keep ESPEasy-NOW knowledge if data is received via ethernet --- src/src/DataStructs/NodeStruct.cpp | 7 ++++ src/src/DataStructs/NodeStruct.h | 2 + src/src/DataStructs/NodesHandler.cpp | 28 +++++++++++-- src/src/DataStructs/NodesHandler.h | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 52 +++++++++++-------------- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index c853153280..1532bea633 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -121,6 +121,7 @@ MAC_address NodeStruct::STA_MAC() const { } MAC_address NodeStruct::ESPEasy_Now_MAC() const { + if (ESPEasyNowPeer == 0) return MAC_address(); if (useAP_ESPEasyNow) { return MAC_address(ap_mac); } @@ -161,6 +162,7 @@ String NodeStruct::getSummary() const { bool NodeStruct::setESPEasyNow_mac(const MAC_address& received_mac) { + if (received_mac.all_zero()) return false; if (received_mac == sta_mac) { ESPEasyNowPeer = 1; useAP_ESPEasyNow = 0; @@ -234,4 +236,9 @@ bool NodeStruct::markedAsPriorityPeer() const bool NodeStruct::match(const MAC_address& mac) const { return (mac == sta_mac || mac == ap_mac); +} + +void NodeStruct::setAP_MAC(const MAC_address& mac) +{ + mac.get(ap_mac); } \ No newline at end of file diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 803d835f24..405cbf306d 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -65,6 +65,8 @@ struct __attribute__((__packed__)) NodeStruct bool match(const MAC_address& mac) const; + void setAP_MAC(const MAC_address& mac); + // Do not change the order of this data, as it is being sent via P2P UDP. // 6 byte mac (STA interface) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index eb63611322..50c652e9be 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -12,17 +12,29 @@ #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" -void NodesHandler::addNode(const NodeStruct& node) +bool NodesHandler::addNode(const NodeStruct& node) { int8_t rssi = 0; + MAC_address match_sta; + MAC_address match_ap; + MAC_address ESPEasy_NOW_MAC; + + bool isNewNode = true; // Erase any existing node with matching MAC address for (auto it = _nodes.begin(); it != _nodes.end(); ) { - const MAC_address sta(it->second.sta_mac); - const MAC_address ap(it->second.ap_mac); + const MAC_address sta = it->second.sta_mac; + const MAC_address ap = it->second.ap_mac; if ((!sta.all_zero() && node.match(sta)) || (!ap.all_zero() && node.match(ap))) { rssi = it->second.getRSSI(); + if (!sta.all_zero()) + match_sta = sta; + if (!ap.all_zero()) + match_ap = ap; + ESPEasy_NOW_MAC = it->second.ESPEasy_Now_MAC(); + + isNewNode = false; it = _nodes.erase(it); } else { ++it; @@ -30,9 +42,17 @@ void NodesHandler::addNode(const NodeStruct& node) } _nodes[node.unit] = node; _nodes[node.unit].lastUpdated = millis(); - if (node.getRSSI() >= 0) { + if (node.getRSSI() >= 0 && rssi < 0) { _nodes[node.unit].setRSSI(rssi); } + const MAC_address node_ap(node.ap_mac); + if (node_ap.all_zero()) { + _nodes[node.unit].setAP_MAC(node_ap); + } + if (node.ESPEasy_Now_MAC().all_zero()) { + _nodes[node.unit].setESPEasyNow_mac(ESPEasy_NOW_MAC); + } + return isNewNode; } bool NodesHandler::hasNode(uint8_t unit_nr) const diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index ae443a8875..69d8b726c4 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -8,7 +8,9 @@ class NodesHandler { public: - void addNode(const NodeStruct& node); + // Add node to the list of known nodes. + // @retval true when the node was not yet present in the list. + bool addNode(const NodeStruct& node); bool hasNode(uint8_t unit_nr) const; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f3fc079613..301ae4af55 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -312,21 +312,20 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) tmpNodeInfo.setESPEasyNow_mac(peer_mac); if (tmpNodeInfo.markedAsPriorityPeer()) { - Nodes.addNode(tmpNodeInfo); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-Now: Found node via WiFi scan: "); - log += peer_mac.toString(); - log += F(" "); - log += tmpNodeInfo.getRSSI(); - log += F(" dBm ch: "); - log += tmpNodeInfo.channel; - addLog(LOG_LEVEL_INFO, log); - } + if (Nodes.addNode(tmpNodeInfo)) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-Now: Found node via WiFi scan: "); + log += peer_mac.toString(); + log += F(" "); + log += tmpNodeInfo.getRSSI(); + log += F(" dBm ch: "); + log += tmpNodeInfo.channel; + addLog(LOG_LEVEL_INFO, log); + } - // Must trigger a discovery request from the node. - // FIXME TD-er: Disable auto discovery for now - // sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + // Must trigger a discovery request from the node. + sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + } } } } @@ -427,17 +426,14 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (!received.setESPEasyNow_mac(mac)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - log = F("ESPEasy Now: Received discovery message from MAC not stated in message: "); + log = F("ESPEasy-NOW: Received discovery message from MAC not stated in message: "); log += mac.toString(); addLog(LOG_LEVEL_ERROR, log); } return false; } - // FIXME TD-er: Disable auto discovery for now - // bool isNewNode = Nodes.getNodeByMac(mac) == nullptr; - - Nodes.addNode(received); + bool isNewNode = Nodes.addNode(received); // Test to see if the discovery announce could be a good candidate for next NTP query. _best_NTP_candidate.find_best_NTP( @@ -449,20 +445,16 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m String log; size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); - log = F("ESPEasy Now discovery: "); + log = F("ESPEasy-NOW discovery: "); log += message.getLogString(); log += '\n'; log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); } - // FIXME TD-er: Disable auto discovery for now - - /* - if (isNewNode) { - sendDiscoveryAnnounce(mac); - } - */ + if (isNewNode) { + sendDiscoveryAnnounce(mac); + } const uint8_t new_distance = Nodes.getDistance(); if (new_distance != cur_distance) { @@ -633,7 +625,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge query.setState(queue_full); if (loglevelActiveFor(LOG_LEVEL_INFO) && queue_full) { - addLog(LOG_LEVEL_INFO, F("ESPEasy Now: After MQTT message received: Full")); + addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW: After MQTT message received: Full")); } sendMQTTCheckControllerQueue(mac, 0, query.state); } @@ -716,7 +708,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { String log; - log = F("ESPEasy Now: Received Queue state: "); + log = F("ESPEasy-NOW: Received Queue state: "); log += _preferredNodeMQTTqueueState.isFull() ? F("Full") : F("not Full"); addLog(LOG_LEVEL_DEBUG_MORE, log); } @@ -729,7 +721,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me // We have to give our own queue state and reply query.setState(MQTT_queueFull(controllerIndex)); - // addLog(LOG_LEVEL_INFO, F("ESPEasy Now: reply to queue state query")); + // addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW: reply to queue state query")); size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); msg.addBinaryData(reinterpret_cast(&query), len); From 3f82321865a7563acf01d419b133b30ce6e29298 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 17 Feb 2021 15:54:51 +0100 Subject: [PATCH 080/404] [ESPEasy-NOW] uniform use of strings of ESPEasy-NOW in logs. --- src/_C019.ino | 4 ++-- src/_P098_ESPEasyNowReceiver.ino | 4 ++-- src/src/ControllerQueue/C019_queue_element.h | 2 +- src/src/CustomBuild/ESPEasyLimits.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 4 ++-- src/src/DataStructs/ESPEasy_now_splitter.cpp | 10 +++++----- src/src/DataStructs/NodeStruct.h | 8 ++++---- src/src/DataStructs/NodesHandler.cpp | 4 ++-- .../SendData_DuplicateChecker_struct.cpp | 2 +- src/src/DataStructs/TimingStats.cpp | 14 +++++++------- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 16 ++++++++-------- src/src/Helpers/StringProvider.cpp | 4 ++-- src/src/Helpers/_CPlugin_Helper_webform.cpp | 2 +- src/src/WebServer/ConfigPage.cpp | 2 +- src/src/WebServer/RootPage.cpp | 2 +- tools/pio/pre_custom_esp32.py | 4 ++-- tools/pio/pre_custom_esp82xx.py | 4 ++-- 19 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/_C019.ino b/src/_C019.ino index 027ccd66ce..cf139e7c05 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -1,7 +1,7 @@ #ifdef USES_C019 // ####################################################################################################### -// ################### Controller Plugin 019: ESPEasy-Now ################################################ +// ################### Controller Plugin 019: ESPEasy-NOW ################################################ // ####################################################################################################### #include "ESPEasy_fdwdecl.h" @@ -13,7 +13,7 @@ #define CPLUGIN_019 #define CPLUGIN_ID_019 19 -#define CPLUGIN_NAME_019 "ESPEasy-Now" +#define CPLUGIN_NAME_019 "ESPEasy-NOW" bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& string) { diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 067f69ebec..768b9389c7 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -2,7 +2,7 @@ #ifdef USES_P098 // ####################################################################################################### -// #################################### Plugin 098: ESPEasy-Now Receiver ################################# +// #################################### Plugin 098: ESPEasy-NOW Receiver ################################# // ####################################################################################################### @@ -11,7 +11,7 @@ #define PLUGIN_098 #define PLUGIN_ID_098 98 -#define PLUGIN_NAME_098 "Generic - ESPEasy-Now Receiver" +#define PLUGIN_NAME_098 "Generic - ESPEasy-NOW Receiver" #define PLUGIN_VALUENAME1_098 "Value" diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 307c8d738f..e60e7e79dd 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -10,7 +10,7 @@ // #ifdef USES_C019 /*********************************************************************************************\ -* C019_queue_element for queueing requests for C019: ESPEasy-Now +* C019_queue_element for queueing requests for C019: ESPEasy-NOW \*********************************************************************************************/ diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index 4758ee9513..6a0b285ac9 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -65,7 +65,7 @@ // *********************************************************************** -// * ESPEasy-Now related limits +// * ESPEasy-NOW related limits // *********************************************************************** #ifndef ESPEASY_NOW_PEER_MAX diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index b65b02b701..89126620f7 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -920,7 +920,7 @@ To create/register a plugin, you have to : //#define USES_P095 // TFT ILI9341 //#define USES_P096 // eInk (Needs lib_deps = Adafruit GFX Library, LOLIN_EPD ) #define USES_P097 // Touch (ESP32) - #define USES_P098 // ESPEasy-Now Reader + #define USES_P098 // ESPEasy-NOW Reader //#define USES_P099 // XPT2046 Touchscreen #define USES_P100 // Pulse Counter - DS2423 #define USES_P101 // Wake On Lan @@ -1007,7 +1007,7 @@ To create/register a plugin, you have to : //#define USES_C015 // Blynk #define USES_C017 // Zabbix // #define USES_C018 // TTN RN2483 - // #define USES_C019 // ESPEasy-Now + // #define USES_C019 // ESPEasy-NOW #endif diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 4ac657a62c..1c0ddaa9b9 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -124,7 +124,7 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(64); - log = F("ESPEasy Now: Best NTP peer: "); + log = F("ESPEasy-NOW: Best NTP peer: "); log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; @@ -210,7 +210,7 @@ void ESPEasy_Now_NTP_query::createReply(unsigned long queryReceiveTimestamp) if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(64); - log = F("ESPEasy Now: Create NTP reply to: "); + log = F("ESPEasy-NOW: Create NTP reply to: "); log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index d07f4f3882..917c8b7888 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -118,17 +118,17 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t switch (sendStatus) { case WifiEspNowSendStatus::NONE: { - log = F("ESPEasy Now: TIMEOUT to: "); + log = F("ESPEasy-NOW: TIMEOUT to: "); break; } case WifiEspNowSendStatus::FAIL: { - log = F("ESPEasy Now: Sent FAILED to: "); + log = F("ESPEasy-NOW: Sent FAILED to: "); break; } case WifiEspNowSendStatus::OK: { - log = F("ESPEasy Now: Sent to: "); + log = F("ESPEasy-NOW: Sent to: "); break; } } @@ -192,7 +192,7 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) } { - // Set TX power based on RSSI of other ESPEasy NOW node. + // Set TX power based on RSSI of other ESPEasy-NOW node. // For broadcast messages power must be max. float tx_pwr = 0; // Will be set higher based on RSSI when needed. // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power @@ -241,7 +241,7 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) _queue[i].setHeader(header); _queue[i].setMac(mac); if (!_queue[i].valid()) { - addLog(LOG_LEVEL_ERROR, F("ESPEasy Now: Could not prepare for send")); + addLog(LOG_LEVEL_ERROR, F("ESPEasy-NOW: Could not prepare for send")); return false; } } diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 405cbf306d..cdf9e5cfef 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -28,9 +28,9 @@ struct __attribute__((__packed__)) NodeStruct bool validate(); // Compare nodes. - // Return true when this node has better credentials to be used as ESPEasy-Now neighbor + // Return true when this node has better credentials to be used as ESPEasy-NOW neighbor // - Shorter distance to a network connected gateway node. - // - confirmed ESPEasy-Now peer + // - confirmed ESPEasy-NOW peer // - better RSSI // - lower load (TODO TD-er) bool operator<(const NodeStruct &other) const; @@ -95,8 +95,8 @@ struct __attribute__((__packed__)) NodeStruct uint8_t distance = 255; // Administrative distance for routing uint8_t timeSource = static_cast(timeSource_t::No_time_source); uint8_t channel = 0; // The WiFi channel used - uint8_t ESPEasyNowPeer : 1; // Signalling if the node is an ESPEasy-Now peer - uint8_t useAP_ESPEasyNow : 1; // ESPEasy-Now can either use STA or AP for communications. + uint8_t ESPEasyNowPeer : 1; // Signalling if the node is an ESPEasy-NOW peer + uint8_t useAP_ESPEasyNow : 1; // ESPEasy-NOW can either use STA or AP for communications. uint8_t scaled_rssi : 6; // "shortened" RSSI value // When sending system info, this value contains the time since last time sync. diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 50c652e9be..52380eec35 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -164,7 +164,7 @@ void NodesHandler::updateThisNode() { bool addIP = true; #ifdef USES_ESPEASY_NOW if (WiFi_AP_Candidates.isESPEasy_now_only()) { - // Connected via 'virtual ESPEasy-now AP' + // Connected via 'virtual ESPEasy-NOW AP' addIP = false; } #endif @@ -282,7 +282,7 @@ bool NodesHandler::isEndpoint() const controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(enabledMqttController)) { // FIXME TD-er: Must call updateMQTTclient_connected() and see what effect - // the MQTTclient_connected state has when using ESPEasy-now. + // the MQTTclient_connected state has when using ESPEasy-NOW. return MQTTclient.connected(); } #endif diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 97dd3f2882..7030fd058a 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -68,7 +68,7 @@ void SendData_DuplicateChecker_struct::remove(uint32_t key) auto it = _queue.find(key); if (it != _queue.end()) { - addLog(LOG_LEVEL_DEBUG, F("ESPEasy-Now message not sent as processed elsewhere")); + addLog(LOG_LEVEL_DEBUG, F("ESPEasy-NOW message not sent as processed elsewhere")); _queue.erase(it); } } diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 1816954854..fbc3aa2aed 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -230,14 +230,14 @@ String getMiscStatsName(int stat) { case PARSE_SYSVAR: return F("parseSystemVariables()"); case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); - case HANDLE_ESPEASY_NOW_LOOP: return F("Handle Received ESPEasy Now message"); - case EXPIRED_ESPEASY_NOW_LOOP: return F("ESPEasy Now incomplete expired"); - case INVALID_ESPEASY_NOW_LOOP: return F("ESPEasy Now incomplete invalid"); + case HANDLE_ESPEASY_NOW_LOOP: return F("Handle Received ESPEasy-NOW message"); + case EXPIRED_ESPEASY_NOW_LOOP: return F("ESPEasy-NOW incomplete expired"); + case INVALID_ESPEASY_NOW_LOOP: return F("ESPEasy-NOW incomplete invalid"); case RECEIVE_ESPEASY_NOW_LOOP: return F("ESPEasy_now_onReceive()"); - case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy Now send Message Success"); - case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy Now send Message Fail"); - case ESPEASY_NOW_SEND_PCKT: return F("ESPEasy Now send Packet"); - case ESPEASY_NOW_DEDUP_LOOP: return F("ESPEasy Now DuplicateCheck loop"); + case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy-NOW send Message Success"); + case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy-NOW send Message Fail"); + case ESPEASY_NOW_SEND_PCKT: return F("ESPEasy-NOW send Packet"); + case ESPEASY_NOW_DEDUP_LOOP: return F("ESPEasy-NOW DuplicateCheck loop"); case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time"); case C001_DELAY_QUEUE: case C002_DELAY_QUEUE: diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index e9df09142b..d99d4d42d1 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -363,7 +363,7 @@ void processProbeRequestAPmode() { addLog(LOG_LEVEL_INFO, log); } - // FIXME TD-er: Must create an answer for ESPEasy-now node discovery + // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.sendDiscoveryAnnounce(); #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 301ae4af55..bc24f3bd13 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -125,13 +125,13 @@ bool ESPEasy_now_handler_t::begin() // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-Now: begin on channel "); + String log = F("ESPEasy-NOW: begin on channel "); log += channel; addLog(LOG_LEVEL_INFO, log); } if (!WifiEspNow.begin()) { - addLog(LOG_LEVEL_ERROR, F("ESPEasy-Now: Failed to initialize ESPEasy-Now")); + addLog(LOG_LEVEL_ERROR, F("ESPEasy-NOW: Failed to initialize ESPEasy-NOW")); return false; } @@ -154,7 +154,7 @@ bool ESPEasy_now_handler_t::begin() sendDiscoveryAnnounce(); use_EspEasy_now = true; - addLog(LOG_LEVEL_INFO, F("ESPEasy-Now enabled")); + addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW enabled")); return true; } @@ -167,7 +167,7 @@ void ESPEasy_now_handler_t::end() WifiEspNow.end(); _last_used = 0; } - addLog(LOG_LEVEL_INFO, F("ESPEasy-Now disabled")); + addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW disabled")); } bool ESPEasy_now_handler_t::loop() @@ -304,7 +304,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) nodeInfo->setRSSI(WiFi.RSSI(scanIndex)); nodeInfo->channel = WiFi.channel(scanIndex); } else { - // FIXME TD-er: For now we assume the other node uses AP for ESPEasy-now + // FIXME TD-er: For now we assume the other node uses AP for ESPEasy-NOW NodeStruct tmpNodeInfo; tmpNodeInfo.setRSSI(WiFi.RSSI(scanIndex)); tmpNodeInfo.channel = WiFi.channel(scanIndex); @@ -314,7 +314,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) if (tmpNodeInfo.markedAsPriorityPeer()) { if (Nodes.addNode(tmpNodeInfo)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-Now: Found node via WiFi scan: "); + String log = F("ESPEasy-NOW: Found node via WiFi scan: "); log += peer_mac.toString(); log += F(" "); log += tmpNodeInfo.getRSSI(); @@ -333,7 +333,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-Now received "); + String log = F("ESPEasy-NOW received "); log += message.getLogString(); addLog(LOG_LEVEL_INFO, log); } @@ -476,7 +476,7 @@ void ESPEasy_now_handler_t::sendNTPquery() if (!_best_NTP_candidate.getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-Now: Send NTP query to: "); + String log = F("ESPEasy-NOW: Send NTP query to: "); log += mac.toString(); addLog(LOG_LEVEL_INFO, log); } diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 9d9deb61c2..c4a0ea449c 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -110,8 +110,8 @@ String getLabel(LabelType::Enum label) { case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); #ifdef USES_ESPEASY_NOW - case LabelType::USE_ESPEASY_NOW: return F("Use ESPEasy-Now"); - case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable ESPEasy-Now"); + case LabelType::USE_ESPEASY_NOW: return F("Use ESPEasy-NOW"); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable ESPEasy-NOW"); #endif diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index c38a6c575c..8944cd4ca8 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -61,7 +61,7 @@ String getControllerParameterName(protocolIndex_t ProtocolInde case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: name = F("Send Binary"); break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: name = F("Client Timeout"); break; case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: name = F("Sample Set Initiator"); break; - case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: name = F("Enable ESPEasy-Now Fallback"); break; + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: name = F("Enable ESPEasy-NOW Fallback"); break; case ControllerSettingsStruct::CONTROLLER_ENABLED: diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index f76cce6dd0..f1e5371978 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -203,7 +203,7 @@ void handle_config() { #endif #ifdef USES_ESPEASY_NOW - addFormSubHeader(F("ESPEasy Now")); + addFormSubHeader(F("ESPEasy-NOW")); for (int peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { String label = F("Peer "); label += String(peer + 1); diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index f56e554cfb..78f5d3c303 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -285,7 +285,7 @@ void handle_root() { } html_TD(); if (it->second.ESPEasyNowPeer) { - addHtml(F("ESPEasy-Now ")); + addHtml(F("ESPEasy-NOW ")); addHtml(it->second.ESPEasy_Now_MAC().toString()); addHtml(F(" (ch: ")); addHtml(String(it->second.channel)); diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index b6a04c0203..d917d30147 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -45,14 +45,14 @@ # "-DUSES_P094", # CUL Reader # "-DUSES_P095", # TFT ILI9341 "-DUSES_P097", # Touch (ESP32) - "-DUSES_P098", # ESPEasy-Now Reader + "-DUSES_P098", # ESPEasy-NOW Reader "-DUSES_P106", # BME680 "-DUSES_P107", # SI1145 UV index # "-DUSES_C015", # Blynk "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 - "-DUSES_C019", # ESPEasy-Now + "-DUSES_C019", # ESPEasy-NOW "-DFEATURE_SD", diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index d7551869c1..6a1b967491 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -47,12 +47,12 @@ # "-DUSES_P095", # TFT ILI9341 "-DUSES_P106", # BME680 "-DUSES_P107", # SI1145 UV index - "-DUSES_P098", # ESPEasy-Now Reader + "-DUSES_P098", # ESPEasy-NOW Reader # "-DUSES_C015", # Blynk "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 - "-DUSES_C019", # ESPEasy-Now + "-DUSES_C019", # ESPEasy-NOW "-DFEATURE_MDNS", "-DFEATURE_SD", From 1d2370ffb61b39dad7b1e261e66ca0fa2e0bbf9e Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 19 Feb 2021 13:22:37 +0100 Subject: [PATCH 081/404] [ESPEasy-NOW] Add some checks for out-of-memory issues --- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 2 + src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 8 ++- src/src/Helpers/ESPEasy_now_handler.cpp | 73 ++++++++++++-------- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 96275fdd39..0220eda959 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -75,6 +75,7 @@ bool ESPEasy_Now_p2p_data::addBinaryData(uint8_t *binaryData, size_t size) { const uint8_t * ESPEasy_Now_p2p_data::getBinaryData(size_t offset, size_t& size) const { if (offset >= dataSize) { + size = 0; return nullptr; } @@ -92,6 +93,7 @@ uint8_t * ESPEasy_Now_p2p_data::prepareBinaryData(size_t& size) { data = nullptr; if (!allocate(size, oldSize)) { + size = 0; return nullptr; } size = dataSize; diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index b0fa61e2b4..0f6a5d5e0e 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -19,7 +19,7 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *bu { setSize(packetSize); mac.get(_mac); - size_t bufsize = _buf.size(); + const size_t bufsize = _buf.size(); if (packetSize > bufsize) { // Cannot store the whole packet, so consider it as invalid. packetSize = bufsize; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 917c8b7888..694eec1786 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -19,11 +19,17 @@ ESPEasy_now_splitter::ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_ty size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) { + if (data == nullptr) { + return 0; + } size_t data_left = length; while ((data_left > 0) && (_totalSize > _bytesStored)) { createNextPacket(); - size_t bytesAdded = _queue.back().addBinaryData(data, data_left, _payload_pos); + const size_t bytesAdded = _queue.back().addBinaryData(data, data_left, _payload_pos); + if (bytesAdded == 0) { + return length - data_left; + } data_left -= bytesAdded; data += bytesAdded; _bytesStored += bytesAdded; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index bc24f3bd13..6aee459990 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -400,10 +400,11 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch // Should not happen return; } - size_t len = sizeof(NodeStruct); + const size_t len = sizeof(NodeStruct); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); - msg.addBinaryData(reinterpret_cast(thisNode), len); - msg.send(mac, channel); + if (len == msg.addBinaryData(reinterpret_cast(thisNode), len)) { + msg.send(mac, channel); + } } bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep) @@ -483,10 +484,12 @@ void ESPEasy_now_handler_t::sendNTPquery() _best_NTP_candidate.markSendTime(); ESPEasy_Now_NTP_query query; - size_t len = sizeof(ESPEasy_Now_NTP_query); + const size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); - msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(mac.mac); + + if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { + msg.send(mac.mac); + } } void ESPEasy_now_handler_t::sendNTPbroadcast() @@ -494,10 +497,11 @@ void ESPEasy_now_handler_t::sendNTPbroadcast() ESPEasy_Now_NTP_query query; query.createBroadcastNTP(); - size_t len = sizeof(ESPEasy_Now_NTP_query); + const size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); - msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(query._mac); + if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { + msg.send(query._mac); + } } bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, bool& mustKeep) @@ -519,11 +523,13 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // Fill the reply query.createReply(message.getFirstPacketTimestamp()); - size_t len = sizeof(ESPEasy_Now_NTP_query); + const size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); - msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(query._mac); - return true; + if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { + msg.send(query._mac); + return true; + } + return false; } // Received a reply on our own query @@ -576,8 +582,12 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTControllerMessage, len); - msg.addString(topic); - msg.addString(payload); + if (topic_length != msg.addString(topic)) { + return false; + } + if (payload_length != msg.addString(payload)) { + return false; + } MAC_address mac = preferred->ESPEasy_Now_MAC(); WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * _ClientTimeout, preferred->channel); @@ -668,9 +678,11 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address ESPEasy_Now_MQTT_queue_check_packet query; query.state = state; - size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); + const size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); - msg.addBinaryData(reinterpret_cast(&query), len); + if (len != msg.addBinaryData(reinterpret_cast(&query), len)) { + return false; + } size_t timeout = 10; WifiEspNowSendStatus sendStatus = msg.send(mac, timeout, channel); @@ -722,11 +734,12 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me query.setState(MQTT_queueFull(controllerIndex)); // addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW: reply to queue state query")); - size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); + const size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); - msg.addBinaryData(reinterpret_cast(&query), len); - msg.send(mac); - return true; + if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { + msg.send(mac); + return true; + } } } } @@ -744,10 +757,12 @@ void ESPEasy_now_handler_t::sendSendData_DuplicateCheck(uint32_t const MAC_address & mac) { ESPEasy_Now_DuplicateCheck check(key, message_type); - size_t len = sizeof(ESPEasy_Now_DuplicateCheck); + const size_t len = sizeof(ESPEasy_Now_DuplicateCheck); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::SendData_DuplicateCheck, len); - msg.addBinaryData(reinterpret_cast(&check), len); + if (len != msg.addBinaryData(reinterpret_cast(&check), len)) { + return; + } switch (message_type) { case ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck: @@ -857,14 +872,18 @@ void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t contr bool ESPEasy_now_handler_t::sendESPEasyNow_p2p(controllerIndex_t controllerIndex, const MAC_address& mac, const ESPEasy_Now_p2p_data& data) { if (!use_EspEasy_now) { return false; } - size_t size = data.getTotalSize(); - ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::P2P_data, size); + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::P2P_data, data.getTotalSize()); // Add the first part of the data object, without the data array. - msg.addBinaryData(reinterpret_cast(&data), data.dataOffset); + if (data.dataOffset != msg.addBinaryData(reinterpret_cast(&data), data.dataOffset)) { + return false; + } // Fetch the data array information, will also update size. + size_t size = 0; const uint8_t* data_ptr = data.getBinaryData(0, size); - msg.addBinaryData(data_ptr, size); + if (size != msg.addBinaryData(data_ptr, size)) { + return false; + } return msg.send(mac); } From 1d957f339761cc6a53b085747dde33b3fcbd9226 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 19 Feb 2021 14:13:59 +0100 Subject: [PATCH 082/404] [ESPEasy-NOW] Check for max size ESPEasy-NOW packet --- src/src/Helpers/CRC_functions.h | 4 ++-- src/src/Helpers/ESPEasy_now_handler.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/src/Helpers/CRC_functions.h b/src/src/Helpers/CRC_functions.h index 49a943341e..3a00511357 100644 --- a/src/src/Helpers/CRC_functions.h +++ b/src/src/Helpers/CRC_functions.h @@ -5,8 +5,8 @@ int calc_CRC16(const String& text); -int calc_CRC16(const char *ptr, - int count); +int ICACHE_FLASH_ATTR calc_CRC16(const char *ptr, + int count); uint32_t calc_CRC32(const uint8_t *data, size_t length); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 6aee459990..977b083bd6 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -33,7 +33,7 @@ # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" -static uint64_t mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messageType, uint8_t message_count) +static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr::message_t messageType, uint8_t message_count) { uint64_t key = message_count; @@ -51,10 +51,12 @@ std::map ESPEasy_now_in_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; - if (count < sizeof(ESPEasy_now_hdr)) { + size_t payload_length = count - sizeof(ESPEasy_now_hdr); + if (count < sizeof(ESPEasy_now_hdr) || (payload_length > ESPEasy_Now_packet::getMaxPayloadSize())) { STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; // Too small } + ESPEasy_now_hdr header(buf); if (header.header_version != ESPEASY_NOW_HEADER_VERSION) { @@ -62,9 +64,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t return; } - size_t payload_length = count - sizeof(ESPEasy_now_hdr); const uint8_t *payload = buf + sizeof(ESPEasy_now_hdr); - const uint16_t checksum = calc_CRC16(reinterpret_cast(payload), payload_length); if (header.checksum != checksum) { From 504f20ae7eb1fecc95fb253412b8c982305691cd Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 19 Feb 2021 14:15:02 +0100 Subject: [PATCH 083/404] [ESPEasy p2p] Check for memory allocation receiving UDP packets --- src/src/Helpers/Networking.cpp | 193 +++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 84 deletions(-) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index fd65a508e8..780488a5eb 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -64,7 +64,6 @@ void etharp_gratuitous_r(struct netif *netif) { #endif // USE_SETTINGS_ARCHIVE - /*********************************************************************************************\ Syslog client \*********************************************************************************************/ @@ -73,6 +72,7 @@ void syslog(byte logLevel, const char *message) if ((Settings.Syslog_IP[0] != 0) && NetworkConnected()) { IPAddress broadcastIP(Settings.Syslog_IP[0], Settings.Syslog_IP[1], Settings.Syslog_IP[2], Settings.Syslog_IP[3]); + if (portUDP.beginPacket(broadcastIP, Settings.SyslogPort) == 0) { // problem resolving the hostname or port return; @@ -98,32 +98,34 @@ void syslog(byte logLevel, const char *message) hostname.trim(); hostname.replace(' ', '_'); header.reserve(16 + hostname.length()); - char str[8] = {0}; + char str[8] = { 0 }; snprintf_P(str, sizeof(str), PSTR("<%u>"), prio); - header = str; + header = str; header += hostname; header += F(" EspEasy: "); #ifdef ESP8266 - portUDP.write(header.c_str(), header.length()); - #endif + portUDP.write(header.c_str(), header.length()); + #endif // ifdef ESP8266 #ifdef ESP32 portUDP.write((uint8_t *)header.c_str(), header.length()); - #endif + #endif // ifdef ESP32 } - const char* c = message; - bool done = false; + const char *c = message; + bool done = false; + while (!done) { // Must use PROGMEM aware functions here to process message char ch = pgm_read_byte(c++); + if (ch == '\0') { done = true; } else { #ifdef ESP8266 portUDP.write(ch); - #endif + #endif // ifdef ESP8266 #ifdef ESP32 portUDP.write((uint8_t)ch); - #endif + #endif // ifdef ESP32 } } portUDP.endPacket(); @@ -140,13 +142,16 @@ void updateUDPport() if (Settings.UDPPort == lastUsedUDPPort) { return; } + if (lastUsedUDPPort != 0) { portUDP.stop(); lastUsedUDPPort = 0; } + if (!NetworkConnected()) { return; } + if (Settings.UDPPort != 0) { if (portUDP.begin(Settings.UDPPort) == 0) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { @@ -156,6 +161,7 @@ void updateUDPport() } } else { lastUsedUDPPort = Settings.UDPPort; + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("UDP : Start listening on port "); log += String(Settings.UDPPort); @@ -165,8 +171,6 @@ void updateUDPport() } } - - /*********************************************************************************************\ Check UDP messages (ESPEasy propiertary protocol) \*********************************************************************************************/ @@ -199,77 +203,82 @@ void checkUDP() return; } - // UDP_PACKETSIZE_MAX should be as small as possible but still enough to hold all + // UDP_PACKETSIZE_MAX should be as small as possible but still enough to hold all // data for PLUGIN_UDP_IN or CPLUGIN_UDP_IN calls - // This node may also receive other UDP packets which may be quite large + // This node may also receive other UDP packets which may be quite large // and then crash due to memory allocation failures if ((packetSize >= 2) && (packetSize < UDP_PACKETSIZE_MAX)) { // Allocate buffer to process packet. std::vector packetBuffer; - packetBuffer.resize(packetSize + 1); - memset(&packetBuffer[0], 0, packetSize + 1); + packetBuffer.resize(packetSize + 1, 0); - int len = portUDP.read(&packetBuffer[0], packetSize); + if (packetBuffer.size() >= packetSize) { + int len = portUDP.read(&packetBuffer[0], packetSize); - if (len >= 2) { - if (reinterpret_cast(packetBuffer[0]) != 255) - { - packetBuffer[len] = 0; - addLog(LOG_LEVEL_DEBUG, &packetBuffer[0]); - ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0]); - } - else - { - // binary data! - switch (packetBuffer[1]) + if (len >= 2) { + if (reinterpret_cast(packetBuffer[0]) != 255) + { + packetBuffer[len] = 0; + addLog(LOG_LEVEL_DEBUG, &packetBuffer[0]); + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SYSTEM, &packetBuffer[0]); + } + else { - case 1: // sysinfo message + // binary data! + switch (packetBuffer[1]) { - if (len < 13) { - break; - } - int copy_length = sizeof(NodeStruct); - if (copy_length > len) { - copy_length = len; - } - NodeStruct received; - memcpy(&received, &packetBuffer[2], copy_length); - if (received.validate()) { - Nodes.addNode(received); // Create a new element when not present + case 1: // sysinfo message + { + if (len < 13) { + break; + } + int copy_length = sizeof(NodeStruct); -#ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - String log; - log.reserve(64); - log = F("UDP : "); - log += received.STA_MAC().toString(); - log += ','; - log += received.IP().toString(); - log += ','; - log += received.unit; - addLog(LOG_LEVEL_DEBUG_MORE, log); + if (copy_length > len) { + copy_length = len; } + NodeStruct received; + memcpy(&received, &packetBuffer[2], copy_length); + + if (received.validate()) { + Nodes.addNode(received); // Create a new element when not present + +#ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + String log; + log.reserve(64); + log = F("UDP : "); + log += received.STA_MAC().toString(); + log += ','; + log += received.IP().toString(); + log += ','; + log += received.unit; + addLog(LOG_LEVEL_DEBUG_MORE, log); + } #endif // ifndef BUILD_NO_DEBUG + } + break; } - break; - } - default: - { - struct EventStruct TempEvent; - TempEvent.Data = reinterpret_cast(&packetBuffer[0]); - TempEvent.Par1 = remoteIP[3]; - TempEvent.Par2 = len; - String dummy; - PluginCall(PLUGIN_UDP_IN, &TempEvent, dummy); - CPluginCall(CPlugin::Function::CPLUGIN_UDP_IN, &TempEvent); - break; + default: + { + struct EventStruct TempEvent; + TempEvent.Data = reinterpret_cast(&packetBuffer[0]); + TempEvent.Par1 = remoteIP[3]; + TempEvent.Par2 = len; + String dummy; + PluginCall(PLUGIN_UDP_IN, &TempEvent, dummy); + CPluginCall(CPlugin::Function::CPLUGIN_UDP_IN, &TempEvent); + break; + } } } } } } } + // Flush any remaining content of the packet. while (portUDP.available()) { // Do not call portUDP.flush() as that's meant to sending the packet (on ESP8266) @@ -311,7 +320,7 @@ String formatUnitToIPAddress(byte unit, byte formatCode) { if (unitIPAddress[0] == 0) { // Invalid? switch (formatCode) { - case 1: // Return empty string + case 1: // Return empty string { return F(""); } @@ -323,6 +332,7 @@ String formatUnitToIPAddress(byte unit, byte formatCode) { } return unitIPAddress.toString(); } + /*********************************************************************************************\ Get IP address for unit \*********************************************************************************************/ @@ -357,6 +367,7 @@ void sendUDP(byte unit, const byte *data, byte size) } IPAddress remoteNodeIP = getIPAddressForUnit(unit); + if (remoteNodeIP[0] == 0) { return; } @@ -383,15 +394,18 @@ void refreshNodeList() { unsigned long max_age; const unsigned long max_age_allowed = 10 * 60 * 1000; // 10 minutes + Nodes.refreshNodeList(max_age_allowed, max_age); #if defined(USES_ESPEASY_NOW) && defined(ESP8266) + // ESP32 does not (yet) allow to scan a single channel so may take too long const uint8_t channel = Nodes.getESPEasyNOW_channel(); + if (channel != 0) { WifiScan(true, channel); } - #endif + #endif // if defined(USES_ESPEASY_NOW) && defined(ESP8266) if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); @@ -400,7 +414,7 @@ void refreshNodeList() #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.sendDiscoveryAnnounce(); ESPEasy_now_handler.sendNTPquery(); - #endif + #endif // ifdef USES_ESPEASY_NOW } /*********************************************************************************************\ @@ -421,20 +435,21 @@ void sendSysInfoUDP(byte repeats) addLog(LOG_LEVEL_DEBUG_MORE, F("UDP : Send Sysinfo message")); #endif // ifndef BUILD_NO_DEBUG - const NodeStruct * thisNode = Nodes.getThisNode(); + const NodeStruct *thisNode = Nodes.getThisNode(); + if (thisNode == nullptr) { // Should not happen return; } // Prepare UDP packet to send - byte data[80]; + byte data[80]; data[0] = 255; data[1] = 1; memcpy(&data[2], thisNode, sizeof(NodeStruct)); + for (byte counter = 0; counter < repeats; counter++) { - statusLED(true); IPAddress broadcastIP(255, 255, 255, 255); @@ -463,6 +478,7 @@ void SSDP_schema(WiFiClient& client) { const IPAddress ip = NetworkLocalIP(); const uint32_t chipId = ESP.getChipId(); char uuid[64]; + sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"), (uint16_t)((chipId >> 16) & 0xff), (uint16_t)((chipId >> 8) & 0xff), @@ -481,6 +497,7 @@ void SSDP_schema(WiFiClient& client) { "0" "" "http://"); + ssdp_schema += formatIP(ip); ssdp_schema += F(":80/" "" @@ -548,8 +565,10 @@ bool SSDP_begin() { _server->ref(); ip_addr_t ifaddr; + ifaddr.addr = NetworkLocalIP(); ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t)SSDP_MULTICAST_ADDR; if (igmp_joingroup(&ifaddr, &multicast_addr) != ERR_OK) { @@ -624,15 +643,16 @@ void SSDP_send(byte method) { (uint16_t)chipId & 0xff); char *buffer = new (std::nothrow) char[1460](); + if (buffer == nullptr) { return; } - int len = snprintf(buffer, 1460, - _ssdp_packet_template.c_str(), - (method == 0) ? _ssdp_response_template.c_str() : _ssdp_notify_template.c_str(), - SSDP_INTERVAL, - Settings.Build, - uuid, - IPADDR2STR(&ip) - ); + int len = snprintf(buffer, 1460, + _ssdp_packet_template.c_str(), + (method == 0) ? _ssdp_response_template.c_str() : _ssdp_notify_template.c_str(), + SSDP_INTERVAL, + Settings.Build, + uuid, + IPADDR2STR(&ip) + ); _server->append(buffer, len); delete[] buffer; @@ -793,7 +813,7 @@ void SSDP_update() { } # endif // ifdef USES_SSDP -#endif // if defined(ESP8266) +#endif // if defined(ESP8266) // ******************************************************************************** @@ -804,10 +824,10 @@ bool getSubnetRange(IPAddress& low, IPAddress& high) if (!WiFiEventData.WiFiGotIP()) { return false; } - - const IPAddress ip = NetworkLocalIP(); + + const IPAddress ip = NetworkLocalIP(); const IPAddress subnet = NetworkSubnetMask(); - + low = ip; high = ip; @@ -831,8 +851,8 @@ bool getSubnetRange(IPAddress& low, IPAddress& high) bool hasIPaddr() { - if (useStaticIP()) return true; - + if (useStaticIP()) { return true; } + #ifdef CORE_POST_2_5_0 bool configured = false; @@ -874,7 +894,7 @@ bool NetworkConnected(uint32_t timeout_ms) { } bool hostReachable(const IPAddress& ip) { - if (!NetworkConnected()) { return false; } + if (!NetworkConnected()) { return false; } return true; // Disabled ping as requested here: // https://github.com/letscontrolit/ESPEasy/issues/1494#issuecomment-397872538 @@ -924,10 +944,12 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port) return false; } PrepareSend(); + // In case of domain name resolution error result can be negative. // https://github.com/esp8266/Arduino/blob/18f643c7e2d6a0da9d26ff2b14c94e6536ab78c1/libraries/Ethernet/src/Dns.cpp#L44 // Thus must match the result with 1. bool connected = (client.connect(ip, port) == 1); + delay(0); if (!connected) { @@ -972,6 +994,7 @@ bool hostReachable(const String& hostname) { return hostReachable(remote_addr); } String log = F("Hostname cannot be resolved: "); + log += hostname; addLog(LOG_LEVEL_ERROR, log); return false; @@ -1056,6 +1079,7 @@ String splitURL(const String& fullURL, String& host, uint16_t& port, String& fil starthost += 2; } int endhost = fullURL.indexOf('/', starthost); + splitHostPortString(fullURL.substring(starthost, endhost), host, port); int startfile = fullURL.lastIndexOf('/'); @@ -1114,6 +1138,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const unsigned long timeout = millis() + 2000; WiFiClient client; HTTPClient http; + http.begin(client, host, port, uri); { if ((user.length() > 0) && (pass.length() > 0)) { From 6fc54d6a70585b88f267336797f856419f3503a7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 20 Feb 2021 02:02:38 +0100 Subject: [PATCH 084/404] [ESPEasy-NOW] Make sure expired ESPEasy-NOW packets will be removed Still a problem: If a node is connected to a network and has received lots of messages before getting connected, its memory remains almost completely used. --- src/src/Helpers/ESPEasy_now_handler.cpp | 14 ++++++++------ src/src/Helpers/Networking.cpp | 2 +- src/src/Helpers/PeriodicalActions.cpp | 12 ++++++++++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 977b083bd6..9e54f0d481 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -14,6 +14,7 @@ # include "../ESPEasyCore/ESPEasy_Log.h" # include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/ESPEasy_time.h" +# include "../Globals/MQTT.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" # include "../Globals/SendData_DuplicateChecker.h" @@ -197,13 +198,12 @@ bool ESPEasy_now_handler_t::loop() if (!ESPEasy_now_in_queue.empty()) { unsigned long timeout = millis() + 50; for (auto it = ESPEasy_now_in_queue.begin(); !timeOutReached(timeout) && it != ESPEasy_now_in_queue.end();) { + const bool expired = it->second.expired(); bool removeMessage = true; START_TIMER; bool valid = it->second.valid(); if (!valid || !it->second.messageComplete()) { - bool expired = it->second.expired(); - if (!valid || expired) { if (expired) { STOP_TIMER(EXPIRED_ESPEASY_NOW_LOOP); @@ -221,9 +221,11 @@ bool ESPEasy_now_handler_t::loop() addLog(LOG_LEVEL_ERROR, log); } } else { - removeMessage = false; + if (!expired) { + removeMessage = false; + } } - } else { + } else if (!expired) { // Process it bool mustKeep = !removeMessage; somethingProcessed = processMessage(it->second, mustKeep); @@ -546,9 +548,9 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const const uint8_t distance = Nodes.getDistance(); - if ((distance == 0) || (distance == 255)) { + if (((distance == 0) && MQTTclient_connected) || (distance == 255)) { // No need to send via ESPEasy_Now. - // We're either connected (distance == 0) + // We're either connected ((distance == 0) && MQTTclient_connected) // or have no neighbor that can forward the message (distance == 255) return false; } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 780488a5eb..8577d8c83f 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -212,7 +212,7 @@ void checkUDP() std::vector packetBuffer; packetBuffer.resize(packetSize + 1, 0); - if (packetBuffer.size() >= packetSize) { + if (packetBuffer.size() >= static_cast(packetSize)) { int len = portUDP.read(&packetBuffer[0], packetSize); if (len >= 2) { diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index d4771056c6..83b24bb495 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -297,10 +297,18 @@ void schedule_all_tasks_using_MQTT_controller() { } void processMQTTdelayQueue() { - if (MQTTDelayHandler == nullptr || !MQTTclient_connected) { + if (MQTTDelayHandler == nullptr) { return; } + #ifndef USES_ESPEASY_NOW + // When using ESPEasy_NOW we may still send MQTT messages even when we're not connected. + // For all other situations no need to continue. + if (!MQTTclient_connected) { + return; + } + #endif + START_TIMER; MQTT_queue_element *element(MQTTDelayHandler->getNext()); @@ -321,7 +329,7 @@ void processMQTTdelayQueue() { bool processed = false; #ifdef USES_ESPEASY_NOW - if (!MQTTclient.connected()) { + if (!MQTTclient_connected) { processed = ESPEasy_now_handler.sendToMQTT(element->controller_idx, element->_topic, element->_payload); } #endif From 708724e5fcf590dd9d91dfbd083d8f771b8fa2d3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 20 Feb 2021 02:06:19 +0100 Subject: [PATCH 085/404] [MQTT] PubSubClient checks when callback + publish happen simultaneous After discussion with @arjenhiemstra on issue: https://github.com/knolleary/pubsubclient/issues/832 --- lib/pubsubclient/src/PubSubClient.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/pubsubclient/src/PubSubClient.cpp b/lib/pubsubclient/src/PubSubClient.cpp index 7ac306e899..a775d252f5 100644 --- a/lib/pubsubclient/src/PubSubClient.cpp +++ b/lib/pubsubclient/src/PubSubClient.cpp @@ -330,16 +330,22 @@ bool PubSubClient::loop_read() { case MQTTPUBLISH: { if (callback) { - uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */ - memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */ - buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */ - char *topic = (char*) buffer+llen+2; + const uint16_t tl_offset = llen+1; + const uint16_t tl = (buffer[tl_offset]<<8)+buffer[tl_offset+1]; /* topic length in bytes */ + const uint16_t topic_offset = tl_offset+2; + const uint16_t msgId_offset = topic_offset+tl; + const uint16_t payload_offset = msgId_offset+2; + if (payload_offset >= MQTT_MAX_PACKET_SIZE) return false; + if (len < payload_offset) return false; + memmove(buffer+topic_offset-1,buffer+topic_offset,tl); /* move topic inside buffer 1 byte to front */ + buffer[topic_offset-1+tl] = 0; /* end the topic as a 'C' string with \x00 */ + char *topic = (char*) buffer+topic_offset-1; uint8_t *payload; // msgId only present for QOS>0 if ((buffer[0]&0x06) == MQTTQOS1) { - const uint16_t msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; - payload = buffer+llen+3+tl+2; - callback(topic,payload,len-llen-3-tl-2); + const uint16_t msgId = (buffer[msgId_offset]<<8)+buffer[msgId_offset+1]; + payload = buffer+payload_offset; + callback(topic,payload,len-payload_offset); if (_client->connected()) { buffer[0] = MQTTPUBACK; buffer[1] = 2; @@ -350,8 +356,9 @@ bool PubSubClient::loop_read() { } } } else { - payload = buffer+llen+3+tl; - callback(topic,payload,len-llen-3-tl); + // No msgId, thus payload starts 2 bytes earlier. + payload = buffer+payload_offset-2; + callback(topic,payload,len-(payload_offset-2)); } } break; From 23723a7e9dfc92bb7956ddb395b647e7f662efdd Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 20 Feb 2021 14:52:18 +0100 Subject: [PATCH 086/404] [MQTT] Fix rejecting QoS=0 messages with 0 or 1 byte length --- lib/pubsubclient/src/PubSubClient.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pubsubclient/src/PubSubClient.cpp b/lib/pubsubclient/src/PubSubClient.cpp index a775d252f5..288bb20093 100644 --- a/lib/pubsubclient/src/PubSubClient.cpp +++ b/lib/pubsubclient/src/PubSubClient.cpp @@ -330,11 +330,12 @@ bool PubSubClient::loop_read() { case MQTTPUBLISH: { if (callback) { + const bool msgId_present = (buffer[0]&0x06) == MQTTQOS1; const uint16_t tl_offset = llen+1; const uint16_t tl = (buffer[tl_offset]<<8)+buffer[tl_offset+1]; /* topic length in bytes */ const uint16_t topic_offset = tl_offset+2; const uint16_t msgId_offset = topic_offset+tl; - const uint16_t payload_offset = msgId_offset+2; + const uint16_t payload_offset = msgId_present ? msgId_offset+2 : msgId_offset; if (payload_offset >= MQTT_MAX_PACKET_SIZE) return false; if (len < payload_offset) return false; memmove(buffer+topic_offset-1,buffer+topic_offset,tl); /* move topic inside buffer 1 byte to front */ @@ -342,7 +343,7 @@ bool PubSubClient::loop_read() { char *topic = (char*) buffer+topic_offset-1; uint8_t *payload; // msgId only present for QOS>0 - if ((buffer[0]&0x06) == MQTTQOS1) { + if (msgId_present) { const uint16_t msgId = (buffer[msgId_offset]<<8)+buffer[msgId_offset+1]; payload = buffer+payload_offset; callback(topic,payload,len-payload_offset); @@ -356,9 +357,9 @@ bool PubSubClient::loop_read() { } } } else { - // No msgId, thus payload starts 2 bytes earlier. - payload = buffer+payload_offset-2; - callback(topic,payload,len-(payload_offset-2)); + // No msgId + payload = buffer+payload_offset; + callback(topic,payload,len-payload_offset); } } break; From 083dab546d64465b9adbdeb9ba0ae7ff6ca9be73 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 22 Feb 2021 14:54:29 +0100 Subject: [PATCH 087/404] [ESPEasy-NOW] Allow for reconnect to either WiFi or mesh on disconnect --- src/ESPEasy.ino | 2 +- src/src/DataStructs/NodesHandler.cpp | 5 +++-- src/src/DataStructs/WiFiEventData.cpp | 7 ++++++ src/src/DataStructs/WiFiEventData.h | 8 ++++++- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 12 +++++----- src/src/Helpers/ESPEasy_now_handler.cpp | 11 ++++++---- src/src/Helpers/Networking.cpp | 8 +++++++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 22 +++++++++---------- src/src/Helpers/WiFi_AP_CandidatesList.h | 4 ---- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index b142db5fa2..ad31e569fa 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -430,7 +430,7 @@ void setup() } #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only() || Settings.UseESPEasyNow()) { + if (WiFiEventData.isESPEasy_now_only() || Settings.UseESPEasyNow()) { RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. RTC.lastWiFiChannel = 0; // Force slow connect } diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 52380eec35..6cdd8f5c67 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -7,6 +7,7 @@ #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/PeriodicalActions.h" #include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" @@ -163,7 +164,7 @@ void NodesHandler::updateThisNode() { { bool addIP = true; #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (WiFiEventData.isESPEasy_now_only()) { // Connected via 'virtual ESPEasy-NOW AP' addIP = false; } @@ -217,7 +218,7 @@ void NodesHandler::updateThisNode() { _lastTimeValidDistance = millis(); if (_distance != lastDistance) { #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFiConnected()) { + if (WiFiEventData.isESPEasy_now_only() && WiFiConnected()) { // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP // Try to reconnect to it. RTC.clearLastWiFi(); // Force a WiFi scan diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 594379eb37..da0c630b41 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -151,3 +151,10 @@ void WiFiEventData_t::markDisconnectedAPmode(const uint8_t mac[6]) { lastMacDisconnectedAPmode.set(mac); processedDisconnectAPmode = false; } + + +#ifdef USES_ESPEASY_NOW + bool WiFiEventData_t::isESPEasy_now_only() const { + return RTC.lastWiFiSettingsIndex == 3; + } +#endif diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 96bd6b7afa..22393c5b0a 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -1,6 +1,8 @@ #ifndef DATASTRUCTS_WIFIEVENTDATA_H #define DATASTRUCTS_WIFIEVENTDATA_H +#include "../../ESPEasy-Globals.h" + #include "../DataStructs/MAC_address.h" #include "../DataTypes/WiFiDisconnectReason.h" #include "../Helpers/LongTermTimer.h" @@ -51,6 +53,11 @@ struct WiFiEventData_t { void markConnectedAPmode(const uint8_t mac[6]); void markDisconnectedAPmode(const uint8_t mac[6]); +#ifdef USES_ESPEASY_NOW + bool isESPEasy_now_only() const; +#endif + + // WiFi related data bool wifiSetup = false; @@ -64,7 +71,6 @@ struct WiFiEventData_t { float wifi_TX_pwr = 0; bool bssid_changed = false; bool channel_changed = false; - bool espeasy_now_only = false; WiFiDisconnectReason lastDisconnectReason = WIFI_DISCONNECT_REASON_UNSPECIFIED; LongTermTimer lastConnectMoment; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index d99d4d42d1..5fa0f26cb6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -180,7 +180,7 @@ void processDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW - if (wifiAPmodeActivelyUsed() || WiFiEventData.espeasy_now_only) return; + if (WiFiEventData.isESPEasy_now_only()) return; ESPEasy_now_handler.end(); #endif @@ -450,10 +450,12 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); - if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFi_AP_Candidates.addedKnownCandidate() && WiFiConnected()) { - RTC.clearLastWiFi(); // Force a WiFi scan - WifiDisconnect(); - } else if (WiFiEventData.espeasy_now_only) { return; } + if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.addedKnownCandidate() && WiFiConnected()) { + WiFi_AP_Candidates.force_reload(); + WifiDisconnect(); + } else { return; } + } #endif const WiFi_AP_Candidate bestCandidate = WiFi_AP_Candidates.getBestScanResult(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 9e54f0d481..0a3b2c28c3 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -16,6 +16,7 @@ # include "../Globals/ESPEasy_time.h" # include "../Globals/MQTT.h" # include "../Globals/Nodes.h" +# include "../Globals/RTC.h" # include "../Globals/SecuritySettings.h" # include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" @@ -90,8 +91,8 @@ bool ESPEasy_now_handler_t::begin() MAC_address bssid; _controllerIndex = INVALID_CONTROLLER_INDEX; - if (WiFiEventData.espeasy_now_only) { - WifiScan(false, false); + if (WiFiEventData.isESPEasy_now_only()) { + WifiScan(false, 0); addPeerFromWiFiScan(); } @@ -110,7 +111,7 @@ bool ESPEasy_now_handler_t::begin() setAP(true); /* // FIXME TD-er: Must use standard WiFi connection setup. - if (WiFiEventData.espeasy_now_only) { + if (WiFiEventData.isESPEasy_now_only()) { if (bssid.all_zero()) { WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel); } else { @@ -163,11 +164,13 @@ void ESPEasy_now_handler_t::end() { _controllerIndex = INVALID_CONTROLLER_INDEX; use_EspEasy_now = false; + RTC.clearLastWiFi(); // Force a WiFi scan if (_last_used != 0) { // Only call WifiEspNow.end() if it was started. WifiEspNow.end(); _last_used = 0; } + setAP(false); addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW disabled")); } @@ -250,7 +253,7 @@ bool ESPEasy_now_handler_t::loop() if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; - WiFiEventData.espeasy_now_only = true; + // FIXME TD-er: Must check/mark so this becomes true: WiFiEventData.isESPEasy_now_only() // Start scanning the next channel to see if we may end up with a new found node // WifiScan(false, false); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index cd6ecc63ab..059f0d37fc 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -876,6 +876,14 @@ bool hasIPaddr() { // Check connection. Maximum timeout 500 msec. bool NetworkConnected(uint32_t timeout_ms) { + +#ifdef USES_ESPEASY_NOW + if (WiFiEventData.isESPEasy_now_only()) { + return false; + } +#endif + + uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms); uint32_t min_delay = timeout_ms / 20; diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 8b716f5644..ce74d60cb4 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -155,12 +155,6 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { addFromRTC(); // Store the current one from RTC as the first candidate for a reconnect. } -#ifdef USES_ESPEASY_NOW -bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { - return RTC.lastWiFiSettingsIndex == 3; -} -#endif - void WiFi_AP_CandidatesList::add(uint8_t networkItem) { WiFi_AP_Candidate tmp(networkItem); @@ -232,8 +226,10 @@ void WiFi_AP_CandidatesList::purge_unusable() { it = known.erase(it); } } - known.sort(); - known.unique(); + if (known.size() > 1) { + known.sort(); + known.unique(); + } for (auto it = candidates.begin(); it != candidates.end();) { if (it->usable()) { @@ -242,8 +238,10 @@ void WiFi_AP_CandidatesList::purge_unusable() { it = candidates.erase(it); } } - candidates.sort(); - candidates.unique(); + if (candidates.size() > 1) { + candidates.sort(); + candidates.unique(); + } } bool WiFi_AP_CandidatesList::get_SSID_key(byte index, String& ssid, String& key) const { @@ -268,7 +266,7 @@ bool WiFi_AP_CandidatesList::get_SSID_key(byte index, String& ssid, String& key) // TODO TD-er: Read other credentials from extra file. - ssid.trim(); - key.trim(); + + // Spaces are allowed in both SSID and pass phrase, so make sure to not trim the ssid and key. return true; } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index c7e6fbae7c..099ff22ea9 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -34,10 +34,6 @@ struct WiFi_AP_CandidatesList { // This will force a reconnect to the current AP if connection is lost. void markCurrentConnectionStable(); -#ifdef USES_ESPEASY_NOW - bool isESPEasy_now_only() const; -#endif - bool addedKnownCandidate() const { return _addedKnownCandidate; } private: From 2ce62b7ace07321ff320ef2151c9ae8156aaf5a6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 23 Feb 2021 13:58:27 +0100 Subject: [PATCH 088/404] [C006] Allow to create MQTT messages before WiFi connection is active --- src/_C006.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/_C006.ino b/src/_C006.ino index a45f0b9a9e..73b9728d36 100644 --- a/src/_C006.ino +++ b/src/_C006.ino @@ -107,10 +107,6 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - if (!NetworkConnected(10)) { - success = false; - break; - } String pubname = CPlugin_006_pubname; bool mqtt_retainFlag = CPlugin_006_mqtt_retainFlag; From 57c6991559dc0150ce244c95f2e93598cb2d32ad Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 26 Feb 2021 12:15:59 +0100 Subject: [PATCH 089/404] [C005] Fix sending duplicate messages on OpenHAB MQTT Probably caused by some merge error. --- src/_C005.ino | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/src/_C005.ino b/src/_C005.ino index 33bb110cc6..633b70049a 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -142,35 +142,9 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& for (byte x = 0; x < valueCount; x++) { - statusLED(true); - - byte valueCount = getValueCountForTask(event->TaskIndex); - for (byte x = 0; x < valueCount; x++) - { - //MFD: skip publishing for values with empty labels (removes unnecessary publishing of unwanted values) - if (ExtraTaskSettings.TaskDeviceValueNames[x][0]==0) - continue; //we skip values with empty labels - - String tmppubname = pubname; - tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - String value; - // Small optimization so we don't try to copy potentially large strings - if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); - value = event->String2.substring(0, 20); // For the log - } else { - value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); - } -#ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("MQTT : "); - log += tmppubname; - log += ' '; - log += value; - addLog(LOG_LEVEL_DEBUG, log); - } -#endif + // MFD: skip publishing for values with empty labels (removes unnecessary publishing of unwanted values) + if (ExtraTaskSettings.TaskDeviceValueNames[x][0] == 0) { + continue; // we skip values with empty labels } String tmppubname = pubname; parseSingleControllerVariable(tmppubname, event, x, false); From dcb65fd7d027c9a199346acf9d18b5611d0aa124 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 13:51:11 +0100 Subject: [PATCH 090/404] [Controller Queue] Add flag to allow messages to expire --- docs/source/Controller/_Controller.rst | 1 + src/src/DataStructs/ControllerSettingsStruct.cpp | 10 ++++++++++ src/src/DataStructs/ControllerSettingsStruct.h | 6 ++++++ src/src/Helpers/_CPlugin_Helper_webform.cpp | 8 ++++++++ src/src/WebServer/ControllerPage.cpp | 1 + 5 files changed, 26 insertions(+) diff --git a/docs/source/Controller/_Controller.rst b/docs/source/Controller/_Controller.rst index cdc80d9207..0eb266252d 100644 --- a/docs/source/Controller/_Controller.rst +++ b/docs/source/Controller/_Controller.rst @@ -61,6 +61,7 @@ before WiFi connection is made or during lost connection. - **Max Queue Depth** - Maximum length of the buffer queue to keep unsent messages. - **Max Retries** - Maximum number of retries to send a message. - **Full Queue Action** - How to handle when queue is full, ignore new or delete oldest message. +- **Allow Expire** - Remove a queued message from the queue after x x . - **Check Reply** - When set to false, a sent message is considered always successful. - **Client Timeout** - Timeout in msec for an network connection used by the controller. - **Sample Set Initiator** - Some controllers (e.g. C018 LoRa/TTN) can mark samples to belong to a set of samples. A new sample from set task index will increment this counter. diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index be3b00b550..a0bdb4e51b 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -265,3 +265,13 @@ void ControllerSettingsStruct::enableESPEasyNowFallback(bool value) { bitWrite(VariousFlags, 8, value); } + +bool ControllerSettingsStruct::allowExpire() const +{ + return bitRead(VariousFlags, 8); +} + +void ControllerSettingsStruct::allowExpire(bool value) +{ + bitWrite(VariousFlags, 8, value); +} diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index b62206735b..9b44b8790b 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -69,6 +69,7 @@ struct ControllerSettingsStruct CONTROLLER_MAX_QUEUE_DEPTH, CONTROLLER_MAX_RETRIES, CONTROLLER_FULL_QUEUE_ACTION, + CONTROLLER_ALLOW_EXPIRE, CONTROLLER_CHECK_REPLY, CONTROLLER_CLIENT_ID, CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT, @@ -139,6 +140,11 @@ struct ControllerSettingsStruct void enableESPEasyNowFallback(bool value); bool UseDNS; + bool allowExpire() const; + void allowExpire(bool value); + + + boolean UseDNS; byte IP[4]; unsigned int Port; char HostName[65]; diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index 8944cd4ca8..bc68d680ff 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -44,6 +44,8 @@ String getControllerParameterName(protocolIndex_t ProtocolInde case ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH: name = F("Max Queue Depth"); break; case ControllerSettingsStruct::CONTROLLER_MAX_RETRIES: name = F("Max Retries"); break; case ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION: name = F("Full Queue Action"); break; + case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: name = F("Allow Expire"); break; + case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: name = F("Check Reply"); break; case ControllerSettingsStruct::CONTROLLER_CLIENT_ID: name = F("Controller Client ID"); break; @@ -193,6 +195,9 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin addFormSelector(displayName, internalName, 2, options, NULL, NULL, ControllerSettings.DeleteOldest, false); break; } + case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: + addFormCheckBox(displayName, internalName, ControllerSettings.allowExpire()); + break; case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: { String options[2]; @@ -317,6 +322,9 @@ void saveControllerParameterForm(ControllerSettingsStruct & ControllerSet case ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION: ControllerSettings.DeleteOldest = getFormItemInt(internalName, ControllerSettings.DeleteOldest); break; + case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: + ControllerSettings.allowExpire(isFormItemChecked(internalName)); + break; case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: ControllerSettings.MustCheckReply = getFormItemInt(internalName, ControllerSettings.MustCheckReply); break; diff --git a/src/src/WebServer/ControllerPage.cpp b/src/src/WebServer/ControllerPage.cpp index 1581f8ab55..1c3d42bdef 100644 --- a/src/src/WebServer/ControllerPage.cpp +++ b/src/src/WebServer/ControllerPage.cpp @@ -339,6 +339,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE); } if (Protocol[ProtocolIndex].usesCheckReply) { From df7dbdfa13dcc196f9b5688ccd9287866eac2002 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 13:52:28 +0100 Subject: [PATCH 091/404] [Controller Queue] Add deduplicate check in controller queue --- docs/source/Controller/_Controller.rst | 1 + src/_C001.ino | 2 +- src/_C002.ino | 2 +- src/_C003.ino | 2 +- src/_C005.ino | 4 +- src/_C006.ino | 4 +- src/_C014.ino | 59 ++++++++++--------- src/_C016.ino | 1 + src/src/Commands/MQTT.cpp | 4 +- .../ControllerQueue/C011_queue_element.cpp | 14 +++++ src/src/ControllerQueue/C011_queue_element.h | 3 + .../ControllerQueue/C015_queue_element.cpp | 20 +++++++ src/src/ControllerQueue/C015_queue_element.h | 3 + .../ControllerQueue/C016_queue_element.cpp | 19 +++++- src/src/ControllerQueue/C016_queue_element.h | 9 ++- .../ControllerQueue/C018_queue_element.cpp | 15 +++++ src/src/ControllerQueue/C018_queue_element.h | 4 ++ .../ControllerDelayHandlerStruct.h | 35 ++++++++++- .../ControllerQueue/MQTT_queue_element.cpp | 20 ++++++- src/src/ControllerQueue/MQTT_queue_element.h | 5 ++ .../SimpleQueueElement_string_only.cpp | 17 +++++- .../SimpleQueueElement_string_only.h | 10 +++- .../queue_element_formatted_uservar.cpp | 15 +++++ .../queue_element_formatted_uservar.h | 3 + .../queue_element_single_value_base.cpp | 15 +++++ .../queue_element_single_value_base.h | 3 + .../DataStructs/ControllerSettingsStruct.cpp | 10 ++++ .../DataStructs/ControllerSettingsStruct.h | 3 + src/src/DataStructs/ProtocolStruct.cpp | 2 +- src/src/DataStructs/ProtocolStruct.h | 1 + src/src/ESPEasyCore/Controller.cpp | 6 +- src/src/ESPEasyCore/Controller.h | 2 +- src/src/Globals/C016_ControllerCache.cpp | 2 +- src/src/Helpers/ESPEasy_checks.cpp | 9 +++ src/src/Helpers/_CPlugin_Helper_webform.cpp | 7 +++ src/src/WebServer/ControllerPage.cpp | 5 +- 36 files changed, 280 insertions(+), 56 deletions(-) diff --git a/docs/source/Controller/_Controller.rst b/docs/source/Controller/_Controller.rst index 0eb266252d..e990276c9d 100644 --- a/docs/source/Controller/_Controller.rst +++ b/docs/source/Controller/_Controller.rst @@ -62,6 +62,7 @@ before WiFi connection is made or during lost connection. - **Max Retries** - Maximum number of retries to send a message. - **Full Queue Action** - How to handle when queue is full, ignore new or delete oldest message. - **Allow Expire** - Remove a queued message from the queue after x x . +- **De-duplicate** - Do not add a message to the queue if the same message from the same task is already present. - **Check Reply** - When set to false, a sent message is considered always successful. - **Client Timeout** - Timeout in msec for an network connection used by the controller. - **Sample Set Initiator** - Some controllers (e.g. C018 LoRa/TTN) can mark samples to belong to a set of samples. A new sample from set task index will increment this counter. diff --git a/src/_C001.ino b/src/_C001.ino index 15d2f88ca5..3913984a43 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -112,7 +112,7 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& url += mapVccToDomoticz(); # endif // if FEATURE_ADC_VCC - success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, url)); + success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, event->TaskIndex, url)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C001_DELAY_QUEUE, C001_DelayHandler->getNextScheduleTime()); } // if ixd !=0 diff --git a/src/_C002.ino b/src/_C002.ino index 240facd59b..a53adf66b6 100644 --- a/src/_C002.ino +++ b/src/_C002.ino @@ -267,7 +267,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& String pubname = CPlugin_002_pubname; parseControllerVariables(pubname, event, false); - success = MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), CPlugin_002_mqtt_retainFlag); + success = MQTTpublish(event->ControllerIndex, event->TaskIndex, pubname.c_str(), json.c_str(), CPlugin_002_mqtt_retainFlag); } // if ixd !=0 else { diff --git a/src/_C003.ino b/src/_C003.ino index c4b0b50013..f0455b9cf5 100644 --- a/src/_C003.ino +++ b/src/_C003.ino @@ -56,7 +56,7 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& url += ","; url += formatUserVarNoCheck(event, 0); url += "\n"; - success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, url)); + success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, event->TaskIndex, url)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C005.ino b/src/_C005.ino index 633b70049a..c51fad5377 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -152,11 +152,11 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& // Small optimization so we don't try to copy potentially large strings if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); value = event->String2.substring(0, 20); // For the log } else { value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); } # ifndef BUILD_NO_DEBUG diff --git a/src/_C006.ino b/src/_C006.ino index 73b9728d36..06e38b4cc5 100644 --- a/src/_C006.ino +++ b/src/_C006.ino @@ -124,10 +124,10 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& // Small optimization so we don't try to copy potentially large strings if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); } else { String value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); } } break; diff --git a/src/_C014.ino b/src/_C014.ino index 931c0c1229..e78c5fbdc9 100644 --- a/src/_C014.ino +++ b/src/_C014.ino @@ -42,10 +42,10 @@ byte msgCounter=0; // counter for send Messages (currently for information / log String CPlugin_014_pubname; bool CPlugin_014_mqtt_retainFlag = false; - +/* // send MQTT Message with complete Topic / Payload bool CPlugin_014_sendMQTTmsg(String& topic, const char* payload, int& errorCounter) { - bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, topic.c_str(), payload, true); + bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, INVALID_TASK_INDEX, topic.c_str(), payload, true); if (mqttReturn) msgCounter++; else errorCounter++; if (loglevelActiveFor(LOG_LEVEL_INFO) && mqttReturn) { @@ -64,11 +64,12 @@ bool CPlugin_014_sendMQTTmsg(String& topic, const char* payload, int& errorCount } return mqttReturn; } +*/ // send MQTT Message with CPLUGIN_014_BASE_TOPIC Topic scheme / Payload -bool CPlugin_014_sendMQTTdevice(String tmppubname, const char* topic, const char* payload, int& errorCounter) { +bool CPlugin_014_sendMQTTdevice(String tmppubname, taskIndex_t taskIndex, const char* topic, const char* payload, int& errorCounter) { tmppubname.replace(F("#"), topic); - bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, tmppubname.c_str(), payload, true); + bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, taskIndex, tmppubname.c_str(), payload, true); if (mqttReturn) msgCounter++; else errorCounter++; if (loglevelActiveFor(LOG_LEVEL_INFO) && mqttReturn) { @@ -95,7 +96,7 @@ bool CPlugin_014_sendMQTTnode(String tmppubname, const char* node, const char* v tmppubname.replace(F("%device%"), node); tmppubname.replace(F("%node%"), value); tmppubname.replace(F("/%property%"), topic); // leading forward slash required to send "homie/device/value" topics - bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, tmppubname.c_str(), payload, true); + bool mqttReturn = MQTTpublish(CPLUGIN_ID_014, INVALID_TASK_INDEX, tmppubname.c_str(), payload, true); if (mqttReturn) msgCounter++; else errorCounter++; if (loglevelActiveFor(LOG_LEVEL_INFO) && mqttReturn) { @@ -180,24 +181,24 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& #ifdef CPLUGIN_014_V3 // $stats/uptime Device → Controller Time elapsed in seconds since the boot of the device Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$stats/uptime",toString((wdcounter / 2)*60,0).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$stats/uptime",toString((wdcounter / 2)*60,0).c_str(),errorCounter); // $stats/signal Device → Controller Signal strength in % Yes No float RssI = WiFi.RSSI(); RssI = isnan(RssI) ? -100.0f : RssI; RssI = min(max(2 * (RssI + 100.0f), 0.0f), 100.0f); - CPlugin_014_sendMQTTdevice(pubname,"$stats/signal",toString(RssI,1).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$stats/signal",toString(RssI,1).c_str(),errorCounter); #endif if (errorCounter>0) { // alert: this is the state the device is when connected to the MQTT broker, but something wrong is happening. E.g. a sensor is not providing data and needs human intervention. You have to send this message when something is wrong. - CPlugin_014_sendMQTTdevice(pubname,"$state","alert",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","alert",errorCounter); success = false; } else { // ready: this is the state the device is in when it is connected to the MQTT broker, has sent all Homie messages and is ready to operate. You have to send this message after all other announcements message have been sent. - CPlugin_014_sendMQTTdevice(pubname,"$state","ready",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","ready",errorCounter); success = true; } if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { @@ -236,37 +237,37 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& String unitName; // estaimate Units // init: this is the state the device is in when it is connected to the MQTT broker, but has not yet sent all Homie messages and is not yet ready to operate. This is the first message that must that must be sent. - CPlugin_014_sendMQTTdevice(pubname,"$state","init",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","init",errorCounter); // $homie Device → Controller Version of the Homie convention the device conforms to Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$homie",CPLUGIN_014_HOMIE_VERSION,errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$homie",CPLUGIN_014_HOMIE_VERSION,errorCounter); // $name Device → Controller Friendly name of the device Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$name",Settings.Name,errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$name",Settings.Name,errorCounter); // $localip Device → Controller IP of the device on the local network Yes Yes #ifdef CPLUGIN_014_V3 - CPlugin_014_sendMQTTdevice(pubname,"$localip",formatIP(NetworkLocalIP()).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$localip",formatIP(NetworkLocalIP()).c_str(),errorCounter); // $mac Device → Controller Mac address of the device network interface. The format MUST be of the type A1:B2:C3:D4:E5:F6 Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$mac",NetworkMacAddress().c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$mac",NetworkMacAddress().c_str(),errorCounter); // $implementation Device → Controller An identifier for the Homie implementation (example esp8266) Yes Yes #if defined(ESP8266) - CPlugin_014_sendMQTTdevice(pubname,"$implementation","ESP8266",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$implementation","ESP8266",errorCounter); #endif #if defined(ESP32) - CPlugin_014_sendMQTTdevice(pubname,"$implementation","ESP32",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$implementation","ESP32",errorCounter); #endif // $fw/version Device → Controller Version of the firmware running on the device Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$fw/version",toString(Settings.Build,0).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$fw/version",toString(Settings.Build,0).c_str(),errorCounter); // $fw/name Device → Controller Name of the firmware running on the device. Allowed characters are the same as the device ID Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$fw/name",getNodeTypeDisplayString(NODE_TYPE_ID).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$fw/name",getNodeTypeDisplayString(NODE_TYPE_ID).c_str(),errorCounter); // $stats/interval Device → Controller Interval in seconds at which the device refreshes its $stats/+: See next section for details about statistical attributes Yes Yes - CPlugin_014_sendMQTTdevice(pubname,"$stats/interval",CPLUGIN_014_INTERVAL,errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$stats/interval",CPLUGIN_014_INTERVAL,errorCounter); #endif //always send the SYSTEM device with the cmd node @@ -460,17 +461,17 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& // and finally ... // $nodes Device → Controller Nodes the device exposes, with format id separated by a , if there are multiple nodes. To make a node an array, append [] to the ID. Yes Yes - CPlugin_014_sendMQTTdevice(pubname, "$nodes", nodesList.c_str(), errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex, "$nodes", nodesList.c_str(), errorCounter); } if (errorCounter>0) { // alert: this is the state the device is when connected to the MQTT broker, but something wrong is happening. E.g. a sensor is not providing data and needs human intervention. You have to send this message when something is wrong. - CPlugin_014_sendMQTTdevice(pubname,"$state","alert",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","alert",errorCounter); success = false; } else { // ready: this is the state the device is in when it is connected to the MQTT broker, has sent all Homie messages and is ready to operate. You have to send this message after all other announcements message have been sent. - CPlugin_014_sendMQTTdevice(pubname,"$state","ready",errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","ready",errorCounter); success = true; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -503,7 +504,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& pubname = CPLUGIN_014_BASE_TOPIC; // Scheme to form device messages pubname.replace(F("%sysname%"), Settings.Name); // disconnected: this is the state the device is in when it is cleanly disconnected from the MQTT broker. You must send this message before cleanly disconnecting - success = CPlugin_014_sendMQTTdevice(pubname,"$state","disconnected",errorCounter); + success = CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","disconnected",errorCounter); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("C014 : Device: "); log += Settings.Name; @@ -519,7 +520,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& pubname = CPLUGIN_014_BASE_TOPIC; // Scheme to form device messages pubname.replace(F("%sysname%"), Settings.Name); // sleeping: this is the state the device is in when the device is sleeping. You have to send this message before sleeping. - success = CPlugin_014_sendMQTTdevice(pubname,"$state","sleeping",errorCounter); + success = CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$state","sleeping",errorCounter); break; } @@ -709,11 +710,11 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& // Small optimization so we don't try to copy potentially large strings if (event->getSensorType() == Sensor_VType::SENSOR_TYPE_STRING) { - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); value = event->String2.substring(0, 20); // For the log } else { value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); } if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("C014 : Sent to "); @@ -779,7 +780,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& topic.replace(F("%tskname%"), CPLUGIN_014_SYSTEM_DEVICE); topic.replace(F("%valname%"), CPLUGIN_014_GPIO_VALUE + toString(port,0)); - success = MQTTpublish(CPLUGIN_ID_014, topic.c_str(), valueBool.c_str(), false); + success = MQTTpublish(CPLUGIN_ID_014, INVALID_TASK_INDEX, topic.c_str(), valueBool.c_str(), false); if (loglevelActiveFor(LOG_LEVEL_INFO) && success) { String log = F("C014 : Acknowledged GPIO"); log += port; @@ -819,7 +820,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& if ((commandName == F("taskvalueset")) || (commandName == F("dummyvalueset"))) // should work for both { valueStr = formatUserVarNoCheck(event, taskVarIndex); //parseString(string, 4); - success = MQTTpublish(CPLUGIN_ID_014, topic.c_str(), valueStr.c_str(), false); + success = MQTTpublish(CPLUGIN_ID_014, INVALID_TASK_INDEX, topic.c_str(), valueStr.c_str(), false); if (loglevelActiveFor(LOG_LEVEL_INFO) && success) { String log = F("C014 : Acknowledged: "); log += deviceName; @@ -872,7 +873,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& valueStr = parseStringToEnd(string,4); break; } - success = MQTTpublish(CPLUGIN_ID_014, topic.c_str(), valueStr.c_str(), false); + success = MQTTpublish(CPLUGIN_ID_014, INVALID_TASK_INDEX, topic.c_str(), valueStr.c_str(), false); if (loglevelActiveFor(LOG_LEVEL_INFO) && success) { String log = F("C014 : homie acknowledge: "); log += deviceName; diff --git a/src/_C016.ino b/src/_C016.ino index 5cbe8416da..a4cd949287 100644 --- a/src/_C016.ino +++ b/src/_C016.ino @@ -54,6 +54,7 @@ bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesPort = false; Protocol[protocolCount].usesSampleSets = false; Protocol[protocolCount].needsNetwork = false; + Protocol[protocolCount].allowsExpire = false; break; } diff --git a/src/src/Commands/MQTT.cpp b/src/src/Commands/MQTT.cpp index b09f3a13f5..1dfb9adecd 100644 --- a/src/src/Commands/MQTT.cpp +++ b/src/src/Commands/MQTT.cpp @@ -59,10 +59,10 @@ String Command_MQTT_Publish(struct EventStruct *event, const char *Line) bool success = false; if (value[0] != '=') { - success = MQTTpublish(enabledMqttController, topic.c_str(), value.c_str(), mqtt_retainFlag); + success = MQTTpublish(enabledMqttController, INVALID_TASK_INDEX, topic.c_str(), value.c_str(), mqtt_retainFlag); } else { - success = MQTTpublish(enabledMqttController, topic.c_str(), String(event->Par2).c_str(), mqtt_retainFlag); + success = MQTTpublish(enabledMqttController, INVALID_TASK_INDEX, topic.c_str(), String(event->Par2).c_str(), mqtt_retainFlag); } if (success) { return return_command_success(); diff --git a/src/src/ControllerQueue/C011_queue_element.cpp b/src/src/ControllerQueue/C011_queue_element.cpp index c9c8b01c86..ca58a27057 100644 --- a/src/src/ControllerQueue/C011_queue_element.cpp +++ b/src/src/ControllerQueue/C011_queue_element.cpp @@ -21,4 +21,18 @@ size_t C011_queue_element::getSize() const { return total; } +bool C011_queue_element::isDuplicate(const C011_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.sensorType != sensorType || + other.idx != idx) { + return false; + } + return (other.uri.equals(uri) && + other.HttpMethod.equals(HttpMethod) && + other.header.equals(header) && + other.postStr.equals(postStr)); +} + + #endif diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 3a34081fc9..e348c6d4af 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -22,6 +22,8 @@ class C011_queue_element { C011_queue_element(const struct EventStruct *event); + bool isDuplicate(const C011_queue_element& other) const; + size_t getSize() const; String uri; @@ -29,6 +31,7 @@ class C011_queue_element { String header; String postStr; int idx = 0; + unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; diff --git a/src/src/ControllerQueue/C015_queue_element.cpp b/src/src/ControllerQueue/C015_queue_element.cpp index 3a25b7e06f..4b2971845b 100644 --- a/src/src/ControllerQueue/C015_queue_element.cpp +++ b/src/src/ControllerQueue/C015_queue_element.cpp @@ -27,4 +27,24 @@ size_t C015_queue_element::getSize() const { return total; } +bool C015_queue_element::isDuplicate(const C015_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.sensorType != sensorType || + other.valueCount != valueCount || + other.idx != idx) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.txt[i] != txt[i]) { + return false; + } + if (other.vPin[i] != vPin[i]) { + return false; + } + } + return true; +} + + #endif diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index 10e3bf4530..0bcb070256 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -26,9 +26,12 @@ class C015_queue_element { size_t getSize() const; + bool isDuplicate(const C015_queue_element& other) const; + String txt[VARS_PER_TASK]; int vPin[VARS_PER_TASK] = { 0 }; int idx = 0; + unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() diff --git a/src/src/ControllerQueue/C016_queue_element.cpp b/src/src/ControllerQueue/C016_queue_element.cpp index 518e2191d8..8b783e04bf 100644 --- a/src/src/ControllerQueue/C016_queue_element.cpp +++ b/src/src/ControllerQueue/C016_queue_element.cpp @@ -6,11 +6,11 @@ #ifdef USES_C016 -C016_queue_element::C016_queue_element() : timestamp(0), TaskIndex(INVALID_TASK_INDEX), controller_idx(0), sensorType( +C016_queue_element::C016_queue_element() : _timestamp(0), TaskIndex(INVALID_TASK_INDEX), controller_idx(0), sensorType( Sensor_VType::SENSOR_TYPE_NONE) {} C016_queue_element::C016_queue_element(const struct EventStruct *event, byte value_count, unsigned long unixTime) : - timestamp(unixTime), + _timestamp(unixTime), TaskIndex(event->TaskIndex), controller_idx(event->ControllerIndex), sensorType(event->sensorType), @@ -29,4 +29,19 @@ size_t C016_queue_element::getSize() const { return sizeof(*this); } +bool C016_queue_element::isDuplicate(const C016_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.sensorType != sensorType || + other.valueCount != valueCount) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.values[i] != values[i]) { + return false; + } + } + return true; +} + #endif diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 9e2b1f1652..132189bdc4 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -14,6 +14,9 @@ struct EventStruct; /*********************************************************************************************\ * C016_queue_element for queueing requests for C016: Cached HTTP. \*********************************************************************************************/ + +// TD-er: This one has a fixed byte order and is stored. +// This also means the order of members should not be changed! class C016_queue_element { public: @@ -25,10 +28,12 @@ class C016_queue_element { size_t getSize() const; + bool isDuplicate(const C016_queue_element& other) const; + float values[VARS_PER_TASK] = { 0 }; - unsigned long timestamp = 0; // Unix timestamp + unsigned long _timestamp = 0; // Unix timestamp taskIndex_t TaskIndex = INVALID_TASK_INDEX; - byte controller_idx = 0; + controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; byte valueCount = 0; }; diff --git a/src/src/ControllerQueue/C018_queue_element.cpp b/src/src/ControllerQueue/C018_queue_element.cpp index 669cc211ad..032de24f11 100644 --- a/src/src/ControllerQueue/C018_queue_element.cpp +++ b/src/src/ControllerQueue/C018_queue_element.cpp @@ -11,6 +11,7 @@ C018_queue_element::C018_queue_element() {} C018_queue_element::C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount) : + TaskIndex(event->TaskIndex), controller_idx(event->ControllerIndex) { #ifdef USES_PACKED_RAW_DATA @@ -27,4 +28,18 @@ size_t C018_queue_element::getSize() const { return sizeof(*this) + packed.length(); } +bool C018_queue_element::isDuplicate(const C018_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.packed[i] != packed[i]) { + return false; + } + } + return true; +} + + #endif diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index ee9dd98089..29d2d4f9eb 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -25,7 +25,11 @@ class C018_queue_element { size_t getSize() const; + bool isDuplicate(const C018_queue_element& other) const; + String packed; + unsigned long _timestamp = millis(); + taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; }; diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 285b416682..d1c1340878 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -28,11 +28,13 @@ struct ControllerDelayHandlerStruct { ControllerDelayHandlerStruct() : lastSend(0), minTimeBetweenMessages(CONTROLLER_DELAY_QUEUE_DELAY_DFLT), + expire_timeout(0), max_queue_depth(CONTROLLER_DELAY_QUEUE_DEPTH_DFLT), attempt(0), max_retries(CONTROLLER_DELAY_QUEUE_RETRY_DFLT), delete_oldest(false), - must_check_reply(false) {} + must_check_reply(false), + deduplicate(false) {} void configureControllerSettings(const ControllerSettingsStruct& settings) { minTimeBetweenMessages = settings.MinimalTimeBetweenMessages; @@ -40,6 +42,10 @@ struct ControllerDelayHandlerStruct { max_retries = settings.MaxRetry; delete_oldest = settings.DeleteOldest; must_check_reply = settings.MustCheckReply; + deduplicate = settings.deduplicate(); + if (settings.allowExpire()) { + expire_timeout = max_queue_depth * max_retries * (minTimeBetweenMessages + settings.ClientTimeout); + } // Set some sound limits when not configured if (max_queue_depth == 0) { max_queue_depth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT; } @@ -92,11 +98,22 @@ struct ControllerDelayHandlerStruct { // Try to add to the queue, if permitted by "delete_oldest" // Return false when no item was added. bool addToQueue(T&& element) { + if (deduplicate && !sendQueue.empty()) { + // If message is already present consider adding to be a success. + for (auto it = sendQueue.begin(); it != sendQueue.end(); ++it) { + if (it->TaskIndex == element.TaskIndex && validTaskIndex(it->TaskIndex)) { + if (element.isDuplicate(*it)) { + return true; + } + } + } + } if (delete_oldest) { // Force add to the queue. // If max buffer is reached, the oldest in the queue (first to be served) will be removed. while (queueFull(element)) { sendQueue.pop_front(); + attempt = 0; } sendQueue.emplace_back(element); return true; @@ -126,9 +143,21 @@ struct ControllerDelayHandlerStruct { if (attempt > max_retries) { sendQueue.pop_front(); attempt = 0; + } - if (sendQueue.empty()) { return NULL; } + if (expire_timeout != 0) { + bool done = false; + while (!done && !sendQueue.empty()) { + if (timePassedSince(sendQueue.front()._timestamp) < expire_timeout) { + done = true; + } else { + sendQueue.pop_front(); + attempt = 0; + } + } } + + if (sendQueue.empty()) { return NULL; } return &sendQueue.front(); } @@ -180,11 +209,13 @@ struct ControllerDelayHandlerStruct { std::list sendQueue; unsigned long lastSend; unsigned int minTimeBetweenMessages; + unsigned long expire_timeout; byte max_queue_depth; byte attempt; byte max_retries; bool delete_oldest; bool must_check_reply; + bool deduplicate; }; diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index d0648fa5a9..1228e10c69 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -4,8 +4,9 @@ MQTT_queue_element::MQTT_queue_element() {} MQTT_queue_element::MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, const String& topic, const String& payload, bool retained) : - _topic(topic), _payload(payload), controller_idx(ctrl_idx), _retained(retained) + _topic(topic), _payload(payload), TaskIndex(TaskIndex), controller_idx(ctrl_idx), _retained(retained) { // some parts of the topic may have been replaced by empty strings, // or "/status" may have been appended to a topic ending with a "/" @@ -18,3 +19,20 @@ MQTT_queue_element::MQTT_queue_element(int ctrl_idx, size_t MQTT_queue_element::getSize() const { return sizeof(*this) + _topic.length() + _payload.length(); } + +bool MQTT_queue_element::isDuplicate(const MQTT_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other._retained != _retained) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other._topic[i] != _topic[i]) { + return false; + } + if (other._payload[i] != _payload[i]) { + return false; + } + } + return true; +} diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index 13127e9bd9..e59cf658ca 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -14,14 +14,19 @@ class MQTT_queue_element { MQTT_queue_element(); explicit MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, const String& topic, const String& payload, bool retained); size_t getSize() const; + bool isDuplicate(const MQTT_queue_element& other) const; + String _topic; String _payload; + unsigned long _timestamp = millis(); + taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; bool _retained = false; }; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp index 5afd46d832..0bfab48a52 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp @@ -2,9 +2,22 @@ simple_queue_element_string_only::simple_queue_element_string_only() {} -simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, const String& req) : - txt(req), controller_idx(ctrl_idx) {} +simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, const String& req) : + txt(req), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} size_t simple_queue_element_string_only::getSize() const { return sizeof(*this) + txt.length(); } + +bool simple_queue_element_string_only::isDuplicate(const simple_queue_element_string_only& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.txt[i] != txt[i]) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 92d784c3ad..68763fb7f7 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -13,12 +13,18 @@ class simple_queue_element_string_only { simple_queue_element_string_only(); - simple_queue_element_string_only(int ctrl_idx, - const String& req); + explicit simple_queue_element_string_only(int ctrl_idx, + taskIndex_t TaskIndex, + const String& req); size_t getSize() const; + bool isDuplicate(const simple_queue_element_string_only& other) const; + + String txt; + unsigned long _timestamp = millis(); + taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; }; diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp index 84d470efcb..93a61a2aa1 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp @@ -27,3 +27,18 @@ size_t queue_element_formatted_uservar::getSize() const { } return total; } + +bool queue_element_formatted_uservar::isDuplicate(const queue_element_formatted_uservar& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.sensorType != sensorType || + other.valueCount != valueCount) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.txt[i] != txt[i]) { + return false; + } + } + return true; +} diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index 932d9ea270..b900df5831 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -21,8 +21,11 @@ class queue_element_formatted_uservar { size_t getSize() const; + bool isDuplicate(const queue_element_formatted_uservar& other) const; + String txt[VARS_PER_TASK]; int idx = 0; + unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; diff --git a/src/src/ControllerQueue/queue_element_single_value_base.cpp b/src/src/ControllerQueue/queue_element_single_value_base.cpp index ec0704e993..c2740ddaaf 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.cpp +++ b/src/src/ControllerQueue/queue_element_single_value_base.cpp @@ -37,3 +37,18 @@ size_t queue_element_single_value_base::getSize() const { } return total; } + +bool queue_element_single_value_base::isDuplicate(const queue_element_single_value_base& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.valueCount != valueCount || + other.idx != idx) { + return false; + } + for (byte i = 0; i < VARS_PER_TASK; ++i) { + if (other.txt[i] != txt[i]) { + return false; + } + } + return true; +} diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index fc1fd77d83..683f79b841 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -27,8 +27,11 @@ class queue_element_single_value_base { size_t getSize() const; + bool isDuplicate(const queue_element_single_value_base& other) const; + String txt[VARS_PER_TASK]; int idx = 0; + unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index a0bdb4e51b..4994001107 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -275,3 +275,13 @@ void ControllerSettingsStruct::allowExpire(bool value) { bitWrite(VariousFlags, 8, value); } + +bool ControllerSettingsStruct::deduplicate() const +{ + return bitRead(VariousFlags, 9); +} + +void ControllerSettingsStruct::deduplicate(bool value) +{ + bitWrite(VariousFlags, 9, value); +} diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 9b44b8790b..2685254557 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -70,6 +70,7 @@ struct ControllerSettingsStruct CONTROLLER_MAX_RETRIES, CONTROLLER_FULL_QUEUE_ACTION, CONTROLLER_ALLOW_EXPIRE, + CONTROLLER_DEDUPLICATE, CONTROLLER_CHECK_REPLY, CONTROLLER_CLIENT_ID, CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT, @@ -143,6 +144,8 @@ struct ControllerSettingsStruct bool allowExpire() const; void allowExpire(bool value); + bool deduplicate() const; + void deduplicate(bool value); boolean UseDNS; byte IP[4]; diff --git a/src/src/DataStructs/ProtocolStruct.cpp b/src/src/DataStructs/ProtocolStruct.cpp index 90ce9b6482..59aacbd8b0 100644 --- a/src/src/DataStructs/ProtocolStruct.cpp +++ b/src/src/DataStructs/ProtocolStruct.cpp @@ -4,7 +4,7 @@ ProtocolStruct::ProtocolStruct() : defaultPort(0), Number(0), usesMQTT(false), usesAccount(false), usesPassword(false), usesTemplate(false), usesID(false), Custom(false), usesHost(true), usesPort(true), usesQueue(true), usesCheckReply(true), usesTimeout(true), usesSampleSets(false), - usesExtCreds(false), needsNetwork(true) {} + usesExtCreds(false), needsNetwork(true), allowsExpire(true) {} bool ProtocolStruct::useCredentials() const { return usesAccount || usesPassword; diff --git a/src/src/DataStructs/ProtocolStruct.h b/src/src/DataStructs/ProtocolStruct.h index c322a26860..40785bd863 100644 --- a/src/src/DataStructs/ProtocolStruct.h +++ b/src/src/DataStructs/ProtocolStruct.h @@ -31,6 +31,7 @@ struct ProtocolStruct bool usesSampleSets : 1; bool usesExtCreds : 1; bool needsNetwork : 1; + bool allowsExpire : 1; }; typedef std::vector ProtocolVector; diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index baa9fd1e0f..ab119568ef 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -546,7 +546,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes #endif -bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained) +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained) { if (MQTTDelayHandler == nullptr) { return false; @@ -555,7 +555,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char if (MQTT_queueFull(controller_idx)) { return false; } - const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, topic, payload, retained)); + const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained)); scheduleNextMQTTdelayQueue(); return success; @@ -603,7 +603,7 @@ void MQTTStatus(struct EventStruct *event, const String& status) pubname += F("/status"); } - MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(), mqtt_retainFlag); + MQTTpublish(enabledMqttController, event->TaskIndex, pubname.c_str(), status.c_str(), mqtt_retainFlag); } } diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 16326831cf..38d02ed242 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -74,7 +74,7 @@ bool MQTT_queueFull(controllerIndex_t controller_idx); bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); #endif -bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char *payload, bool retained); +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained); /*********************************************************************************************\ diff --git a/src/src/Globals/C016_ControllerCache.cpp b/src/src/Globals/C016_ControllerCache.cpp index e27e3947f6..3812105846 100644 --- a/src/src/Globals/C016_ControllerCache.cpp +++ b/src/src/Globals/C016_ControllerCache.cpp @@ -33,7 +33,7 @@ bool C016_getCSVline( { C016_queue_element element; bool result = ControllerCache.peek((uint8_t*)&element, sizeof(element)); - timestamp = element.timestamp; + timestamp = element._timestamp; controller_idx = element.controller_idx; TaskIndex = element.TaskIndex; sensorType = element.sensorType; diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index faf3f338dc..13511ba44d 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -32,6 +32,10 @@ #include "../DataStructs/C013_p2p_dataStructs.h" #endif +#ifdef USES_C016 +#include "../ControllerQueue/C016_queue_element.h" +#endif + #ifdef USES_NOTIFIER #include "../DataStructs/NotificationStruct.h" #include "../DataStructs/NotificationSettingsStruct.h" @@ -99,6 +103,11 @@ void run_compiletime_checks() { check_size(); check_size(); #endif + #ifdef USES_C016 + check_size(); + #endif + + #if defined(USE_NON_STANDARD_24_TASKS) && defined(ESP8266) static_assert(TASKS_MAX == 24, "TASKS_MAX invalid size"); #endif diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index bc68d680ff..41f7e766bd 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -45,6 +45,7 @@ String getControllerParameterName(protocolIndex_t ProtocolInde case ControllerSettingsStruct::CONTROLLER_MAX_RETRIES: name = F("Max Retries"); break; case ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION: name = F("Full Queue Action"); break; case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: name = F("Allow Expire"); break; + case ControllerSettingsStruct::CONTROLLER_DEDUPLICATE: name = F("De-duplicate"); break; case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: name = F("Check Reply"); break; @@ -198,6 +199,9 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: addFormCheckBox(displayName, internalName, ControllerSettings.allowExpire()); break; + case ControllerSettingsStruct::CONTROLLER_DEDUPLICATE: + addFormCheckBox(displayName, internalName, ControllerSettings.deduplicate()); + break; case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: { String options[2]; @@ -325,6 +329,9 @@ void saveControllerParameterForm(ControllerSettingsStruct & ControllerSet case ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE: ControllerSettings.allowExpire(isFormItemChecked(internalName)); break; + case ControllerSettingsStruct::CONTROLLER_DEDUPLICATE: + ControllerSettings.deduplicate(isFormItemChecked(internalName)); + break; case ControllerSettingsStruct::CONTROLLER_CHECK_REPLY: ControllerSettings.MustCheckReply = getFormItemInt(internalName, ControllerSettings.MustCheckReply); break; diff --git a/src/src/WebServer/ControllerPage.cpp b/src/src/WebServer/ControllerPage.cpp index 1c3d42bdef..5446a48cc5 100644 --- a/src/src/WebServer/ControllerPage.cpp +++ b/src/src/WebServer/ControllerPage.cpp @@ -339,7 +339,10 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE); + if (Protocol[ProtocolIndex].allowsExpire) { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE); + } + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_DEDUPLICATE); } if (Protocol[ProtocolIndex].usesCheckReply) { From 3c2e5ac3b213eb6febcc61a9be452e68f0adbe1a Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 13:53:43 +0100 Subject: [PATCH 092/404] [Controller Settings] Fix merge conflict with ESPEasy-NOW PR --- src/src/DataStructs/ControllerSettingsStruct.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index 4994001107..1c697b8192 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -268,20 +268,20 @@ void ControllerSettingsStruct::enableESPEasyNowFallback(bool value) bool ControllerSettingsStruct::allowExpire() const { - return bitRead(VariousFlags, 8); + return bitRead(VariousFlags, 9); } void ControllerSettingsStruct::allowExpire(bool value) { - bitWrite(VariousFlags, 8, value); + bitWrite(VariousFlags, 9, value); } bool ControllerSettingsStruct::deduplicate() const { - return bitRead(VariousFlags, 9); + return bitRead(VariousFlags, 10); } void ControllerSettingsStruct::deduplicate(bool value) { - bitWrite(VariousFlags, 9, value); + bitWrite(VariousFlags, 10, value); } From a0672d4ef7c01296a644ddb71962bae2aac3ca08 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 14:01:52 +0100 Subject: [PATCH 093/404] [ESPEasy-NOW] Fix other merge conflicts --- src/src/ControllerQueue/C019_queue_element.cpp | 12 ++++++++++++ src/src/ControllerQueue/C019_queue_element.h | 5 +++++ src/src/DataStructs/ControllerSettingsStruct.h | 3 +-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 2be0029ccf..80ca2e6af5 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -32,3 +32,15 @@ C019_queue_element::C019_queue_element(struct EventStruct *event_p) : size_t C019_queue_element::getSize() const { return sizeof(*this) + packed.length(); } + + +bool C019_queue_element::isDuplicate(const C019_queue_element& other) const { + if (other.controller_idx != controller_idx || + other.TaskIndex != TaskIndex || + other.plugin_id != plugin_id || + other.packed != packed) { + return false; + } + // FIXME TD-er: Must check event too? + return false; +} \ No newline at end of file diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index e60e7e79dd..0be765b23b 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -23,7 +23,12 @@ class C019_queue_element { size_t getSize() const; + bool isDuplicate(const C019_queue_element& other) const; + + String packed; + unsigned long _timestamp = millis(); + taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; EventStruct event; diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 2685254557..a5537889b7 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -140,14 +140,13 @@ struct ControllerSettingsStruct bool enableESPEasyNowFallback() const; void enableESPEasyNowFallback(bool value); - bool UseDNS; bool allowExpire() const; void allowExpire(bool value); bool deduplicate() const; void deduplicate(bool value); - boolean UseDNS; + bool UseDNS; byte IP[4]; unsigned int Port; char HostName[65]; From dd262963b96f6f7ac5b8a4438db8fdb8c119bfc0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 16:03:34 +0100 Subject: [PATCH 094/404] [ESPEasy-NOW] Apply duplicate check for ESPEasy-NOW messages --- .../ControllerDelayHandlerStruct.h | 43 ++++++++++++++----- .../ControllerQueue/MQTT_queue_element.cpp | 3 +- src/src/ESPEasyCore/Controller.cpp | 16 ++++--- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index d1c1340878..5232b4c34e 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -19,6 +19,9 @@ #include // For std::shared_ptr #include // std::nothrow +#ifndef CONTROLLER_QUEUE_MINIMAL_EXPIRE_TIME + #define CONTROLLER_QUEUE_MINIMAL_EXPIRE_TIME 10000 +#endif /*********************************************************************************************\ * ControllerDelayHandlerStruct @@ -45,6 +48,11 @@ struct ControllerDelayHandlerStruct { deduplicate = settings.deduplicate(); if (settings.allowExpire()) { expire_timeout = max_queue_depth * max_retries * (minTimeBetweenMessages + settings.ClientTimeout); + if (expire_timeout < CONTROLLER_QUEUE_MINIMAL_EXPIRE_TIME) { + expire_timeout = CONTROLLER_QUEUE_MINIMAL_EXPIRE_TIME; + } + } else { + expire_timeout = 0; } // Set some sound limits when not configured @@ -95,19 +103,26 @@ struct ControllerDelayHandlerStruct { return true; } - // Try to add to the queue, if permitted by "delete_oldest" - // Return false when no item was added. - bool addToQueue(T&& element) { + // Return true if last element was removed + bool removeLastIfDuplicate() { if (deduplicate && !sendQueue.empty()) { - // If message is already present consider adding to be a success. - for (auto it = sendQueue.begin(); it != sendQueue.end(); ++it) { - if (it->TaskIndex == element.TaskIndex && validTaskIndex(it->TaskIndex)) { - if (element.isDuplicate(*it)) { - return true; - } + auto back = sendQueue.back(); + // Use reverse iterator here, as it is more likely a duplicate is added shortly after another. + auto it = sendQueue.rbegin(); // Same as back() + ++it; // The last element before back() + for (; it != sendQueue.rend(); ++it) { + if (back.isDuplicate(*it)) { + sendQueue.pop_back(); + return true; } } } + return false; + } + + // Try to add to the queue, if permitted by "delete_oldest" + // Return false when no item was added. + bool addToQueue(T&& element, bool checkDuplicate = true) { if (delete_oldest) { // Force add to the queue. // If max buffer is reached, the oldest in the queue (first to be served) will be removed. @@ -116,11 +131,19 @@ struct ControllerDelayHandlerStruct { attempt = 0; } sendQueue.emplace_back(element); + if (checkDuplicate) { + // If message is already present consider adding to be a success. + removeLastIfDuplicate(); + } return true; } if (!queueFull(element)) { sendQueue.emplace_back(element); + if (checkDuplicate) { + // If message is already present consider adding to be a success. + removeLastIfDuplicate(); + } return true; } #ifndef BUILD_NO_DEBUG @@ -209,7 +232,7 @@ struct ControllerDelayHandlerStruct { std::list sendQueue; unsigned long lastSend; unsigned int minTimeBetweenMessages; - unsigned long expire_timeout; + unsigned long expire_timeout = 0; byte max_queue_depth; byte attempt; byte max_retries; diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index 1228e10c69..f5c4fbc2f4 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -21,8 +21,7 @@ size_t MQTT_queue_element::getSize() const { } bool MQTT_queue_element::isDuplicate(const MQTT_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || + if (other.controller_idx != controller_idx || other._retained != _retained) { return false; } diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index ab119568ef..1dc25d331c 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -525,19 +525,21 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes bool success = false; if (!MQTT_queueFull(controller_idx)) { - success = MQTTDelayHandler->addToQueue(MQTT_queue_element()); + success = MQTTDelayHandler->addToQueue(MQTT_queue_element(), false); if (success) { size_t pos = 0; MQTTDelayHandler->sendQueue.back().controller_idx = controller_idx; MQTTDelayHandler->sendQueue.back()._retained = retained; message.getString(MQTTDelayHandler->sendQueue.back()._topic, pos); message.getString(MQTTDelayHandler->sendQueue.back()._payload, pos); - } - - size_t payloadSize = message.getPayloadSize(); - if ((MQTTDelayHandler->sendQueue.back()._topic.length() + MQTTDelayHandler->sendQueue.back()._payload.length() + 2) < payloadSize) { - success = false; - MQTTDelayHandler->sendQueue.pop_back(); + // Check to see if it was successful. + size_t payloadSize = message.getPayloadSize(); + if ((MQTTDelayHandler->sendQueue.back()._topic.length() + MQTTDelayHandler->sendQueue.back()._payload.length() + 2) < payloadSize) { + success = false; + MQTTDelayHandler->sendQueue.pop_back(); + } else { + MQTTDelayHandler->removeLastIfDuplicate(); + } } } scheduleNextMQTTdelayQueue(); From c7427e33baaeec7e331ef7d5200e790820397297 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 2 Mar 2021 16:58:52 +0100 Subject: [PATCH 095/404] [CUL reader] Add option to append Unix time stamp --- src/_P094_CULReader.ino | 10 ++++++++-- src/src/PluginStructs/P094_data_struct.cpp | 15 ++++++++++++--- src/src/PluginStructs/P094_data_struct.h | 2 +- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 163bdf05fd..dae6e6130e 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -26,6 +26,8 @@ #define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) #define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) +#define P094_APPEND_RECEIVE_SYSTIME PCONFIG(0) + #define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. #define P094_NR_OUTPUT_OPTIONS 1 @@ -150,6 +152,8 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); + addFormCheckBox(F("Append system time"), F("systime"), P094_APPEND_RECEIVE_SYSTIME); + success = true; break; } @@ -171,6 +175,8 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { success = true; } + P094_APPEND_RECEIVE_SYSTIME = isFormItemChecked(F("systime")); + break; } @@ -207,7 +213,7 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { // Scheduler.schedule_task_device_timer(event->TaskIndex, millis() + 10); delay(0); // Processing a full sentence may take a while, run some // background tasks. - P094_data->getSentence(event->String2); + P094_data->getSentence(event->String2, P094_APPEND_RECEIVE_SYSTIME); if (event->String2.length() > 0) { if (Plugin_094_match_all(event->TaskIndex, event->String2)) { @@ -434,7 +440,7 @@ void P094_html_show_stats(struct EventStruct *event) { { addRowLabel(F("Current Sentence")); String sentencePart; - P094_data->getSentence(sentencePart); + P094_data->getSentence(sentencePart, false); addHtml(sentencePart); } diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index a0443cadcf..ea06630159 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -8,6 +8,7 @@ #ifdef USES_P094 +#include "../Globals/ESPEasy_time.h" #include "../Helpers/StringConverter.h" @@ -145,9 +146,17 @@ bool P094_data_struct::loop() { return fullSentenceReceived; } -void P094_data_struct::getSentence(String& string) { - string = sentence_part; - sentence_part = ""; +void P094_data_struct::getSentence(String& string, bool appendSysTime) { + if (appendSysTime) { + // Unix timestamp = 10 decimals + separator + string.reserve(sentence_part.length() + 11); + string = sentence_part; + string += ';'; + string += node_time.getUnixTime(); + sentence_part = ""; + } else { + string = std::move(sentence_part); + } } void P094_data_struct::getSentencesReceived(uint32_t& succes, uint32_t& error, uint32_t& length_last) const { diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 387868abb2..59348039d8 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -75,7 +75,7 @@ struct P094_data_struct : public PluginTaskData_base { bool loop(); - void getSentence(String& string); + void getSentence(String& string, bool appendSysTime); void getSentencesReceived(uint32_t& succes, uint32_t& error, From 9e68ed24c136bd2bd4741f5d864a7336f052d826 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 3 Mar 2021 11:36:51 +0100 Subject: [PATCH 096/404] [ESPEasy-NOW] Cleanup --- src/ESPEasy.ino | 2 +- src/_P094_CULReader.ino | 1 + .../ControllerDelayHandlerStruct.h | 21 +++++++---- src/src/DataStructs/NodesHandler.cpp | 4 +-- src/src/DataStructs/WiFiEventData.cpp | 6 ---- src/src/DataStructs/WiFiEventData.h | 4 --- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 +-- src/src/Helpers/ESPEasy_now_handler.cpp | 7 ++-- src/src/Helpers/Networking.cpp | 3 +- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 35 ++++++++++++++++--- src/src/Helpers/WiFi_AP_CandidatesList.h | 4 +++ 11 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index ad31e569fa..b142db5fa2 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -430,7 +430,7 @@ void setup() } #ifdef USES_ESPEASY_NOW - if (WiFiEventData.isESPEasy_now_only() || Settings.UseESPEasyNow()) { + if (WiFi_AP_Candidates.isESPEasy_now_only() || Settings.UseESPEasyNow()) { RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. RTC.lastWiFiChannel = 0; // Force slow connect } diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index dae6e6130e..764092d3e5 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -10,6 +10,7 @@ // +#include "src/Helpers/ESPEasy_Storage.h" #include "src/Helpers/StringConverter.h" #include "src/PluginStructs/P094_data_struct.h" diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 5232b4c34e..3d2e1809d0 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -88,15 +88,15 @@ struct ControllerDelayHandlerStruct { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = "Controller-"; + String log = F("Controller-"); log += element.controller_idx + 1; - log += " : Memory used: "; + log += F(" : Memory used: "); log += getQueueMemorySize(); - log += " bytes "; + log += F(" bytes "); log += sendQueue.size(); - log += " items "; + log += F(" items "); log += freeHeap; - log += " free"; + log += F(" free"); addLog(LOG_LEVEL_DEBUG, log); } #endif // ifndef BUILD_NO_DEBUG @@ -112,6 +112,15 @@ struct ControllerDelayHandlerStruct { ++it; // The last element before back() for (; it != sendQueue.rend(); ++it) { if (back.isDuplicate(*it)) { +#ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + const cpluginID_t cpluginID = getCPluginID_from_ControllerIndex(element.controller_idx); + String log = get_formatted_Controller_number(cpluginID); + log += F(" : Remove duplicate"); + addLog(LOG_LEVEL_DEBUG, log); + } +#endif // ifndef BUILD_NO_DEBUG + sendQueue.pop_back(); return true; } @@ -151,7 +160,7 @@ struct ControllerDelayHandlerStruct { if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { const cpluginID_t cpluginID = getCPluginID_from_ControllerIndex(element.controller_idx); String log = get_formatted_Controller_number(cpluginID); - log += " : queue full"; + log += F(" : queue full"); addLog(LOG_LEVEL_DEBUG, log); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 6cdd8f5c67..ebc05f2f70 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -164,7 +164,7 @@ void NodesHandler::updateThisNode() { { bool addIP = true; #ifdef USES_ESPEASY_NOW - if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { // Connected via 'virtual ESPEasy-NOW AP' addIP = false; } @@ -218,7 +218,7 @@ void NodesHandler::updateThisNode() { _lastTimeValidDistance = millis(); if (_distance != lastDistance) { #ifdef USES_ESPEASY_NOW - if (WiFiEventData.isESPEasy_now_only() && WiFiConnected()) { + if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFiConnected()) { // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP // Try to reconnect to it. RTC.clearLastWiFi(); // Force a WiFi scan diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index da0c630b41..8f2e0ece6c 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -152,9 +152,3 @@ void WiFiEventData_t::markDisconnectedAPmode(const uint8_t mac[6]) { processedDisconnectAPmode = false; } - -#ifdef USES_ESPEASY_NOW - bool WiFiEventData_t::isESPEasy_now_only() const { - return RTC.lastWiFiSettingsIndex == 3; - } -#endif diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 22393c5b0a..e6cdf1b8e7 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -53,10 +53,6 @@ struct WiFiEventData_t { void markConnectedAPmode(const uint8_t mac[6]); void markDisconnectedAPmode(const uint8_t mac[6]); -#ifdef USES_ESPEASY_NOW - bool isESPEasy_now_only() const; -#endif - // WiFi related data diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 5fa0f26cb6..f7009ac59e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -180,7 +180,7 @@ void processDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW - if (WiFiEventData.isESPEasy_now_only()) return; + if (WiFi_AP_Candidates.isESPEasy_now_only()) return; ESPEasy_now_handler.end(); #endif @@ -450,7 +450,7 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); - if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { if (WiFi_AP_Candidates.addedKnownCandidate() && WiFiConnected()) { WiFi_AP_Candidates.force_reload(); WifiDisconnect(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 0a3b2c28c3..3e7afa6e87 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -20,6 +20,7 @@ # include "../Globals/SecuritySettings.h" # include "../Globals/SendData_DuplicateChecker.h" # include "../Globals/Settings.h" +# include "../Globals/WiFi_AP_Candidates.h" # include "../Helpers/CRC_functions.h" # include "../Helpers/ESPEasy_Storage.h" # include "../Helpers/ESPEasy_time_calc.h" @@ -91,7 +92,7 @@ bool ESPEasy_now_handler_t::begin() MAC_address bssid; _controllerIndex = INVALID_CONTROLLER_INDEX; - if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { WifiScan(false, 0); addPeerFromWiFiScan(); } @@ -111,7 +112,7 @@ bool ESPEasy_now_handler_t::begin() setAP(true); /* // FIXME TD-er: Must use standard WiFi connection setup. - if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { if (bssid.all_zero()) { WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel); } else { @@ -253,7 +254,7 @@ bool ESPEasy_now_handler_t::loop() if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; - // FIXME TD-er: Must check/mark so this becomes true: WiFiEventData.isESPEasy_now_only() + // FIXME TD-er: Must check/mark so this becomes true: WiFi_AP_Candidates.isESPEasy_now_only() // Start scanning the next channel to see if we may end up with a new found node // WifiScan(false, false); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 059f0d37fc..1df086ba31 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -13,6 +13,7 @@ #include "../Globals/NetworkState.h" #include "../Globals/Nodes.h" #include "../Globals/Settings.h" +#include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/ESPEasy_Storage.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/Network.h" @@ -878,7 +879,7 @@ bool hasIPaddr() { bool NetworkConnected(uint32_t timeout_ms) { #ifdef USES_ESPEASY_NOW - if (WiFiEventData.isESPEasy_now_only()) { + if (WiFi_AP_Candidates.isESPEasy_now_only()) { return false; } #endif diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 47cad31753..6000814df3 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -1,15 +1,19 @@ #include "../Helpers/WiFi_AP_CandidatesList.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/RTC.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" + #ifdef USES_ESPEASY_NOW #define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" #define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" #endif +#define WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX 3 + WiFi_AP_CandidatesList::WiFi_AP_CandidatesList() { known.clear(); candidates.clear(); @@ -29,9 +33,16 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { // Add the known SSIDs String ssid, key; byte index = 1; // Index 0 is the "unset" value - - while (get_SSID_key(index, ssid, key)) { - known.emplace_back(index, ssid, key); + bool done = false; + + while (!done) { + if (get_SSID_key(index, ssid, key)) { + known.emplace_back(index, ssid, key); + } else if (index != WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX) { + // There may be other credentials so don't stop at ESPEasy-now index + // For example on builds without ESPEasy-NOW these credentials will not be returned. + done = true; + } ++index; } } @@ -155,6 +166,13 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { addFromRTC(); // Store the current one from RTC as the first candidate for a reconnect. } +#ifdef USES_ESPEASY_NOW +bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { + return RTC.lastWiFiSettingsIndex == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX; +} +#endif + + void WiFi_AP_CandidatesList::add(uint8_t networkItem) { WiFi_AP_Candidate tmp(networkItem); @@ -189,6 +207,15 @@ void WiFi_AP_CandidatesList::add(uint8_t networkItem) { void WiFi_AP_CandidatesList::addFromRTC() { if (!RTC.lastWiFi_set()) { return; } + #ifdef USES_ESPEASY_NOW + if (isESPEasy_now_only()) { + // Connected via 'virtual ESPEasy-NOW AP' + // This should be a last resort. + return; + } + #endif + + String ssid, key; if (!get_SSID_key(RTC.lastWiFiSettingsIndex, ssid, key)) { @@ -255,7 +282,7 @@ bool WiFi_AP_CandidatesList::get_SSID_key(byte index, String& ssid, String& key) key = SecuritySettings.WifiKey2; break; #ifdef USES_ESPEASY_NOW - case 3: + case WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX: ssid = F(ESPEASY_NOW_TMP_SSID); key = F(ESPEASY_NOW_TMP_PASSPHRASE); break; diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 099ff22ea9..fdb2ce42c5 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -36,6 +36,10 @@ struct WiFi_AP_CandidatesList { bool addedKnownCandidate() const { return _addedKnownCandidate; } +#ifdef USES_ESPEASY_NOW + bool isESPEasy_now_only() const; +#endif + private: // Add item from WiFi scan. From 9937adedccefacdf1129915d1940ecc837672ece Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 3 Mar 2021 15:11:15 +0100 Subject: [PATCH 097/404] [ESPEasy-NOW] Add traceroute for MQTT node hopping Just use a command like this: `publish,"traceroute/","%unixtime%"` --- src/src/DataStructs/NodesHandler.cpp | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 27 ++++++++++--- src/src/Helpers/ESPEasy_now_handler.h | 2 + src/src/Helpers/PeriodicalActions.cpp | 53 +++++++++++++++++++------ src/src/Helpers/PeriodicalActions.h | 5 +++ 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index ebc05f2f70..b191ce5f00 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -167,6 +167,7 @@ void NodesHandler::updateThisNode() { if (WiFi_AP_Candidates.isESPEasy_now_only()) { // Connected via 'virtual ESPEasy-NOW AP' addIP = false; + thisNode.useAP_ESPEasyNow = 1; } #endif if (addIP) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 3e7afa6e87..caccd5fbb7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -280,6 +280,20 @@ bool ESPEasy_now_handler_t::active() const return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVITY_TIMEOUT; } +MAC_address ESPEasy_now_handler_t::getActiveESPEasyNOW_MAC() const +{ + MAC_address this_mac; + + if (use_EspEasy_now) { + if (WifiIsAP(WiFi.getMode())) { + WiFi.softAPmacAddress(this_mac.mac); + } else { + WiFi.macAddress(this_mac.mac); + } + } + return this_mac; +} + void ESPEasy_now_handler_t::addPeerFromWiFiScan() { const int8_t scanCompleteStatus = WiFi.scanComplete(); @@ -836,12 +850,15 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const { - MAC_address this_mac; - - WiFi.macAddress(this_mac.mac); + { + // Don't add yourself as a peer + MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + if (this_mac == mac) { return false; } - // Don't add yourself as a peer - if (this_mac == mac) { return false; } + WiFi.softAPmacAddress(this_mac.mac); + if (this_mac == mac) { return false; } + } if (!WifiEspNow.addPeer(mac.mac, channel)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 36202c40ff..9770632778 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -29,6 +29,8 @@ class ESPEasy_now_handler_t { bool active() const; + MAC_address getActiveESPEasyNOW_MAC() const; + void addPeerFromWiFiScan(); void addPeerFromWiFiScan(uint8_t scanIndex); diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 83b24bb495..f02a82d889 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -329,20 +329,24 @@ void processMQTTdelayQueue() { bool processed = false; #ifdef USES_ESPEASY_NOW - if (!MQTTclient_connected) { - processed = ESPEasy_now_handler.sendToMQTT(element->controller_idx, element->_topic, element->_payload); - } + if (element->_topic.startsWith(F("traceroute/")) || element->_topic.startsWith(F("/traceroute/"))) { + // Special debug feature for ESPEasy-NOW to perform a traceroute of packets. + // Topic should start with the MAC used on this node for ESPEasy-NOW. + String replacement = F("traceroute/"); + replacement += ESPEasy_now_handler.getActiveESPEasyNOW_MAC().toString(); + replacement += '/'; + String topic; + topic.reserve(element->_topic.length() + replacement.length()); + topic = element->_topic; + topic.replace(F("traceroute/"), replacement); + processed = processMQTT_message(element->controller_idx, topic, element->_payload, element->_retained); + } else #endif - - if (!processed) { - PrepareSend(); - if (MQTTclient.publish(element->_topic.c_str(), element->_payload.c_str(), element->_retained)) { - if (WiFiEventData.connectionFailures > 0) { - --WiFiEventData.connectionFailures; - } - processed = true; - } + { + processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained); } + + MQTTDelayHandler->markProcessed(processed); if (processed) { statusLED(true); @@ -362,6 +366,31 @@ void processMQTTdelayQueue() { STOP_TIMER(MQTT_DELAY_QUEUE); } +bool processMQTT_message(controllerIndex_t controllerIndex, + const String & topic, + const String & payload, + bool retained) +{ + bool processed = false; + + #ifdef USES_ESPEASY_NOW + if (!MQTTclient_connected) { + processed = ESPEasy_now_handler.sendToMQTT(controllerIndex, topic, payload); + } + #endif + + if (!processed) { + PrepareSend(); + if (MQTTclient.publish(topic.c_str(), payload.c_str(), retained)) { + if (WiFiEventData.connectionFailures > 0) { + --WiFiEventData.connectionFailures; + } + processed = true; + } + } + return processed; +} + void updateMQTTclient_connected() { if (MQTTclient_connected != MQTTclient.connected()) { MQTTclient_connected = !MQTTclient_connected; diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 90188d8d40..8da731dc3c 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -36,6 +36,11 @@ void schedule_all_tasks_using_MQTT_controller(); void processMQTTdelayQueue(); +bool processMQTT_message(controllerIndex_t controllerIndex, + const String & topic, + const String & payload, + bool retained); + void updateMQTTclient_connected(); void runPeriodicalMQTT(); From ecf017c69daf4b98e9729e25c36487f8cce8291c Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 08:45:23 +0100 Subject: [PATCH 098/404] [ESPEasy-NOW] Traceroute using %unit% instead of MAC address Example publish command: `publish,"%sysname%/traceroute/",%systime%` --- src/src/Helpers/PeriodicalActions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index f02a82d889..4d1de048d9 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -329,11 +329,12 @@ void processMQTTdelayQueue() { bool processed = false; #ifdef USES_ESPEASY_NOW - if (element->_topic.startsWith(F("traceroute/")) || element->_topic.startsWith(F("/traceroute/"))) { + if (element->_topic.startsWith(F("traceroute/")) || element->_topic.indexOf(F("/traceroute/")) != -1) { // Special debug feature for ESPEasy-NOW to perform a traceroute of packets. // Topic should start with the MAC used on this node for ESPEasy-NOW. String replacement = F("traceroute/"); - replacement += ESPEasy_now_handler.getActiveESPEasyNOW_MAC().toString(); + replacement += getValue(LabelType::UNIT_NR); +// replacement += ESPEasy_now_handler.getActiveESPEasyNOW_MAC().toString(); replacement += '/'; String topic; topic.reserve(element->_topic.length() + replacement.length()); From 16fbec5f78516392ac2c3233b16a88a44476360f Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 09:02:32 +0100 Subject: [PATCH 099/404] [ESP32] Handle more WiFi events (e.g. STA_LOST_IP) If we process the SYSTEM_EVENT_LOST_IP, we may hopefully not end up in a limbo "connected but unreachable" state. --- src/src/DataStructs/WiFiEventData.cpp | 5 ++++ src/src/DataStructs/WiFiEventData.h | 1 + src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 29 +++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 8f2e0ece6c..44f3f39310 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -113,6 +113,11 @@ void WiFiEventData_t::markGotIP() { processedGotIP = false; } +void WiFiEventData_t::markLostIP() { + bitClear(wifiStatus, ESPEASY_WIFI_GOT_IP); + bitClear(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); +} + void WiFiEventData_t::markDisconnect(WiFiDisconnectReason reason) { lastDisconnectMoment.setNow(); diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index e6cdf1b8e7..1c1d0278ed 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -46,6 +46,7 @@ struct WiFiEventData_t { void markGotIP(); + void markLostIP(); void markDisconnect(WiFiDisconnectReason reason); void markConnected(const String& ssid, const uint8_t bssid[6], diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 12551c58d4..cb1191f96b 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -55,6 +55,33 @@ static bool ignoreDisconnectEvent = false; void WiFiEvent(system_event_id_t event, system_event_info_t info) { switch (event) { + case SYSTEM_EVENT_WIFI_READY: + // ESP32 WiFi ready + break; + case SYSTEM_EVENT_STA_START: + addLog(LOG_LEVEL_INFO, F("WiFi : STA Started")); + break; + case SYSTEM_EVENT_STA_STOP: + addLog(LOG_LEVEL_INFO, F("WiFi : STA Stopped")); + break; + case SYSTEM_EVENT_AP_START: + addLog(LOG_LEVEL_INFO, F("WiFi : AP Started")); + break; + case SYSTEM_EVENT_AP_STOP: + addLog(LOG_LEVEL_INFO, F("WiFi : AP Stopped")); + break; + case SYSTEM_EVENT_STA_LOST_IP: + // ESP32 station lost IP and the IP is reset to 0 + WiFiEventData.markLostIP(); + addLog(LOG_LEVEL_INFO, F("WiFi : Lost IP")); + break; + + case SYSTEM_EVENT_AP_PROBEREQRECVED: + // Receive probe request packet in soft-AP interface + // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 + addLog(LOG_LEVEL_INFO, F("WiFi : AP got probed")); + break; + case SYSTEM_EVENT_STA_CONNECTED: { char ssid_copy[33] = { 0 }; // Ensure space for maximum len SSID (32) plus trailing 0 @@ -131,7 +158,7 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { #endif //HAS_ETHERNET default: { - String log = F("UNKNOWN EVENT: "); + String log = F("UNKNOWN WIFI/ETH EVENT: "); log += event; addLog(LOG_LEVEL_ERROR, log); } From ab249ac6c7b8e18121db9d9b462915e3b0fba40a Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 12:08:19 +0100 Subject: [PATCH 100/404] [ESPEasy-NOW] Update known node RSSI if it scans this node. --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 48bf93bbc1..41c30085f7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -386,6 +386,8 @@ void initWiFi() stationModeAuthModeChangeHandler = WiFi.onStationModeAuthModeChanged(onStationModeAuthModeChanged); APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode); APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode); + APModeProbeRequestReceivedHandler = WiFi.onSoftAPModeProbeRequestReceived(onProbeRequestAPmode); + #endif } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index f7009ac59e..5635520512 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -16,6 +16,7 @@ #include "../Globals/EventQueue.h" #include "../Globals/MQTT.h" #include "../Globals/NetworkState.h" +#include "../Globals/Nodes.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" #include "../Globals/Services.h" @@ -354,6 +355,11 @@ void processProbeRequestAPmode() { const MAC_address mac(APModeProbeRequestReceived_list.front().mac); const int rssi = APModeProbeRequestReceived_list.front().rssi; + NodeStruct* matchingNode = Nodes.getNodeByMac(mac); + if (matchingNode != nullptr) { + matchingNode->setRSSI(rssi); + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("AP Mode: Probe Request: "); log += mac.toString(); From a8c511bc0745ebf23ee213f67df890dd64acfd84 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 12:09:26 +0100 Subject: [PATCH 101/404] [Controller] Fix typo on "debug log" builds --- src/src/ControllerQueue/ControllerDelayHandlerStruct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 3d2e1809d0..ddfaac975c 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -114,7 +114,7 @@ struct ControllerDelayHandlerStruct { if (back.isDuplicate(*it)) { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - const cpluginID_t cpluginID = getCPluginID_from_ControllerIndex(element.controller_idx); + const cpluginID_t cpluginID = getCPluginID_from_ControllerIndex(it->controller_idx); String log = get_formatted_Controller_number(cpluginID); log += F(" : Remove duplicate"); addLog(LOG_LEVEL_DEBUG, log); @@ -180,7 +180,7 @@ struct ControllerDelayHandlerStruct { if (expire_timeout != 0) { bool done = false; while (!done && !sendQueue.empty()) { - if (timePassedSince(sendQueue.front()._timestamp) < expire_timeout) { + if (timePassedSince(sendQueue.front()._timestamp) < static_cast(expire_timeout)) { done = true; } else { sendQueue.pop_front(); From bc28f248e2ed8935233ca2ae51dfd9bdd74b6050 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 12:14:32 +0100 Subject: [PATCH 102/404] [GPIO] Fix warning of unused variable --- src/src/Commands/GPIO.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/src/Commands/GPIO.cpp b/src/src/Commands/GPIO.cpp index efe5576dca..46bfdbe528 100644 --- a/src/src/Commands/GPIO.cpp +++ b/src/src/Commands/GPIO.cpp @@ -873,7 +873,7 @@ bool gpio_mode_range_helper(byte pin, byte pinMode, struct EventStruct *event, c { //int8_t state=0; byte mode=255; - bool setSuccess=false; + //bool setSuccess=false; switch (pinMode) { case 0: @@ -893,14 +893,14 @@ bool gpio_mode_range_helper(byte pin, byte pinMode, struct EventStruct *event, c if (mode < 255) { switch(pluginID) { case PLUGIN_GPIO: - setSuccess = setGPIOMode(pin, mode); + /* setSuccess = */ setGPIOMode(pin, mode); break; case PLUGIN_PCF: //set pin = 1 when INPUT - setSuccess = setPCFMode(pin, mode); + /* setSuccess = */ setPCFMode(pin, mode); break; case PLUGIN_MCP: - setSuccess = setMCPMode(pin, mode); + /* setSuccess = */ setMCPMode(pin, mode); break; } From 641e553d22f46da165186d952f5ea5014bed4f60 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 12:54:32 +0100 Subject: [PATCH 103/404] [Cleanup] Remove ICACHE_RAM_ATTR on wifi event function Is not needed and does use up extra IRAM. --- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWiFiEvent.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index d5bded0eeb..21f4c19b57 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -191,7 +191,7 @@ void onGotIP(const WiFiEventStationModeGotIP& event) { WiFiEventData.markGotIP(); } -void ICACHE_RAM_ATTR onDHCPTimeout() { +void onDHCPTimeout() { WiFiEventData.processedDHCPTimeout = false; } diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h index 254bf76ff8..af58a7f2b7 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h @@ -51,7 +51,7 @@ void onDisconnect(const WiFiEventStationModeDisconnected& event); void onGotIP(const WiFiEventStationModeGotIP& event); -void ICACHE_RAM_ATTR onDHCPTimeout(); +void onDHCPTimeout(); void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event); From 815dce9b9f484126c1f06f546b95712183a9a749 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 4 Mar 2021 15:55:24 +0100 Subject: [PATCH 104/404] [ESPEasy-NOW] Prioritize known APs + speed up announce to all channels ESPEasy-NOW hidden AP should be last resort to connect to. If a node becomes distance 0, it will broadcast to all channels to help others speed up reconnecting to the one with lowest distance. --- src/src/DataStructs/NodeStruct.h | 2 -- src/src/DataStructs/NodesHandler.cpp | 14 +++++++++- src/src/DataStructs/NodesHandler.h | 4 +++ src/src/DataStructs/WiFi_AP_Candidate.cpp | 12 ++++++--- src/src/DataStructs/WiFi_AP_Candidate.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 30 +++++++++++++++++++--- src/src/Helpers/ESPEasy_now_handler.h | 2 +- src/src/Helpers/Networking.cpp | 7 ++++- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 3 +++ 9 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index cdf9e5cfef..150ad33571 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -35,8 +35,6 @@ struct __attribute__((__packed__)) NodeStruct // - lower load (TODO TD-er) bool operator<(const NodeStruct &other) const; - void setLocalData(); - String getNodeTypeDisplayString() const; String getNodeName() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index b191ce5f00..cd0db3c6a1 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -206,10 +206,14 @@ void NodesHandler::updateThisNode() { } } + const uint8_t lastDistance = _distance; if (isEndpoint()) { _distance = 0; + _lastTimeValidDistance = millis(); + if (lastDistance != _distance) { + _recentlyBecameDistanceZero = true; + } } else { - const uint8_t lastDistance = _distance; _distance = 255; const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); @@ -303,6 +307,14 @@ uint8_t NodesHandler::getESPEasyNOW_channel() const return 0; } +bool NodesHandler::recentlyBecameDistanceZero() { + if (!_recentlyBecameDistanceZero) { + return false; + } + _recentlyBecameDistanceZero = false; + return true; +} + bool NodesHandler::lastTimeValidDistanceExpired() const { // if (_lastTimeValidDistance == 0) return false; diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 69d8b726c4..84300a91fd 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -56,6 +56,8 @@ class NodesHandler { uint8_t getESPEasyNOW_channel() const; + bool recentlyBecameDistanceZero(); + private: unsigned long _lastTimeValidDistance = 0; @@ -63,6 +65,8 @@ class NodesHandler { uint8_t _distance = 255; // Cached value NodesMap _nodes; + + bool _recentlyBecameDistanceZero = false; }; diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index 1ed6040669..b73c59cbed 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -37,16 +37,20 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { WiFi_AP_Candidate::WiFi_AP_Candidate() {} bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { - // RSSI values >= 0 are invalid - if (rssi >= 0) { return false; } - - if (other.rssi >= 0) { return true; } + if (lowPrio != other.lowPrio) { + return !lowPrio; + } // Prefer non hidden over hidden. if (isHidden != other.isHidden) { return !isHidden; } + // RSSI values >= 0 are invalid + if (rssi >= 0) { return false; } + + if (other.rssi >= 0) { return true; } + // RSSI values are negative, so the larger value is the better one. return rssi > other.rssi; } diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index 993d7dfab2..afcdf90ec5 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -52,6 +52,7 @@ struct WiFi_AP_Candidate { byte index = 0; // Index of the matching credentials byte enc_type = 0; // Encryption used (e.g. WPA2) bool isHidden = false; // Hidden SSID + bool lowPrio = false; // Use as last option. }; #endif // ifndef DATASTRUCTS_WIFI_AP_CANDIDATES_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index caccd5fbb7..0ae3af74b7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -402,14 +402,14 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo // * Discovery Announcement // ************************************************************* -void ESPEasy_now_handler_t::sendDiscoveryAnnounce() +void ESPEasy_now_handler_t::sendDiscoveryAnnounce(int channel) { MAC_address broadcast; for (int i = 0; i < 6; ++i) { broadcast.mac[i] = 0xFF; } - sendDiscoveryAnnounce(broadcast); + sendDiscoveryAnnounce(broadcast, channel); } void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int channel) @@ -423,7 +423,25 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch const size_t len = sizeof(NodeStruct); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); if (len == msg.addBinaryData(reinterpret_cast(thisNode), len)) { - msg.send(mac, channel); + if (channel < 0) { + // Send to all channels + + const unsigned long start = millis(); + + // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. + for (int ch = 1; ch < 11; ++ch) { + msg.send(mac, ch); + delay(0); + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ESPEasy-NOW : Sent discovery to all channels in "); + log += String(timePassedSince(start)); + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); + } + } else { + msg.send(mac, channel); + } } } @@ -479,7 +497,11 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m const uint8_t new_distance = Nodes.getDistance(); if (new_distance != cur_distance) { - sendDiscoveryAnnounce(); + if (new_distance == 0) { + sendDiscoveryAnnounce(-1); // Send to all channels + } else { + sendDiscoveryAnnounce(); + } } return true; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 9770632778..bfac355fbc 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -42,7 +42,7 @@ class ESPEasy_now_handler_t { // Send out the discovery announcement via broadcast. // This may be picked up by others - void sendDiscoveryAnnounce(); + void sendDiscoveryAnnounce(int channel = 0); void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); void sendNTPquery(); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 1df086ba31..2e1b8ca1af 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -414,7 +414,12 @@ void refreshNodeList() } sendSysInfoUDP(1); #ifdef USES_ESPEASY_NOW - ESPEasy_now_handler.sendDiscoveryAnnounce(); + if (Nodes.recentlyBecameDistanceZero()) { + // Send to all channels + ESPEasy_now_handler.sendDiscoveryAnnounce(-1); + } else { + ESPEasy_now_handler.sendDiscoveryAnnounce(); + } ESPEasy_now_handler.sendNTPquery(); #endif // ifdef USES_ESPEASY_NOW } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 6000814df3..87ff0e4add 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -38,6 +38,9 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { while (!done) { if (get_SSID_key(index, ssid, key)) { known.emplace_back(index, ssid, key); + if (index == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX) { + known.back().lowPrio = true; + } } else if (index != WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX) { // There may be other credentials so don't stop at ESPEasy-now index // For example on builds without ESPEasy-NOW these credentials will not be returned. From 5125662c26cd69ecbb2afc9cba21452f7b41b027 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 5 Mar 2021 11:52:36 +0100 Subject: [PATCH 105/404] [ESPEasy-NOW] Change traceroute to prepend message instead of topic Having the route in the payload is more practical compared to having it in the topic. --- src/src/Helpers/PeriodicalActions.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 4d1de048d9..ff4f9cb358 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -331,16 +331,14 @@ void processMQTTdelayQueue() { #ifdef USES_ESPEASY_NOW if (element->_topic.startsWith(F("traceroute/")) || element->_topic.indexOf(F("/traceroute/")) != -1) { // Special debug feature for ESPEasy-NOW to perform a traceroute of packets. - // Topic should start with the MAC used on this node for ESPEasy-NOW. - String replacement = F("traceroute/"); - replacement += getValue(LabelType::UNIT_NR); -// replacement += ESPEasy_now_handler.getActiveESPEasyNOW_MAC().toString(); - replacement += '/'; - String topic; - topic.reserve(element->_topic.length() + replacement.length()); - topic = element->_topic; - topic.replace(F("traceroute/"), replacement); - processed = processMQTT_message(element->controller_idx, topic, element->_payload, element->_retained); + // The message is prepended by each unit number handling the message. + const String replacement = getValue(LabelType::UNIT_NR); + String message; + message.reserve(replacement.length() + 1 + element->_payload.length()); + message = replacement; + message += ';'; + message += element->_payload; + processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained); } else #endif { From c2614ce6aec8c4d23bac4f18f949e7325f1f3976 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 5 Mar 2021 11:57:09 +0100 Subject: [PATCH 106/404] [ESPEasy-NOW] For now disable sending announce to all channels Units tend to loose connection, which may be related to this quick switching of channels. --- src/src/Helpers/ESPEasy_now_handler.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 0ae3af74b7..39ac7c09c7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -491,14 +491,11 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m addLog(LOG_LEVEL_INFO, log); } - if (isNewNode) { - sendDiscoveryAnnounce(mac); - } - const uint8_t new_distance = Nodes.getDistance(); - if (new_distance != cur_distance) { + if (new_distance != cur_distance || isNewNode) { if (new_distance == 0) { - sendDiscoveryAnnounce(-1); // Send to all channels + //sendDiscoveryAnnounce(-1); // Send to all channels + sendDiscoveryAnnounce(); // For now disable sending the announce to all channels. } else { sendDiscoveryAnnounce(); } From c765baf76c4e0326c7d8addf3e188a63b5efc10c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 5 Mar 2021 16:53:49 +0100 Subject: [PATCH 107/404] [ESPEasy-NOW] Fix preferred order of nodes + ESPEasy-NOW only check --- src/src/DataStructs/NodeStruct.cpp | 2 +- src/src/DataStructs/NodesHandler.cpp | 3 +++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 1532bea633..d64d168c56 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -84,7 +84,7 @@ bool NodeStruct::operator<(const NodeStruct &other) const { score_this -= (thisRssi + 38) * 2; score_other -= (otherRssi + 38) * 2; } - return score_this > score_other; + return score_this < score_other; } String NodeStruct::getNodeTypeDisplayString() const { diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index cd0db3c6a1..a61a1ab02b 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -169,6 +169,9 @@ void NodesHandler::updateThisNode() { addIP = false; thisNode.useAP_ESPEasyNow = 1; } + if (!isEndpoint()) { + addIP = false; + } #endif if (addIP) { IPAddress localIP = NetworkLocalIP(); diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 87ff0e4add..ae80c60bc5 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -171,7 +171,7 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { #ifdef USES_ESPEASY_NOW bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { - return RTC.lastWiFiSettingsIndex == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX; + return currentCandidate.index == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX; } #endif From 8fd09a617168d26beffa65a40c4a16c72253e867 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Mar 2021 10:22:48 +0100 Subject: [PATCH 108/404] [ESPEasy-NOW] Use max TX power and force B/G mode on ESPEasy-NOW only --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 70a69e54aa..6fbefeb3bc 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -408,6 +408,13 @@ void SetWiFiTXpower(float dBm, float rssi) { return; } +#ifdef USES_ESPEASY_NOW + if (WiFi_AP_Candidates.isESPEasy_now_only()) { + // Force using max. TX power. + dBm = 30; // Some high number which will be corrected below + } +#endif + // Range ESP32 : 2dBm - 20dBm // Range ESP8266: 0dBm - 20.5dBm float maxTXpwr; @@ -923,6 +930,12 @@ bool wifiAPmodeActivelyUsed() void setConnectionSpeed() { #ifdef ESP8266 + #ifdef USES_ESPEASY_NOW + if (WiFi_AP_Candidates.isESPEasy_now_only()) { + WiFi.setPhyMode(WIFI_PHY_MODE_11G); + return; + } + #endif if (!Settings.ForceWiFi_bg_mode() || (WiFiEventData.wifi_connect_attempt > 10)) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); From 8003ae8711b9e23d3dcd895163babf25f7c29a65 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Mar 2021 11:21:55 +0100 Subject: [PATCH 109/404] [ESPEasy-NOW] Use central defined name for ESPEasy-NOW Development of ESPEasy-NOW layer has been paid for by a customer who agreed to make it Open Source. Therefore they use a different name in their builds. --- src/_C019.ino | 2 +- src/_P098_ESPEasyNowReceiver.ino | 2 +- src/src/CustomBuild/ESPEasy_buildinfo.h | 5 ++++ src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 6 +++-- src/src/DataStructs/ESPEasy_now_splitter.cpp | 13 +++++++--- .../SendData_DuplicateChecker_struct.cpp | 6 ++++- src/src/DataStructs/TimingStats.cpp | 16 ++++++------ src/src/DataTypes/ESPEasyTimeSource.cpp | 4 ++- src/src/Helpers/ESPEasy_now_handler.cpp | 26 +++++++++---------- src/src/Helpers/_CPlugin_Helper_webform.cpp | 4 ++- src/src/WebServer/RootPage.cpp | 2 +- 11 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/_C019.ino b/src/_C019.ino index cf139e7c05..4b124e4e59 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -13,7 +13,7 @@ #define CPLUGIN_019 #define CPLUGIN_ID_019 19 -#define CPLUGIN_NAME_019 "ESPEasy-NOW" +#define CPLUGIN_NAME_019 ESPEASY_NOW_NAME bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& string) { diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 768b9389c7..69f736c33b 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -11,7 +11,7 @@ #define PLUGIN_098 #define PLUGIN_ID_098 98 -#define PLUGIN_NAME_098 "Generic - ESPEasy-NOW Receiver" +#define PLUGIN_NAME_098 "Generic - " ESPEASY_NOW_NAME " Receiver" #define PLUGIN_VALUENAME1_098 "Value" diff --git a/src/src/CustomBuild/ESPEasy_buildinfo.h b/src/src/CustomBuild/ESPEasy_buildinfo.h index b80eefdc4a..989f7d8d39 100644 --- a/src/src/CustomBuild/ESPEasy_buildinfo.h +++ b/src/src/CustomBuild/ESPEasy_buildinfo.h @@ -34,5 +34,10 @@ # define BUILD_GIT "(custom)" #endif // ifndef BUILD_GIT +// Development of ESPEasy-NOW layer has been paid for by a customer who agreed to make it Open Source. +// Therefore they use a different name in their builds. +#ifndef ESPEASY_NOW_NAME +# define ESPEASY_NOW_NAME "ESPEasy-NOW" +#endif #endif // ESPEASY_BUILD_INFO_H diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 1c0ddaa9b9..6f0aeaa1ac 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -124,7 +124,8 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(64); - log = F("ESPEasy-NOW: Best NTP peer: "); + log += F(ESPEASY_NOW_NAME); + log += F(": Best NTP peer: "); log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; @@ -210,7 +211,8 @@ void ESPEasy_Now_NTP_query::createReply(unsigned long queryReceiveTimestamp) if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(64); - log = F("ESPEasy-NOW: Create NTP reply to: "); + log += F(ESPEASY_NOW_NAME); + log += F(": Create NTP reply to: "); log += MAC_address(_mac).toString(); log += F(" Wander "); log += _expectedWander_ms; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 694eec1786..4ec8c31107 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -124,17 +124,20 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t switch (sendStatus) { case WifiEspNowSendStatus::NONE: { - log = F("ESPEasy-NOW: TIMEOUT to: "); + log += F(ESPEASY_NOW_NAME); + log += F(": TIMEOUT to: "); break; } case WifiEspNowSendStatus::FAIL: { - log = F("ESPEasy-NOW: Sent FAILED to: "); + log += F(ESPEASY_NOW_NAME); + log += F(": Sent FAILED to: "); break; } case WifiEspNowSendStatus::OK: { - log = F("ESPEasy-NOW: Sent to: "); + log += F(ESPEASY_NOW_NAME); + log += F(": Sent to: "); break; } } @@ -247,7 +250,9 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) _queue[i].setHeader(header); _queue[i].setMac(mac); if (!_queue[i].valid()) { - addLog(LOG_LEVEL_ERROR, F("ESPEasy-NOW: Could not prepare for send")); + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": Could not prepare for send")); + } return false; } } diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 7030fd058a..d654312e03 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -68,7 +68,11 @@ void SendData_DuplicateChecker_struct::remove(uint32_t key) auto it = _queue.find(key); if (it != _queue.end()) { - addLog(LOG_LEVEL_DEBUG, F("ESPEasy-NOW message not sent as processed elsewhere")); + #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + addLog(LOG_LEVEL_DEBUG, String(F(ESPEASY_NOW_NAME)) + F(": message not sent as processed elsewhere")); + } + #endif _queue.erase(it); } } diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index d746612255..ffe2592132 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -231,14 +231,14 @@ String getMiscStatsName(int stat) { case PARSE_SYSVAR: return F("parseSystemVariables()"); case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); - case HANDLE_ESPEASY_NOW_LOOP: return F("Handle Received ESPEasy-NOW message"); - case EXPIRED_ESPEASY_NOW_LOOP: return F("ESPEasy-NOW incomplete expired"); - case INVALID_ESPEASY_NOW_LOOP: return F("ESPEasy-NOW incomplete invalid"); - case RECEIVE_ESPEASY_NOW_LOOP: return F("ESPEasy_now_onReceive()"); - case ESPEASY_NOW_SEND_MSG_SUC: return F("ESPEasy-NOW send Message Success"); - case ESPEASY_NOW_SEND_MSG_FAIL: return F("ESPEasy-NOW send Message Fail"); - case ESPEASY_NOW_SEND_PCKT: return F("ESPEasy-NOW send Packet"); - case ESPEASY_NOW_DEDUP_LOOP: return F("ESPEasy-NOW DuplicateCheck loop"); + case HANDLE_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" handle received message"); + case EXPIRED_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" incomplete expired"); + case INVALID_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" incomplete invalid"); + case RECEIVE_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" onReceive()"); + case ESPEASY_NOW_SEND_MSG_SUC: return String(F(ESPEASY_NOW_NAME)) + F(" send Message Success"); + case ESPEASY_NOW_SEND_MSG_FAIL: return String(F(ESPEASY_NOW_NAME)) + F(" send Message Fail"); + case ESPEASY_NOW_SEND_PCKT: return String(F(ESPEASY_NOW_NAME)) + F(" send Packet"); + case ESPEASY_NOW_DEDUP_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" DuplicateCheck loop"); case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time"); case C001_DELAY_QUEUE: case C002_DELAY_QUEUE: diff --git a/src/src/DataTypes/ESPEasyTimeSource.cpp b/src/src/DataTypes/ESPEasyTimeSource.cpp index 7f62f3c669..1538a8e0fd 100644 --- a/src/src/DataTypes/ESPEasyTimeSource.cpp +++ b/src/src/DataTypes/ESPEasyTimeSource.cpp @@ -2,6 +2,8 @@ #include +#include "../../ESPEasy_common.h" + String toString(timeSource_t timeSource) { @@ -10,7 +12,7 @@ String toString(timeSource_t timeSource) case timeSource_t::GPS_time_source: return F("GPS"); case timeSource_t::NTP_time_source: return F("NTP"); case timeSource_t::Manual_set: return F("Manual"); - case timeSource_t::ESP_now_peer: return F("ESPEasy-NOW peer"); + case timeSource_t::ESP_now_peer: return String(F(ESPEASY_NOW_NAME)) + F(" peer"); case timeSource_t::Restore_RTC_time_source: return F("RTC at boot"); case timeSource_t::No_time_source: return F("No time set"); } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 39ac7c09c7..d3111d1a44 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -128,13 +128,13 @@ bool ESPEasy_now_handler_t::begin() // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-NOW: begin on channel "); + String log = String(F(ESPEASY_NOW_NAME)) + F(": begin on channel "); log += channel; addLog(LOG_LEVEL_INFO, log); } if (!WifiEspNow.begin()) { - addLog(LOG_LEVEL_ERROR, F("ESPEasy-NOW: Failed to initialize ESPEasy-NOW")); + addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": Failed to initialize ESPEasy-NOW")); return false; } @@ -157,7 +157,7 @@ bool ESPEasy_now_handler_t::begin() sendDiscoveryAnnounce(); use_EspEasy_now = true; - addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW enabled")); + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" enabled")); return true; } @@ -172,7 +172,7 @@ void ESPEasy_now_handler_t::end() _last_used = 0; } setAP(false); - addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW disabled")); + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" disabled")); } bool ESPEasy_now_handler_t::loop() @@ -334,7 +334,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) if (tmpNodeInfo.markedAsPriorityPeer()) { if (Nodes.addNode(tmpNodeInfo)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-NOW: Found node via WiFi scan: "); + String log = String(F(ESPEASY_NOW_NAME)) + F(": Found node via WiFi scan: "); log += peer_mac.toString(); log += F(" "); log += tmpNodeInfo.getRSSI(); @@ -353,7 +353,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-NOW received "); + String log = String(F(ESPEASY_NOW_NAME)) + F(" received "); log += message.getLogString(); addLog(LOG_LEVEL_INFO, log); } @@ -434,7 +434,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-NOW : Sent discovery to all channels in "); + String log = String(F(ESPEASY_NOW_NAME)) + F(" : Sent discovery to all channels in "); log += String(timePassedSince(start)); log += F(" ms"); addLog(LOG_LEVEL_INFO, log); @@ -465,7 +465,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (!received.setESPEasyNow_mac(mac)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - log = F("ESPEasy-NOW: Received discovery message from MAC not stated in message: "); + log = String(F(ESPEASY_NOW_NAME)) + F(": Received discovery message from MAC not stated in message: "); log += mac.toString(); addLog(LOG_LEVEL_ERROR, log); } @@ -484,7 +484,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m String log; size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); - log = F("ESPEasy-NOW discovery: "); + log = String(F(ESPEASY_NOW_NAME)) + F(" discovery: "); log += message.getLogString(); log += '\n'; log += received.getSummary(); @@ -516,7 +516,7 @@ void ESPEasy_now_handler_t::sendNTPquery() if (!_best_NTP_candidate.getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ESPEasy-NOW: Send NTP query to: "); + String log = String(F(ESPEASY_NOW_NAME)) + F(": Send NTP query to: "); log += mac.toString(); addLog(LOG_LEVEL_INFO, log); } @@ -674,7 +674,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge query.setState(queue_full); if (loglevelActiveFor(LOG_LEVEL_INFO) && queue_full) { - addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW: After MQTT message received: Full")); + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": After MQTT message received: Full")); } sendMQTTCheckControllerQueue(mac, 0, query.state); } @@ -759,7 +759,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { String log; - log = F("ESPEasy-NOW: Received Queue state: "); + log = String(F(ESPEASY_NOW_NAME)) + F(": Received Queue state: "); log += _preferredNodeMQTTqueueState.isFull() ? F("Full") : F("not Full"); addLog(LOG_LEVEL_DEBUG_MORE, log); } @@ -772,7 +772,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me // We have to give our own queue state and reply query.setState(MQTT_queueFull(controllerIndex)); - // addLog(LOG_LEVEL_INFO, F("ESPEasy-NOW: reply to queue state query")); + // addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": reply to queue state query")); const size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index 41f7e766bd..7cc64ac889 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -64,7 +64,9 @@ String getControllerParameterName(protocolIndex_t ProtocolInde case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: name = F("Send Binary"); break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: name = F("Client Timeout"); break; case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: name = F("Sample Set Initiator"); break; - case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: name = F("Enable ESPEasy-NOW Fallback"); break; + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: name = F("Enable "); + name += F(ESPEASY_NOW_NAME); + name += F(" Fallback"); break; case ControllerSettingsStruct::CONTROLLER_ENABLED: diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 78f5d3c303..25a52c32d1 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -285,7 +285,7 @@ void handle_root() { } html_TD(); if (it->second.ESPEasyNowPeer) { - addHtml(F("ESPEasy-NOW ")); + addHtml(String(F(ESPEASY_NOW_NAME)) + F(" ")); addHtml(it->second.ESPEasy_Now_MAC().toString()); addHtml(F(" (ch: ")); addHtml(String(it->second.channel)); From 0973a8dfa9be7e82f10e0fcfd902c4ea0d2d9aad Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 15 Mar 2021 11:54:39 +0100 Subject: [PATCH 110/404] [ESPEasy-NOW] Only send MQTT messages to nodes with shorter 'distance' --- src/src/Helpers/ESPEasy_now_handler.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d3111d1a44..93d3a19319 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -89,7 +89,6 @@ bool ESPEasy_now_handler_t::begin() _last_used = millis(); int channel = WiFi.channel(); - MAC_address bssid; _controllerIndex = INVALID_CONTROLLER_INDEX; if (WiFi_AP_Candidates.isESPEasy_now_only()) { @@ -98,28 +97,13 @@ bool ESPEasy_now_handler_t::begin() } if (!Nodes.isEndpoint()) { - const NodeStruct *preferred = Nodes.getPreferredNode(); - - if (preferred != nullptr) { - channel = preferred->channel; - bssid.set(preferred->ap_mac); - } + channel = Nodes.getESPEasyNOW_channel(); } const String ssid = F(ESPEASY_NOW_TMP_SSID); const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); setAP(true); - /* - // FIXME TD-er: Must use standard WiFi connection setup. - if (WiFi_AP_Candidates.isESPEasy_now_only()) { - if (bssid.all_zero()) { - WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel); - } else { - WiFi.begin(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase(), channel, bssid.mac); - } - } - */ int ssid_hidden = 1; int max_connection = 6; @@ -601,7 +585,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { const NodeStruct *preferred = Nodes.getPreferredNode(); - if (preferred != nullptr) { + if (preferred != nullptr && Nodes.getDistance() > preferred->distance) { switch (_preferredNodeMQTTqueueState.state) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: @@ -705,7 +689,7 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(controllerIndex_t contr } const NodeStruct *preferred = Nodes.getPreferredNode(); - if (preferred != nullptr) { + if (preferred != nullptr && Nodes.getDistance() > preferred->distance) { return sendMQTTCheckControllerQueue(preferred->ESPEasy_Now_MAC(), preferred->channel); } return false; From 63e46d67d088bf96e67565412212fcad48613805 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 16 Mar 2021 13:28:39 +0100 Subject: [PATCH 111/404] [ESPEasy-NOW] Add traceroute from gateway node --- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 3 +- .../DataStructs/ESPEasy_now_traceroute.cpp | 156 ++++++++++++++++++ src/src/DataStructs/ESPEasy_now_traceroute.h | 60 +++++++ src/src/DataStructs/NodesHandler.cpp | 95 ++++++++++- src/src/DataStructs/NodesHandler.h | 21 +++ src/src/Helpers/ESPEasy_now_handler.cpp | 78 ++++++--- 6 files changed, 385 insertions(+), 28 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_now_traceroute.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_traceroute.h diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 6f0aeaa1ac..35c3eaf11c 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -254,7 +254,8 @@ bool ESPEasy_Now_NTP_query::processReply(const ESPEasy_Now_NTP_query& received, if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(64); - log = F("ESPEasy_Now_NTP: air time: "); + log = F(ESPEASY_NOW_NAME); + log += F(": NTP air time: "); log += air_time; log += F(" Compensation: "); log += String(compensation_ms, 1); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp new file mode 100644 index 0000000000..a78feddddc --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -0,0 +1,156 @@ +#include "ESPEasy_now_traceroute.h" + +#include + +ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct() {} + +ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct(uint8_t size) { + unit_vector.resize(size); +} + +uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, int8_t& rssi) const +{ + if (unit_vector.size() < static_cast((distance + 1) * 2)) { + return 0; + } + const int temp_rssi = unit_vector[(distance * 2) + 1]; + + rssi = temp_rssi - 127; + return unit_vector[distance * 2]; +} + +void ESPEasy_now_traceroute_struct::addUnit(uint8_t unit, int8_t rssi) +{ + const uint8_t index = unit_vector.size(); + + unit_vector.resize(index + 2); + unit_vector[index] = unit; + unit_vector[index + 1] = static_cast(static_cast(rssi + 127)); +} + +uint8_t ESPEasy_now_traceroute_struct::getDistance() const +{ + if (unit_vector.size() == 0) { return 255; } + return (unit_vector.size() / 2) - 1; +} + +const uint8_t * ESPEasy_now_traceroute_struct::getData(uint8_t& size) const +{ + size = unit_vector.size(); + return &(unit_vector[0]); +} + +uint8_t * ESPEasy_now_traceroute_struct::get() +{ + if (unit_vector.size() == 0) { + return nullptr; + } + return &(unit_vector[0]); +} + +void ESPEasy_now_traceroute_struct::setRSSI_last_node(int8_t rssi) const +{ + const uint8_t index = unit_vector.size(); + + if (index == 0) { + return; + } + unit_vector[index - 1] = static_cast(static_cast(rssi + 127)); +} + +bool ESPEasy_now_traceroute_struct::operator<(const ESPEasy_now_traceroute_struct& other) const +{ + return compute_penalty() < other.compute_penalty(); +} + +int ESPEasy_now_traceroute_struct::compute_penalty() const +{ + const uint8_t max_distance = getDistance(); + + if (max_distance == 255) { + // No values stored, so huge penalty + return max_distance * 100; + } + + int penalty = 0; + + for (uint8_t distance = 0; distance <= max_distance; ++distance) { + int8_t rssi = 0; + getUnit(distance, rssi); + + if (rssi >= 0) { + // Some "average" RSSI values for unknown RSSI + rssi = -75; + } else if (rssi < -80) { + // Some extra penaly for low quality signals + rssi -= 10; + } + + // RSSI values are negative, with lower value being a worse signal + penalty -= rssi; + } + return penalty; +} + +void ESPEasy_now_traceroute_struct::sanetize() +{ + std::list units; + + for (size_t i = 0; i < unit_vector.size(); i += 2) { + units.push_back(unit_vector[i]); + } + + // Remove duplicates by sort and unique + units.sort(); + units.unique(); + + if (units.size() == (unit_vector.size() / 2)) { + // No loops + return; + } + + std::vector new_unit_vector; + + new_unit_vector.reserve(units.size() * 2); + + const uint8_t max_distance = getDistance(); + + for (uint8_t distance = 0; distance <= max_distance; ++distance) { + const uint8_t unit = unit_vector[distance * 2]; + bool found = false; + + for (auto it = units.begin(); !found && it != units.end(); ++it) { + if (*it == unit) { + // Present in the unique list so remove it + units.erase(it); + found = true; + } + } + + if (found) { + // It was present in the unique list, so we can add it to the new vector + new_unit_vector.push_back(unit); + new_unit_vector.push_back(unit_vector[(distance * 2) + 1]); + } + } + unit_vector = new_unit_vector; +} + +String ESPEasy_now_traceroute_struct::toString() +{ + const uint8_t max_distance = getDistance(); + + if (max_distance == 255) { + return String(); + } + String res; + res.reserve(4*unit_vector.size()); + for (uint8_t distance = 0; distance <= max_distance; ++distance) { + int8_t rssi = 0; + res += getUnit(distance, rssi); + res += '/'; + res += rssi; + res += ' '; + } + return res; +} \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h new file mode 100644 index 0000000000..70722042d4 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -0,0 +1,60 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_TRACEROUTE_H +#define DATASTRUCTS_ESPEASY_NOW_TRACEROUTE_H + +#include "../../ESPEasy_common.h" + +#include +#include + +/*********************************************************************************************\ +* ESPEasy-NOW Trace route +\*********************************************************************************************/ +struct ESPEasy_now_traceroute_struct +{ + ESPEasy_now_traceroute_struct(); + + ESPEasy_now_traceroute_struct(uint8_t size); + + // Return the unit and RSSI given a distance. + // @retval 0 when giving invalid distance. + uint8_t getUnit(uint8_t distance, + int8_t& rssi) const; + + // Append unit at the end (thus furthest distance) + void addUnit(uint8_t unit, + int8_t rssi = 0); + + uint8_t getDistance() const; + + const uint8_t* getData(uint8_t& size) const; + + // Get pointer to the raw data. + // Make sure the array is large enough to store the data. + uint8_t* get(); + + void setRSSI_last_node(int8_t rssi) const; + + // Return true when this traceroute has lower penalty (thus more favorable) + bool operator<(const ESPEasy_now_traceroute_struct& other) const; + + // Remove duplicate entries (e.g. loops) + void sanetize(); + + // For debugging purposes + String toString(); + +private: + + // Compute penalty. Higher value means less preferred. + int compute_penalty() const; + + // Node with distance 0 at front, so index/2 equals distance. + // index%2 == 0 is unit + // index%2 == 1 is RSSI + // Made mutable so setRSSI_last_node can remain const. + mutable std::vectorunit_vector; +}; + +typedef std::map TraceRouteMap; + +#endif // ifndef DATASTRUCTS_ESPEASY_NOW_TRACEROUTE_H diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index a61a1ab02b..e6edd08d03 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -2,6 +2,7 @@ #include "../../ESPEasy-Globals.h" #include "../../ESPEasy_fdwdecl.h" +#include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Helpers/ESPEasy_time_calc.h" @@ -56,6 +57,20 @@ bool NodesHandler::addNode(const NodeStruct& node) return isNewNode; } +#ifdef USES_ESPEASY_NOW +bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute) +{ + const bool isNewNode = addNode(node); + _traceRoutes[node.unit] = traceRoute; + + _traceRoutes[node.unit].addUnit(node.unit, 0); // Will update the RSSI of the last node in getTraceRoute + _traceRoutes[node.unit].sanetize(); + + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": traceroute received ") + _traceRoutes[node.unit].toString()); + return isNewNode; +} +#endif + bool NodesHandler::hasNode(uint8_t unit_nr) const { return _nodes.find(unit_nr) != _nodes.end(); @@ -143,18 +158,53 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { if ((&(it->second) != reject) && (&(it->second) != thisNode)) { + bool mustSet = false; if (res == nullptr) { - res = &(it->second); + mustSet = true; } else { + #ifdef USES_ESPEASY_NOW + if (getTraceRoute(it->second.unit) < getTraceRoute(res->unit)) + { + mustSet = true; + } + #else if (it->second < *res) { + mustSet = true; + } + #endif + } + if (mustSet) { + #ifdef USES_ESPEASY_NOW + if (it->second.ESPEasyNowPeer && hasTraceRoute(it->second.unit)) { res = &(it->second); } + #else + res = &(it->second); + #endif } } } return res; } +#ifdef USES_ESPEASY_NOW +const ESPEasy_now_traceroute_struct* NodesHandler::getTraceRoute(uint8_t unit) const +{ + auto trace_it = _traceRoutes.find(unit); + if (trace_it == _traceRoutes.end()) { + return nullptr; + } + + auto node_it = _nodes.find(unit); + if (node_it != _nodes.end()) { + trace_it->second.setRSSI_last_node(node_it->second.getRSSI()); + } + + return &(trace_it->second); +} +#endif + + void NodesHandler::updateThisNode() { NodeStruct thisNode; @@ -208,37 +258,57 @@ void NodesHandler::updateThisNode() { break; } } + #ifdef USES_ESPEASY_NOW + if (Settings.UseESPEasyNow()) { + thisNode.ESPEasyNowPeer = 1; + } + #endif const uint8_t lastDistance = _distance; + #ifdef USES_ESPEASY_NOW + ESPEasy_now_traceroute_struct thisTraceRoute; + #endif if (isEndpoint()) { _distance = 0; _lastTimeValidDistance = millis(); if (lastDistance != _distance) { _recentlyBecameDistanceZero = true; } + #ifdef USES_ESPEASY_NOW + thisTraceRoute.addUnit(thisNode.unit); + #endif } else { _distance = 255; + #ifdef USES_ESPEASY_NOW const NodeStruct *preferred = getPreferredNode_notMatching(thisNode.sta_mac); if (preferred != nullptr) { - if (preferred->distance < 255 && !preferred->isExpired()) { - _distance = preferred->distance + 1; - _lastTimeValidDistance = millis(); + if (!preferred->isExpired()) { + const ESPEasy_now_traceroute_struct* tracert_ptr = getTraceRoute(preferred->unit); + if (tracert_ptr != nullptr && tracert_ptr->getDistance() < 255) { + // Make a copy of the traceroute + thisTraceRoute = *tracert_ptr; + _distance = thisTraceRoute.getDistance() + 1; + _lastTimeValidDistance = millis(); + } if (_distance != lastDistance) { - #ifdef USES_ESPEASY_NOW if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFiConnected()) { // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP // Try to reconnect to it. RTC.clearLastWiFi(); // Force a WiFi scan WifiDisconnect(); } - #endif } } } + #endif } thisNode.distance = _distance; + #ifdef USES_ESPEASY_NOW + addNode(thisNode, thisTraceRoute); + #else addNode(thisNode); + #endif } const NodeStruct * NodesHandler::getThisNode() { @@ -270,6 +340,12 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& unsigned long age = it->second.getAge(); if (age > max_age_allowed) { + #ifdef USES_ESPEASY_NOW + auto route_it = _traceRoutes.find(it->second.unit); + if (route_it != _traceRoutes.end()) { + _traceRoutes.erase(route_it); + } + #endif it = _nodes.erase(it); nodeRemoved = true; } else { @@ -323,3 +399,10 @@ bool NodesHandler::lastTimeValidDistanceExpired() const // if (_lastTimeValidDistance == 0) return false; return timePassedSince(_lastTimeValidDistance) > 120000; // 2 minutes } + +#ifdef USES_ESPEASY_NOW +bool NodesHandler::hasTraceRoute(uint8_t unit) const +{ + return _traceRoutes.find(unit) != _traceRoutes.end(); +} +#endif diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 84300a91fd..f2f60df5cc 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -5,6 +5,10 @@ #include "MAC_address.h" +#ifdef USES_ESPEASY_NOW +#include "ESPEasy_now_traceroute.h" +#endif + class NodesHandler { public: @@ -12,6 +16,11 @@ class NodesHandler { // @retval true when the node was not yet present in the list. bool addNode(const NodeStruct& node); +#ifdef USES_ESPEASY_NOW + bool addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute); +#endif + + bool hasNode(uint8_t unit_nr) const; bool hasNode(const uint8_t *mac) const; @@ -37,6 +46,10 @@ class NodesHandler { const NodeStruct* getPreferredNode() const; const NodeStruct* getPreferredNode_notMatching(const MAC_address& not_matching) const; +#ifdef USES_ESPEASY_NOW + const ESPEasy_now_traceroute_struct* getTraceRoute(uint8_t unit) const; +#endif + // Update the node referring to this unit with the most recent info. void updateThisNode(); @@ -60,12 +73,20 @@ class NodesHandler { private: +#ifdef USES_ESPEASY_NOW + bool hasTraceRoute(uint8_t unit) const; +#endif + unsigned long _lastTimeValidDistance = 0; uint8_t _distance = 255; // Cached value NodesMap _nodes; +#ifdef USES_ESPEASY_NOW + TraceRouteMap _traceRoutes; +#endif + bool _recentlyBecameDistanceZero = false; }; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 93d3a19319..54a098d651 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -337,7 +337,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(" received "); + String log = String(F(ESPEASY_NOW_NAME)) + F(": received "); log += message.getLogString(); addLog(LOG_LEVEL_INFO, log); } @@ -404,28 +404,48 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch // Should not happen return; } - const size_t len = sizeof(NodeStruct); + + // Append traceroute (if available) + const ESPEasy_now_traceroute_struct* thisTraceRoute = Nodes.getTraceRoute(thisNode->unit); + + size_t len = sizeof(NodeStruct) + 1; // Append length indicator for traceroute + uint8_t traceroute_size = 0; + const uint8_t* traceroute_data = nullptr; + if (thisTraceRoute != nullptr) { + traceroute_data = thisTraceRoute->getData(traceroute_size); + len += traceroute_size; + } + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::Announcement, len); - if (len == msg.addBinaryData(reinterpret_cast(thisNode), len)) { - if (channel < 0) { - // Send to all channels + if (sizeof(NodeStruct) != msg.addBinaryData(reinterpret_cast(thisNode), sizeof(NodeStruct))) { + return; + } + if (sizeof(uint8_t) != msg.addBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t))) { + return; + } + if (traceroute_data != nullptr) { + if (traceroute_size != msg.addBinaryData(traceroute_data, traceroute_size)) { + return; + } + } + if (channel < 0) { + // Send to all channels - const unsigned long start = millis(); + const unsigned long start = millis(); - // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. - for (int ch = 1; ch < 11; ++ch) { - msg.send(mac, ch); - delay(0); - } - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(" : Sent discovery to all channels in "); - log += String(timePassedSince(start)); - log += F(" ms"); - addLog(LOG_LEVEL_INFO, log); - } - } else { - msg.send(mac, channel); + // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. + for (int ch = 1; ch < 11; ++ch) { + msg.send(mac, ch); + delay(0); + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = String(F(ESPEASY_NOW_NAME)) + F(": Sent discovery to all channels in "); + log += String(timePassedSince(start)); + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); } + } else { + msg.send(mac, channel); } } @@ -433,6 +453,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m { mustKeep = false; NodeStruct received; + ESPEasy_now_traceroute_struct traceRoute; const uint8_t cur_distance = Nodes.getDistance(); @@ -456,7 +477,22 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m return false; } - bool isNewNode = Nodes.addNode(received); + uint8_t traceroute_size = 0; + bool isNewNode = false; + bool nodeAdded = false; + if (message.getBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t), payload_pos) != 0) { + if (traceroute_size != 0) { + ESPEasy_now_traceroute_struct traceroute(traceroute_size); + if (message.getBinaryData(traceroute.get(), traceroute_size, payload_pos) == traceroute_size) { + isNewNode = Nodes.addNode(received, traceroute); + nodeAdded = true; + } + } + } + if (!nodeAdded) { + isNewNode = Nodes.addNode(received, ESPEasy_now_traceroute_struct()); + nodeAdded = true; + } // Test to see if the discovery announce could be a good candidate for next NTP query. _best_NTP_candidate.find_best_NTP( @@ -468,7 +504,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m String log; size_t payloadSize = message.getPayloadSize(); log.reserve(payloadSize + 40); - log = String(F(ESPEASY_NOW_NAME)) + F(" discovery: "); + log = String(F(ESPEASY_NOW_NAME)) + F(": discovery: "); log += message.getLogString(); log += '\n'; log += received.getSummary(); From 8cc629542c09323ae737f6ef20c9e49f6086279d Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 16 Mar 2021 21:07:39 +0100 Subject: [PATCH 112/404] [ESPEasy-NOW] Simplify route selection + show route on main page per node --- .../DataStructs/ESPEasy_now_traceroute.cpp | 9 +++++++-- src/src/DataStructs/ESPEasy_now_traceroute.h | 6 +++--- src/src/DataStructs/NodesHandler.cpp | 19 ++++++++++++++++--- src/src/WebServer/RootPage.cpp | 5 +++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index a78feddddc..d61432dedb 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -67,11 +67,15 @@ int ESPEasy_now_traceroute_struct::compute_penalty() const { const uint8_t max_distance = getDistance(); + // FIXME TD-er: for now just base it on the distance, not on the combination of RSSI & distance + return max_distance; +/* if (max_distance == 255) { // No values stored, so huge penalty return max_distance * 100; } + int penalty = 0; for (uint8_t distance = 0; distance <= max_distance; ++distance) { @@ -82,7 +86,7 @@ int ESPEasy_now_traceroute_struct::compute_penalty() const // Some "average" RSSI values for unknown RSSI rssi = -75; } else if (rssi < -80) { - // Some extra penaly for low quality signals + // Some extra penalty for low quality signals rssi -= 10; } @@ -90,6 +94,7 @@ int ESPEasy_now_traceroute_struct::compute_penalty() const penalty -= rssi; } return penalty; + */ } void ESPEasy_now_traceroute_struct::sanetize() @@ -136,7 +141,7 @@ void ESPEasy_now_traceroute_struct::sanetize() unit_vector = new_unit_vector; } -String ESPEasy_now_traceroute_struct::toString() +String ESPEasy_now_traceroute_struct::toString() const { const uint8_t max_distance = getDistance(); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 70722042d4..7b9aa203c3 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -41,13 +41,13 @@ struct ESPEasy_now_traceroute_struct void sanetize(); // For debugging purposes - String toString(); - -private: + String toString() const; // Compute penalty. Higher value means less preferred. int compute_penalty() const; +private: + // Node with distance 0 at front, so index/2 equals distance. // index%2 == 0 is unit // index%2 == 1 is RSSI diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index e6edd08d03..2c1760738b 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -163,9 +163,18 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& mustSet = true; } else { #ifdef USES_ESPEASY_NOW - if (getTraceRoute(it->second.unit) < getTraceRoute(res->unit)) - { - mustSet = true; + + const int penalty_new = it->second.distance; + const int penalty_res = res->distance; + + if (penalty_new < penalty_res) { + mustSet = true; + } else if (penalty_new == penalty_res) { + if (res->getAge() > 30000) { + if (it->second.getAge() < res->getAge()) { + mustSet = true; + } + } } #else if (it->second < *res) { @@ -338,6 +347,10 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& for (auto it = _nodes.begin(); it != _nodes.end();) { unsigned long age = it->second.getAge(); + if (it->second.ESPEasyNowPeer) { + // ESPEasy-NOW peers should see updates every 30 seconds. + if (age > 70000) age = max_age_allowed + 1; + } if (age > max_age_allowed) { #ifdef USES_ESPEASY_NOW diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 25a52c32d1..59fe768419 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -295,6 +295,11 @@ void handle_root() { addHtml(String(rssi)); } addHtml(')'); + const ESPEasy_now_traceroute_struct* trace = Nodes.getTraceRoute(it->second.unit); + if (trace != nullptr) { + addHtml(' '); + addHtml(trace->toString()); + } } #endif } From ce18a73f2f9638a9ecd5f4fe7624560073b5bdf7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 18 Mar 2021 11:34:35 +0100 Subject: [PATCH 113/404] [ESPEasy-NOW] Add ESPEasy-NOW-only as virtual network medium --- src/ESPEasy.ino | 5 +++++ src/_N001_Email.ino | 1 - src/_P020_Ser2Net.ino | 1 - src/src/DataStructs/ControllerSettingsStruct.cpp | 1 - src/src/DataStructs/Web_StreamingBuffer.cpp | 3 --- src/src/DataTypes/NetworkMedium.cpp | 13 +++++++++++++ src/src/DataTypes/NetworkMedium.h | 6 ++++-- src/src/ESPEasyCore/Controller.cpp | 2 -- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 15 ++++----------- src/src/ESPEasyCore/ESPEasyNetwork.h | 1 - src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 +++++--- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 ++-- src/src/Globals/NetworkState.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 1 - src/src/Helpers/Networking.cpp | 5 +---- src/src/Helpers/PeriodicalActions.cpp | 2 -- src/src/Helpers/StringProvider.cpp | 5 +++-- src/src/Helpers/_CPlugin_Helper.cpp | 2 -- src/src/PluginStructs/P044_data_struct.cpp | 1 - 19 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 86805af306..7b71319959 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -584,6 +584,11 @@ void loop() updateUDPport(); } break; + case NetworkMedium_t::ESPEasyNOW_only: + // FIXME TD-er: Should ESPEasy-NOW handler be stopped? + break; + case NetworkMedium_t::NotSet: + break; } bool firstLoopConnectionsEstablished = NetworkConnected() && firstLoop; diff --git a/src/_N001_Email.ino b/src/_N001_Email.ino index 171b52de39..170f11d454 100644 --- a/src/_N001_Email.ino +++ b/src/_N001_Email.ino @@ -86,7 +86,6 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, // Use WiFiClient class to create TCP connections WiFiClient client; client.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT); - PrepareSend(); String aHost = notificationsettings.Server; addLog(LOG_LEVEL_DEBUG, String(F("EMAIL: Connecting to ")) + aHost + notificationsettings.Port); if (!connectClient(client, aHost.c_str(), notificationsettings.Port)) { diff --git a/src/_P020_Ser2Net.ino b/src/_P020_Ser2Net.ino index 4f1ea244b0..d752a9f195 100644 --- a/src/_P020_Ser2Net.ino +++ b/src/_P020_Ser2Net.ino @@ -238,7 +238,6 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string) int timeOut = RXWait; size_t bytes_read = 0; - PrepareSend(); while (timeOut > 0) { while (Serial.available()) { diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index 1c697b8192..00778bf793 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -104,7 +104,6 @@ bool ControllerSettingsStruct::checkHostReachable(bool quick) { } delay(1); // Make sure the Watchdog will not trigger a reset. - PrepareSend(); if (quick && ipSet()) { return true; } if (UseDNS) { diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index 1f17f98938..5788d4b30b 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -140,7 +140,6 @@ void Web_StreamingBuffer::startStream(bool json, const String& origin) { sentBytes = 0; buf = ""; - PrepareSend(); if (beforeTXRam < 3000) { lowMemorySkip = true; web_server.send(200, "text/plain", "Low memory. Cannot display webpage :-("); @@ -209,7 +208,6 @@ void Web_StreamingBuffer::sendContentBlocking(String& data) { beforeTXRam = freeBeforeSend; } duringTXRam = freeBeforeSend; - PrepareSend(); #if defined(ESP8266) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) String size = formatToHex(length) + "\r\n"; @@ -249,7 +247,6 @@ void Web_StreamingBuffer::sendHeaderBlocking(bool json, const String& origin) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("sendHeaderBlocking")); #endif - PrepareSend(); web_server.client().flush(); String contenttype; diff --git a/src/src/DataTypes/NetworkMedium.cpp b/src/src/DataTypes/NetworkMedium.cpp index 8631ac685c..74fbd92a5d 100644 --- a/src/src/DataTypes/NetworkMedium.cpp +++ b/src/src/DataTypes/NetworkMedium.cpp @@ -1,10 +1,21 @@ #include "NetworkMedium.h" +#include "../../ESPEasy_common.h" + bool isValid(NetworkMedium_t medium) { switch (medium) { case NetworkMedium_t::WIFI: case NetworkMedium_t::Ethernet: return true; + case NetworkMedium_t::ESPEasyNOW_only: + #ifdef USES_ESPEASY_NOW + return true; + #else + return false; + #endif + + case NetworkMedium_t::NotSet: + return false; // Do not use default: as this allows the compiler to detect any missing cases. } @@ -15,6 +26,8 @@ String toString(NetworkMedium_t medium) { switch (medium) { case NetworkMedium_t::WIFI: return F("WiFi"); case NetworkMedium_t::Ethernet: return F("Ethernet"); + case NetworkMedium_t::ESPEasyNOW_only: return String(F(ESPEASY_NOW_NAME)) + F(" only"); + case NetworkMedium_t::NotSet: return F("Not Set"); // Do not use default: as this allows the compiler to detect any missing cases. } diff --git a/src/src/DataTypes/NetworkMedium.h b/src/src/DataTypes/NetworkMedium.h index 799e44cfec..61586ff70b 100644 --- a/src/src/DataTypes/NetworkMedium.h +++ b/src/src/DataTypes/NetworkMedium.h @@ -5,8 +5,10 @@ // Is stored in settings enum class NetworkMedium_t : uint8_t { - WIFI = 0, - Ethernet = 1 + WIFI = 0, + Ethernet = 1, + ESPEasyNOW_only = 2, + NotSet = 255 }; bool isValid(NetworkMedium_t medium); diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 1dc25d331c..1e76ef6426 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -213,7 +213,6 @@ bool MQTTConnect(controllerIndex_t controller_idx) if (MQTTclient.connected()) { MQTTclient.disconnect(); } - PrepareSend(); updateMQTTclient_connected(); // mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864 @@ -388,7 +387,6 @@ bool MQTTCheck(controllerIndex_t controller_idx) if (MQTTclient_must_send_LWT_connected) { if (mqtt_sendLWT) { - PrepareSend(); if (MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), willRetain)) { MQTTclient_must_send_LWT_connected = false; } diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 8919464f4e..7b7f71ef1b 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -23,6 +23,10 @@ void setNetworkMedium(NetworkMedium_t medium) { case NetworkMedium_t::WIFI: WiFi.mode(WIFI_OFF); break; + case NetworkMedium_t::ESPEasyNOW_only: + break; + case NetworkMedium_t::NotSet: + break; } active_network_medium = medium; addLog(LOG_LEVEL_INFO, String(F("Set Network mode: ")) + toString(active_network_medium)); @@ -56,17 +60,6 @@ bool NetworkConnected() { return WiFiConnected(); } -void PrepareSend() { - #ifdef HAS_ETHERNET - if (active_network_medium == NetworkMedium_t::Ethernet) { - return; - } - #endif - if (Settings.UseMaxTXpowerForSending()) { - SetWiFiTXpower(30); // Just some max, will be limited in SetWiFiTXpower - } -} - IPAddress NetworkLocalIP() { #ifdef HAS_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 58bab1226e..04edaa04c5 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -10,7 +10,6 @@ void setNetworkMedium(NetworkMedium_t medium); void NetworkConnectRelaxed(); bool NetworkConnected(); -void PrepareSend(); IPAddress NetworkLocalIP(); IPAddress NetworkSubnetMask(); IPAddress NetworkGatewayIP(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 5fdae6179e..e0cb444c03 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -411,12 +411,14 @@ void SetWiFiTXpower(float dBm, float rssi) { return; } + if (Settings.UseMaxTXpowerForSending() #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + || WiFi_AP_Candidates.isESPEasy_now_only() +#endif + ) { // Force using max. TX power. dBm = 30; // Some high number which will be corrected below } -#endif // Range ESP32 : 2dBm - 20dBm // Range ESP8266: 0dBm - 20.5dBm @@ -610,7 +612,7 @@ void WifiScan(bool async, uint8_t channel) { #ifdef ESP32 const bool passive = false; const uint32_t max_ms_per_chan = 300; - WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); + WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan, channel); #endif } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 79d96e77c3..0b76010374 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -181,7 +181,7 @@ void processDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) return; + //if (WiFi_AP_Candidates.isESPEasy_now_only()) return; ESPEasy_now_handler.end(); #endif @@ -457,7 +457,7 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); if (WiFi_AP_Candidates.isESPEasy_now_only()) { - if (WiFi_AP_Candidates.addedKnownCandidate() && WiFiConnected()) { + if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); WifiDisconnect(); } else { return; } diff --git a/src/src/Globals/NetworkState.cpp b/src/src/Globals/NetworkState.cpp index 473f965cd2..5360dddfca 100644 --- a/src/src/Globals/NetworkState.cpp +++ b/src/src/Globals/NetworkState.cpp @@ -4,7 +4,7 @@ // Ethernet Connection status -NetworkMedium_t active_network_medium = DEFAULT_NETWORK_MEDIUM; +NetworkMedium_t active_network_medium = NetworkMedium_t::NotSet; bool eth_connected = false; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 54a098d651..c91e70f53c 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -93,7 +93,6 @@ bool ESPEasy_now_handler_t::begin() if (WiFi_AP_Candidates.isESPEasy_now_only()) { WifiScan(false, 0); - addPeerFromWiFiScan(); } if (!Nodes.isEndpoint()) { diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 2e1b8ca1af..31a75dddcc 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -958,7 +958,6 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port) if (!NetworkConnected()) { return false; } - PrepareSend(); // In case of domain name resolution error result can be negative. // https://github.com/esp8266/Arduino/blob/18f643c7e2d6a0da9d26ff2b14c94e6536ab78c1/libraries/Ethernet/src/Dns.cpp#L44 @@ -987,7 +986,7 @@ bool resolveHostByName(const char *aHostname, IPAddress& aResult) { if (!NetworkConnected()) { return false; } - PrepareSend(); + #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) bool resolvedIP = WiFi.hostByName(aHostname, aResult) == 1; #else // if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ESP32) @@ -1040,8 +1039,6 @@ void sendGratuitousARP() { } #ifdef SUPPORT_ARP - PrepareSend(); - // See https://github.com/letscontrolit/ESPEasy/issues/2374 START_TIMER; netif *n = netif_list; diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index ff4f9cb358..d4e300fe41 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -379,7 +379,6 @@ bool processMQTT_message(controllerIndex_t controllerIndex, #endif if (!processed) { - PrepareSend(); if (MQTTclient.publish(topic.c_str(), payload.c_str(), retained)) { if (WiFiEventData.connectionFailures > 0) { --WiFiEventData.connectionFailures; @@ -432,7 +431,6 @@ void runPeriodicalMQTT() { //dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683) controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(enabledMqttController)) { - PrepareSend(); if (!MQTTclient.loop()) { updateMQTTclient_connected(); if (MQTTCheck(enabledMqttController)) { diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 5f90b19b5c..f837e08972 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -5,6 +5,7 @@ #endif // ifdef HAS_ETHERNET #include "../../ESPEasy_fdwdecl.h" #include "../../ESPEasy-Globals.h" +#include "../../ESPEasy_common.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" @@ -110,8 +111,8 @@ String getLabel(LabelType::Enum label) { case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); #ifdef USES_ESPEASY_NOW - case LabelType::USE_ESPEASY_NOW: return F("Use ESPEasy-NOW"); - case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable ESPEasy-NOW"); + case LabelType::USE_ESPEASY_NOW: return String(F("Enable ")) + F(ESPEASY_NOW_NAME); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return String(F("Temporary disable ")) + F(ESPEASY_NOW_NAME); #endif diff --git a/src/src/Helpers/_CPlugin_Helper.cpp b/src/src/Helpers/_CPlugin_Helper.cpp index b2326529ed..64d368ea6f 100644 --- a/src/src/Helpers/_CPlugin_Helper.cpp +++ b/src/src/Helpers/_CPlugin_Helper.cpp @@ -523,8 +523,6 @@ String send_via_http(const String& logIdentifier, // "if you have XXX, send it; or failing that, just give me what you've got." http.addHeader(F("Accept"), F("*/*;q=0.1")); - PrepareSend(); - delay(0); #if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri, false); // HTTP diff --git a/src/src/PluginStructs/P044_data_struct.cpp b/src/src/PluginStructs/P044_data_struct.cpp index 54805ace07..14d73e51bd 100644 --- a/src/src/PluginStructs/P044_data_struct.cpp +++ b/src/src/PluginStructs/P044_data_struct.cpp @@ -262,7 +262,6 @@ void P044_Task::handleSerialIn(struct EventStruct *event) { } while (true); if (done) { - PrepareSend(); P1GatewayClient.print(serial_buffer); P1GatewayClient.flush(); From 9bf015a08901d0a0e5b703f08ac4a0185da83d5d Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 18 Mar 2021 13:40:47 +0100 Subject: [PATCH 114/404] [ESPEasy-NOW] Use only AP for ESPEasy-NOW in ESPEasy-NOW-only mode --- src/ESPEasy.ino | 2 +- src/src/DataStructs/NodesHandler.cpp | 4 +- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 19 ++++++++++ src/src/ESPEasyCore/ESPEasyNetwork.h | 2 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 28 +++++++++++++- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 10 ++--- src/src/Globals/ESPEasy_now_handler.cpp | 2 +- src/src/Globals/NetworkState.cpp | 1 + src/src/Globals/NetworkState.h | 3 ++ src/src/Helpers/ESPEasy_now_handler.cpp | 5 +-- src/src/Helpers/Networking.cpp | 2 +- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 37 +------------------ src/src/Helpers/WiFi_AP_CandidatesList.h | 4 -- 13 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 7b71319959..3ded68db12 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -429,7 +429,7 @@ void setup() } #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only() || Settings.UseESPEasyNow()) { + if (isESPEasy_now_only() || Settings.UseESPEasyNow()) { RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. RTC.lastWiFiChannel = 0; // Force slow connect } diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 2c1760738b..e1634b1246 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -223,7 +223,7 @@ void NodesHandler::updateThisNode() { { bool addIP = true; #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (isESPEasy_now_only()) { // Connected via 'virtual ESPEasy-NOW AP' addIP = false; thisNode.useAP_ESPEasyNow = 1; @@ -301,7 +301,7 @@ void NodesHandler::updateThisNode() { _lastTimeValidDistance = millis(); } if (_distance != lastDistance) { - if (WiFi_AP_Candidates.isESPEasy_now_only() && WiFiConnected()) { + if (isESPEasy_now_only() && WiFiConnected()) { // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP // Try to reconnect to it. RTC.clearLastWiFi(); // Force a WiFi scan diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 7b7f71ef1b..8007b965c9 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -13,6 +13,16 @@ #endif void setNetworkMedium(NetworkMedium_t medium) { + if (medium == NetworkMedium_t::ESPEasyNOW_only) { + if (!Settings.UseESPEasyNow()) { + return; + } + if (active_network_medium != NetworkMedium_t::WIFI) { + // Only allow to set to ESPEasyNOW_only from WiFi + return; + } + } + switch (active_network_medium) { case NetworkMedium_t::Ethernet: #ifdef HAS_ETHERNET @@ -29,9 +39,18 @@ void setNetworkMedium(NetworkMedium_t medium) { break; } active_network_medium = medium; + last_network_medium_set_moment.setNow(); addLog(LOG_LEVEL_INFO, String(F("Set Network mode: ")) + toString(active_network_medium)); } +bool isESPEasy_now_only() { + #ifdef USES_EASPEASY_NOW + return active_network_medium == NetworkMedium_t::ESPEasyNOW_only; + #else + return false; + #endif +} + /*********************************************************************************************\ Ethernet or Wifi Support for ESP32 Build flag HAS_ETHERNET diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 04edaa04c5..b4663e76cd 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -8,6 +8,8 @@ void setNetworkMedium(NetworkMedium_t medium); +bool isESPEasy_now_only(); + void NetworkConnectRelaxed(); bool NetworkConnected(); IPAddress NetworkLocalIP(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 6310e5aeef..f06b40027e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -20,6 +20,10 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_WiFi.h" +#ifdef USES_ESPEASY_NOW +# include "../Globals/ESPEasy_now_handler.h" +#endif + // ******************************************************************************** // WiFi state @@ -254,6 +258,10 @@ void AttemptWiFiConnect() { // Maybe not scan async to give the ESP some slack in power consumption? const bool async = true; WifiScan(async); + } else { + if (!WiFi_AP_Candidates.addedKnownCandidate()) { + setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); + } } } @@ -413,7 +421,7 @@ void SetWiFiTXpower(float dBm, float rssi) { if (Settings.UseMaxTXpowerForSending() #ifdef USES_ESPEASY_NOW - || WiFi_AP_Candidates.isESPEasy_now_only() + || isESPEasy_now_only() #endif ) { // Force using max. TX power. @@ -676,6 +684,12 @@ void setSTA(bool enable) { void setAP(bool enable) { WiFiMode_t wifimode = WiFi.getMode(); + #ifdef USES_ESPEASY_NOW + if (!enable && use_EspEasy_now) { + ESPEasy_now_handler.end(); + } + #endif + switch (wifimode) { case WIFI_OFF: @@ -927,6 +941,16 @@ bool wifiAPmodeActivelyUsed() // AP not active or soon to be disabled in processDisableAPmode() return false; } + #ifdef USES_ESPEASY_NOW + if (isESPEasy_now_only() && + last_network_medium_set_moment.timeoutReached(600 * 1000)) + { + // Only allow the ESPEasy_NOW_only mode for 10 minutes + setNetworkMedium(Settings.NetworkMedium); + } else if (ESPEasy_now_handler.active()) { + return true; + } + #endif return WiFi.softAPgetStationNum() != 0; // FIXME TD-er: is effectively checking for AP active enough or must really check for connected clients to prevent automatic wifi @@ -936,7 +960,7 @@ bool wifiAPmodeActivelyUsed() void setConnectionSpeed() { #ifdef ESP8266 #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (isESPEasy_now_only()) { WiFi.setPhyMode(WIFI_PHY_MODE_11G); return; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 0b76010374..d92baf088b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -181,7 +181,7 @@ void processDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW - //if (WiFi_AP_Candidates.isESPEasy_now_only()) return; + //if (isESPEasy_now_only()) return; ESPEasy_now_handler.end(); #endif @@ -408,13 +408,9 @@ void processConnectAPmode() { void processDisableAPmode() { if (!WiFiEventData.timerAPoff.isSet()) { return; } - #ifdef USES_ESPEASY_NOW - if (Settings.UseESPEasyNow()) { return;} - #endif - if (WifiIsAP(WiFi.getMode())) { // disable AP after timeout and no clients connected. - if (WiFiEventData.timerAPoff.timeoutReached(WIFI_AP_OFF_TIMER_DURATION) && (WiFi.softAPgetStationNum() == 0)) { + if (WiFiEventData.timerAPoff.timeoutReached(WIFI_AP_OFF_TIMER_DURATION) && !wifiAPmodeActivelyUsed()) { setAP(false); } } @@ -456,7 +452,7 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (isESPEasy_now_only()) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); WifiDisconnect(); diff --git a/src/src/Globals/ESPEasy_now_handler.cpp b/src/src/Globals/ESPEasy_now_handler.cpp index 271820404e..5dcc7abbc3 100644 --- a/src/src/Globals/ESPEasy_now_handler.cpp +++ b/src/src/Globals/ESPEasy_now_handler.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_handler.h" +#include "../Globals/ESPEasy_now_handler.h" #ifdef USES_ESPEASY_NOW diff --git a/src/src/Globals/NetworkState.cpp b/src/src/Globals/NetworkState.cpp index 5360dddfca..054a3f3e78 100644 --- a/src/src/Globals/NetworkState.cpp +++ b/src/src/Globals/NetworkState.cpp @@ -5,6 +5,7 @@ // Ethernet Connection status NetworkMedium_t active_network_medium = NetworkMedium_t::NotSet; +LongTermTimer last_network_medium_set_moment; bool eth_connected = false; diff --git a/src/src/Globals/NetworkState.h b/src/src/Globals/NetworkState.h index 28a5c1c804..2999f2dd4c 100644 --- a/src/src/Globals/NetworkState.h +++ b/src/src/Globals/NetworkState.h @@ -9,8 +9,11 @@ #include "../DataTypes/ESPEasy_plugin_functions.h" #include "../DataTypes/NetworkMedium.h" +#include "../Helpers/LongTermTimer.h" + // Ethernet Connectiopn status extern NetworkMedium_t active_network_medium; +extern LongTermTimer last_network_medium_set_moment;; extern bool eth_connected; extern bool webserverRunning; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index c91e70f53c..19b48bfa43 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -91,7 +91,7 @@ bool ESPEasy_now_handler_t::begin() int channel = WiFi.channel(); _controllerIndex = INVALID_CONTROLLER_INDEX; - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (isESPEasy_now_only()) { WifiScan(false, 0); } @@ -154,7 +154,6 @@ void ESPEasy_now_handler_t::end() WifiEspNow.end(); _last_used = 0; } - setAP(false); addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" disabled")); } @@ -237,7 +236,7 @@ bool ESPEasy_now_handler_t::loop() if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; - // FIXME TD-er: Must check/mark so this becomes true: WiFi_AP_Candidates.isESPEasy_now_only() + // FIXME TD-er: Must check/mark so this becomes true: isESPEasy_now_only() // Start scanning the next channel to see if we may end up with a new found node // WifiScan(false, false); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 31a75dddcc..e7dedf4551 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -884,7 +884,7 @@ bool hasIPaddr() { bool NetworkConnected(uint32_t timeout_ms) { #ifdef USES_ESPEASY_NOW - if (WiFi_AP_Candidates.isESPEasy_now_only()) { + if (isESPEasy_now_only()) { return false; } #endif diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index ae80c60bc5..655d8e572b 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -12,7 +12,6 @@ #define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" #endif -#define WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX 3 WiFi_AP_CandidatesList::WiFi_AP_CandidatesList() { known.clear(); @@ -33,19 +32,8 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { // Add the known SSIDs String ssid, key; byte index = 1; // Index 0 is the "unset" value - bool done = false; - - while (!done) { - if (get_SSID_key(index, ssid, key)) { - known.emplace_back(index, ssid, key); - if (index == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX) { - known.back().lowPrio = true; - } - } else if (index != WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX) { - // There may be other credentials so don't stop at ESPEasy-now index - // For example on builds without ESPEasy-NOW these credentials will not be returned. - done = true; - } + while (get_SSID_key(index, ssid, key)) { + known.emplace_back(index, ssid, key); ++index; } } @@ -169,12 +157,6 @@ void WiFi_AP_CandidatesList::markCurrentConnectionStable() { addFromRTC(); // Store the current one from RTC as the first candidate for a reconnect. } -#ifdef USES_ESPEASY_NOW -bool WiFi_AP_CandidatesList::isESPEasy_now_only() const { - return currentCandidate.index == WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX; -} -#endif - void WiFi_AP_CandidatesList::add(uint8_t networkItem) { WiFi_AP_Candidate tmp(networkItem); @@ -210,15 +192,6 @@ void WiFi_AP_CandidatesList::add(uint8_t networkItem) { void WiFi_AP_CandidatesList::addFromRTC() { if (!RTC.lastWiFi_set()) { return; } - #ifdef USES_ESPEASY_NOW - if (isESPEasy_now_only()) { - // Connected via 'virtual ESPEasy-NOW AP' - // This should be a last resort. - return; - } - #endif - - String ssid, key; if (!get_SSID_key(RTC.lastWiFiSettingsIndex, ssid, key)) { @@ -284,12 +257,6 @@ bool WiFi_AP_CandidatesList::get_SSID_key(byte index, String& ssid, String& key) ssid = SecuritySettings.WifiSSID2; key = SecuritySettings.WifiKey2; break; - #ifdef USES_ESPEASY_NOW - case WIFI_AP_CANDIDATE_ESPEASY_NOW_INDEX: - ssid = F(ESPEASY_NOW_TMP_SSID); - key = F(ESPEASY_NOW_TMP_PASSPHRASE); - break; - #endif default: return false; } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index fdb2ce42c5..099ff22ea9 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -36,10 +36,6 @@ struct WiFi_AP_CandidatesList { bool addedKnownCandidate() const { return _addedKnownCandidate; } -#ifdef USES_ESPEASY_NOW - bool isESPEasy_now_only() const; -#endif - private: // Add item from WiFi scan. From 3d466e567efd50ec5f0c00e94e843894141b93c3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 19 Mar 2021 01:13:20 +0100 Subject: [PATCH 115/404] [ESPEasy-NOW] Try to reconnect when known WiFi is near --- src/ESPEasy.ino | 2 -- src/src/DataStructs/NodesHandler.cpp | 10 ++----- src/src/DataStructs/WiFiEventData.cpp | 5 ++++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 8 +++++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 26 +++++++++++++---- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 28 +++++++++++++------ src/src/Helpers/Networking.cpp | 6 ++-- 7 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 3ded68db12..cb41533a08 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -342,11 +342,9 @@ void setup() toDisable = disableNotification(toDisable); } } - #ifdef HAS_ETHERNET // This ensures, that changing WIFI OR ETHERNET MODE happens properly only after reboot. Changing without reboot would not be a good idea. // This only works after LoadSettings(); setNetworkMedium(Settings.NetworkMedium); - #endif if (active_network_medium == NetworkMedium_t::WIFI) { if (!WiFi_AP_Candidates.hasKnownCredentials()) { WiFiEventData.wifiSetup = true; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index e1634b1246..bffac99636 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -8,6 +8,7 @@ #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/PeriodicalActions.h" #include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" #include "../Globals/RTC.h" @@ -221,16 +222,11 @@ void NodesHandler::updateThisNode() { WiFi.macAddress(thisNode.sta_mac); WiFi.softAPmacAddress(thisNode.ap_mac); { - bool addIP = true; + bool addIP = NetworkConnected(); #ifdef USES_ESPEASY_NOW - if (isESPEasy_now_only()) { - // Connected via 'virtual ESPEasy-NOW AP' - addIP = false; + if (use_EspEasy_now) { thisNode.useAP_ESPEasyNow = 1; } - if (!isEndpoint()) { - addIP = false; - } #endif if (addIP) { IPAddress localIP = NetworkLocalIP(); diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 89cf6bd6e4..89eca53d7d 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -1,6 +1,7 @@ #include "WiFiEventData.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#include "../Globals/ESPEasy_now_state.h" #include "../Globals/RTC.h" #include "../Globals/WiFi_AP_Candidates.h" @@ -101,6 +102,10 @@ void WiFiEventData_t::setWiFiServicesInitialized() { addLog(LOG_LEVEL_DEBUG, F("WiFi : WiFi services initialized")); bitSet(wifiStatus, ESPEASY_WIFI_SERVICES_INITIALIZED); wifiConnectInProgress = false; + + #ifdef USES_ESPEASY_NOW + temp_disable_EspEasy_now_timer = 0; + #endif } } diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 8007b965c9..8cbff8f2b0 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -22,6 +22,12 @@ void setNetworkMedium(NetworkMedium_t medium) { return; } } + #ifndef HAS_ETHERNET + if (medium == NetworkMedium_t::Ethernet) { + // When no ethernet is present in the build, make sure to fall-back on WiFi. + medium = NetworkMedium_t::WIFI; + } + #endif switch (active_network_medium) { case NetworkMedium_t::Ethernet: @@ -31,7 +37,7 @@ void setNetworkMedium(NetworkMedium_t medium) { #endif break; case NetworkMedium_t::WIFI: - WiFi.mode(WIFI_OFF); + setSTA(false); break; case NetworkMedium_t::ESPEasyNOW_only: break; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index f06b40027e..1cd220c145 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -207,6 +207,11 @@ void WiFiConnectRelaxed() { return; } + #ifdef USES_ESPEASY_NOW + // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + temp_disable_EspEasy_now_timer = millis() + 10000; + #endif + // FIXME TD-er: Should not try to prepare when a scan is still busy. // This is a logic error which may lead to strange issues if some kind of timeout happens and/or RF calibration was not OK. @@ -610,7 +615,16 @@ void WifiScan(bool async, uint8_t channel) { // Scan still busy return; } - addLog(LOG_LEVEL_INFO, F("WIFI : Start network scan")); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log = F("WIFI : Start network scan"); + if (channel != 0) { + log += F(" ch. "); + log += channel; + } + addLog(LOG_LEVEL_INFO, log); + } + bool show_hidden = true; WiFiEventData.processedScanDone = false; WiFiEventData.lastGetScanMoment.setNow(); @@ -937,10 +951,6 @@ bool wifiConnectTimeoutReached() { bool wifiAPmodeActivelyUsed() { - if (!WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { - // AP not active or soon to be disabled in processDisableAPmode() - return false; - } #ifdef USES_ESPEASY_NOW if (isESPEasy_now_only() && last_network_medium_set_moment.timeoutReached(600 * 1000)) @@ -951,6 +961,12 @@ bool wifiAPmodeActivelyUsed() return true; } #endif + + if (!WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { + // AP not active or soon to be disabled in processDisableAPmode() + return false; + } + return WiFi.softAPgetStationNum() != 0; // FIXME TD-er: is effectively checking for AP active enough or must really check for connected clients to prevent automatic wifi diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index d92baf088b..6b436ebd92 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -452,19 +452,29 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW ESPEasy_now_handler.addPeerFromWiFiScan(); - if (isESPEasy_now_only()) { - if (WiFi_AP_Candidates.addedKnownCandidate()) { - WiFi_AP_Candidates.force_reload(); - WifiDisconnect(); - } else { return; } + if (use_EspEasy_now) { + if (!WiFiConnected()) { + if (WiFi_AP_Candidates.addedKnownCandidate()) { + WiFi_AP_Candidates.force_reload(); + if (isESPEasy_now_only()) { + setNetworkMedium(NetworkMedium_t::WIFI); + WifiDisconnect(); + setAP(false); + } + } else { + setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); + } + } } #endif const WiFi_AP_Candidate bestCandidate = WiFi_AP_Candidates.getBestScanResult(); - if (bestCandidate.usable() && loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("WIFI : Selected: "); - log += bestCandidate.toString(); - addLog(LOG_LEVEL_INFO, log); + if (bestCandidate.usable()) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("WIFI : Selected: "); + log += bestCandidate.toString(); + addLog(LOG_LEVEL_INFO, log); + } } } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index e7dedf4551..1a4953eee1 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -399,15 +399,13 @@ void refreshNodeList() Nodes.refreshNodeList(max_age_allowed, max_age); - #if defined(USES_ESPEASY_NOW) && defined(ESP8266) - - // ESP32 does not (yet) allow to scan a single channel so may take too long + #ifdef USES_ESPEASY_NOW const uint8_t channel = Nodes.getESPEasyNOW_channel(); if (channel != 0) { WifiScan(true, channel); } - #endif // if defined(USES_ESPEASY_NOW) && defined(ESP8266) + #endif if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); From f16fb373bd8298535926afcab14e8829bec629be Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 22 Mar 2021 22:43:05 +0100 Subject: [PATCH 116/404] [ESPEasy-NOW] Improve WiFi reconnect + traceroute --- src/ESPEasy.ino | 5 ++ .../DataStructs/ESPEasy_now_traceroute.cpp | 76 ++++++------------- src/src/DataStructs/ESPEasy_now_traceroute.h | 8 +- src/src/DataStructs/NodesHandler.cpp | 24 ++++-- src/src/DataStructs/NodesHandler.h | 2 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 5 -- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 7 +- src/src/Helpers/ESPEasy_now_handler.cpp | 3 + 8 files changed, 58 insertions(+), 72 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index cb41533a08..51450342ab 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -433,6 +433,11 @@ void setup() } #endif + #ifdef USES_ESPEASY_NOW + // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + temp_disable_EspEasy_now_timer = millis() + 10000; + #endif + NetworkConnectRelaxed(); setWebserverRunning(true); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index d61432dedb..d01e2495bb 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -19,13 +19,24 @@ uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, int8_t& rssi) c return unit_vector[distance * 2]; } -void ESPEasy_now_traceroute_struct::addUnit(uint8_t unit, int8_t rssi) +void ESPEasy_now_traceroute_struct::addUnit(const NodeStruct& node) { + if (node.distance == 255) { + // No distance set, so don't add the traceroute. + return; + } + + // Only add the unit if it isn't already part of the traceroute. const uint8_t index = unit_vector.size(); + for (size_t i = 0; i < index; i+=2) { + if (unit_vector[i] == node.unit) { + unit_vector[i + 1] = static_cast(static_cast(node.getRSSI() + 127)); + return; + } + } unit_vector.resize(index + 2); - unit_vector[index] = unit; - unit_vector[index + 1] = static_cast(static_cast(rssi + 127)); + unit_vector[index] = node.unit; } uint8_t ESPEasy_now_traceroute_struct::getDistance() const @@ -48,14 +59,19 @@ uint8_t * ESPEasy_now_traceroute_struct::get() return &(unit_vector[0]); } -void ESPEasy_now_traceroute_struct::setRSSI_last_node(int8_t rssi) const +void ESPEasy_now_traceroute_struct::setRSSI_last_node(byte unit, int8_t rssi) const { - const uint8_t index = unit_vector.size(); + int index = unit_vector.size() - 2; + int attempt = 0; - if (index == 0) { - return; + while (index >= 0 && attempt < 2) { + if (unit_vector[index] == unit) { + unit_vector[index + 1] = static_cast(static_cast(rssi + 127)); + return; + } + index -= 2; + ++attempt; } - unit_vector[index - 1] = static_cast(static_cast(rssi + 127)); } bool ESPEasy_now_traceroute_struct::operator<(const ESPEasy_now_traceroute_struct& other) const @@ -97,50 +113,6 @@ int ESPEasy_now_traceroute_struct::compute_penalty() const */ } -void ESPEasy_now_traceroute_struct::sanetize() -{ - std::list units; - - for (size_t i = 0; i < unit_vector.size(); i += 2) { - units.push_back(unit_vector[i]); - } - - // Remove duplicates by sort and unique - units.sort(); - units.unique(); - - if (units.size() == (unit_vector.size() / 2)) { - // No loops - return; - } - - std::vector new_unit_vector; - - new_unit_vector.reserve(units.size() * 2); - - const uint8_t max_distance = getDistance(); - - for (uint8_t distance = 0; distance <= max_distance; ++distance) { - const uint8_t unit = unit_vector[distance * 2]; - bool found = false; - - for (auto it = units.begin(); !found && it != units.end(); ++it) { - if (*it == unit) { - // Present in the unique list so remove it - units.erase(it); - found = true; - } - } - - if (found) { - // It was present in the unique list, so we can add it to the new vector - new_unit_vector.push_back(unit); - new_unit_vector.push_back(unit_vector[(distance * 2) + 1]); - } - } - unit_vector = new_unit_vector; -} - String ESPEasy_now_traceroute_struct::toString() const { const uint8_t max_distance = getDistance(); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 7b9aa203c3..b08940f4a3 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -21,8 +21,7 @@ struct ESPEasy_now_traceroute_struct int8_t& rssi) const; // Append unit at the end (thus furthest distance) - void addUnit(uint8_t unit, - int8_t rssi = 0); + void addUnit(const NodeStruct& node); uint8_t getDistance() const; @@ -32,14 +31,11 @@ struct ESPEasy_now_traceroute_struct // Make sure the array is large enough to store the data. uint8_t* get(); - void setRSSI_last_node(int8_t rssi) const; + void setRSSI_last_node(byte unit, int8_t rssi) const; // Return true when this traceroute has lower penalty (thus more favorable) bool operator<(const ESPEasy_now_traceroute_struct& other) const; - // Remove duplicate entries (e.g. loops) - void sanetize(); - // For debugging purposes String toString() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index bffac99636..dfad6cab9c 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -64,8 +64,7 @@ bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_ const bool isNewNode = addNode(node); _traceRoutes[node.unit] = traceRoute; - _traceRoutes[node.unit].addUnit(node.unit, 0); // Will update the RSSI of the last node in getTraceRoute - _traceRoutes[node.unit].sanetize(); + _traceRoutes[node.unit].addUnit(node); addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": traceroute received ") + _traceRoutes[node.unit].toString()); return isNewNode; @@ -207,7 +206,7 @@ const ESPEasy_now_traceroute_struct* NodesHandler::getTraceRoute(uint8_t unit) c auto node_it = _nodes.find(unit); if (node_it != _nodes.end()) { - trace_it->second.setRSSI_last_node(node_it->second.getRSSI()); + trace_it->second.setRSSI_last_node(node_it->second.unit, node_it->second.getRSSI()); } return &(trace_it->second); @@ -280,7 +279,8 @@ void NodesHandler::updateThisNode() { _recentlyBecameDistanceZero = true; } #ifdef USES_ESPEASY_NOW - thisTraceRoute.addUnit(thisNode.unit); + thisNode.distance = _distance; + thisTraceRoute.addUnit(thisNode); #endif } else { _distance = 255; @@ -345,7 +345,7 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& unsigned long age = it->second.getAge(); if (it->second.ESPEasyNowPeer) { // ESPEasy-NOW peers should see updates every 30 seconds. - if (age > 70000) age = max_age_allowed + 1; + if (age > 125000) age = max_age_allowed + 1; } if (age > max_age_allowed) { @@ -403,6 +403,20 @@ bool NodesHandler::recentlyBecameDistanceZero() { return true; } +void NodesHandler::setRSSI(const MAC_address& mac, int rssi) +{ + NodeStruct* matchingNode = getNodeByMac(mac); + if (matchingNode != nullptr) { + matchingNode->setRSSI(rssi); + #ifdef USES_ESPEASY_NOW + auto it = _traceRoutes.find(matchingNode->unit); + if (it != _traceRoutes.end()) { + it->second.setRSSI_last_node(matchingNode->unit, rssi); + } + #endif + } +} + bool NodesHandler::lastTimeValidDistanceExpired() const { // if (_lastTimeValidDistance == 0) return false; diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index f2f60df5cc..ca413c5cf5 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -71,6 +71,8 @@ class NodesHandler { bool recentlyBecameDistanceZero(); + void setRSSI(const MAC_address& mac, int rssi); + private: #ifdef USES_ESPEASY_NOW diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 1cd220c145..cff186d1a4 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -207,11 +207,6 @@ void WiFiConnectRelaxed() { return; } - #ifdef USES_ESPEASY_NOW - // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. - temp_disable_EspEasy_now_timer = millis() + 10000; - #endif - // FIXME TD-er: Should not try to prepare when a scan is still busy. // This is a logic error which may lead to strange issues if some kind of timeout happens and/or RF calibration was not OK. diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 6b436ebd92..9d2859d89a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -355,10 +355,7 @@ void processProbeRequestAPmode() { const MAC_address mac(APModeProbeRequestReceived_list.front().mac); const int rssi = APModeProbeRequestReceived_list.front().rssi; - NodeStruct* matchingNode = Nodes.getNodeByMac(mac); - if (matchingNode != nullptr) { - matchingNode->setRSSI(rssi); - } + Nodes.setRSSI(mac, rssi); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("AP Mode: Probe Request: "); @@ -460,6 +457,8 @@ void processScanDone() { setNetworkMedium(NetworkMedium_t::WIFI); WifiDisconnect(); setAP(false); + // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + temp_disable_EspEasy_now_timer = millis() + 10000; } } else { setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 19b48bfa43..5da4aef47e 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -148,6 +148,7 @@ void ESPEasy_now_handler_t::end() { _controllerIndex = INVALID_CONTROLLER_INDEX; use_EspEasy_now = false; + ESPEasy_now_in_queue.clear(); RTC.clearLastWiFi(); // Force a WiFi scan if (_last_used != 0) { // Only call WifiEspNow.end() if it was started. @@ -176,6 +177,7 @@ bool ESPEasy_now_handler_t::loop() begin(); } else { end(); + return false; } } } @@ -445,6 +447,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch } else { msg.send(mac, channel); } +// WifiScan(true, channel); } bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep) From 55f5103b153d319217d71bfc96fbbf1929af622d Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 25 Mar 2021 14:08:49 +0100 Subject: [PATCH 117/404] [ESPEasy-NOW] Fix WiFi reconnect + improve traceroute --- .../DataStructs/ESPEasy_now_traceroute.cpp | 6 ++- src/src/DataStructs/ESPEasy_now_traceroute.h | 5 +- src/src/DataStructs/NodeStruct.cpp | 12 +++++ src/src/DataStructs/NodeStruct.h | 2 + src/src/DataStructs/NodesHandler.cpp | 47 ++++++++++++++----- src/src/DataStructs/NodesHandler.h | 5 ++ src/src/Helpers/ESPEasy_now_handler.cpp | 11 +++-- 7 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index d01e2495bb..8ed59fedfa 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -37,6 +37,7 @@ void ESPEasy_now_traceroute_struct::addUnit(const NodeStruct& node) unit_vector.resize(index + 2); unit_vector[index] = node.unit; + unit_vector[index + 1] = static_cast(static_cast(node.getRSSI() + 127)); } uint8_t ESPEasy_now_traceroute_struct::getDistance() const @@ -59,8 +60,11 @@ uint8_t * ESPEasy_now_traceroute_struct::get() return &(unit_vector[0]); } -void ESPEasy_now_traceroute_struct::setRSSI_last_node(byte unit, int8_t rssi) const +void ESPEasy_now_traceroute_struct::setRSSI_last_node(byte unit, int8_t rssi) { + if (rssi > 0) { + rssi = 0; + } int index = unit_vector.size() - 2; int attempt = 0; diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index b08940f4a3..852a2c651a 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -31,7 +31,7 @@ struct ESPEasy_now_traceroute_struct // Make sure the array is large enough to store the data. uint8_t* get(); - void setRSSI_last_node(byte unit, int8_t rssi) const; + void setRSSI_last_node(byte unit, int8_t rssi); // Return true when this traceroute has lower penalty (thus more favorable) bool operator<(const ESPEasy_now_traceroute_struct& other) const; @@ -47,8 +47,7 @@ struct ESPEasy_now_traceroute_struct // Node with distance 0 at front, so index/2 equals distance. // index%2 == 0 is unit // index%2 == 1 is RSSI - // Made mutable so setRSSI_last_node can remain const. - mutable std::vectorunit_vector; + std::vectorunit_vector; }; typedef std::map TraceRouteMap; diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index d64d168c56..c3aff336c0 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -238,6 +238,18 @@ bool NodeStruct::match(const MAC_address& mac) const return (mac == sta_mac || mac == ap_mac); } +bool NodeStruct::isThisNode() const +{ + // Check to see if we process a node we've sent ourselves. + MAC_address tmp; + WiFi.softAPmacAddress(tmp.mac); + if (tmp == ap_mac) return true; + WiFi.macAddress(tmp.mac); + if (tmp == sta_mac) return true; + + return false; +} + void NodeStruct::setAP_MAC(const MAC_address& mac) { mac.get(ap_mac); diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 150ad33571..aadc4c0f01 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -63,6 +63,8 @@ struct __attribute__((__packed__)) NodeStruct bool match(const MAC_address& mac) const; + bool isThisNode() const; + void setAP_MAC(const MAC_address& mac); diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index dfad6cab9c..a210d330ab 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -66,7 +66,9 @@ bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_ _traceRoutes[node.unit].addUnit(node); - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": traceroute received ") + _traceRoutes[node.unit].toString()); + if (traceRoute.getDistance() != 255 && !node.isThisNode()) { + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": Node: ") + String(node.unit) + F(" Traceroute received: ") + _traceRoutes[node.unit].toString()); + } return isNewNode; } #endif @@ -81,6 +83,16 @@ bool NodesHandler::hasNode(const uint8_t *mac) const return getNodeByMac(mac) != nullptr; } +NodeStruct * NodesHandler::getNode(uint8_t unit_nr) +{ + auto it = _nodes.find(unit_nr); + + if (it == _nodes.end()) { + return nullptr; + } + return &(it->second); +} + const NodeStruct * NodesHandler::getNode(uint8_t unit_nr) const { auto it = _nodes.find(unit_nr); @@ -203,12 +215,6 @@ const ESPEasy_now_traceroute_struct* NodesHandler::getTraceRoute(uint8_t unit) c if (trace_it == _traceRoutes.end()) { return nullptr; } - - auto node_it = _nodes.find(unit); - if (node_it != _nodes.end()) { - trace_it->second.setRSSI_last_node(node_it->second.unit, node_it->second.getRSSI()); - } - return &(trace_it->second); } #endif @@ -280,7 +286,9 @@ void NodesHandler::updateThisNode() { } #ifdef USES_ESPEASY_NOW thisNode.distance = _distance; + thisNode.setRSSI(WiFi.RSSI()); thisTraceRoute.addUnit(thisNode); + thisTraceRoute.setRSSI_last_node(thisNode.unit, WiFi.RSSI()); #endif } else { _distance = 255; @@ -291,8 +299,11 @@ void NodesHandler::updateThisNode() { if (!preferred->isExpired()) { const ESPEasy_now_traceroute_struct* tracert_ptr = getTraceRoute(preferred->unit); if (tracert_ptr != nullptr && tracert_ptr->getDistance() < 255) { - // Make a copy of the traceroute + // Make a copy of the traceroute thisTraceRoute = *tracert_ptr; + thisTraceRoute.addUnit(thisNode); + thisTraceRoute.setRSSI_last_node(thisNode.unit, preferred->getRSSI()); + _distance = thisTraceRoute.getDistance() + 1; _lastTimeValidDistance = millis(); } @@ -309,6 +320,7 @@ void NodesHandler::updateThisNode() { #endif } thisNode.distance = _distance; + #ifdef USES_ESPEASY_NOW addNode(thisNode, thisTraceRoute); #else @@ -405,13 +417,22 @@ bool NodesHandler::recentlyBecameDistanceZero() { void NodesHandler::setRSSI(const MAC_address& mac, int rssi) { - NodeStruct* matchingNode = getNodeByMac(mac); - if (matchingNode != nullptr) { - matchingNode->setRSSI(rssi); + setRSSI(getNodeByMac(mac), rssi); +} + +void NodesHandler::setRSSI(uint8_t unit, int rssi) +{ + setRSSI(getNode(unit), rssi); +} + +void NodesHandler::setRSSI(NodeStruct * node, int rssi) +{ + if (node != nullptr) { + node->setRSSI(rssi); #ifdef USES_ESPEASY_NOW - auto it = _traceRoutes.find(matchingNode->unit); + auto it = _traceRoutes.find(node->unit); if (it != _traceRoutes.end()) { - it->second.setRSSI_last_node(matchingNode->unit, rssi); + it->second.setRSSI_last_node(node->unit, rssi); } #endif } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index ca413c5cf5..4b6b9a52a0 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -25,6 +25,7 @@ class NodesHandler { bool hasNode(const uint8_t *mac) const; + NodeStruct * getNode(uint8_t unit_nr); const NodeStruct * getNode(uint8_t unit_nr) const; NodeStruct * getNodeByMac(const MAC_address& mac); @@ -73,8 +74,12 @@ class NodesHandler { void setRSSI(const MAC_address& mac, int rssi); + void setRSSI(uint8_t unit, int rssi); + private: + void setRSSI(NodeStruct * node, int rssi); + #ifdef USES_ESPEASY_NOW bool hasTraceRoute(uint8_t unit) const; #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 5da4aef47e..f7f2fe4e36 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -305,17 +305,17 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) auto nodeInfo = Nodes.getNodeByMac(peer_mac); if (nodeInfo != nullptr) { - nodeInfo->setRSSI(WiFi.RSSI(scanIndex)); + Nodes.setRSSI(peer_mac, WiFi.RSSI(scanIndex)); nodeInfo->channel = WiFi.channel(scanIndex); } else { - // FIXME TD-er: For now we assume the other node uses AP for ESPEasy-NOW NodeStruct tmpNodeInfo; tmpNodeInfo.setRSSI(WiFi.RSSI(scanIndex)); tmpNodeInfo.channel = WiFi.channel(scanIndex); peer_mac.get(tmpNodeInfo.ap_mac); - tmpNodeInfo.setESPEasyNow_mac(peer_mac); if (tmpNodeInfo.markedAsPriorityPeer()) { + // FIXME TD-er: For now we assume the other node uses AP for ESPEasy-NOW + tmpNodeInfo.setESPEasyNow_mac(peer_mac); if (Nodes.addNode(tmpNodeInfo)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = String(F(ESPEASY_NOW_NAME)) + F(": Found node via WiFi scan: "); @@ -468,6 +468,11 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m MAC_address mac; message.getMac(mac); + // Check to see if we process a node we've sent ourselves. + if (received.isThisNode()) { + return false; + } + if (!received.setESPEasyNow_mac(mac)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; From 8be53e4aab804c5271efaaa1f14f55cc9b4fad3c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 26 Mar 2021 11:57:43 +0100 Subject: [PATCH 118/404] [ESPEasy-NOW] Make sure to force WiFi reconnect when a known AP is seen --- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 8cbff8f2b0..c4199543b0 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -3,6 +3,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyEth.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" #include "../Globals/Settings.h" #include "../Helpers/StringConverter.h" @@ -40,6 +41,7 @@ void setNetworkMedium(NetworkMedium_t medium) { setSTA(false); break; case NetworkMedium_t::ESPEasyNOW_only: + WiFiEventData.clearAll(); break; case NetworkMedium_t::NotSet: break; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 6369212c2a..fc96fdf39c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -956,6 +956,7 @@ bool wifiAPmodeActivelyUsed() { // Only allow the ESPEasy_NOW_only mode for 10 minutes setNetworkMedium(Settings.NetworkMedium); + return false; } else if (ESPEasy_now_handler.active()) { return true; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index c1d1627417..9c408e015c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -458,6 +458,7 @@ void processScanDone() { WifiDisconnect(); setAP(false); // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + WiFiEventData.wifiConnectAttemptNeeded = true; temp_disable_EspEasy_now_timer = millis() + 10000; } } else { From 490c38cc3ffe6f46d755b929fb03eab84f984b8b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 27 Mar 2021 10:32:07 +0100 Subject: [PATCH 119/404] [ESPEasy-NOW] Set WiFi to 802.11B mode for ESPEasy-NOW-only mode To extend range --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 31 ++++++++++++++++++------- src/src/Helpers/ESPEasy_now_handler.h | 1 + 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index fc96fdf39c..9e79c38191 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -977,7 +977,7 @@ void setConnectionSpeed() { #ifdef ESP8266 #ifdef USES_ESPEASY_NOW if (isESPEasy_now_only()) { - WiFi.setPhyMode(WIFI_PHY_MODE_11G); + WiFi.setPhyMode(WIFI_PHY_MODE_11B); return; } #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f7f2fe4e36..1b7c420616 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -82,13 +82,10 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } - - if (use_EspEasy_now) { - return true; - } + if (use_EspEasy_now) { return true; } _last_used = millis(); - int channel = WiFi.channel(); + _usedWiFiChannel = WiFi.channel(); _controllerIndex = INVALID_CONTROLLER_INDEX; if (isESPEasy_now_only()) { @@ -96,7 +93,7 @@ bool ESPEasy_now_handler_t::begin() } if (!Nodes.isEndpoint()) { - channel = Nodes.getESPEasyNOW_channel(); + _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); } const String ssid = F(ESPEASY_NOW_TMP_SSID); @@ -106,13 +103,13 @@ bool ESPEasy_now_handler_t::begin() int ssid_hidden = 1; int max_connection = 6; - WiFi.softAP(ssid.c_str(), passphrase.c_str(), channel, ssid_hidden, max_connection); + WiFi.softAP(ssid.c_str(), passphrase.c_str(), _usedWiFiChannel, ssid_hidden, max_connection); // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = String(F(ESPEASY_NOW_NAME)) + F(": begin on channel "); - log += channel; + log += _usedWiFiChannel; addLog(LOG_LEVEL_INFO, log); } @@ -147,6 +144,7 @@ bool ESPEasy_now_handler_t::begin() void ESPEasy_now_handler_t::end() { _controllerIndex = INVALID_CONTROLLER_INDEX; + _usedWiFiChannel = 0; use_EspEasy_now = false; ESPEasy_now_in_queue.clear(); RTC.clearLastWiFi(); // Force a WiFi scan @@ -160,6 +158,13 @@ void ESPEasy_now_handler_t::end() bool ESPEasy_now_handler_t::loop() { + if (!WifiIsAP(WiFi.getMode())) { + // AP mode may be turned off externally, and if so restart ESPEasy-now handler + if (use_EspEasy_now) { + end(); + } + } + if (temp_disable_EspEasy_now_timer != 0) { if (timeOutReached(temp_disable_EspEasy_now_timer)) { if (begin()) { @@ -244,6 +249,7 @@ bool ESPEasy_now_handler_t::loop() // WifiScan(false, false); // addPeerFromWiFiScan(); // _last_used = millis(); + end(); begin(); } return somethingProcessed; @@ -517,6 +523,13 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m addLog(LOG_LEVEL_INFO, log); } + const NodeStruct * preferred = Nodes.getPreferredNode(); + if (preferred != nullptr) { + if (preferred->unit == received.unit) { + Nodes.updateThisNode(); + } + } + const uint8_t new_distance = Nodes.getDistance(); if (new_distance != cur_distance || isNewNode) { if (new_distance == 0) { @@ -627,7 +640,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { const NodeStruct *preferred = Nodes.getPreferredNode(); - if (preferred != nullptr && Nodes.getDistance() > preferred->distance) { + if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { switch (_preferredNodeMQTTqueueState.state) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index bfac355fbc..f848df7a04 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -91,6 +91,7 @@ class ESPEasy_now_handler_t { ESPEasy_Now_MQTT_queue_check_packet _preferredNodeMQTTqueueState; unsigned int _ClientTimeout = 0; + uint8_t _usedWiFiChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; bool _enableESPEasyNowFallback = false; bool _mqtt_retainFlag = false; From 4bdf2106bbee97786ff991ebaf416f4758cbe3b6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 29 Mar 2021 15:46:09 +0200 Subject: [PATCH 120/404] [ESPEasy-NOW] Base routing on success rate, not RSSI --- .../ESPEasy_now_Node_statistics.cpp | 99 +++++++++++++++++++ .../DataStructs/ESPEasy_now_Node_statistics.h | 43 ++++++++ src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/DataStructs/ESPEasy_now_splitter.cpp | 2 + .../DataStructs/ESPEasy_now_traceroute.cpp | 97 +++++++++--------- src/src/DataStructs/ESPEasy_now_traceroute.h | 16 +-- src/src/DataStructs/NodesHandler.cpp | 91 ++++++++++++----- src/src/DataStructs/NodesHandler.h | 18 +++- src/src/Helpers/ESPEasy_now_handler.cpp | 92 ++++++++++++++++- src/src/Helpers/ESPEasy_now_handler.h | 5 + src/src/Helpers/Networking.cpp | 7 ++ 11 files changed, 387 insertions(+), 84 deletions(-) create mode 100644 src/src/DataStructs/ESPEasy_now_Node_statistics.cpp create mode 100644 src/src/DataStructs/ESPEasy_now_Node_statistics.h diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp new file mode 100644 index 0000000000..2c3562fc72 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -0,0 +1,99 @@ +#include "../DataStructs/ESPEasy_now_Node_statistics.h" + +#include "../ESPEasyCore/ESPEasy_Log.h" +#include "../Helpers/ESPEasy_time_calc.h" + +unsigned long ESPEasy_now_Node_statistics_t::getAge() const +{ + return timePassedSince(last_update); +} + +void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_traceroute_struct& route) +{ + if (route.getDistance() == 255) { + return; + } + + if (timePassedSince(last_update_route) < 10000) { + // Handling a burst of updates, only add those which have a higher success rate. + if (bestRouteSuccessRate > route.computeSuccessRate()) { + return; + } + } + + ++last_route_index; + + if (last_route_index >= ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES) { + last_route_index = 0; + } + routes[last_route_index] = route; + routes[last_route_index].addUnit(unit); + routes[last_route_index].setSuccessRate_last_node(unit, success_rate); + last_update_route = millis(); + last_update = millis(); + + bestRouteSuccessRate = 0; + + for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { + const int successRate = routes[i].computeSuccessRate(); + + if (successRate > bestRouteSuccessRate) { + bestRouteSuccessRate = successRate; + } + } + + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F(ESPEASY_NOW_NAME); + log += F(": addRoute: "); + log += route.toString(); + addLog(LOG_LEVEL_INFO, log); + } +} + +void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) +{ + if (success) { + if (success_rate < 255) { ++success_rate; } + last_update = millis(); + } else { + if (success_rate > 0) { --success_rate; } + } + + for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { + routes[i].setSuccessRate_last_node(unit, success_rate); + } +} + +ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::latestRoute() +{ + return routes[last_route_index]; +} + +const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::latestRoute() const +{ + return routes[last_route_index]; +} + +const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() const +{ + if (timePassedSince(last_update_route) < 125000) { + int bestIndex = -1; + int bestSuccessRate = -1; + + for (int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { + const int successRate = routes[i].computeSuccessRate(); + + if (successRate > bestSuccessRate) { + bestSuccessRate = successRate; + bestIndex = i; + } + } + + if (bestIndex >= 0) { + return &routes[bestIndex]; + } + } + + return nullptr; +} diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h new file mode 100644 index 0000000000..e55513a2b3 --- /dev/null +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -0,0 +1,43 @@ +#ifndef DATASTRUCTS_ESPEASY_NOW_NODE_STATISTICS_H +#define DATASTRUCTS_ESPEASY_NOW_NODE_STATISTICS_H + +#include "../../ESPEasy_common.h" + +#include "../DataStructs/ESPEasy_now_traceroute.h" + +#include + +#define ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES 2 + +struct ESPEasy_now_Node_statistics_t { + + unsigned long getAge() const; + + void addRoute(byte unit, const ESPEasy_now_traceroute_struct& route); + + void updateSuccessRate(byte unit, bool success); + + ESPEasy_now_traceroute_struct& latestRoute(); + + const ESPEasy_now_traceroute_struct& latestRoute() const; + + const ESPEasy_now_traceroute_struct* bestRoute() const; + + ESPEasy_now_traceroute_struct routes[ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES]; + + unsigned long last_update = 0; + + unsigned long last_update_route = 0; + + int bestRouteSuccessRate = 0; + + uint8_t last_route_index = 0; + + // Increase on success, decrease on fail, with limits of 255 and 0. + uint8_t success_rate = 127; +}; + +typedef std::map ESPEasy_now_Node_statisticsMap; + + +#endif // ifndef DATASTRUCTS_ESPEASY_NOW_NODE_STATISTICS_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 93ea2ffbe4..81bc56e597 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -25,6 +25,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { SendData_DuplicateCheck, MQTTCheckControllerQueue, P2P_data, + TraceRoute, ChecksumError = 255 }; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 4ec8c31107..1b17ad5544 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -155,11 +155,13 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t case WifiEspNowSendStatus::NONE: case WifiEspNowSendStatus::FAIL: { + Nodes.updateSuccessRate(mac, false); STOP_TIMER(ESPEASY_NOW_SEND_MSG_FAIL); return sendStatus; } case WifiEspNowSendStatus::OK: { + Nodes.updateSuccessRate(mac, true); break; } } diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index 8ed59fedfa..7e9e90471b 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -1,43 +1,44 @@ -#include "ESPEasy_now_traceroute.h" +#include "../DataStructs/ESPEasy_now_traceroute.h" #include -ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct() {} +ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct() { +// unit_vector.reserve(32); // prevent re-allocations +} ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct(uint8_t size) { unit_vector.resize(size); } -uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, int8_t& rssi) const +void ESPEasy_now_traceroute_struct::clear() +{ + unit_vector.clear(); +} + +uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, uint8_t& successRate) const { if (unit_vector.size() < static_cast((distance + 1) * 2)) { + successRate = 0; return 0; } - const int temp_rssi = unit_vector[(distance * 2) + 1]; - - rssi = temp_rssi - 127; + successRate = unit_vector[(distance * 2) + 1]; return unit_vector[distance * 2]; } -void ESPEasy_now_traceroute_struct::addUnit(const NodeStruct& node) +void ESPEasy_now_traceroute_struct::addUnit(byte unit) { - if (node.distance == 255) { - // No distance set, so don't add the traceroute. - return; - } - // Only add the unit if it isn't already part of the traceroute. const uint8_t index = unit_vector.size(); for (size_t i = 0; i < index; i+=2) { - if (unit_vector[i] == node.unit) { - unit_vector[i + 1] = static_cast(static_cast(node.getRSSI() + 127)); + if (unit_vector[i] == unit) { return; } } unit_vector.resize(index + 2); - unit_vector[index] = node.unit; - unit_vector[index + 1] = static_cast(static_cast(node.getRSSI() + 127)); + unit_vector[index] = unit; + // Set default success rate to average + unit_vector[index + 1] = 127; } uint8_t ESPEasy_now_traceroute_struct::getDistance() const @@ -60,17 +61,14 @@ uint8_t * ESPEasy_now_traceroute_struct::get() return &(unit_vector[0]); } -void ESPEasy_now_traceroute_struct::setRSSI_last_node(byte unit, int8_t rssi) +void ESPEasy_now_traceroute_struct::setSuccessRate_last_node(byte unit, uint8_t successRate) { - if (rssi > 0) { - rssi = 0; - } int index = unit_vector.size() - 2; int attempt = 0; while (index >= 0 && attempt < 2) { if (unit_vector[index] == unit) { - unit_vector[index + 1] = static_cast(static_cast(rssi + 127)); + unit_vector[index + 1] = successRate; return; } index -= 2; @@ -80,41 +78,48 @@ void ESPEasy_now_traceroute_struct::setRSSI_last_node(byte unit, int8_t rssi) bool ESPEasy_now_traceroute_struct::operator<(const ESPEasy_now_traceroute_struct& other) const { - return compute_penalty() < other.compute_penalty(); + return computeSuccessRate() > other.computeSuccessRate(); } -int ESPEasy_now_traceroute_struct::compute_penalty() const +int ESPEasy_now_traceroute_struct::computeSuccessRate() const { const uint8_t max_distance = getDistance(); - - // FIXME TD-er: for now just base it on the distance, not on the combination of RSSI & distance - return max_distance; -/* if (max_distance == 255) { // No values stored, so huge penalty - return max_distance * 100; + return 0; + } + if (max_distance == 0) { + // End point, so assume best success rate + return 255; } + int res = 0; + for (uint8_t distance = 0; distance <= max_distance; ++distance) { + uint8_t successRate = 0; + getUnit(distance, successRate); + + if (successRate < 10) { + return 0; + } - int penalty = 0; + res += successRate; + } + if (max_distance > 0) { + res /= max_distance; + } + return res; +} +bool ESPEasy_now_traceroute_struct::unitInTraceRoute(byte unit) const +{ + const uint8_t max_distance = getDistance(); for (uint8_t distance = 0; distance <= max_distance; ++distance) { - int8_t rssi = 0; - getUnit(distance, rssi); - - if (rssi >= 0) { - // Some "average" RSSI values for unknown RSSI - rssi = -75; - } else if (rssi < -80) { - // Some extra penalty for low quality signals - rssi -= 10; + uint8_t success_rate = 0; + if (getUnit(distance, success_rate) == unit) { + return true; } - - // RSSI values are negative, with lower value being a worse signal - penalty -= rssi; } - return penalty; - */ + return false; } String ESPEasy_now_traceroute_struct::toString() const @@ -127,10 +132,10 @@ String ESPEasy_now_traceroute_struct::toString() const String res; res.reserve(4*unit_vector.size()); for (uint8_t distance = 0; distance <= max_distance; ++distance) { - int8_t rssi = 0; - res += getUnit(distance, rssi); + uint8_t success_rate = 0; + res += getUnit(distance, success_rate); res += '/'; - res += rssi; + res += success_rate; res += ' '; } return res; diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 852a2c651a..1c69178362 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -15,13 +15,15 @@ struct ESPEasy_now_traceroute_struct ESPEasy_now_traceroute_struct(uint8_t size); + void clear(); + // Return the unit and RSSI given a distance. // @retval 0 when giving invalid distance. uint8_t getUnit(uint8_t distance, - int8_t& rssi) const; + uint8_t& successRate) const; // Append unit at the end (thus furthest distance) - void addUnit(const NodeStruct& node); + void addUnit(byte unit); uint8_t getDistance() const; @@ -31,7 +33,7 @@ struct ESPEasy_now_traceroute_struct // Make sure the array is large enough to store the data. uint8_t* get(); - void setRSSI_last_node(byte unit, int8_t rssi); + void setSuccessRate_last_node(byte unit, uint8_t successRate); // Return true when this traceroute has lower penalty (thus more favorable) bool operator<(const ESPEasy_now_traceroute_struct& other) const; @@ -39,14 +41,16 @@ struct ESPEasy_now_traceroute_struct // For debugging purposes String toString() const; - // Compute penalty. Higher value means less preferred. - int compute_penalty() const; + // Compute success rate + int computeSuccessRate() const; + + bool unitInTraceRoute(byte unit) const; private: // Node with distance 0 at front, so index/2 equals distance. // index%2 == 0 is unit - // index%2 == 1 is RSSI + // index%2 == 1 is SuccessRate std::vectorunit_vector; }; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index a210d330ab..075a6a43d6 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -62,12 +62,10 @@ bool NodesHandler::addNode(const NodeStruct& node) bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute) { const bool isNewNode = addNode(node); - _traceRoutes[node.unit] = traceRoute; - - _traceRoutes[node.unit].addUnit(node); + _nodeStats[node.unit].addRoute(node.unit, traceRoute); if (traceRoute.getDistance() != 255 && !node.isThisNode()) { - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": Node: ") + String(node.unit) + F(" Traceroute received: ") + _traceRoutes[node.unit].toString()); + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": Node: ") + String(node.unit) + F(" Traceroute received: ") + _nodeStats[node.unit].latestRoute().toString()); } return isNewNode; } @@ -176,8 +174,8 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } else { #ifdef USES_ESPEASY_NOW - const int penalty_new = it->second.distance; - const int penalty_res = res->distance; + const int penalty_new = getSuccessRate(it->second.unit); + const int penalty_res = getSuccessRate(res->unit); if (penalty_new < penalty_res) { mustSet = true; @@ -211,12 +209,28 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& #ifdef USES_ESPEASY_NOW const ESPEasy_now_traceroute_struct* NodesHandler::getTraceRoute(uint8_t unit) const { - auto trace_it = _traceRoutes.find(unit); - if (trace_it == _traceRoutes.end()) { + auto trace_it = _nodeStats.find(unit); + if (trace_it == _nodeStats.end()) { return nullptr; } - return &(trace_it->second); + return trace_it->second.bestRoute(); } + +void NodesHandler::setTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute) +{ + if (traceRoute.computeSuccessRate() == 0) { + // No need to store traceroute with low success rate. + return; + } + NodeStruct* node = getNodeByMac(mac); + if (node != nullptr) { + auto trace_it = _nodeStats.find(node->unit); + if (trace_it != _nodeStats.end()) { + trace_it->second.addRoute(node->unit, traceRoute); + } + } +} + #endif @@ -287,8 +301,7 @@ void NodesHandler::updateThisNode() { #ifdef USES_ESPEASY_NOW thisNode.distance = _distance; thisNode.setRSSI(WiFi.RSSI()); - thisTraceRoute.addUnit(thisNode); - thisTraceRoute.setRSSI_last_node(thisNode.unit, WiFi.RSSI()); + thisTraceRoute.addUnit(thisNode.unit); #endif } else { _distance = 255; @@ -299,12 +312,11 @@ void NodesHandler::updateThisNode() { if (!preferred->isExpired()) { const ESPEasy_now_traceroute_struct* tracert_ptr = getTraceRoute(preferred->unit); if (tracert_ptr != nullptr && tracert_ptr->getDistance() < 255) { - // Make a copy of the traceroute + // Make a copy of the traceroute thisTraceRoute = *tracert_ptr; - thisTraceRoute.addUnit(thisNode); - thisTraceRoute.setRSSI_last_node(thisNode.unit, preferred->getRSSI()); + thisTraceRoute.addUnit(thisNode.unit); - _distance = thisTraceRoute.getDistance() + 1; + _distance = thisTraceRoute.getDistance(); // This node is already included in the traceroute. _lastTimeValidDistance = millis(); } if (_distance != lastDistance) { @@ -323,6 +335,10 @@ void NodesHandler::updateThisNode() { #ifdef USES_ESPEASY_NOW addNode(thisNode, thisTraceRoute); + if (thisNode.distance == 0) { + // Since we're the end node, claim highest success rate + updateSuccessRate(thisNode.unit, 255); + } #else addNode(thisNode); #endif @@ -362,9 +378,9 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& if (age > max_age_allowed) { #ifdef USES_ESPEASY_NOW - auto route_it = _traceRoutes.find(it->second.unit); - if (route_it != _traceRoutes.end()) { - _traceRoutes.erase(route_it); + auto route_it = _nodeStats.find(it->second.unit); + if (route_it != _nodeStats.end()) { + _nodeStats.erase(route_it); } #endif it = _nodes.erase(it); @@ -429,12 +445,6 @@ void NodesHandler::setRSSI(NodeStruct * node, int rssi) { if (node != nullptr) { node->setRSSI(rssi); - #ifdef USES_ESPEASY_NOW - auto it = _traceRoutes.find(node->unit); - if (it != _traceRoutes.end()) { - it->second.setRSSI_last_node(node->unit, rssi); - } - #endif } } @@ -447,6 +457,37 @@ bool NodesHandler::lastTimeValidDistanceExpired() const #ifdef USES_ESPEASY_NOW bool NodesHandler::hasTraceRoute(uint8_t unit) const { - return _traceRoutes.find(unit) != _traceRoutes.end(); + return _nodeStats.find(unit) != _nodeStats.end(); +} + +void NodesHandler::updateSuccessRate(byte unit, bool success) +{ + auto it = _nodeStats.find(unit); + if (it != _nodeStats.end()) { + it->second.updateSuccessRate(unit, success); + } +} + +void NodesHandler::updateSuccessRate(const MAC_address& mac, bool success) +{ + const NodeStruct * node = getNodeByMac(mac); + if (node == nullptr) { + return; + } + updateSuccessRate(node->unit, success); +} + +int NodesHandler::getSuccessRate(byte unit) const +{ + auto it = _nodeStats.find(unit); + if (it != _nodeStats.end()) { + const ESPEasy_now_traceroute_struct* route = it->second.bestRoute(); + if (route != nullptr) { + return route->computeSuccessRate(); + } + } + return 0; } + + #endif diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 4b6b9a52a0..d93fc2585b 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -1,12 +1,13 @@ #ifndef DATASTRUCTS_NODESHANDLER_H #define DATASTRUCTS_NODESHANDLER_H -#include "NodeStruct.h" +#include "../DataStructs/NodeStruct.h" -#include "MAC_address.h" +#include "../DataStructs/MAC_address.h" #ifdef USES_ESPEASY_NOW -#include "ESPEasy_now_traceroute.h" +#include "../DataStructs/ESPEasy_now_traceroute.h" +#include "../DataStructs/ESPEasy_now_Node_statistics.h" #endif class NodesHandler { @@ -49,6 +50,8 @@ class NodesHandler { #ifdef USES_ESPEASY_NOW const ESPEasy_now_traceroute_struct* getTraceRoute(uint8_t unit) const; + + void setTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute); #endif // Update the node referring to this unit with the most recent info. @@ -76,6 +79,13 @@ class NodesHandler { void setRSSI(uint8_t unit, int rssi); +#ifdef USES_ESPEASY_NOW + void updateSuccessRate(byte unit, bool success); + void updateSuccessRate(const MAC_address& mac, bool success); + + int getSuccessRate(byte unit) const; +#endif + private: void setRSSI(NodeStruct * node, int rssi); @@ -91,7 +101,7 @@ class NodesHandler { NodesMap _nodes; #ifdef USES_ESPEASY_NOW - TraceRouteMap _traceRoutes; + ESPEasy_now_Node_statisticsMap _nodeStats; #endif bool _recentlyBecameDistanceZero = false; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 1b7c420616..8c7b24dc6e 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -342,14 +342,25 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { + bool handled = false; + bool considerActive = false; + mustKeep = false; + + { + // Check if message is sent by this node + MAC_address receivedMAC; + message.getMac(receivedMAC.mac); + MAC_address tmp; + WiFi.softAPmacAddress(tmp.mac); + if (tmp == receivedMAC) return handled; + WiFi.macAddress(tmp.mac); + if (tmp == receivedMAC) return handled; + } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = String(F(ESPEASY_NOW_NAME)) + F(": received "); log += message.getLogString(); addLog(LOG_LEVEL_INFO, log); } - bool handled = false; - mustKeep = true; - bool considerActive = false; switch (message.getMessageType()) { @@ -379,6 +390,10 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo handled = handle_ESPEasyNow_p2p(message, mustKeep); considerActive = true; break; + case ESPEasy_now_hdr::message_t::TraceRoute: + handled = handle_TraceRoute(message, mustKeep); + considerActive = true; + break; } if (handled && considerActive) { @@ -456,6 +471,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch // WifiScan(true, channel); } + bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep) { mustKeep = false; @@ -543,6 +559,75 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m return true; } + +// ************************************************************* +// * Trace Route +// ************************************************************* +void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel) +{ + MAC_address broadcast; + for (int i = 0; i < 6; ++i) { + broadcast.mac[i] = 0xFF; + } + + size_t len = 1; + uint8_t traceroute_size = 0; + const uint8_t* traceroute_data = traceRoute.getData(traceroute_size); + len += traceroute_size; + + ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::TraceRoute, len); + if (sizeof(uint8_t) != msg.addBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t))) { + return; + } + if (traceroute_size != msg.addBinaryData(traceroute_data, traceroute_size)) { + return; + } + if (channel < 0) { + // Send to all channels + + const unsigned long start = millis(); + + // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. + for (int ch = 1; ch < 11; ++ch) { + msg.send(broadcast, ch); + delay(0); + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = String(F(ESPEASY_NOW_NAME)) + F(": Sent Traceroute to all channels in "); + log += String(timePassedSince(start)); + log += F(" ms"); + addLog(LOG_LEVEL_INFO, log); + } + } else { + msg.send(broadcast, channel); + } +} + +bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, bool& mustKeep) +{ + size_t payload_pos = 0; + uint8_t traceroute_size = 0; + if (message.getBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t), payload_pos) != 0) { + if (traceroute_size != 0) { + ESPEasy_now_traceroute_struct traceroute(traceroute_size); + if (message.getBinaryData(traceroute.get(), traceroute_size, payload_pos) == traceroute_size) { + const uint8_t thisunit = Settings.Unit; + if (!traceroute.unitInTraceRoute(thisunit)) { + MAC_address mac; + message.getMac(mac); + Nodes.setTraceRoute(mac, traceroute); + if (thisunit != 0 && thisunit != 255) { + traceroute.addUnit(thisunit); + sendTraceRoute(traceroute); + } + } + } + } + } + mustKeep = false; + return true; +} + // ************************************************************* // * NTP Query // ************************************************************* @@ -679,6 +764,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const case WifiEspNowSendStatus::NONE: case WifiEspNowSendStatus::FAIL: { + _preferredNodeMQTTqueueState.state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; ++_send_failed_count; break; } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index f848df7a04..f346ef5375 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -12,6 +12,7 @@ # include "../DataStructs/ESPEasy_Now_NTP_query.h" # include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" # include "../DataStructs/ESPEasy_Now_p2p_data.h" +# include "../DataStructs/ESPEasy_now_traceroute.h" # include "../DataStructs/MAC_address.h" # include "../Globals/CPlugins.h" @@ -45,6 +46,8 @@ class ESPEasy_now_handler_t { void sendDiscoveryAnnounce(int channel = 0); void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); + void sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); + void sendNTPquery(); void sendNTPbroadcast(); @@ -68,6 +71,8 @@ class ESPEasy_now_handler_t { bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_TraceRoute(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_NTPquery(const ESPEasy_now_merger& message, bool& mustKeep); bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message, bool& mustKeep); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index f3078755bb..378353d37a 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -419,6 +419,13 @@ void refreshNodeList() ESPEasy_now_handler.sendDiscoveryAnnounce(); } ESPEasy_now_handler.sendNTPquery(); + if (Nodes.getDistance() == 0) { + ESPEasy_now_traceroute_struct thisTraceRoute; + thisTraceRoute.addUnit(Settings.Unit); + // Since we're the end node, claim highest success rate + thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); + ESPEasy_now_handler.sendTraceRoute(thisTraceRoute); + } #endif // ifdef USES_ESPEASY_NOW } From bdc93ac0305b6552f53c7b73c61a591f3966ed47 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 30 Mar 2021 17:38:21 +0200 Subject: [PATCH 121/404] [ESPEasy-NOW] Let traceroutes expire & only route on traceroutes Routes advertised in "discovery" packets are of no use for routing. But they are useful for showing the nodes state on the root page of the web UI. So the routes received via traceroute are now used for routing and those received via discovery packets are used for viewing/debugging purposes only. A traceroute will be valued on the quality of the hops and the number of hops. --- src/ESPEasy.ino | 2 +- .../ESPEasy_now_Node_statistics.cpp | 43 +++++++++++-------- .../DataStructs/ESPEasy_now_Node_statistics.h | 20 ++++++--- .../DataStructs/ESPEasy_now_traceroute.cpp | 2 +- src/src/DataStructs/NodesHandler.cpp | 15 ++++++- src/src/DataStructs/NodesHandler.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 23 +++++----- src/src/Helpers/PeriodicalActions.cpp | 6 +++ src/src/WebServer/RootPage.cpp | 2 +- 9 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 052c191b2c..b401515669 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -489,7 +489,7 @@ void setup() Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_1SEC, 777); // timer for periodic actions once per/sec Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_30SEC, 1333); // timer for watchdog once per 30 sec Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 88); // timer for interaction with MQTT - Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_STATISTICS, 2222); + Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_STATISTICS, 0); } #ifdef USE_RTOS_MULTITASKING diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 2c3562fc72..2cfbbc1153 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -13,10 +13,9 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer if (route.getDistance() == 255) { return; } - - if (timePassedSince(last_update_route) < 10000) { + if (timePassedSince(last_update_route[last_route_index]) < 10000) { // Handling a burst of updates, only add those which have a higher success rate. - if (bestRouteSuccessRate > route.computeSuccessRate()) { + if (routes[last_route_index].computeSuccessRate() > route.computeSuccessRate()) { return; } } @@ -29,20 +28,9 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer routes[last_route_index] = route; routes[last_route_index].addUnit(unit); routes[last_route_index].setSuccessRate_last_node(unit, success_rate); - last_update_route = millis(); + last_update_route[last_route_index] = millis(); last_update = millis(); - bestRouteSuccessRate = 0; - - for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - const int successRate = routes[i].computeSuccessRate(); - - if (successRate > bestRouteSuccessRate) { - bestRouteSuccessRate = successRate; - } - } - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F(ESPEASY_NOW_NAME); log += F(": addRoute: "); @@ -51,6 +39,13 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer } } +void ESPEasy_now_Node_statistics_t::setDiscoveryRoute(byte unit, const ESPEasy_now_traceroute_struct& route) +{ + discovery_route = route; + discovery_route.addUnit(unit); + discovery_route.setSuccessRate_last_node(unit, success_rate); +} + void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) { if (success) { @@ -61,7 +56,12 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) } for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - routes[i].setSuccessRate_last_node(unit, success_rate); + if (timePassedSince(last_update_route[i]) > 125000) { + last_update_route[i] = 0; + routes[i].clear(); + } else { + routes[i].setSuccessRate_last_node(unit, success_rate); + } } } @@ -77,9 +77,9 @@ const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::latestRoute( const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() const { - if (timePassedSince(last_update_route) < 125000) { +// if (timePassedSince(last_update_route[last_route_index]) < 125000) { int bestIndex = -1; - int bestSuccessRate = -1; + int bestSuccessRate = 0; for (int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { const int successRate = routes[i].computeSuccessRate(); @@ -93,7 +93,12 @@ const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() if (bestIndex >= 0) { return &routes[bestIndex]; } - } +// } return nullptr; } + +const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::discoveryRoute() const +{ + return discovery_route; +} \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index e55513a2b3..8645bc7d10 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -7,29 +7,35 @@ #include -#define ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES 2 +#define ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES 3 struct ESPEasy_now_Node_statistics_t { - unsigned long getAge() const; + // Store route received via traceroute packet void addRoute(byte unit, const ESPEasy_now_traceroute_struct& route); + // Store route received via Discovery packet + void setDiscoveryRoute(byte unit, const ESPEasy_now_traceroute_struct& route); + void updateSuccessRate(byte unit, bool success); - ESPEasy_now_traceroute_struct& latestRoute(); + ESPEasy_now_traceroute_struct & latestRoute(); const ESPEasy_now_traceroute_struct& latestRoute() const; const ESPEasy_now_traceroute_struct* bestRoute() const; - ESPEasy_now_traceroute_struct routes[ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES]; + const ESPEasy_now_traceroute_struct& discoveryRoute() const; - unsigned long last_update = 0; +private: - unsigned long last_update_route = 0; + ESPEasy_now_traceroute_struct discovery_route; + ESPEasy_now_traceroute_struct routes[ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES]; + + unsigned long last_update_route[ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES] = { 0 }; - int bestRouteSuccessRate = 0; + unsigned long last_update = 0; uint8_t last_route_index = 0; diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index 7e9e90471b..fc166d3217 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -102,7 +102,7 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const return 0; } - res += successRate; + res += (successRate / (distance + 1)); } if (max_distance > 0) { res /= max_distance; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 075a6a43d6..32712a2c8e 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -62,7 +62,7 @@ bool NodesHandler::addNode(const NodeStruct& node) bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute) { const bool isNewNode = addNode(node); - _nodeStats[node.unit].addRoute(node.unit, traceRoute); + _nodeStats[node.unit].setDiscoveryRoute(node.unit, traceRoute); if (traceRoute.getDistance() != 255 && !node.isThisNode()) { addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": Node: ") + String(node.unit) + F(" Traceroute received: ") + _nodeStats[node.unit].latestRoute().toString()); @@ -179,7 +179,7 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& if (penalty_new < penalty_res) { mustSet = true; - } else if (penalty_new == penalty_res) { + } else { if (res->getAge() > 30000) { if (it->second.getAge() < res->getAge()) { mustSet = true; @@ -216,6 +216,15 @@ const ESPEasy_now_traceroute_struct* NodesHandler::getTraceRoute(uint8_t unit) c return trace_it->second.bestRoute(); } +const ESPEasy_now_traceroute_struct* NodesHandler::getDiscoveryRoute(uint8_t unit) const +{ + auto trace_it = _nodeStats.find(unit); + if (trace_it == _nodeStats.end()) { + return nullptr; + } + return &(trace_it->second.discoveryRoute()); +} + void NodesHandler::setTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute) { if (traceRoute.computeSuccessRate() == 0) { @@ -319,6 +328,7 @@ void NodesHandler::updateThisNode() { _distance = thisTraceRoute.getDistance(); // This node is already included in the traceroute. _lastTimeValidDistance = millis(); } +/* if (_distance != lastDistance) { if (isESPEasy_now_only() && WiFiConnected()) { // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP @@ -327,6 +337,7 @@ void NodesHandler::updateThisNode() { WifiDisconnect(); } } + */ } } #endif diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index d93fc2585b..d8a27f7ad9 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -50,6 +50,7 @@ class NodesHandler { #ifdef USES_ESPEASY_NOW const ESPEasy_now_traceroute_struct* getTraceRoute(uint8_t unit) const; + const ESPEasy_now_traceroute_struct* getDiscoveryRoute(uint8_t unit) const; void setTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute); #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 8c7b24dc6e..f2b1d95651 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -427,7 +427,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch } // Append traceroute (if available) - const ESPEasy_now_traceroute_struct* thisTraceRoute = Nodes.getTraceRoute(thisNode->unit); + const ESPEasy_now_traceroute_struct* thisTraceRoute = Nodes.getDiscoveryRoute(thisNode->unit); size_t len = sizeof(NodeStruct) + 1; // Append length indicator for traceroute uint8_t traceroute_size = 0; @@ -605,26 +605,29 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, bool& mustKeep) { + mustKeep = false; size_t payload_pos = 0; uint8_t traceroute_size = 0; if (message.getBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t), payload_pos) != 0) { if (traceroute_size != 0) { ESPEasy_now_traceroute_struct traceroute(traceroute_size); if (message.getBinaryData(traceroute.get(), traceroute_size, payload_pos) == traceroute_size) { - const uint8_t thisunit = Settings.Unit; - if (!traceroute.unitInTraceRoute(thisunit)) { - MAC_address mac; - message.getMac(mac); - Nodes.setTraceRoute(mac, traceroute); - if (thisunit != 0 && thisunit != 255) { - traceroute.addUnit(thisunit); - sendTraceRoute(traceroute); + if (traceroute.getDistance() < 255) { + const uint8_t thisunit = Settings.Unit; + if (!traceroute.unitInTraceRoute(thisunit)) { + MAC_address mac; + message.getMac(mac); + Nodes.setTraceRoute(mac, traceroute); + if (thisunit != 0 && thisunit != 255 && !Nodes.isEndpoint()) { + // Do not forward the trace route if we're an endpoint. + traceroute.addUnit(thisunit); + sendTraceRoute(traceroute); + } } } } } } - mustKeep = false; return true; } diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index d4e300fe41..c6641f6cfc 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -463,6 +463,12 @@ controllerIndex_t firstEnabledMQTT_ControllerIndex() { void logTimerStatistics() { + static bool firstRun = true; + if (firstRun) { + Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_STATISTICS, 1000); + firstRun = false; + } + byte loglevel = LOG_LEVEL_DEBUG; updateLoopStats_30sec(loglevel); #ifndef BUILD_NO_DEBUG diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 957ef7a599..eac6d3b595 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -299,7 +299,7 @@ void handle_root() { addHtml(String(rssi)); } addHtml(')'); - const ESPEasy_now_traceroute_struct* trace = Nodes.getTraceRoute(it->second.unit); + const ESPEasy_now_traceroute_struct* trace = Nodes.getDiscoveryRoute(it->second.unit); if (trace != nullptr) { addHtml(' '); addHtml(trace->toString()); From 11b1966fb611d13517498452f3dbfca993fb2cfd Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 30 Mar 2021 21:34:51 +0200 Subject: [PATCH 122/404] [ESPEasy-NOW] Queue traceroute packets to not jam other messages With several nodes close by the traceroute replies will be sent at the same time, corrupting other trace route messages. --- src/ESPEasy.ino | 2 +- .../DataStructs/ESPEasy_now_Node_statistics.cpp | 5 +++++ src/src/DataStructs/ESPEasy_now_Node_statistics.h | 2 ++ src/src/DataStructs/ESPEasy_now_traceroute.cpp | 6 ++++-- src/src/DataStructs/NodesHandler.cpp | 14 +++++++++++--- src/src/DataStructs/NodesHandler.h | 4 +++- src/src/Helpers/ESPEasy_now_handler.cpp | 10 +++++++++- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index b401515669..a0c2d5c87e 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -489,7 +489,7 @@ void setup() Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_1SEC, 777); // timer for periodic actions once per/sec Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_30SEC, 1333); // timer for watchdog once per 30 sec Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 88); // timer for interaction with MQTT - Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_STATISTICS, 0); + Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_STATISTICS, 2000); } #ifdef USE_RTOS_MULTITASKING diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 2cfbbc1153..af65e57baa 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -65,6 +65,11 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) } } +uint8_t ESPEasy_now_Node_statistics_t::getNodeSuccessRate() const +{ + return success_rate; +} + ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::latestRoute() { return routes[last_route_index]; diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index 8645bc7d10..8e13ed0fd6 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -20,6 +20,8 @@ struct ESPEasy_now_Node_statistics_t { void updateSuccessRate(byte unit, bool success); + uint8_t getNodeSuccessRate() const; + ESPEasy_now_traceroute_struct & latestRoute(); const ESPEasy_now_traceroute_struct& latestRoute() const; diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index fc166d3217..5e48f482c6 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -98,15 +98,17 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const uint8_t successRate = 0; getUnit(distance, successRate); - if (successRate < 10) { + if (successRate < 50) { return 0; } - res += (successRate / (distance + 1)); + res += successRate; } if (max_distance > 0) { res /= max_distance; } + res -= 10* max_distance; + if (res < 0) res = 0; return res; } diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 32712a2c8e..863ef80799 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -174,8 +174,8 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } else { #ifdef USES_ESPEASY_NOW - const int penalty_new = getSuccessRate(it->second.unit); - const int penalty_res = getSuccessRate(res->unit); + const int penalty_new = getRouteSuccessRate(it->second.unit); + const int penalty_res = getRouteSuccessRate(res->unit); if (penalty_new < penalty_res) { mustSet = true; @@ -488,7 +488,7 @@ void NodesHandler::updateSuccessRate(const MAC_address& mac, bool success) updateSuccessRate(node->unit, success); } -int NodesHandler::getSuccessRate(byte unit) const +int NodesHandler::getRouteSuccessRate(byte unit) const { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { @@ -500,5 +500,13 @@ int NodesHandler::getSuccessRate(byte unit) const return 0; } +uint8_t NodesHandler::getSuccessRate(byte unit) const +{ + auto it = _nodeStats.find(unit); + if (it != _nodeStats.end()) { + return it->second.getNodeSuccessRate(); + } + return 127; +} #endif diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index d8a27f7ad9..5bb21dfc91 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -84,7 +84,9 @@ class NodesHandler { void updateSuccessRate(byte unit, bool success); void updateSuccessRate(const MAC_address& mac, bool success); - int getSuccessRate(byte unit) const; + int getRouteSuccessRate(byte unit) const; + + uint8_t getSuccessRate(byte unit) const; #endif private: diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f2b1d95651..160bc00528 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -52,6 +52,8 @@ static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr std::map ESPEasy_now_in_queue; +std::list ESPEasy_now_traceroute_queue; + void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; size_t payload_length = count - sizeof(ESPEasy_now_hdr); @@ -241,6 +243,11 @@ bool ESPEasy_now_handler_t::loop() } } + if (!ESPEasy_now_traceroute_queue.empty()) { + sendTraceRoute(ESPEasy_now_traceroute_queue.front()); + ESPEasy_now_traceroute_queue.pop_front(); + } + if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; // FIXME TD-er: Must check/mark so this becomes true: isESPEasy_now_only() @@ -621,7 +628,8 @@ bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, if (thisunit != 0 && thisunit != 255 && !Nodes.isEndpoint()) { // Do not forward the trace route if we're an endpoint. traceroute.addUnit(thisunit); - sendTraceRoute(traceroute); + traceroute.setSuccessRate_last_node(thisunit, Nodes.getSuccessRate(thisunit)); + ESPEasy_now_traceroute_queue.push_back(traceroute); } } } From 6a1f4e7bea01eac4e872fcac4c2e317402edceeb Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 1 Apr 2021 19:32:53 +0200 Subject: [PATCH 123/404] [ESPEasy-NOW] Fix selecting best route + resend missed broadcast Announce packets and traceroute is being sent via broadcasts. However a node may miss a broadcast message. If a known node is not seen for a while, it is addressed directly for receiving an announce or traceroute packet thus improving stability of longer mesh trails. --- .../ESPEasy_now_Node_statistics.cpp | 23 ++++++++++++++----- .../DataStructs/ESPEasy_now_traceroute.cpp | 14 +++++++---- src/src/DataStructs/ESPEasy_now_traceroute.h | 2 +- src/src/DataStructs/MAC_address.cpp | 10 ++++++++ src/src/DataStructs/MAC_address.h | 2 ++ src/src/DataStructs/NodesHandler.cpp | 22 ++++++++++-------- src/src/DataStructs/NodesHandler.h | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 23 +++++++++++++++++-- src/src/Helpers/ESPEasy_now_handler.h | 1 + 9 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index af65e57baa..a853636805 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -13,9 +13,9 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer if (route.getDistance() == 255) { return; } - if (timePassedSince(last_update_route[last_route_index]) < 10000) { + if (timePassedSince(last_update_route[last_route_index]) < 1000) { // Handling a burst of updates, only add those which have a higher success rate. - if (routes[last_route_index].computeSuccessRate() > route.computeSuccessRate()) { + if (routes[last_route_index] < route) { return; } } @@ -49,7 +49,10 @@ void ESPEasy_now_Node_statistics_t::setDiscoveryRoute(byte unit, const ESPEasy_n void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) { if (success) { - if (success_rate < 255) { ++success_rate; } + if (timePassedSince(last_update) < 200) { + // Apply some rate limiter. + if (success_rate > 100) { --success_rate; } + } else if (success_rate < 255) { ++success_rate; } last_update = millis(); } else { if (success_rate > 0) { --success_rate; } @@ -63,6 +66,7 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) routes[i].setSuccessRate_last_node(unit, success_rate); } } + discovery_route.setSuccessRate_last_node(unit, success_rate); } uint8_t ESPEasy_now_Node_statistics_t::getNodeSuccessRate() const @@ -85,13 +89,20 @@ const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() // if (timePassedSince(last_update_route[last_route_index]) < 125000) { int bestIndex = -1; int bestSuccessRate = 0; + uint8_t bestDistance = 255; for (int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { + const uint8_t distance = routes[i].getDistance(); const int successRate = routes[i].computeSuccessRate(); - - if (successRate > bestSuccessRate) { + if (distance == bestDistance) { + if (successRate > bestSuccessRate) { + bestSuccessRate = successRate; + bestIndex = i; + } + } else if (distance < bestDistance) { + bestIndex = i; + bestDistance = distance; bestSuccessRate = successRate; - bestIndex = i; } } diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index 5e48f482c6..f6e6ee2ecf 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -78,9 +78,13 @@ void ESPEasy_now_traceroute_struct::setSuccessRate_last_node(byte unit, uint8_t bool ESPEasy_now_traceroute_struct::operator<(const ESPEasy_now_traceroute_struct& other) const { - return computeSuccessRate() > other.computeSuccessRate(); + if (getDistance() == other.getDistance()) { + return computeSuccessRate() > other.computeSuccessRate(); + } + return getDistance() < other.getDistance(); } + int ESPEasy_now_traceroute_struct::computeSuccessRate() const { const uint8_t max_distance = getDistance(); @@ -98,7 +102,7 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const uint8_t successRate = 0; getUnit(distance, successRate); - if (successRate < 50) { + if (successRate < 50 && distance < max_distance) { return 0; } @@ -107,8 +111,10 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const if (max_distance > 0) { res /= max_distance; } - res -= 10* max_distance; - if (res < 0) res = 0; + /* + res -= 10 * max_distance; + if (res < 50) res = 50; + */ return res; } diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 1c69178362..e8e48f03b2 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -35,7 +35,7 @@ struct ESPEasy_now_traceroute_struct void setSuccessRate_last_node(byte unit, uint8_t successRate); - // Return true when this traceroute has lower penalty (thus more favorable) + // Return true when this tracerouteis more favorable bool operator<(const ESPEasy_now_traceroute_struct& other) const; // For debugging purposes diff --git a/src/src/DataStructs/MAC_address.cpp b/src/src/DataStructs/MAC_address.cpp index 85659fb99b..e9fd0f4cb9 100644 --- a/src/src/DataStructs/MAC_address.cpp +++ b/src/src/DataStructs/MAC_address.cpp @@ -45,6 +45,16 @@ bool MAC_address::all_zero() const return true; } +bool MAC_address::all_one() const +{ + for (int i = 0; i < 6; ++i) { + if (mac[i] != 0xFF) { + return false; + } + } + return true; +} + String MAC_address::toString() const { char str[20] = { 0 }; diff --git a/src/src/DataStructs/MAC_address.h b/src/src/DataStructs/MAC_address.h index e05533cc3f..847d54b628 100644 --- a/src/src/DataStructs/MAC_address.h +++ b/src/src/DataStructs/MAC_address.h @@ -37,6 +37,8 @@ class __attribute__((__packed__)) MAC_address { bool all_zero() const; + bool all_one() const; + String toString() const; void toString(char (& strMAC)[20]) const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 863ef80799..8224d8095f 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -174,17 +174,17 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } else { #ifdef USES_ESPEASY_NOW - const int penalty_new = getRouteSuccessRate(it->second.unit); - const int penalty_res = getRouteSuccessRate(res->unit); + uint8_t distance_new, distance_res = 0; - if (penalty_new < penalty_res) { - mustSet = true; - } else { - if (res->getAge() > 30000) { - if (it->second.getAge() < res->getAge()) { - mustSet = true; - } + const int successRate_new = getRouteSuccessRate(it->second.unit, distance_new); + const int successRate_res = getRouteSuccessRate(res->unit, distance_res); + + if (distance_new == distance_res) { + if (successRate_new > successRate_res) { + mustSet = true; } + } else if (distance_new < distance_res) { + mustSet = true; } #else if (it->second < *res) { @@ -488,12 +488,14 @@ void NodesHandler::updateSuccessRate(const MAC_address& mac, bool success) updateSuccessRate(node->unit, success); } -int NodesHandler::getRouteSuccessRate(byte unit) const +int NodesHandler::getRouteSuccessRate(byte unit, uint8_t& distance) const { + distance = 255; auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { const ESPEasy_now_traceroute_struct* route = it->second.bestRoute(); if (route != nullptr) { + distance = route->getDistance(); return route->computeSuccessRate(); } } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 5bb21dfc91..6f65248030 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -84,7 +84,7 @@ class NodesHandler { void updateSuccessRate(byte unit, bool success); void updateSuccessRate(const MAC_address& mac, bool success); - int getRouteSuccessRate(byte unit) const; + int getRouteSuccessRate(byte unit, uint8_t& distance) const; uint8_t getSuccessRate(byte unit) const; #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 160bc00528..1c612d6361 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -473,6 +473,14 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch addLog(LOG_LEVEL_INFO, log); } } else { + if (mac.all_one()) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { + if (it->second.getAge() > 65000) { + msg.send(it->second.ESPEasy_Now_MAC(), channel); + } + } + } + msg.send(mac, channel); } // WifiScan(true, channel); @@ -572,11 +580,22 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m // ************************************************************* void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { + if (it->second.getAge() > 65000) { + sendTraceRoute(it->second.ESPEasy_Now_MAC(), traceRoute, channel); + } + } + MAC_address broadcast; for (int i = 0; i < 6; ++i) { broadcast.mac[i] = 0xFF; } + sendTraceRoute(broadcast, traceRoute, channel); +} + +void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute, int channel) +{ size_t len = 1; uint8_t traceroute_size = 0; const uint8_t* traceroute_data = traceRoute.getData(traceroute_size); @@ -596,7 +615,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. for (int ch = 1; ch < 11; ++ch) { - msg.send(broadcast, ch); + msg.send(mac, ch); delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -606,7 +625,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& addLog(LOG_LEVEL_INFO, log); } } else { - msg.send(broadcast, channel); + msg.send(mac, channel); } } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index f346ef5375..b1ac620012 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -47,6 +47,7 @@ class ESPEasy_now_handler_t { void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); void sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); + void sendTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); void sendNTPquery(); From 6de1f51e23bf02acacae58f0a9df02f8e34de28f Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 5 Apr 2021 23:15:34 +0200 Subject: [PATCH 124/404] [ESPEasy-NOW] Allow to let WiFi reconnect when in range again. --- .../ESPEasy_now_Node_statistics.cpp | 2 +- src/src/DataStructs/NodeStruct.cpp | 2 +- src/src/DataStructs/NodesHandler.cpp | 20 ++++++++++--------- src/src/Helpers/ESPEasy_now_handler.cpp | 15 ++++++++++---- src/src/Helpers/ESPEasy_now_handler.h | 1 + 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index a853636805..b5bae78aa2 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -5,7 +5,7 @@ unsigned long ESPEasy_now_Node_statistics_t::getAge() const { - return timePassedSince(last_update); + return timePassedSince(last_update_route[last_route_index]); } void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_traceroute_struct& route) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index c3aff336c0..6b79cca028 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -5,7 +5,7 @@ #include "../Globals/Settings.h" #include "../Helpers/ESPEasy_time_calc.h" -#define NODE_STRUCT_AGE_TIMEOUT 120000 // 2 minutes +#define NODE_STRUCT_AGE_TIMEOUT 300000 // 5 minutes NodeStruct::NodeStruct() : ESPEasyNowPeer(0), useAP_ESPEasyNow(0), scaled_rssi(0) {} diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 8224d8095f..6366d76361 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -235,6 +235,7 @@ void NodesHandler::setTraceRoute(const MAC_address& mac, const ESPEasy_now_trace if (node != nullptr) { auto trace_it = _nodeStats.find(node->unit); if (trace_it != _nodeStats.end()) { + _lastTimeValidDistance = millis(); trace_it->second.addRoute(node->unit, traceRoute); } } @@ -326,7 +327,6 @@ void NodesHandler::updateThisNode() { thisTraceRoute.addUnit(thisNode.unit); _distance = thisTraceRoute.getDistance(); // This node is already included in the traceroute. - _lastTimeValidDistance = millis(); } /* if (_distance != lastDistance) { @@ -382,20 +382,22 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& for (auto it = _nodes.begin(); it != _nodes.end();) { unsigned long age = it->second.getAge(); - if (it->second.ESPEasyNowPeer) { - // ESPEasy-NOW peers should see updates every 30 seconds. - if (age > 125000) age = max_age_allowed + 1; - } - if (age > max_age_allowed) { + bool mustErase = true; #ifdef USES_ESPEASY_NOW auto route_it = _nodeStats.find(it->second.unit); if (route_it != _nodeStats.end()) { - _nodeStats.erase(route_it); + if (route_it->second.getAge() > max_age_allowed) { + _nodeStats.erase(route_it); + } else { + mustErase = false; + } } #endif - it = _nodes.erase(it); - nodeRemoved = true; + if (mustErase) { + it = _nodes.erase(it); + nodeRemoved = true; + } } else { ++it; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 1c612d6361..b1dc169fe2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -31,7 +31,8 @@ # include -# define ESPEASY_NOW_ACTIVITY_TIMEOUT 120000 // 2 minutes +# define ESPEASY_NOW_ACTIVITY_TIMEOUT 125000 // 2 minutes + 5 sec +# define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" @@ -87,6 +88,7 @@ bool ESPEasy_now_handler_t::begin() if (use_EspEasy_now) { return true; } _last_used = millis(); + _last_started = millis(); _usedWiFiChannel = WiFi.channel(); _controllerIndex = INVALID_CONTROLLER_INDEX; @@ -154,6 +156,7 @@ void ESPEasy_now_handler_t::end() // Only call WifiEspNow.end() if it was started. WifiEspNow.end(); _last_used = 0; + _last_started = 0; } addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" disabled")); } @@ -268,9 +271,13 @@ bool ESPEasy_now_handler_t::active() const return false; } - if (_last_used == 0) { + if (_last_started == 0) { return false; } + if (timePassedSince(_last_started) < ESPEASY_NOW_SINCE_LAST_BROADCAST) { + // Give the unit some time to find other nodes. + return true; + } if (Nodes.lastTimeValidDistanceExpired()) { return false; } @@ -475,7 +482,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch } else { if (mac.all_one()) { for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.getAge() > 65000) { + if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { msg.send(it->second.ESPEasy_Now_MAC(), channel); } } @@ -581,7 +588,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel) { for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.getAge() > 65000) { + if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { sendTraceRoute(it->second.ESPEasy_Now_MAC(), traceRoute, channel); } } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index b1ac620012..b047ce7e4f 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -91,6 +91,7 @@ class ESPEasy_now_handler_t { ESPEasy_Now_NTP_query _best_NTP_candidate; unsigned long _last_used = 0; + unsigned long _last_started = 0; uint8_t _send_failed_count = 0; From 854dcd83afa4fd357cd12e85a51fbf4c6ff91b49 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Apr 2021 13:03:55 +0200 Subject: [PATCH 125/404] [ESPEasy-NOW] Add peer manager to help broadcast packets succeed ESP-now does send broadcast packets to known peers (and those that still may receive it). This makes broadcast packets much more reliable when the intended recipient is a known peer. However we only have a limited number of peer slots (depending on whether or not an encryption key is used), so we must keep track of 'popular' nodes to keep those active as peer. --- src/src/DataStructs/ESPEasy_now_splitter.cpp | 58 ++------------ src/src/DataStructs/ESPEasy_now_splitter.h | 2 - src/src/ESPEasyCore/ESPEasyWifi.cpp | 7 +- src/src/Globals/ESPEasy_now_peermanager.cpp | 7 ++ src/src/Globals/ESPEasy_now_peermanager.h | 15 ++++ src/src/Helpers/ESPEasy_now_handler.cpp | 5 +- src/src/Helpers/ESPEasy_now_peermanager.cpp | 81 ++++++++++++++++++++ src/src/Helpers/ESPEasy_now_peermanager.h | 28 +++++++ 8 files changed, 148 insertions(+), 55 deletions(-) create mode 100644 src/src/Globals/ESPEasy_now_peermanager.cpp create mode 100644 src/src/Globals/ESPEasy_now_peermanager.h create mode 100644 src/src/Helpers/ESPEasy_now_peermanager.cpp create mode 100644 src/src/Helpers/ESPEasy_now_peermanager.h diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 1b17ad5544..5d5141ae22 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -7,6 +7,7 @@ # include "../DataStructs/TimingStats.h" # include "../Globals/Nodes.h" # include "../Globals/Settings.h" +# include "../Globals/ESPEasy_now_peermanager.h" # include "../Helpers/ESPEasy_time_calc.h" static uint8_t ESPEasy_now_message_count = 1; @@ -77,7 +78,7 @@ void ESPEasy_now_splitter::createNextPacket() bool ESPEasy_now_splitter::sendToBroadcast() { - return send(getBroadcastMAC(), 0); + return send(ESPEasy_now_peermanager.getBroadcastMAC(), 0); } bool ESPEasy_now_splitter::send(const MAC_address& mac, @@ -162,6 +163,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t case WifiEspNowSendStatus::OK: { Nodes.updateSuccessRate(mac, true); + ESPEasy_now_peermanager.addPeer(mac, channel); break; } } @@ -172,51 +174,17 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) { + bool res = false; START_TIMER; - int8_t rssi = 0; - const MAC_address mac(packet._mac); - const NodeStruct *nodeInfo = Nodes.getNodeByMac(packet._mac); - if (nodeInfo != nullptr) { - if (mac != getBroadcastMAC()) { - rssi = nodeInfo->getRSSI(); - } - if (channel == 0) { - channel = nodeInfo->channel; - } - } - - if (!WifiEspNow.hasPeer(packet._mac)) { - // Only have a single temp peer added, so we don't run out of slots for peers. - static MAC_address last_tmp_mac; - - if (last_tmp_mac != packet._mac) { - if (!last_tmp_mac.all_zero()) { - WifiEspNow.removePeer(last_tmp_mac.mac); - } - last_tmp_mac.set(packet._mac); - } - - // FIXME TD-er: Not sure why, but setting the channel does not work well. - WifiEspNow.addPeer(packet._mac, channel); - - // WifiEspNow.addPeer(packet._mac, 0); - } - - { + if (ESPEasy_now_peermanager.addPeer(packet._mac, channel)) { // Set TX power based on RSSI of other ESPEasy-NOW node. // For broadcast messages power must be max. - float tx_pwr = 0; // Will be set higher based on RSSI when needed. - // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power - if (Settings.UseMaxTXpowerForSending() || rssi == 0) { - // Force highest power here, so assume the worst RSSI - rssi = -90; - tx_pwr = Settings.getWiFi_TX_power(); - } + float tx_pwr = 30; // Will be set higher based on RSSI when needed. + int8_t rssi = -99; // Assume worst RSSI for broadcast SetWiFiTXpower(tx_pwr, rssi); + res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); } - bool res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); - STOP_TIMER(ESPEASY_NOW_SEND_PCKT); delay(0); @@ -261,15 +229,5 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) return true; } -MAC_address ESPEasy_now_splitter::getBroadcastMAC() -{ - static MAC_address ESPEasy_now_broadcast_MAC; - if (ESPEasy_now_broadcast_MAC.mac[0] != 0xFF) { - for (int i = 0; i < 6; ++i) { - ESPEasy_now_broadcast_MAC.mac[i] = 0xFF; - } - } - return ESPEasy_now_broadcast_MAC; -} #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 0f86e446b4..71accb876c 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -39,8 +39,6 @@ class ESPEasy_now_splitter { WifiEspNowSendStatus waitForSendStatus(size_t timeout) const; - static MAC_address getBroadcastMAC(); - std::vector_queue; ESPEasy_now_hdr _header; size_t _payload_pos = 255; // Position in the last packet where we left of. diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 8ec6cc0187..f0102a43ca 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -414,7 +414,12 @@ void initWiFi() // Configure WiFi TX power // ******************************************************************************** void SetWiFiTXpower() { - SetWiFiTXpower(0.0f); // Just some minimal value, will be adjusted in SetWiFiTXpower + if (Settings.UseESPEasyNow()) { + // Set at max power for use with ESPEasy-NOW. + SetWiFiTXpower(30, -90); + } else { + SetWiFiTXpower(0.0f); // Just some minimal value, will be adjusted in SetWiFiTXpower + } } void SetWiFiTXpower(float dBm) { diff --git a/src/src/Globals/ESPEasy_now_peermanager.cpp b/src/src/Globals/ESPEasy_now_peermanager.cpp new file mode 100644 index 0000000000..47d232a9a0 --- /dev/null +++ b/src/src/Globals/ESPEasy_now_peermanager.cpp @@ -0,0 +1,7 @@ +#include "../Globals/ESPEasy_now_peermanager.h" + +#ifdef USES_ESPEASY_NOW + +ESPEasy_now_peermanager_t ESPEasy_now_peermanager; + +#endif \ No newline at end of file diff --git a/src/src/Globals/ESPEasy_now_peermanager.h b/src/src/Globals/ESPEasy_now_peermanager.h new file mode 100644 index 0000000000..10b64be740 --- /dev/null +++ b/src/src/Globals/ESPEasy_now_peermanager.h @@ -0,0 +1,15 @@ +#ifndef GLOBALS_ESPEASY_NOW_H +#define GLOBALS_ESPEASY_NOW_H + +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + +# include "../Helpers/ESPEasy_now_peermanager.h" + +extern ESPEasy_now_peermanager_t ESPEasy_now_peermanager; + + +#endif // ifdef USES_ESPEASY_NOW + +#endif // GLOBALS_ESPEASY_NOW_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index b1dc169fe2..0edb7fab17 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -12,6 +12,7 @@ # include "../ESPEasyCore/Controller.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../ESPEasyCore/ESPEasy_Log.h" +# include "../Globals/ESPEasy_now_peermanager.h" # include "../Globals/ESPEasyWiFiEvent.h" # include "../Globals/ESPEasy_time.h" # include "../Globals/MQTT.h" @@ -428,7 +429,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(int channel) for (int i = 0; i < 6; ++i) { broadcast.mac[i] = 0xFF; } - sendDiscoveryAnnounce(broadcast, channel); + sendDiscoveryAnnounce(ESPEasy_now_peermanager.getBroadcastMAC(), channel); } void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int channel) @@ -1041,7 +1042,7 @@ bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const if (this_mac == mac) { return false; } } - if (!WifiEspNow.addPeer(mac.mac, channel)) { + if (!ESPEasy_now_peermanager.addPeer(mac.mac, channel)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; log.reserve(48); diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp new file mode 100644 index 0000000000..c6f7aa2841 --- /dev/null +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -0,0 +1,81 @@ +#include "../Helpers/ESPEasy_now_peermanager.h" + +#ifdef USES_ESPEASY_NOW + +# include "../ESPEasyCore/ESPEasyWifi.h" +# include "../Globals/Nodes.h" + + +ESPEasy_now_peermanager_t::ESPEasy_now_peermanager_t() { + removeAllPeers(); +} + +MAC_address ESPEasy_now_peermanager_t::getBroadcastMAC() +{ + static MAC_address ESPEasy_now_broadcast_MAC; + + if (ESPEasy_now_broadcast_MAC.mac[0] != 0xFF) { + for (int i = 0; i < 6; ++i) { + ESPEasy_now_broadcast_MAC.mac[i] = 0xFF; + } + } + return ESPEasy_now_broadcast_MAC; +} + +bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, const uint8_t key[WIFIESPNOW_KEYLEN]) +{ + bool res = true; + + if (mac != getBroadcastMAC()) { + const NodeStruct *nodeInfo = Nodes.getNodeByMac(mac); + + if (nodeInfo != nullptr) { + if (channel == 0) { + channel = nodeInfo->channel; + } + } + + if (!WifiEspNow.hasPeer(mac.mac)) { + res = WifiEspNow.addPeer(mac.mac, channel); + + if (!res && (activePeers.size() != 0)) { + WifiEspNow.removePeer(activePeers.front().mac); + activePeers.pop_front(); + res = WifiEspNow.addPeer(mac.mac, channel, key); + } + + if (res) { + activePeers.push_back(mac); + } + } else { + // Move the MAC address to the back of the list as it is actively used + if (activePeers.back() != mac) { + auto it = activePeers.begin(); + bool found = false; + + while (it != activePeers.end() && !found) { + if (*it == mac) { + found = true; + activePeers.erase(it); + } + ++it; + } + activePeers.push_back(mac); + } + } + } + return res; +} + +void ESPEasy_now_peermanager_t::removeAllPeers() { + const int MAX_PEERS = 20; + WifiEspNowPeerInfo oldPeers[MAX_PEERS]; + int nOldPeers = std::min(WifiEspNow.listPeers(oldPeers, MAX_PEERS), MAX_PEERS); + + for (int i = 0; i < nOldPeers; ++i) { + WifiEspNow.removePeer(oldPeers[i].mac); + } + activePeers.clear(); +} + +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_peermanager.h b/src/src/Helpers/ESPEasy_now_peermanager.h new file mode 100644 index 0000000000..97229c4572 --- /dev/null +++ b/src/src/Helpers/ESPEasy_now_peermanager.h @@ -0,0 +1,28 @@ +#ifndef HELPERS_ESPEASY_NOW_PEERMANAGER_H +#define HELPERS_ESPEASY_NOW_PEERMANAGER_H + +#include "../../ESPEasy_common.h" +#include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW +# include "../DataStructs/MAC_address.h" + +# include + +struct ESPEasy_now_peermanager_t { + ESPEasy_now_peermanager_t(); + + static MAC_address getBroadcastMAC(); + + bool addPeer(const MAC_address& mac, + int channel, + const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); + + void removeAllPeers(); + +private: + + // Keep track of active peers so we can remove the oldest when the max. nr. of peers is reached. + std::list activePeers; +}; +#endif // ifdef USES_ESPEASY_NOW +#endif // ifndef HELPERS_ESPEASY_NOW_PEERMANAGER_H From 213d79368869c12cf61be6f8beadb8e67129da77 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 8 Apr 2021 12:52:35 +0200 Subject: [PATCH 126/404] [ESPEasy-NOW] keep MQTT queue state per neighbor node --- .../ESPEasy_Now_MQTT_queue_check_packet.cpp | 4 +- .../ESPEasy_now_Node_statistics.cpp | 72 ++++++++++-------- .../DataStructs/ESPEasy_now_Node_statistics.h | 7 ++ src/src/DataStructs/NodesHandler.cpp | 27 +++++++ src/src/DataStructs/NodesHandler.h | 6 ++ src/src/ESPEasyCore/ESPEasy_Log.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 75 +++++++------------ src/src/Helpers/ESPEasy_now_handler.h | 4 - src/src/Helpers/ESPEasy_now_peermanager.cpp | 46 +++++++++++- src/src/Helpers/ESPEasy_now_peermanager.h | 19 ++++- 10 files changed, 169 insertions(+), 93 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp index 74e627135d..94dae3ad6c 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_MQTT_queue_check_packet.h" +#include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" #ifdef USES_ESPEASY_NOW @@ -15,7 +15,7 @@ void ESPEasy_Now_MQTT_queue_check_packet::setState(bool isFull) bool ESPEasy_Now_MQTT_queue_check_packet::isFull() const { - return state != QueueState::Empty; + return state == QueueState::Full; } bool ESPEasy_Now_MQTT_queue_check_packet::isSet() const diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index b5bae78aa2..444476e212 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -13,6 +13,7 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer if (route.getDistance() == 255) { return; } + if (timePassedSince(last_update_route[last_route_index]) < 1000) { // Handling a burst of updates, only add those which have a higher success rate. if (routes[last_route_index] < route) { @@ -29,7 +30,7 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer routes[last_route_index].addUnit(unit); routes[last_route_index].setSuccessRate_last_node(unit, success_rate); last_update_route[last_route_index] = millis(); - last_update = millis(); + last_update = millis(); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F(ESPEASY_NOW_NAME); @@ -50,8 +51,8 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) { if (success) { if (timePassedSince(last_update) < 200) { - // Apply some rate limiter. - if (success_rate > 100) { --success_rate; } + // Apply some rate limiter. + if (success_rate > 100) { --success_rate; } } else if (success_rate < 255) { ++success_rate; } last_update = millis(); } else { @@ -59,12 +60,12 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) } for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - if (timePassedSince(last_update_route[i]) > 125000) { - last_update_route[i] = 0; - routes[i].clear(); - } else { - routes[i].setSuccessRate_last_node(unit, success_rate); - } + if (timePassedSince(last_update_route[i]) > 125000) { + last_update_route[i] = 0; + routes[i].clear(); + } else { + routes[i].setSuccessRate_last_node(unit, success_rate); + } } discovery_route.setSuccessRate_last_node(unit, success_rate); } @@ -86,35 +87,44 @@ const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::latestRoute( const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() const { -// if (timePassedSince(last_update_route[last_route_index]) < 125000) { - int bestIndex = -1; - int bestSuccessRate = 0; - uint8_t bestDistance = 255; - - for (int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - const uint8_t distance = routes[i].getDistance(); - const int successRate = routes[i].computeSuccessRate(); - if (distance == bestDistance) { - if (successRate > bestSuccessRate) { - bestSuccessRate = successRate; - bestIndex = i; - } - } else if (distance < bestDistance) { - bestIndex = i; - bestDistance = distance; + int bestIndex = -1; + int bestSuccessRate = 0; + uint8_t bestDistance = 255; + + for (int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { + const uint8_t distance = routes[i].getDistance(); + const int successRate = routes[i].computeSuccessRate(); + + if (distance == bestDistance) { + if (successRate > bestSuccessRate) { bestSuccessRate = successRate; + bestIndex = i; } + } else if (distance < bestDistance) { + bestIndex = i; + bestDistance = distance; + bestSuccessRate = successRate; } + } - if (bestIndex >= 0) { - return &routes[bestIndex]; - } -// } + if (bestIndex >= 0) { + return &routes[bestIndex]; + } return nullptr; } const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::discoveryRoute() const { - return discovery_route; -} \ No newline at end of file + return discovery_route; +} + +ESPEasy_Now_MQTT_queue_check_packet::QueueState ESPEasy_now_Node_statistics_t::getMQTTQueueState() const +{ + return mqtt_queue_state; +} + +void ESPEasy_now_Node_statistics_t::setMQTTQueueState(ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +{ + mqtt_queue_state = state; +} diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index 8e13ed0fd6..d3f75c0950 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" +#include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" #include "../DataStructs/ESPEasy_now_traceroute.h" #include @@ -30,6 +31,10 @@ struct ESPEasy_now_Node_statistics_t { const ESPEasy_now_traceroute_struct& discoveryRoute() const; + ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState() const; + + void setMQTTQueueState(ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + private: ESPEasy_now_traceroute_struct discovery_route; @@ -43,6 +48,8 @@ struct ESPEasy_now_Node_statistics_t { // Increase on success, decrease on fail, with limits of 255 and 0. uint8_t success_rate = 127; + + ESPEasy_Now_MQTT_queue_check_packet::QueueState mqtt_queue_state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; }; typedef std::map ESPEasy_now_Node_statisticsMap; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 6366d76361..81093bc026 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -513,4 +513,31 @@ uint8_t NodesHandler::getSuccessRate(byte unit) const return 127; } +ESPEasy_Now_MQTT_queue_check_packet::QueueState NodesHandler::getMQTTQueueState(byte unit) const +{ + auto it = _nodeStats.find(unit); + if (it != _nodeStats.end()) { + return it->second.getMQTTQueueState(); + } + return ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; + +} + +void NodesHandler::setMQTTQueueState(byte unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +{ + auto it = _nodeStats.find(unit); + if (it != _nodeStats.end()) { + it->second.setMQTTQueueState(state); + } +} + +void NodesHandler::setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +{ + const NodeStruct * node = getNodeByMac(mac); + if (node != nullptr) { + setMQTTQueueState(node->unit, state); + } +} + + #endif diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 6f65248030..1fcab6a73b 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -87,6 +87,12 @@ class NodesHandler { int getRouteSuccessRate(byte unit, uint8_t& distance) const; uint8_t getSuccessRate(byte unit) const; + + ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState(byte unit) const; + + void setMQTTQueueState(byte unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + void setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + #endif private: diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index 2dff26f48a..339576216b 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasy_Log.h" #include "../DataStructs/LogStruct.h" #include "../ESPEasyCore/Serial.h" diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 0edb7fab17..1a0057e723 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -55,6 +55,7 @@ static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr std::map ESPEasy_now_in_queue; std::list ESPEasy_now_traceroute_queue; +std::list ESPEasy_now_MQTT_check_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; @@ -122,19 +123,8 @@ bool ESPEasy_now_handler_t::begin() addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": Failed to initialize ESPEasy-NOW")); return false; } - - for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { - if (SecuritySettings.peerMacSet(peer)) { - add_peer(SecuritySettings.EspEasyNowPeerMAC[peer], 0); - } - } - - for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.ESPEasyNowPeer) { - add_peer(it->second.ESPEasy_Now_MAC(), it->second.channel); - } - } - + ESPEasy_now_peermanager.removeAllPeers(); + ESPEasy_now_peermanager.addKnownPeers(); // FIXME TD-er: Must check in settings if enabled WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); @@ -192,6 +182,7 @@ bool ESPEasy_now_handler_t::loop() } } } + if (!use_EspEasy_now) return false; bool somethingProcessed = false; if (!ESPEasy_now_in_queue.empty()) { @@ -250,6 +241,10 @@ bool ESPEasy_now_handler_t::loop() if (!ESPEasy_now_traceroute_queue.empty()) { sendTraceRoute(ESPEasy_now_traceroute_queue.front()); ESPEasy_now_traceroute_queue.pop_front(); + } else if (!ESPEasy_now_MQTT_check_queue.empty()) { + const uint8_t channel = Nodes.getNodeByMac(ESPEasy_now_MQTT_check_queue.front())->channel; + sendMQTTCheckControllerQueue(ESPEasy_now_MQTT_check_queue.front(), channel); + ESPEasy_now_MQTT_check_queue.pop_front(); } if (_send_failed_count > 30 /*|| !active()*/) { @@ -657,6 +652,9 @@ bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, traceroute.addUnit(thisunit); traceroute.setSuccessRate_last_node(thisunit, Nodes.getSuccessRate(thisunit)); ESPEasy_now_traceroute_queue.push_back(traceroute); + // Send MQTT queue check to the node we received the traceroute from + // It may be a viable path to send MQTT to, so stay informed of its MQTT queue state + ESPEasy_now_MQTT_check_queue.push_back(mac); } } } @@ -764,7 +762,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const const NodeStruct *preferred = Nodes.getPreferredNode(); if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { - switch (_preferredNodeMQTTqueueState.state) { + switch (Nodes.getMQTTQueueState(preferred->unit)) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: sendMQTTCheckControllerQueue(controllerIndex); @@ -802,7 +800,8 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const case WifiEspNowSendStatus::NONE: case WifiEspNowSendStatus::FAIL: { - _preferredNodeMQTTqueueState.state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; + Nodes.setMQTTQueueState(preferred->unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); + ESPEasy_now_MQTT_check_queue.push_back(mac); ++_send_failed_count; break; } @@ -917,16 +916,19 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me if (validControllerIndex(controllerIndex)) { if (query.isSet()) { // Got an answer from our query - _preferredNodeMQTTqueueState = query; - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - String log; - log = String(F(ESPEASY_NOW_NAME)) + F(": Received Queue state: "); - log += _preferredNodeMQTTqueueState.isFull() ? F("Full") : F("not Full"); - addLog(LOG_LEVEL_DEBUG_MORE, log); + MAC_address mac; + if (message.getMac(mac)) { + Nodes.setMQTTQueueState(mac, query.state); + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { + String log; + log = String(F(ESPEASY_NOW_NAME)) + F(": Received Queue state: "); + log += query.isFull() ? F("Full") : F("not Full"); + addLog(LOG_LEVEL_DEBUG_MORE, log); + } + # endif // ifndef BUILD_NO_DEBUG } - # endif // ifndef BUILD_NO_DEBUG return true; } else { MAC_address mac; @@ -1030,31 +1032,6 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer return false; } -bool ESPEasy_now_handler_t::add_peer(const MAC_address& mac, int channel) const -{ - { - // Don't add yourself as a peer - MAC_address this_mac; - WiFi.macAddress(this_mac.mac); - if (this_mac == mac) { return false; } - - WiFi.softAPmacAddress(this_mac.mac); - if (this_mac == mac) { return false; } - } - - if (!ESPEasy_now_peermanager.addPeer(mac.mac, channel)) { - if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log; - log.reserve(48); - log = F("ESPEasy_Now: Failed to add peer "); - log += MAC_address(mac).toString(); - addLog(LOG_LEVEL_ERROR, log); - } - return false; - } - return true; -} - void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t controllerIndex) { if (validControllerIndex(controllerIndex) && controllerIndex != _controllerIndex) diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index b047ce7e4f..308cf60fd7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -84,8 +84,6 @@ class ESPEasy_now_handler_t { bool handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, bool& mustKeep); - bool add_peer(const MAC_address& mac, int channel) const; - void load_ControllerSettingsCache(controllerIndex_t controllerIndex); ESPEasy_Now_NTP_query _best_NTP_candidate; @@ -95,8 +93,6 @@ class ESPEasy_now_handler_t { uint8_t _send_failed_count = 0; - ESPEasy_Now_MQTT_queue_check_packet _preferredNodeMQTTqueueState; - unsigned int _ClientTimeout = 0; uint8_t _usedWiFiChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index c6f7aa2841..308275ffbb 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -2,8 +2,10 @@ #ifdef USES_ESPEASY_NOW +# include "../ESPEasyCore/ESPEasy_Log.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../Globals/Nodes.h" +# include "../Globals/SecuritySettings.h" ESPEasy_now_peermanager_t::ESPEasy_now_peermanager_t() { @@ -14,7 +16,7 @@ MAC_address ESPEasy_now_peermanager_t::getBroadcastMAC() { static MAC_address ESPEasy_now_broadcast_MAC; - if (ESPEasy_now_broadcast_MAC.mac[0] != 0xFF) { + if (!isBroadcastMAC(ESPEasy_now_broadcast_MAC)) { for (int i = 0; i < 6; ++i) { ESPEasy_now_broadcast_MAC.mac[i] = 0xFF; } @@ -22,11 +24,28 @@ MAC_address ESPEasy_now_peermanager_t::getBroadcastMAC() return ESPEasy_now_broadcast_MAC; } +bool ESPEasy_now_peermanager_t::isBroadcastMAC(const MAC_address& mac) +{ + return mac.all_one(); +} + bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, const uint8_t key[WIFIESPNOW_KEYLEN]) { + { + // Don't add yourself as a peer + MAC_address this_mac; + WiFi.macAddress(this_mac.mac); + + if (this_mac == mac) { return false; } + + WiFi.softAPmacAddress(this_mac.mac); + + if (this_mac == mac) { return false; } + } + bool res = true; - if (mac != getBroadcastMAC()) { + if (!isBroadcastMAC(mac)) { const NodeStruct *nodeInfo = Nodes.getNodeByMac(mac); if (nodeInfo != nullptr) { @@ -46,6 +65,14 @@ bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, con if (res) { activePeers.push_back(mac); + } else { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log; + log.reserve(48); + log = F("ESPEasy_Now: Failed to add peer "); + log += MAC_address(mac).toString(); + addLog(LOG_LEVEL_ERROR, log); + } } } else { // Move the MAC address to the back of the list as it is actively used @@ -78,4 +105,19 @@ void ESPEasy_now_peermanager_t::removeAllPeers() { activePeers.clear(); } +void ESPEasy_now_peermanager_t::addKnownPeers() +{ + for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + if (SecuritySettings.peerMacSet(peer)) { + addPeer(SecuritySettings.EspEasyNowPeerMAC[peer], 0); + } + } + + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { + if (it->second.ESPEasyNowPeer) { + addPeer(it->second.ESPEasy_Now_MAC(), it->second.channel); + } + } +} + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_peermanager.h b/src/src/Helpers/ESPEasy_now_peermanager.h index 97229c4572..14447ebba4 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.h +++ b/src/src/Helpers/ESPEasy_now_peermanager.h @@ -11,13 +11,24 @@ struct ESPEasy_now_peermanager_t { ESPEasy_now_peermanager_t(); + // Return FF:FF:FF:FF:FF:FF static MAC_address getBroadcastMAC(); - bool addPeer(const MAC_address& mac, - int channel, - const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); + static bool isBroadcastMAC(const MAC_address& mac); - void removeAllPeers(); + // ESP-now does send broadcast packets to known peers (and those that still may receive it) + // This makes broadcast packets much more reliable when the intended recipient is a known peer + // However we only have a limited number of peer slots (depending on whether or not an encryption key is used), + // so we must keep track of 'popular' nodes to keep those active as peer + bool addPeer(const MAC_address& mac, + int channel, + const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); + + void removeAllPeers(); + + // Add preferred peers from the settings and known nodes. + // Nodes will be added as last, as those are likely to be more up-to-date. + void addKnownPeers(); private: From 87c9d35699464bdbcbabacaa32fc1124d78310bb Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 9 Apr 2021 12:06:53 +0200 Subject: [PATCH 127/404] [ESPEasy-NOW] Make route discovery more stable Routes are now no longer broadcast in bursts, but at a lower pace and only the best 2 in a burst are forwarded. MQTT queue state is now used as a "ping" to keep the success rate to a neighbour node up to date. Success rate of a complete route is now preferring a route with significant higher total success rate in favour of just the distance. --- src/src/Commands/ESPEasy_Now_cmd.cpp | 3 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 20 ++- src/src/DataStructs/ESPEasy_Now_packet.h | 14 +- .../ESPEasy_now_Node_statistics.cpp | 9 +- src/src/DataStructs/ESPEasy_now_hdr.cpp | 17 +++ src/src/DataStructs/ESPEasy_now_hdr.h | 2 + src/src/DataStructs/ESPEasy_now_merger.cpp | 6 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 5 +- .../DataStructs/ESPEasy_now_traceroute.cpp | 27 +++- src/src/DataStructs/ESPEasy_now_traceroute.h | 1 + src/src/DataStructs/NodesHandler.cpp | 19 ++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 4 + .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 5 +- src/src/ESPEasyCore/ESPEasy_Log.cpp | 7 +- src/src/Helpers/CRC_functions.cpp | 55 ++++---- src/src/Helpers/ESPEasy_now_handler.cpp | 128 ++++++++++++------ src/src/Helpers/ESPEasy_now_handler.h | 11 ++ src/src/Helpers/ESPEasy_now_peermanager.cpp | 13 +- src/src/Helpers/Networking.cpp | 5 +- src/src/Helpers/PeriodicalActions.cpp | 21 +-- 20 files changed, 268 insertions(+), 104 deletions(-) diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index 1856408d1a..1b6d326593 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -8,11 +8,12 @@ #include "../Commands/Common.h" #include "../../ESPEasy_fdwdecl.h" #include "../../ESPEasy_common.h" - +#include "../Globals/ESPEasy_now_handler.h" String Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line) { temp_disable_EspEasy_now_timer = millis() + (5*60*1000); + ESPEasy_now_handler.end(); return return_command_success(); } diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 0f6a5d5e0e..4e1d5d8e21 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -14,20 +14,24 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t pay setHeader(header); } +ESPEasy_Now_packet::ESPEasy_Now_packet() : _valid(false) +{} -ESPEasy_Now_packet::ESPEasy_Now_packet(const MAC_address& mac, const uint8_t *buf, size_t packetSize) +bool ESPEasy_Now_packet::setReceivedPacket(const MAC_address& mac, + const uint8_t *buf, + size_t packetSize) { setSize(packetSize); mac.get(_mac); const size_t bufsize = _buf.size(); if (packetSize > bufsize) { // Cannot store the whole packet, so consider it as invalid. - packetSize = bufsize; _valid = false; } else { _valid = true; + memcpy(&_buf[0], buf, packetSize); } - memcpy(&_buf[0], buf, packetSize); + return _valid; } void ESPEasy_Now_packet::setSize(size_t packetSize) @@ -52,6 +56,7 @@ bool ESPEasy_Now_packet::valid() const uint16_t ESPEasy_Now_packet::computeChecksum() const { + if (!_valid) return 0u; return calc_CRC16(reinterpret_cast(begin()), getPayloadSize()); } @@ -62,7 +67,10 @@ bool ESPEasy_Now_packet::checksumValid() const size_t ESPEasy_Now_packet::getSize() const { - return _buf.size(); + if (_valid) { + return _buf.size(); + } + return 0u; } size_t ESPEasy_Now_packet::getPayloadSize() const @@ -83,7 +91,7 @@ size_t ESPEasy_Now_packet::getMaxPayloadSize() ESPEasy_now_hdr ESPEasy_Now_packet::getHeader() const { - if (getSize() >= sizeof(ESPEasy_now_hdr)) { + if (_valid && getSize() >= sizeof(ESPEasy_now_hdr)) { ESPEasy_now_hdr header(&_buf[0]); return header; } @@ -208,7 +216,9 @@ String ESPEasy_Now_packet::getLogString() const const uint8_t * ESPEasy_Now_packet::begin() const { + if (!_valid) return nullptr; return &_buf[sizeof(ESPEasy_now_hdr)]; } + #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 5c5da09da6..c62bebdbd5 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -19,10 +19,11 @@ class ESPEasy_Now_packet { explicit ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize); - // Constructor for receiving a packet - explicit ESPEasy_Now_packet(const MAC_address& mac, - const uint8_t *buf, - size_t packetSize); + ESPEasy_Now_packet(); + + bool setReceivedPacket(const MAC_address& mac, + const uint8_t *buf, + size_t packetSize); // A packet may become invalid if it was not possible to allocate enough memory for the buffer bool valid() const; @@ -71,7 +72,10 @@ class ESPEasy_Now_packet { const uint8_t * begin() const; const uint8_t * operator[](size_t idx) const { - return &_buf[idx]; + if (_valid) { + return &_buf[idx]; + } + return nullptr; } String getLogString() const; diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 444476e212..4ab72cf43d 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -14,7 +14,7 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer return; } - if (timePassedSince(last_update_route[last_route_index]) < 1000) { + if (last_update_route[last_route_index] != 0 && timePassedSince(last_update_route[last_route_index]) < 1000) { // Handling a burst of updates, only add those which have a higher success rate. if (routes[last_route_index] < route) { return; @@ -50,9 +50,10 @@ void ESPEasy_now_Node_statistics_t::setDiscoveryRoute(byte unit, const ESPEasy_n void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) { if (success) { - if (timePassedSince(last_update) < 200) { + if (timePassedSince(last_update) < 100) { // Apply some rate limiter. - if (success_rate > 100) { --success_rate; } + return; + //if (success_rate > 100) { --success_rate; } } else if (success_rate < 255) { ++success_rate; } last_update = millis(); } else { @@ -60,7 +61,7 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) } for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - if (timePassedSince(last_update_route[i]) > 125000) { + if (last_update_route[i] != 0 && timePassedSince(last_update_route[i]) > 125000) { last_update_route[i] = 0; routes[i].clear(); } else { diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index 42b9365677..3b1c977041 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -2,6 +2,23 @@ #ifdef USES_ESPEASY_NOW +String ESPEasy_now_hdr::toString(ESPEasy_now_hdr::message_t messageType) +{ + switch (messageType) { + case ESPEasy_now_hdr::message_t::NotSet: return F("-"); + case ESPEasy_now_hdr::message_t::Acknowledgement: return F("Ack"); + case ESPEasy_now_hdr::message_t::Announcement: return F("Ann"); + case ESPEasy_now_hdr::message_t::MQTTControllerMessage: return F("MQTTctr"); + case ESPEasy_now_hdr::message_t::NTP_Query: return F("NTP"); + case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: return F("DupChk"); + case ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue: return F("MQTTchk"); + case ESPEasy_now_hdr::message_t::P2P_data: return F("p2p"); + case ESPEasy_now_hdr::message_t::TraceRoute: return F("tracert"); + case ESPEasy_now_hdr::message_t::ChecksumError: return F("ChkErr"); + } + return F("?"); +} + ESPEasy_now_hdr::ESPEasy_now_hdr() {} ESPEasy_now_hdr::ESPEasy_now_hdr(ESPEasy_now_hdr::message_t messageType) diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 81bc56e597..6310c88582 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -30,6 +30,8 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { ChecksumError = 255 }; + static String toString(message_t messageType); + ESPEasy_now_hdr(); ESPEasy_now_hdr(message_t messageType); diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 4b7a686f00..1a5bb590bb 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -28,7 +28,8 @@ void ESPEasy_now_merger::addPacket( } #endif - _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet(mac, buf, packetSize))); + _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet())); + _queue[packet_nr].setReceivedPacket(mac, buf, packetSize); _firstPacketTimestamp = millis(); } @@ -104,9 +105,12 @@ String ESPEasy_now_merger::getLogString() const getMac(mac); String log; + log.reserve(64); log += mac.toString(); log += F(" payload: "); log += getPayloadSize(); + log += F(" type: "); + log += ESPEasy_now_hdr::toString(getMessageType()); log += F(" ("); log += _queue.size(); log += '/'; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 5d5141ae22..a448eb9dab 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -121,6 +121,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::send(const MAC_address& mac, size_t t if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log; + log.reserve(85); switch (sendStatus) { case WifiEspNowSendStatus::NONE: @@ -182,7 +183,9 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) float tx_pwr = 30; // Will be set higher based on RSSI when needed. int8_t rssi = -99; // Assume worst RSSI for broadcast SetWiFiTXpower(tx_pwr, rssi); - res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + if (packet.valid()) { + res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); + } } STOP_TIMER(ESPEASY_NOW_SEND_PCKT); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index f6e6ee2ecf..ab6b801d20 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -78,12 +78,35 @@ void ESPEasy_now_traceroute_struct::setSuccessRate_last_node(byte unit, uint8_t bool ESPEasy_now_traceroute_struct::operator<(const ESPEasy_now_traceroute_struct& other) const { + const int this_success = computeSuccessRate(); + const int other_success = other.computeSuccessRate(); if (getDistance() == other.getDistance()) { - return computeSuccessRate() > other.computeSuccessRate(); + // Same distance, just pick the highest success rate + return this_success > other_success; } + + // If success rate of a route differs > 10 points, prefer the one with highest success rate + if (this_success > (other_success + 10)) return true; + if (other_success > (this_success + 10)) return false; + + // Both have somewhat equal success rate, pick one with shortest distance. return getDistance() < other.getDistance(); } +bool ESPEasy_now_traceroute_struct::sameRoute(const ESPEasy_now_traceroute_struct& other) const +{ + const uint8_t max_distance = getDistance(); + if (max_distance != other.getDistance()) { + return false; + } + for (uint8_t distance = 0; distance <= max_distance; ++distance) { + uint8_t success_rate = 0; + if (getUnit(distance, success_rate) != other.getUnit(distance, success_rate)) { + return false; + } + } + return true; +} int ESPEasy_now_traceroute_struct::computeSuccessRate() const { @@ -108,7 +131,7 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const res += successRate; } - if (max_distance > 0) { + if (max_distance > 1) { res /= max_distance; } /* diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index e8e48f03b2..75e7203eaa 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -38,6 +38,7 @@ struct ESPEasy_now_traceroute_struct // Return true when this tracerouteis more favorable bool operator<(const ESPEasy_now_traceroute_struct& other) const; + bool sameRoute(const ESPEasy_now_traceroute_struct& other) const; // For debugging purposes String toString() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 81093bc026..96780e71d7 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -8,6 +8,7 @@ #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/PeriodicalActions.h" #include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasy_now_peermanager.h" #include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" @@ -64,8 +65,22 @@ bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_ const bool isNewNode = addNode(node); _nodeStats[node.unit].setDiscoveryRoute(node.unit, traceRoute); - if (traceRoute.getDistance() != 255 && !node.isThisNode()) { - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": Node: ") + String(node.unit) + F(" Traceroute received: ") + _nodeStats[node.unit].latestRoute().toString()); + ESPEasy_now_peermanager.addPeer(node.ESPEasy_Now_MAC(), node.channel); + + if (!node.isThisNode()) { + if (traceRoute.getDistance() != 255) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(80)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Node: "); + log += String(node.unit); + log += F(" Traceroute received: "); + log += _nodeStats[node.unit].latestRoute().toString(); + addLog(LOG_LEVEL_INFO, log); + } + } + } else {} } return isNewNode; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index f0102a43ca..41b27d7628 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -379,6 +379,9 @@ void resetWiFi() { void initWiFi() { +#ifdef USES_ESPEASY_NOW + ESPEasy_now_handler.end(); +#endif #ifdef ESP8266 // See https://github.com/esp8266/Arduino/issues/5527#issuecomment-460537616 @@ -553,6 +556,7 @@ float GetRSSIthreshold(float& maxTXpwr) { switch (getConnectionProtocol()) { case WiFiConnectionProtocol::WiFi_Protocol_11b: threshold = -91; + if (maxTXpwr > 20.5) maxTXpwr = 20.5; break; case WiFiConnectionProtocol::WiFi_Protocol_11g: threshold = -75; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 8baa8fbef5..dc8d6df65f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -230,7 +230,7 @@ void processDisconnect() { // FIXME TD-er: Disconnect processing is done in several places. #ifdef USES_ESPEASY_NOW //if (isESPEasy_now_only()) return; - ESPEasy_now_handler.end(); + //ESPEasy_now_handler.end(); #endif if (Settings.WiFiRestart_connection_lost()) { @@ -505,9 +505,12 @@ void processScanDone() { setNetworkMedium(NetworkMedium_t::WIFI); WifiDisconnect(); setAP(false); + ESPEasy_now_handler.end(); + // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. WiFiEventData.wifiConnectAttemptNeeded = true; temp_disable_EspEasy_now_timer = millis() + 10000; + NetworkConnectRelaxed(); } } else { setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index 339576216b..826cdf0af6 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -167,8 +167,11 @@ bool loglevelActive(byte logLevel, byte logLevelSettings) { void addToLog(byte loglevel, const __FlashStringHelper *str) { - String copy = str; - addToLog(loglevel, copy.c_str()); + String copy; + if (copy.reserve(strlen_P((PGM_P)str))) { + copy = str; + addToLog(loglevel, copy.c_str()); + } } void addToLog(byte loglevel, const String& string) diff --git a/src/src/Helpers/CRC_functions.cpp b/src/src/Helpers/CRC_functions.cpp index 35b06b1d07..a05b0a53e7 100644 --- a/src/src/Helpers/CRC_functions.cpp +++ b/src/src/Helpers/CRC_functions.cpp @@ -7,24 +7,23 @@ int calc_CRC16(const String& text) { int calc_CRC16(const char *ptr, int count) { - int crc; - - crc = 0; - - while (--count >= 0) - { - crc = crc ^ (int)*ptr++ << 8; - char i = 8; - - do + int crc = 0; + if (ptr != nullptr) { + while (--count >= 0) { - if (crc & 0x8000) { - crc = crc << 1 ^ 0x1021; - } - else { - crc = crc << 1; - } - } while(--i); + crc = crc ^ (int)*ptr++ << 8; + char i = 8; + + do + { + if (crc & 0x8000) { + crc = crc << 1 ^ 0x1021; + } + else { + crc = crc << 1; + } + } while(--i); + } } return crc; } @@ -32,19 +31,21 @@ int calc_CRC16(const char *ptr, int count) uint32_t calc_CRC32(const uint8_t *data, size_t length) { uint32_t crc = 0xffffffff; - while (length--) { - uint8_t c = *data++; + if (data != nullptr) { + while (length--) { + uint8_t c = *data++; - for (uint32_t i = 0x80; i > 0; i >>= 1) { - bool bit = crc & 0x80000000; + for (uint32_t i = 0x80; i > 0; i >>= 1) { + bool bit = crc & 0x80000000; - if (c & i) { - bit = !bit; - } - crc <<= 1; + if (c & i) { + bit = !bit; + } + crc <<= 1; - if (bit) { - crc ^= 0x04c11db7; + if (bit) { + crc ^= 0x04c11db7; + } } } } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 1a0057e723..4bc375cfb7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -96,6 +96,7 @@ bool ESPEasy_now_handler_t::begin() if (isESPEasy_now_only()) { WifiScan(false, 0); + setConnectionSpeed(); } if (!Nodes.isEndpoint()) { @@ -153,6 +154,28 @@ void ESPEasy_now_handler_t::end() } bool ESPEasy_now_handler_t::loop() +{ + loop_check_ESPEasyNOW_run_state(); + if (!use_EspEasy_now) return false; + bool somethingProcessed = loop_process_ESPEasyNOW_in_queue(); + + loop_process_ESPEasyNOW_send_queue(); + + if (_send_failed_count > 30 /*|| !active()*/) { + _send_failed_count = 0; + // FIXME TD-er: Must check/mark so this becomes true: isESPEasy_now_only() + + // Start scanning the next channel to see if we may end up with a new found node + // WifiScan(false, false); + // addPeerFromWiFiScan(); + // _last_used = millis(); + end(); + begin(); + } + return somethingProcessed; +} + +void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() { if (!WifiIsAP(WiFi.getMode())) { // AP mode may be turned off externally, and if so restart ESPEasy-now handler @@ -170,7 +193,6 @@ bool ESPEasy_now_handler_t::loop() if (use_EspEasy_now) { end(); } - return false; } } else { if (Settings.UseESPEasyNow() != use_EspEasy_now) { @@ -178,15 +200,17 @@ bool ESPEasy_now_handler_t::loop() begin(); } else { end(); - return false; } } } - if (!use_EspEasy_now) return false; +} + +bool ESPEasy_now_handler_t::loop_process_ESPEasyNOW_in_queue() +{ bool somethingProcessed = false; if (!ESPEasy_now_in_queue.empty()) { - unsigned long timeout = millis() + 50; + unsigned long timeout = millis() + 20; for (auto it = ESPEasy_now_in_queue.begin(); !timeOutReached(timeout) && it != ESPEasy_now_in_queue.end();) { const bool expired = it->second.expired(); bool removeMessage = true; @@ -202,13 +226,18 @@ bool ESPEasy_now_handler_t::loop() } if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log = it->second.getLogString(); - if (expired) { - log += F(" Expired!"); - } else { - log += F(" Invalid!"); + String log; + if (log.reserve(85)) { + log = F(ESPEASY_NOW_NAME); + log += F(": "); + log += it->second.getLogString(); + if (expired) { + log += F(" Expired!"); + } else { + log += F(" Invalid!"); + } + addLog(LOG_LEVEL_ERROR, log); } - addLog(LOG_LEVEL_ERROR, log); } } else { if (!expired) { @@ -237,28 +266,45 @@ bool ESPEasy_now_handler_t::loop() } } } + return somethingProcessed; +} - if (!ESPEasy_now_traceroute_queue.empty()) { - sendTraceRoute(ESPEasy_now_traceroute_queue.front()); - ESPEasy_now_traceroute_queue.pop_front(); - } else if (!ESPEasy_now_MQTT_check_queue.empty()) { - const uint8_t channel = Nodes.getNodeByMac(ESPEasy_now_MQTT_check_queue.front())->channel; - sendMQTTCheckControllerQueue(ESPEasy_now_MQTT_check_queue.front(), channel); - ESPEasy_now_MQTT_check_queue.pop_front(); - } - - if (_send_failed_count > 30 /*|| !active()*/) { - _send_failed_count = 0; - // FIXME TD-er: Must check/mark so this becomes true: isESPEasy_now_only() - - // Start scanning the next channel to see if we may end up with a new found node - // WifiScan(false, false); - // addPeerFromWiFiScan(); - // _last_used = millis(); - end(); - begin(); +void ESPEasy_now_handler_t::loop_process_ESPEasyNOW_send_queue() +{ + // Try to pace the broadcasts of traceroutes and sending MQTT checks + // Only process one every 100 msec. + static unsigned long last_queue_processed = 0; + if (timePassedSince(last_queue_processed) > 100) { + if (!ESPEasy_now_traceroute_queue.empty()) { + ESPEasy_now_traceroute_queue.sort(); + const ESPEasy_now_traceroute_struct route = ESPEasy_now_traceroute_queue.front(); + sendTraceRoute(route); + last_queue_processed = millis(); + // Remove possible duplicate routes and keep the best 2 + size_t nrRoutes = 0; + for (auto it = ESPEasy_now_traceroute_queue.begin(); it != ESPEasy_now_traceroute_queue.end();) { + if (route.sameRoute(*it) || nrRoutes >= 2) { + it = ESPEasy_now_traceroute_queue.erase(it); + } else { + ++nrRoutes; + ++it; + } + } + } else if (!ESPEasy_now_MQTT_check_queue.empty()) { + const MAC_address mac = ESPEasy_now_MQTT_check_queue.front(); + const uint8_t channel = Nodes.getNodeByMac(mac)->channel; + sendMQTTCheckControllerQueue(mac, channel); + last_queue_processed = millis(); + // Remove duplicate entries in the list. + for (auto it = ESPEasy_now_MQTT_check_queue.begin(); it != ESPEasy_now_MQTT_check_queue.end();) { + if (*it == mac) { + it = ESPEasy_now_MQTT_check_queue.erase(it); + } else { + ++it; + } + } + } } - return somethingProcessed; } bool ESPEasy_now_handler_t::active() const @@ -367,9 +413,13 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo if (tmp == receivedMAC) return handled; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": received "); - log += message.getLogString(); - addLog(LOG_LEVEL_INFO, log); + String log; + if (log.reserve(75)) { + log = F(ESPEASY_NOW_NAME); + log += F(": received "); + log += message.getLogString(); + addLog(LOG_LEVEL_INFO, log); + } } switch (message.getMessageType()) @@ -546,16 +596,17 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m static_cast(received.timeSource), received.lastUpdated); +/* if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; - size_t payloadSize = message.getPayloadSize(); - log.reserve(payloadSize + 40); + log.reserve(128); log = String(F(ESPEASY_NOW_NAME)) + F(": discovery: "); log += message.getLogString(); log += '\n'; log += received.getSummary(); addLog(LOG_LEVEL_INFO, log); } + */ const NodeStruct * preferred = Nodes.getPreferredNode(); if (preferred != nullptr) { @@ -762,10 +813,11 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const const NodeStruct *preferred = Nodes.getPreferredNode(); if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { + MAC_address mac = preferred->ESPEasy_Now_MAC(); switch (Nodes.getMQTTQueueState(preferred->unit)) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: - sendMQTTCheckControllerQueue(controllerIndex); + ESPEasy_now_MQTT_check_queue.push_back(mac); return false; case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Empty: break; @@ -788,8 +840,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return false; } - MAC_address mac = preferred->ESPEasy_Now_MAC(); - WifiEspNowSendStatus sendStatus = msg.send(mac, millis() + 2 * _ClientTimeout, preferred->channel); + WifiEspNowSendStatus sendStatus = msg.send(mac, _ClientTimeout, preferred->channel); switch (sendStatus) { case WifiEspNowSendStatus::OK: @@ -918,6 +969,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me // Got an answer from our query MAC_address mac; if (message.getMac(mac)) { + Nodes.setMQTTQueueState(mac, query.state); # ifndef BUILD_NO_DEBUG diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 308cf60fd7..9f9e89fc2a 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -28,6 +28,17 @@ class ESPEasy_now_handler_t { bool loop(); +private: + + void loop_check_ESPEasyNOW_run_state(); + + bool loop_process_ESPEasyNOW_in_queue(); + + void loop_process_ESPEasyNOW_send_queue(); + + +public: + bool active() const; MAC_address getActiveESPEasyNOW_MAC() const; diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index 308275ffbb..69eda99847 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -31,6 +31,9 @@ bool ESPEasy_now_peermanager_t::isBroadcastMAC(const MAC_address& mac) bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, const uint8_t key[WIFIESPNOW_KEYLEN]) { + if (!use_EspEasy_now || mac.all_zero()) { + return false; + } { // Don't add yourself as a peer MAC_address this_mac; @@ -68,10 +71,12 @@ bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, con } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - log.reserve(48); - log = F("ESPEasy_Now: Failed to add peer "); - log += MAC_address(mac).toString(); - addLog(LOG_LEVEL_ERROR, log); + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Failed to add peer "); + log += MAC_address(mac).toString(); + addLog(LOG_LEVEL_ERROR, log); + } } } } else { diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 378353d37a..15e768bf37 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -894,8 +894,11 @@ bool NetworkConnected(uint32_t timeout_ms) { } #endif + if (timeout_ms > 500) { + timeout_ms = 500; + } - uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms); + uint32_t timer = millis() + timeout_ms; uint32_t min_delay = timeout_ms / 20; if (min_delay < 10) { diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index c6641f6cfc..70c78b0f33 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -59,6 +59,17 @@ void run50TimesPerSecond() { CPluginCall(CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND, 0, dummy); STOP_TIMER(CPLUGIN_CALL_50PS); } + #ifdef USES_ESPEASY_NOW + { + if (ESPEasy_now_handler.loop()) { + // FIXME TD-er: Must check if enabled, etc. + } + START_TIMER; + SendData_DuplicateChecker.loop(); + STOP_TIMER(ESPEASY_NOW_DEDUP_LOOP); + } + #endif + } /*********************************************************************************************\ @@ -88,16 +99,6 @@ void run10TimesPerSecond() { CPluginCall(CPlugin::Function::CPLUGIN_TEN_PER_SECOND, 0, dummy); STOP_TIMER(CPLUGIN_CALL_10PS); } - #ifdef USES_ESPEASY_NOW - { - if (ESPEasy_now_handler.loop()) { - // FIXME TD-er: Must check if enabled, etc. - } - START_TIMER; - SendData_DuplicateChecker.loop(); - STOP_TIMER(ESPEASY_NOW_DEDUP_LOOP); - } - #endif processNextEvent(); #ifdef USES_C015 From 5d0e5cd9c3884948115de43a5ce1db05db3e30f8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 9 Apr 2021 17:41:44 +0200 Subject: [PATCH 128/404] [ESPEasy-NOW] Allow WiFi reconnect + fix crash --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 + src/src/DataStructs/ESPEasy_now_splitter.cpp | 1 + src/src/ESPEasyCore/ESPEasyNetwork.cpp | 51 ++++++++++++------- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 46 ++++++++++++++--- src/src/Helpers/ESPEasy_now_handler.h | 9 ++++ src/src/Helpers/Networking.cpp | 8 +-- 7 files changed, 88 insertions(+), 33 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 4e1d5d8e21..b52201bf35 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -47,6 +47,7 @@ void ESPEasy_Now_packet::setSize(size_t packetSize) #endif _buf.resize(packetSize); + _valid = _buf.size() >= packetSize; } bool ESPEasy_Now_packet::valid() const @@ -136,6 +137,7 @@ size_t ESPEasy_Now_packet::addBinaryData(const uint8_t *data, size_t length, size_t& payload_pos) { size_t bytes_left = getPayloadSize(); + if (!_valid || bytes_left == 0) { return 0; } if (payload_pos > bytes_left) { return 0; } bytes_left -= payload_pos; diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index a448eb9dab..8cebe45639 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -214,6 +214,7 @@ WifiEspNowSendStatus ESPEasy_now_splitter::waitForSendStatus(size_t timeout) con bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) { + if (!use_EspEasy_now) return false; size_t nr_packets = _queue.size(); for (uint8_t i = 0; i < nr_packets; ++i) { diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 3065d7cab7..c995d570ea 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -19,6 +19,7 @@ void setNetworkMedium(NetworkMedium_t medium) { if (active_network_medium == medium) { return; } + bool process_exit_active_medium = true; if (medium == NetworkMedium_t::ESPEasyNOW_only) { if (!Settings.UseESPEasyNow()) { return; @@ -27,24 +28,40 @@ void setNetworkMedium(NetworkMedium_t medium) { // Only allow to set to ESPEasyNOW_only from WiFi return; } - } - switch (active_network_medium) { - case NetworkMedium_t::Ethernet: - #ifdef HAS_ETHERNET - // FIXME TD-er: How to 'end' ETH? -// ETH.end(); - #endif - break; - case NetworkMedium_t::WIFI: - WiFiEventData.timerAPoff.setNow(); + #ifdef USES_EASPEASY_NOW + if (use_EspEasy_now) { + // Work around to force the ESPEasy NOW mode in 802.11b mode. + // This allows for higher TX power and higher sensitivity. + WiFiEventData.timerAPoff.clear(); WiFiEventData.timerAPstart.clear(); - WifiDisconnect(); - break; - case NetworkMedium_t::ESPEasyNOW_only: - WiFiEventData.clearAll(); - break; - case NetworkMedium_t::NotSet: - break; + ESPEasy_now_handler.end(); + active_network_medium = medium; + setConnectionSpeed(); + ESPEasy_now_handler.begin(); + process_exit_active_medium = false; + } + + #endif + } + if (process_exit_active_medium) { + switch (active_network_medium) { + case NetworkMedium_t::Ethernet: + #ifdef HAS_ETHERNET + // FIXME TD-er: How to 'end' ETH? + // ETH.end(); + #endif + break; + case NetworkMedium_t::WIFI: + WiFiEventData.timerAPoff.setNow(); + WiFiEventData.timerAPstart.clear(); + WifiDisconnect(); + break; + case NetworkMedium_t::ESPEasyNOW_only: + WiFiEventData.clearAll(); + break; + case NetworkMedium_t::NotSet: + break; + } } statusLED(true); active_network_medium = medium; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index dc8d6df65f..015035d57c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -501,8 +501,7 @@ void processScanDone() { if (!WiFiConnected()) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); - if (isESPEasy_now_only()) { - setNetworkMedium(NetworkMedium_t::WIFI); + if (isESPEasy_now_only() || !ESPEasy_now_handler.active()) { WifiDisconnect(); setAP(false); ESPEasy_now_handler.end(); @@ -510,6 +509,7 @@ void processScanDone() { // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. WiFiEventData.wifiConnectAttemptNeeded = true; temp_disable_EspEasy_now_timer = millis() + 10000; + setNetworkMedium(Settings.NetworkMedium); NetworkConnectRelaxed(); } } else { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4bc375cfb7..985d1563f9 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -89,6 +89,8 @@ bool ESPEasy_now_handler_t::begin() if (!Settings.UseESPEasyNow()) { return false; } if (use_EspEasy_now) { return true; } + _last_traceroute_sent = 0; + _last_traceroute_received = 0; _last_used = millis(); _last_started = millis(); _usedWiFiChannel = WiFi.channel(); @@ -279,6 +281,7 @@ void ESPEasy_now_handler_t::loop_process_ESPEasyNOW_send_queue() ESPEasy_now_traceroute_queue.sort(); const ESPEasy_now_traceroute_struct route = ESPEasy_now_traceroute_queue.front(); sendTraceRoute(route); + _last_traceroute_received = millis(); last_queue_processed = millis(); // Remove possible duplicate routes and keep the best 2 size_t nrRoutes = 0; @@ -292,9 +295,12 @@ void ESPEasy_now_handler_t::loop_process_ESPEasyNOW_send_queue() } } else if (!ESPEasy_now_MQTT_check_queue.empty()) { const MAC_address mac = ESPEasy_now_MQTT_check_queue.front(); - const uint8_t channel = Nodes.getNodeByMac(mac)->channel; - sendMQTTCheckControllerQueue(mac, channel); - last_queue_processed = millis(); + const NodeStruct * node = Nodes.getNodeByMac(mac); + if (node != nullptr) { + const uint8_t channel = node->channel; + sendMQTTCheckControllerQueue(mac, channel); + last_queue_processed = millis(); + } // Remove duplicate entries in the list. for (auto it = ESPEasy_now_MQTT_check_queue.begin(); it != ESPEasy_now_MQTT_check_queue.end();) { if (*it == mac) { @@ -320,9 +326,26 @@ bool ESPEasy_now_handler_t::active() const // Give the unit some time to find other nodes. return true; } + /* if (Nodes.lastTimeValidDistanceExpired()) { return false; } + */ + const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); + if (traceroute_received_timeout || traceroute_sent_timeout) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Inactive due to not receiving trace routes"); + addLog(LOG_LEVEL_INFO, log); + } + } + + return false; + } + return timePassedSince(_last_used) < ESPEASY_NOW_ACTIVITY_TIMEOUT; } @@ -632,6 +655,18 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m // ************************************************************* // * Trace Route // ************************************************************* +void ESPEasy_now_handler_t::sendTraceRoute() +{ + if (Nodes.getDistance() == 0) { + ESPEasy_now_traceroute_struct thisTraceRoute; + thisTraceRoute.addUnit(Settings.Unit); + // Since we're the end node, claim highest success rate + thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); + sendTraceRoute(thisTraceRoute); + _last_traceroute_sent = millis(); + } +} + void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel) { for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { @@ -640,10 +675,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& } } - MAC_address broadcast; - for (int i = 0; i < 6; ++i) { - broadcast.mac[i] = 0xFF; - } + MAC_address broadcast = ESPEasy_now_peermanager.getBroadcastMAC(); sendTraceRoute(broadcast, traceRoute, channel); } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 9f9e89fc2a..adabc41e89 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -57,6 +57,9 @@ class ESPEasy_now_handler_t { void sendDiscoveryAnnounce(int channel = 0); void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); + // Send trace route as 'connected' node + void sendTraceRoute(); + void sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); void sendTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); @@ -102,6 +105,12 @@ class ESPEasy_now_handler_t { unsigned long _last_used = 0; unsigned long _last_started = 0; + // Trace route is only sent by 'connected' nodes (distance = 0) + unsigned long _last_traceroute_sent = 0; + + // Trace route will be received only when at least one node in the connected mesh has distance = 0 + unsigned long _last_traceroute_received = 0; + uint8_t _send_failed_count = 0; unsigned int _ClientTimeout = 0; diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 15e768bf37..f6b51b2602 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -419,13 +419,7 @@ void refreshNodeList() ESPEasy_now_handler.sendDiscoveryAnnounce(); } ESPEasy_now_handler.sendNTPquery(); - if (Nodes.getDistance() == 0) { - ESPEasy_now_traceroute_struct thisTraceRoute; - thisTraceRoute.addUnit(Settings.Unit); - // Since we're the end node, claim highest success rate - thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); - ESPEasy_now_handler.sendTraceRoute(thisTraceRoute); - } + ESPEasy_now_handler.sendTraceRoute(); #endif // ifdef USES_ESPEASY_NOW } From 794ddf29bff390a649dd9170411faa46f0ba9f5b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 10 Apr 2021 17:17:02 +0200 Subject: [PATCH 129/404] [ESPEasy-NOW] Fix WiFi TX power for ESPEasy-NOW nodes --- src/src/DataStructs/NodesHandler.cpp | 3 ++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 15 ++++------ src/src/ESPEasyCore/ESPEasyWifi.cpp | 29 +++++++------------ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 20 ++++++++----- 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 96780e71d7..7f9701ad03 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -444,6 +444,9 @@ bool NodesHandler::isEndpoint() const uint8_t NodesHandler::getESPEasyNOW_channel() const { + if (isEndpoint() == 0) { + return WiFi.channel(); + } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { return preferred->channel; diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index c995d570ea..b641835677 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -15,12 +15,12 @@ #include #endif -void setNetworkMedium(NetworkMedium_t medium) { - if (active_network_medium == medium) { +void setNetworkMedium(NetworkMedium_t new_medium) { + if (active_network_medium == new_medium) { return; } bool process_exit_active_medium = true; - if (medium == NetworkMedium_t::ESPEasyNOW_only) { + if (new_medium == NetworkMedium_t::ESPEasyNOW_only) { if (!Settings.UseESPEasyNow()) { return; } @@ -30,13 +30,8 @@ void setNetworkMedium(NetworkMedium_t medium) { } #ifdef USES_EASPEASY_NOW if (use_EspEasy_now) { - // Work around to force the ESPEasy NOW mode in 802.11b mode. - // This allows for higher TX power and higher sensitivity. - WiFiEventData.timerAPoff.clear(); - WiFiEventData.timerAPstart.clear(); ESPEasy_now_handler.end(); - active_network_medium = medium; - setConnectionSpeed(); + active_network_medium = new_medium; ESPEasy_now_handler.begin(); process_exit_active_medium = false; } @@ -64,7 +59,7 @@ void setNetworkMedium(NetworkMedium_t medium) { } } statusLED(true); - active_network_medium = medium; + active_network_medium = new_medium; last_network_medium_set_moment.setNow(); addLog(LOG_LEVEL_INFO, String(F("Set Network mode: ")) + toString(active_network_medium)); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 41b27d7628..f3caa1f996 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -419,7 +419,7 @@ void initWiFi() void SetWiFiTXpower() { if (Settings.UseESPEasyNow()) { // Set at max power for use with ESPEasy-NOW. - SetWiFiTXpower(30, -90); + SetWiFiTXpower(30, -99); } else { SetWiFiTXpower(0.0f); // Just some minimal value, will be adjusted in SetWiFiTXpower } @@ -435,15 +435,6 @@ void SetWiFiTXpower(float dBm, float rssi) { return; } - if (Settings.UseMaxTXpowerForSending() -#ifdef USES_ESPEASY_NOW - || isESPEasy_now_only() -#endif - ) { - // Force using max. TX power. - dBm = 30; // Just some max, will be limited later - } - // Range ESP32 : 2dBm - 20dBm // Range ESP8266: 0dBm - 20.5dBm float maxTXpwr; @@ -551,7 +542,15 @@ void SetWiFiTXpower(float dBm, float rssi) { } float GetRSSIthreshold(float& maxTXpwr) { - maxTXpwr = Settings.getWiFi_TX_power(); + if (Settings.UseMaxTXpowerForSending() +#ifdef USES_ESPEASY_NOW + || isESPEasy_now_only() +#endif + ) { + maxTXpwr = 30.0; + } else { + maxTXpwr = Settings.getWiFi_TX_power(); + } float threshold = -72; switch (getConnectionProtocol()) { case WiFiConnectionProtocol::WiFi_Protocol_11b: @@ -988,13 +987,6 @@ bool wifiAPmodeActivelyUsed() void setConnectionSpeed() { #ifdef ESP8266 - #ifdef USES_ESPEASY_NOW - if (isESPEasy_now_only()) { - WiFi.setPhyMode(WIFI_PHY_MODE_11B); - return; - } - #endif - if (!Settings.ForceWiFi_bg_mode() || (WiFiEventData.wifi_connect_attempt > 10)) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } else { @@ -1021,6 +1013,7 @@ void setConnectionSpeed() { } */ #endif // ifdef ESP32 + SetWiFiTXpower(); } void setupStaticIPconfig() { diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 015035d57c..c78eaa9cfc 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -509,6 +509,7 @@ void processScanDone() { // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. WiFiEventData.wifiConnectAttemptNeeded = true; temp_disable_EspEasy_now_timer = millis() + 10000; + setSTA(false); setNetworkMedium(Settings.NetworkMedium); NetworkConnectRelaxed(); } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 985d1563f9..8bb3f703e7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -93,7 +93,7 @@ bool ESPEasy_now_handler_t::begin() _last_traceroute_received = 0; _last_used = millis(); _last_started = millis(); - _usedWiFiChannel = WiFi.channel(); + _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); _controllerIndex = INVALID_CONTROLLER_INDEX; if (isESPEasy_now_only()) { @@ -101,15 +101,16 @@ bool ESPEasy_now_handler_t::begin() setConnectionSpeed(); } - if (!Nodes.isEndpoint()) { - _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); - } - const String ssid = F(ESPEASY_NOW_TMP_SSID); const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); setAP(true); + // Make sure AP will not be turned off. + WiFiEventData.timerAPoff.clear(); + WiFiEventData.timerAPstart.clear(); + + int ssid_hidden = 1; int max_connection = 6; WiFi.softAP(ssid.c_str(), passphrase.c_str(), _usedWiFiChannel, ssid_hidden, max_connection); @@ -179,8 +180,9 @@ bool ESPEasy_now_handler_t::loop() void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() { - if (!WifiIsAP(WiFi.getMode())) { - // AP mode may be turned off externally, and if so restart ESPEasy-now handler + if (!WifiIsAP(WiFi.getMode()) || _usedWiFiChannel != Nodes.getESPEasyNOW_channel()) { + // AP mode may be turned off externally, or WiFi channel may have changed. + // If so restart ESPEasy-now handler if (use_EspEasy_now) { end(); } @@ -391,7 +393,9 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) if (nodeInfo != nullptr) { Nodes.setRSSI(peer_mac, WiFi.RSSI(scanIndex)); - nodeInfo->channel = WiFi.channel(scanIndex); + // Sometimes a scan on one channel may see a node on another channel + // So don't set the channel of known node based on the WiFi scan + //nodeInfo->channel = WiFi.channel(scanIndex); } else { NodeStruct tmpNodeInfo; tmpNodeInfo.setRSSI(WiFi.RSSI(scanIndex)); From ea69c98a073a9d543906c54ab7e62bb8619c5cca Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 16 Apr 2021 14:31:30 +0200 Subject: [PATCH 130/404] [ESPEasy-NOW] Fix merge issues --- src/src/Helpers/ESPEasy_now_handler.cpp | 26 +++++++------------------ src/src/Helpers/ESPEasy_now_handler.h | 3 ++- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 8bb3f703e7..06156eecb3 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -374,32 +374,20 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan() } } -void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) +void ESPEasy_now_handler_t::addPeerFromWiFiScan(const WiFi_AP_Candidate& peer) { - int8_t scanCompleteStatus = WiFi.scanComplete(); - - switch (scanCompleteStatus) { - case 0: // Nothing (yet) found - return; - case -1: // WIFI_SCAN_RUNNING - return; - case -2: // WIFI_SCAN_FAILED - return; - } - - if (scanIndex > scanCompleteStatus) { return; } - MAC_address peer_mac = WiFi.BSSID(scanIndex); - auto nodeInfo = Nodes.getNodeByMac(peer_mac); + MAC_address peer_mac(peer.bssid); + auto nodeInfo = Nodes.getNodeByMac(peer_mac); if (nodeInfo != nullptr) { - Nodes.setRSSI(peer_mac, WiFi.RSSI(scanIndex)); + Nodes.setRSSI(peer_mac, peer.rssi); // Sometimes a scan on one channel may see a node on another channel // So don't set the channel of known node based on the WiFi scan //nodeInfo->channel = WiFi.channel(scanIndex); } else { NodeStruct tmpNodeInfo; - tmpNodeInfo.setRSSI(WiFi.RSSI(scanIndex)); - tmpNodeInfo.channel = WiFi.channel(scanIndex); + tmpNodeInfo.setRSSI(peer.rssi); + tmpNodeInfo.channel = peer.channel; peer_mac.get(tmpNodeInfo.ap_mac); if (tmpNodeInfo.markedAsPriorityPeer()) { @@ -417,7 +405,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(uint8_t scanIndex) } // Must trigger a discovery request from the node. - sendDiscoveryAnnounce(peer_mac, WiFi.channel(scanIndex)); + sendDiscoveryAnnounce(peer_mac, peer.channel); } } } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index adabc41e89..f3e8d978bb 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -14,6 +14,7 @@ # include "../DataStructs/ESPEasy_Now_p2p_data.h" # include "../DataStructs/ESPEasy_now_traceroute.h" # include "../DataStructs/MAC_address.h" +# include "../DataStructs/WiFi_AP_Candidate.h" # include "../Globals/CPlugins.h" @@ -44,7 +45,7 @@ class ESPEasy_now_handler_t { MAC_address getActiveESPEasyNOW_MAC() const; void addPeerFromWiFiScan(); - void addPeerFromWiFiScan(uint8_t scanIndex); + void addPeerFromWiFiScan(const WiFi_AP_Candidate& peer); private: From 14e30a7c781a06b9465f4b329e9199e7ab65c700 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 16 Apr 2021 21:28:06 +0200 Subject: [PATCH 131/404] [ESPEasy-NOW] Fix #ifdef, delete[] and compiler warnings --- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 2 +- src/src/DataStructs/ESPEasy_now_Node_statistics.cpp | 4 ++++ src/src/DataStructs/ESPEasy_now_Node_statistics.h | 2 ++ src/src/DataStructs/ESPEasy_now_traceroute.cpp | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 0220eda959..d7f42f51d7 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -113,7 +113,7 @@ bool ESPEasy_Now_p2p_data::allocate(size_t size, size_t& oldSize) { if (data != nullptr) { memcpy(tmp_ptr, data, oldSize); - delete data; + delete[] data; } data = tmp_ptr; dataSize = newSize; diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 4ab72cf43d..522541f94a 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -3,6 +3,8 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Helpers/ESPEasy_time_calc.h" +#ifdef USES_ESPEASY_NOW + unsigned long ESPEasy_now_Node_statistics_t::getAge() const { return timePassedSince(last_update_route[last_route_index]); @@ -129,3 +131,5 @@ void ESPEasy_now_Node_statistics_t::setMQTTQueueState(ESPEasy_Now_MQTT_queue_che { mqtt_queue_state = state; } + +#endif \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index d3f75c0950..fe5ed50d07 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -10,6 +10,7 @@ #define ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES 3 +#ifdef USES_ESPEASY_NOW struct ESPEasy_now_Node_statistics_t { unsigned long getAge() const; @@ -54,5 +55,6 @@ struct ESPEasy_now_Node_statistics_t { typedef std::map ESPEasy_now_Node_statisticsMap; +#endif #endif // ifndef DATASTRUCTS_ESPEASY_NOW_NODE_STATISTICS_H diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index ab6b801d20..31b5c2111d 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -28,7 +28,7 @@ uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, uint8_t& succes void ESPEasy_now_traceroute_struct::addUnit(byte unit) { // Only add the unit if it isn't already part of the traceroute. - const uint8_t index = unit_vector.size(); + const uint8_t index = static_cast(unit_vector.size()); for (size_t i = 0; i < index; i+=2) { if (unit_vector[i] == unit) { return; @@ -49,7 +49,7 @@ uint8_t ESPEasy_now_traceroute_struct::getDistance() const const uint8_t * ESPEasy_now_traceroute_struct::getData(uint8_t& size) const { - size = unit_vector.size(); + size = static_cast(unit_vector.size()); return &(unit_vector[0]); } From ff6d13d1841060c44e4e7fd4495cab93bc4f6f7c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 16 Apr 2021 21:30:30 +0200 Subject: [PATCH 132/404] Fix Precision issues and initialisation of members in rules --- src/src/DataStructs/NodesHandler.cpp | 1 + src/src/ESPEasyCore/ESPEasyRules.cpp | 9 ++++++--- src/src/ESPEasyCore/ESPEasyWifi.cpp | 10 ++++++---- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 10 ++++++---- src/src/Helpers/ESPEasy_Storage.cpp | 1 - src/src/Helpers/Rules_calculate.cpp | 6 ++++++ src/src/Helpers/Rules_calculate.h | 4 +++- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 7f9701ad03..500bffffe5 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,5 +1,6 @@ #include "NodesHandler.h" +#include "../../ESPEasy_common.h" #include "../../ESPEasy-Globals.h" #include "../../ESPEasy_fdwdecl.h" #include "../ESPEasyCore/ESPEasy_Log.h" diff --git a/src/src/ESPEasyCore/ESPEasyRules.cpp b/src/src/ESPEasyCore/ESPEasyRules.cpp index aad317417c..e729009fe3 100644 --- a/src/src/ESPEasyCore/ESPEasyRules.cpp +++ b/src/src/ESPEasyCore/ESPEasyRules.cpp @@ -457,6 +457,9 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons } if (cmd_s_lower.startsWith(F("bit"))) { + #define bitSetULL(value, bit) ((value) |= (1ULL << (bit))) + #define bitClearULL(value, bit) ((value) &= ~(1ULL << (bit))) + #define bitWriteULL(value, bit, bitvalue) (bitvalue ? bitSetULL(value, bit) : bitClearULL(value, bit)) uint32_t bitnr = 0; uint64_t iarg2 = 0; @@ -470,11 +473,11 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons } else if (cmd_s_lower.equals(F("bitset"))) { // Syntax like {bitset:0:122} to set least significant bit of the given nr '122' to '1' => '123' result = iarg2; - bitSet(result, bitnr); + bitSetULL(result, bitnr); } else if (cmd_s_lower.equals(F("bitclear"))) { // Syntax like {bitclear:0:123} to set least significant bit of the given nr '123' to '0' => '122' result = iarg2; - bitClear(result, bitnr); + bitClearULL(result, bitnr); } else if (cmd_s_lower.equals(F("bitwrite"))) { uint32_t iarg3 = 0; @@ -482,7 +485,7 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons if (validUIntFromString(arg3, iarg3)) { const int bitvalue = (iarg3 & 1); // Only use the last bit of the given parameter result = iarg2; - bitWrite(result, bitnr, bitvalue); + bitWriteULL(result, bitnr, bitvalue); } else { // Need 3 parameters, but 3rd one is not a valid uint return false; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 69de12017d..e964bfeeab 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -527,10 +527,12 @@ void SetWiFiTXpower(float dBm, float rssi) { delay(0); #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - if (WiFiEventData.wifi_TX_pwr != maxTXpwr) { - static float last_log = -1; - if (WiFiEventData.wifi_TX_pwr != last_log) { - last_log = WiFiEventData.wifi_TX_pwr; + const int TX_pwr_int = WiFiEventData.wifi_TX_pwr * 4; + const int maxTXpwr_int = maxTXpwr * 4; + if (TX_pwr_int != maxTXpwr_int) { + static int last_log = -1; + if (TX_pwr_int != last_log) { + last_log = TX_pwr_int; String log = F("WiFi : Set TX power to "); log += String(dBm, 0); log += F("dBm"); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 0684dae33e..265d342e5a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -253,13 +253,15 @@ void processConnect() { ++WiFiEventData.wifi_reconnects; if (WiFi_AP_Candidates.getCurrent().isEmergencyFallback) { - bool mustResetCredentials = false; #ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS - mustResetCredentials = CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS; + const bool mustResetCredentials = CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS; + #else + const bool mustResetCredentials = false; #endif - bool mustStartAP = false; #ifdef CUSTOM_EMERGENCY_FALLBACK_START_AP - mustStartAP = CUSTOM_EMERGENCY_FALLBACK_START_AP; + const boolmustStartAP = CUSTOM_EMERGENCY_FALLBACK_START_AP; + #else + const bool mustStartAP = false; #endif if (mustStartAP) { int allowedUptimeMinutes = 10; diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index c121899df4..bad4b074d2 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -26,7 +26,6 @@ #include "../Helpers/ESPEasyRTC.h" #include "../Helpers/ESPEasy_FactoryDefault.h" -#include "../Helpers/ESPEasy_Storage.h" #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/FS_Helper.h" #include "../Helpers/Hardware.h" diff --git a/src/src/Helpers/Rules_calculate.cpp b/src/src/Helpers/Rules_calculate.cpp index 99e5886073..593f27d6ef 100644 --- a/src/src/Helpers/Rules_calculate.cpp +++ b/src/src/Helpers/Rules_calculate.cpp @@ -9,6 +9,12 @@ #include "../Helpers/StringConverter.h" +RulesCalculate_t::RulesCalculate_t() { + for (int i = 0; i < STACK_SIZE; ++i) { + globalstack[i] = 0.0; + } +} + /********************************************************************************************\ Instance of the RulesCalculate to perform calculations These functions are wrapped in a class to diff --git a/src/src/Helpers/Rules_calculate.h b/src/src/Helpers/Rules_calculate.h index 44029bb4e7..261594f8b8 100644 --- a/src/src/Helpers/Rules_calculate.h +++ b/src/src/Helpers/Rules_calculate.h @@ -59,7 +59,7 @@ class RulesCalculate_t { double globalstack[STACK_SIZE]; double *sp = globalstack - 1; - double *sp_max = &globalstack[STACK_SIZE - 1]; + const double *sp_max = &globalstack[STACK_SIZE - 1]; // Check if it matches part of a number (identifier) // @param oc Previous character @@ -99,6 +99,8 @@ class RulesCalculate_t { public: + RulesCalculate_t(); + CalculateReturnCode doCalculate(const char *input, double *result); From 600c44c18c3c1175464ca3339d13e07912c364bd Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 16 Apr 2021 23:51:04 +0200 Subject: [PATCH 133/404] [WiFi] Feed SW watchdog timer on WiFi related actions that may take time Checking network state may sometimes detect the exact limbo states it was written for. However it may take some time to reset the WiFi if it is in limbo state, but by then the SW watchdog timer may already have reset the node. --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 4 ++++ src/src/Helpers/Misc.cpp | 7 +++++++ src/src/Helpers/Misc.h | 1 + 3 files changed, 12 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e964bfeeab..e562c85ead 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -16,6 +16,7 @@ #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/Misc.h" #include "../Helpers/Networking.h" #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_WiFi.h" @@ -374,6 +375,7 @@ void resetWiFi() { // Don't reset WiFi too often return; } + FeedSW_watchdog(); WiFiEventData.clearAll(); WifiDisconnect(); @@ -696,6 +698,7 @@ void WifiScan(bool async, uint8_t channel) { while (nrScans > 0) { if (!async) { WiFi_AP_Candidates.begin_sync_scan(); + FeedSW_watchdog(); } --nrScans; #ifdef ESP8266 @@ -707,6 +710,7 @@ void WifiScan(bool async, uint8_t channel) { WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); #endif if (!async) { + FeedSW_watchdog(); processScanDone(); } } diff --git a/src/src/Helpers/Misc.cpp b/src/src/Helpers/Misc.cpp index 998de45cc5..dd0b8cb86b 100644 --- a/src/src/Helpers/Misc.cpp +++ b/src/src/Helpers/Misc.cpp @@ -258,6 +258,13 @@ void reboot(ESPEasy_Scheduler::IntendedRebootReason_e reason) { #endif // if defined(ESP32) } +void FeedSW_watchdog() +{ + #ifdef ESP8266 + ESP.wdtFeed(); + #endif +} + void SendValueLogger(taskIndex_t TaskIndex) { #if !defined(BUILD_NO_DEBUG) || defined(FEATURE_SD) diff --git a/src/src/Helpers/Misc.h b/src/src/Helpers/Misc.h index a4b353933f..559339803b 100644 --- a/src/src/Helpers/Misc.h +++ b/src/src/Helpers/Misc.h @@ -122,6 +122,7 @@ void delayedReboot(int rebootDelay, ESPEasy_Scheduler::IntendedRebootReason_e re void reboot(ESPEasy_Scheduler::IntendedRebootReason_e reason); +void FeedSW_watchdog(); void SendValueLogger(taskIndex_t TaskIndex); From 57443ef13e86724c3bce947c36b956a94938d7db Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 18 Apr 2021 15:16:15 +0200 Subject: [PATCH 134/404] [ESPEasy-NOW] Fix WiFi not reconnecting when ESPEasy-NOW active --- src/src/DataStructs/WiFiEventData.cpp | 1 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 6 ++++-- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 7 ++++++- src/src/Helpers/ESPEasy_now_handler.cpp | 1 + src/src/Helpers/StringProvider.cpp | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 22d1feee3c..ea4ef6fc7d 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -144,6 +144,7 @@ void WiFiEventData_t::markDisconnect(WiFiDisconnectReason reason) { } lastDisconnectReason = reason; processedDisconnect = false; + wifiConnectInProgress = false; } void WiFiEventData_t::markConnected(const String& ssid, const uint8_t bssid[6], byte channel) { diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e562c85ead..2d0c7f0242 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -188,9 +188,9 @@ bool WiFiConnected() { if (wifiConnectTimeoutReached() && !WiFiEventData.wifiSetup) { // It took too long to make a connection, set flag we need to try again - if (!wifiAPmodeActivelyUsed()) { + //if (!wifiAPmodeActivelyUsed()) { WiFiEventData.wifiConnectAttemptNeeded = true; - } + //} WiFiEventData.wifiConnectInProgress = false; } delay(1); @@ -1011,6 +1011,7 @@ bool useStaticIP() { bool wifiConnectTimeoutReached() { // For the first attempt, do not wait to start connecting. if (WiFiEventData.wifi_connect_attempt == 0) { return true; } + if (!WiFiEventData.wifiConnectInProgress) { return true; } if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { // No attempt made @@ -1023,6 +1024,7 @@ bool wifiConnectTimeoutReached() { } if (WifiIsAP(WiFi.getMode())) { + // FIXME TD-er: What to do here when using ESPEasy-NOW mode? // Initial setup of WiFi, may take much longer since accesspoint is still active. return WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(20000); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 265d342e5a..2264836a2d 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -85,7 +85,7 @@ void handle_unprocessedNetworkEvents() } #endif - if (active_network_medium == NetworkMedium_t::WIFI) { + if (active_network_medium == NetworkMedium_t::WIFI || active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents()) { if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { delay(10); @@ -509,6 +509,11 @@ void processScanDone() { } return; case -1: // WIFI_SCAN_RUNNING + // FIXME TD-er: Set timeout... + if (WiFiEventData.lastGetScanMoment.timeoutReached(5000)) { + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout")); + WiFiEventData.processedScanDone = true; + } return; case -2: // WIFI_SCAN_FAILED addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed")); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 06156eecb3..d3ce886c3d 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -88,6 +88,7 @@ bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } if (use_EspEasy_now) { return true; } + if (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { return false;} _last_traceroute_sent = 0; _last_traceroute_received = 0; diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index a991920531..792123b75e 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -350,7 +350,7 @@ String getValue(LabelType::Enum label) { case LabelType::ETH_SPEED_STATE: return EthLinkUp() ? getEthLinkSpeedState() : F("Link Down"); case LabelType::ETH_CONNECTED: return ETHConnected() ? F("CONNECTED") : F("DISCONNECTED"); // 0=disconnected, 1=connected #endif // ifdef HAS_ETHERNET - case LabelType::ETH_WIFI_MODE: return active_network_medium == NetworkMedium_t::WIFI ? F("WIFI") : F("ETHERNET"); + case LabelType::ETH_WIFI_MODE: return toString(active_network_medium); case LabelType::SUNRISE: return node_time.getSunriseTimeString(':'); case LabelType::SUNSET: return node_time.getSunsetTimeString(':'); case LabelType::ISNTP: return jsonBool(Settings.UseNTP); From c13ca82f91bd132e06ea72c7a9d340247e2571c5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 18 Apr 2021 16:03:05 +0200 Subject: [PATCH 135/404] [Custom Build] Allow to embed custom CSS Define in Custom.h: ```c++ #define WEBSERVER_EMBED_CUSTOM_CSS static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = { ... ,0}; ``` --- src/src/Static/WebStaticData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Static/WebStaticData.h b/src/src/Static/WebStaticData.h index 947463ca94..6764cbde1b 100644 --- a/src/src/Static/WebStaticData.h +++ b/src/src/Static/WebStaticData.h @@ -83,7 +83,7 @@ static const char DATA_GITHUB_CLIPBOARD_JS[] PROGMEM = {0x66,0x75,0x6e,0x63,0x74 #endif -#ifdef WEBSERVER_CSS +#if defined(WEBSERVER_CSS) && !defined(WEBSERVER_EMBED_CUSTOM_CSS) static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = {0x2e,0x63,0x6c,0x6f,0x73,0x65,0x62,0x74,0x6e,0x2c,0x68,0x31,0x2c,0x68,0x32,0x2c,0x68,0x33,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x77,0x65,0x69,0x67,0x68,0x74,0x3a,0x37,0x30,0x30,0x7d,0x68,0x31,0x2c,0x68,0x36,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x7d,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x2c,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x63,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x3a,0x27,0x27,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x2c,0x2e,0x6d,0x65,0x6e,0x75,0x7b,0x74,0x65,0x78,0x74,0x2d,0x64,0x65,0x63,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x6e,0x6f,0x6e,0x65,0x7d,0x2e,0x64,0x69,0x76,0x5f,0x6c,0x2c,0x2e,0x6d,0x65,0x6e,0x75,0x7b,0x66,0x6c,0x6f,0x61,0x74,0x3a,0x6c,0x65,0x66,0x74,0x7d,0x2e,0x63,0x6c,0x6f,0x73,0x65,0x62,0x74,0x6e,0x2c,0x2e,0x64,0x69,0x76,0x5f,0x72,0x7b,0x66,0x6c,0x6f,0x61,0x74,0x3a,0x72,0x69,0x67,0x68,0x74,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x66,0x66,0x66,0x7d,0x2a,0x7b,0x62,0x6f,0x78,0x2d,0x73,0x69,0x7a,0x69,0x6e,0x67,0x3a,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x62,0x6f,0x78,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x66,0x61,0x6d,0x69,0x6c,0x79,0x3a,0x73,0x61,0x6e,0x73,0x2d,0x73,0x65,0x72,0x69,0x66,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x32,0x70,0x74,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x30,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x30,0x7d,0x68,0x31,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x36,0x70,0x74,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x38,0x70,0x78,0x20,0x30,0x7d,0x68,0x32,0x2c,0x68,0x33,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x32,0x70,0x74,0x7d,0x68,0x32,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x34,0x34,0x34,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x46,0x46,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x30,0x20,0x2d,0x34,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x36,0x70,0x78,0x7d,0x68,0x33,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x45,0x45,0x45,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x34,0x34,0x34,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x31,0x36,0x70,0x78,0x20,0x2d,0x34,0x70,0x78,0x20,0x30,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x7d,0x68,0x36,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x30,0x70,0x74,0x7d,0x63,0x6f,0x64,0x65,0x2c,0x6b,0x62,0x64,0x2c,0x70,0x72,0x65,0x2c,0x73,0x61,0x6d,0x70,0x2c,0x74,0x74,0x2c,0x78,0x6d,0x70,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x66,0x61,0x6d,0x69,0x6c,0x79,0x3a,0x6d,0x6f,0x6e,0x6f,0x73,0x70,0x61,0x63,0x65,0x2c,0x6d,0x6f,0x6e,0x6f,0x73,0x70,0x61,0x63,0x65,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x65,0x6d,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x34,0x70,0x78,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x46,0x46,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x34,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x20,0x31,0x36,0x70,0x78,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x2e,0x68,0x65,0x6c,0x70,0x2c,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x2c,0x69,0x6e,0x70,0x75,0x74,0x2c,0x73,0x65,0x6c,0x65,0x63,0x74,0x2c,0x74,0x65,0x78,0x74,0x61,0x72,0x65,0x61,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x67,0x72,0x61,0x79,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x73,0x74,0x79,0x6c,0x65,0x3a,0x73,0x6f,0x6c,0x69,0x64,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x70,0x78,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x2e,0x6c,0x69,0x6e,0x6b,0x2e,0x77,0x69,0x64,0x65,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x2d,0x62,0x6c,0x6f,0x63,0x6b,0x3b,0x74,0x65,0x78,0x74,0x2d,0x61,0x6c,0x69,0x67,0x6e,0x3a,0x63,0x65,0x6e,0x74,0x65,0x72,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x30,0x30,0x25,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x2e,0x6c,0x69,0x6e,0x6b,0x2e,0x72,0x65,0x64,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x72,0x65,0x64,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x2e,0x68,0x65,0x6c,0x70,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x35,0x30,0x25,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x32,0x70,0x78,0x20,0x34,0x70,0x78,0x7d,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x2c,0x69,0x6e,0x70,0x75,0x74,0x2c,0x73,0x65,0x6c,0x65,0x63,0x74,0x2c,0x74,0x65,0x78,0x74,0x61,0x72,0x65,0x61,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x34,0x70,0x78,0x7d,0x2e,0x62,0x75,0x74,0x74,0x6f,0x6e,0x3a,0x68,0x6f,0x76,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x3a,0x23,0x33,0x36,0x39,0x7d,0x69,0x6e,0x70,0x75,0x74,0x3a,0x68,0x6f,0x76,0x65,0x72,0x2c,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x68,0x6f,0x76,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x63,0x63,0x63,0x7d,0x69,0x6e,0x70,0x75,0x74,0x2c,0x73,0x65,0x6c,0x65,0x63,0x74,0x2c,0x74,0x65,0x78,0x74,0x61,0x72,0x65,0x61,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x65,0x65,0x65,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x34,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x20,0x38,0x70,0x78,0x7d,0x69,0x6e,0x70,0x75,0x74,0x2e,0x77,0x69,0x64,0x65,0x2c,0x73,0x65,0x6c,0x65,0x63,0x74,0x2e,0x77,0x69,0x64,0x65,0x7b,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x35,0x30,0x30,0x70,0x78,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x38,0x30,0x25,0x7d,0x2e,0x77,0x69,0x64,0x65,0x6e,0x75,0x6d,0x62,0x65,0x72,0x7b,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x35,0x30,0x30,0x70,0x78,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x30,0x30,0x70,0x78,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x2c,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x32,0x70,0x74,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x33,0x35,0x70,0x78,0x3b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x7b,0x2d,0x6d,0x6f,0x7a,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x2d,0x6d,0x73,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x62,0x6c,0x6f,0x63,0x6b,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x34,0x70,0x78,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x74,0x6f,0x70,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x72,0x65,0x6c,0x61,0x74,0x69,0x76,0x65,0x3b,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x20,0x69,0x6e,0x70,0x75,0x74,0x7b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x7d,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x2e,0x64,0x69,0x73,0x61,0x62,0x6c,0x65,0x64,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x67,0x72,0x65,0x79,0x7d,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x65,0x65,0x65,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x32,0x35,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x3b,0x74,0x6f,0x70,0x3a,0x30,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x32,0x35,0x70,0x78,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x3a,0x68,0x6f,0x76,0x65,0x72,0x20,0x69,0x6e,0x70,0x75,0x74,0x7e,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x63,0x63,0x63,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x20,0x69,0x6e,0x70,0x75,0x74,0x3a,0x63,0x68,0x65,0x63,0x6b,0x65,0x64,0x7e,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x7d,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x20,0x69,0x6e,0x70,0x75,0x74,0x3a,0x63,0x68,0x65,0x63,0x6b,0x65,0x64,0x7e,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x2c,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x62,0x6c,0x6f,0x63,0x6b,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x20,0x2e,0x63,0x68,0x65,0x63,0x6b,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x2d,0x6d,0x73,0x2d,0x74,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x3a,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x34,0x35,0x64,0x65,0x67,0x29,0x3b,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x74,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x3a,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x34,0x35,0x64,0x65,0x67,0x29,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x3a,0x73,0x6f,0x6c,0x69,0x64,0x20,0x23,0x66,0x66,0x66,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x30,0x20,0x33,0x70,0x78,0x20,0x33,0x70,0x78,0x20,0x30,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x31,0x30,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x37,0x70,0x78,0x3b,0x74,0x6f,0x70,0x3a,0x33,0x70,0x78,0x3b,0x74,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x3a,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x34,0x35,0x64,0x65,0x67,0x29,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x35,0x70,0x78,0x7d,0x23,0x74,0x6f,0x61,0x73,0x74,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x2c,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x2c,0x2e,0x6c,0x6f,0x67,0x76,0x69,0x65,0x77,0x65,0x72,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x67,0x72,0x61,0x79,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x73,0x74,0x79,0x6c,0x65,0x3a,0x73,0x6f,0x6c,0x69,0x64,0x7d,0x23,0x74,0x6f,0x61,0x73,0x74,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x2c,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x70,0x78,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x7b,0x2d,0x6d,0x6f,0x7a,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x2d,0x6d,0x73,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x32,0x30,0x70,0x78,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x39,0x70,0x78,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x72,0x65,0x6c,0x61,0x74,0x69,0x76,0x65,0x3b,0x75,0x73,0x65,0x72,0x2d,0x73,0x65,0x6c,0x65,0x63,0x74,0x3a,0x6e,0x6f,0x6e,0x65,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x20,0x69,0x6e,0x70,0x75,0x74,0x7b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x7d,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x65,0x65,0x65,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x35,0x30,0x25,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x32,0x36,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x3b,0x74,0x6f,0x70,0x3a,0x30,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x32,0x36,0x70,0x78,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x3a,0x68,0x6f,0x76,0x65,0x72,0x20,0x69,0x6e,0x70,0x75,0x74,0x7e,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x63,0x63,0x63,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x20,0x69,0x6e,0x70,0x75,0x74,0x3a,0x63,0x68,0x65,0x63,0x6b,0x65,0x64,0x7e,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x7d,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x6e,0x6f,0x6e,0x65,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x61,0x62,0x73,0x6f,0x6c,0x75,0x74,0x65,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x20,0x69,0x6e,0x70,0x75,0x74,0x3a,0x63,0x68,0x65,0x63,0x6b,0x65,0x64,0x7e,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x62,0x6c,0x6f,0x63,0x6b,0x7d,0x2e,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x65,0x72,0x32,0x20,0x2e,0x64,0x6f,0x74,0x6d,0x61,0x72,0x6b,0x3a,0x61,0x66,0x74,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x3a,0x23,0x66,0x66,0x66,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x35,0x30,0x25,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x38,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x38,0x70,0x78,0x3b,0x74,0x6f,0x70,0x3a,0x38,0x70,0x78,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x38,0x70,0x78,0x7d,0x2e,0x6c,0x6f,0x67,0x76,0x69,0x65,0x77,0x65,0x72,0x2c,0x74,0x65,0x78,0x74,0x61,0x72,0x65,0x61,0x7b,0x66,0x6f,0x6e,0x74,0x2d,0x66,0x61,0x6d,0x69,0x6c,0x79,0x3a,0x27,0x4c,0x75,0x63,0x69,0x64,0x61,0x20,0x43,0x6f,0x6e,0x73,0x6f,0x6c,0x65,0x27,0x2c,0x4d,0x6f,0x6e,0x61,0x63,0x6f,0x2c,0x6d,0x6f,0x6e,0x6f,0x73,0x70,0x61,0x63,0x65,0x3b,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x30,0x30,0x30,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x20,0x38,0x70,0x78,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x38,0x30,0x25,0x7d,0x23,0x74,0x6f,0x61,0x73,0x74,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x34,0x70,0x78,0x3b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x33,0x30,0x25,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x66,0x66,0x66,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x31,0x37,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x32,0x38,0x32,0x70,0x78,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x2d,0x31,0x32,0x35,0x70,0x78,0x3b,0x6d,0x69,0x6e,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x32,0x35,0x30,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x31,0x36,0x70,0x78,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x66,0x69,0x78,0x65,0x64,0x3b,0x74,0x65,0x78,0x74,0x2d,0x61,0x6c,0x69,0x67,0x6e,0x3a,0x63,0x65,0x6e,0x74,0x65,0x72,0x3b,0x76,0x69,0x73,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x3a,0x68,0x69,0x64,0x64,0x65,0x6e,0x3b,0x7a,0x2d,0x69,0x6e,0x64,0x65,0x78,0x3a,0x31,0x7d,0x23,0x74,0x6f,0x61,0x73,0x74,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x2e,0x73,0x68,0x6f,0x77,0x7b,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x61,0x6e,0x69,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x66,0x61,0x64,0x65,0x69,0x6e,0x20,0x2e,0x35,0x73,0x2c,0x66,0x61,0x64,0x65,0x6f,0x75,0x74,0x20,0x2e,0x35,0x73,0x20,0x32,0x2e,0x35,0x73,0x3b,0x61,0x6e,0x69,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x66,0x61,0x64,0x65,0x69,0x6e,0x20,0x2e,0x35,0x73,0x2c,0x66,0x61,0x64,0x65,0x6f,0x75,0x74,0x20,0x2e,0x35,0x73,0x20,0x32,0x2e,0x35,0x73,0x3b,0x76,0x69,0x73,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x3a,0x76,0x69,0x73,0x69,0x62,0x6c,0x65,0x7d,0x40,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x6b,0x65,0x79,0x66,0x72,0x61,0x6d,0x65,0x73,0x20,0x66,0x61,0x64,0x65,0x69,0x6e,0x7b,0x66,0x72,0x6f,0x6d,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x32,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x7d,0x74,0x6f,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x33,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x2e,0x39,0x7d,0x7d,0x40,0x6b,0x65,0x79,0x66,0x72,0x61,0x6d,0x65,0x73,0x20,0x66,0x61,0x64,0x65,0x69,0x6e,0x7b,0x66,0x72,0x6f,0x6d,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x32,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x7d,0x74,0x6f,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x33,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x2e,0x39,0x7d,0x7d,0x40,0x2d,0x77,0x65,0x62,0x6b,0x69,0x74,0x2d,0x6b,0x65,0x79,0x66,0x72,0x61,0x6d,0x65,0x73,0x20,0x66,0x61,0x64,0x65,0x6f,0x75,0x74,0x7b,0x66,0x72,0x6f,0x6d,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x33,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x2e,0x39,0x7d,0x74,0x6f,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x30,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x7d,0x7d,0x40,0x6b,0x65,0x79,0x66,0x72,0x61,0x6d,0x65,0x73,0x20,0x66,0x61,0x64,0x65,0x6f,0x75,0x74,0x7b,0x66,0x72,0x6f,0x6d,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x33,0x30,0x25,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x2e,0x39,0x7d,0x74,0x6f,0x7b,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x30,0x3b,0x6f,0x70,0x61,0x63,0x69,0x74,0x79,0x3a,0x30,0x7d,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x30,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x31,0x46,0x31,0x46,0x31,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x31,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x43,0x46,0x46,0x39,0x35,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x32,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x39,0x44,0x43,0x45,0x46,0x45,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x33,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x41,0x34,0x46,0x43,0x37,0x39,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x34,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x32,0x41,0x42,0x33,0x39,0x7d,0x2e,0x6c,0x65,0x76,0x65,0x6c,0x5f,0x39,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x35,0x30,0x7d,0x2e,0x6c,0x6f,0x67,0x76,0x69,0x65,0x77,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x32,0x37,0x32,0x37,0x32,0x37,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x31,0x46,0x31,0x46,0x31,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x35,0x33,0x30,0x70,0x78,0x3b,0x6f,0x76,0x65,0x72,0x66,0x6c,0x6f,0x77,0x3a,0x61,0x75,0x74,0x6f,0x7d,0x74,0x65,0x78,0x74,0x61,0x72,0x65,0x61,0x3a,0x68,0x6f,0x76,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x63,0x63,0x63,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6d,0x75,0x6c,0x74,0x69,0x72,0x6f,0x77,0x20,0x74,0x68,0x2c,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x20,0x74,0x68,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x34,0x34,0x34,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x38,0x38,0x38,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x46,0x46,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x77,0x65,0x69,0x67,0x68,0x74,0x3a,0x37,0x30,0x30,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x36,0x70,0x78,0x3b,0x61,0x6c,0x69,0x67,0x6e,0x2d,0x63,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x3a,0x63,0x65,0x6e,0x74,0x65,0x72,0x3b,0x74,0x65,0x78,0x74,0x2d,0x61,0x6c,0x69,0x67,0x6e,0x3a,0x63,0x65,0x6e,0x74,0x65,0x72,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6d,0x75,0x6c,0x74,0x69,0x72,0x6f,0x77,0x2c,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x63,0x6f,0x6c,0x6c,0x61,0x70,0x73,0x65,0x3a,0x63,0x6f,0x6c,0x6c,0x61,0x70,0x73,0x65,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x30,0x30,0x3b,0x6d,0x69,0x6e,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x34,0x32,0x30,0x70,0x78,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x30,0x30,0x25,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6d,0x75,0x6c,0x74,0x69,0x72,0x6f,0x77,0x20,0x74,0x72,0x2c,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x20,0x74,0x64,0x2c,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x20,0x74,0x72,0x7b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x20,0x74,0x64,0x7b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x33,0x30,0x70,0x78,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6d,0x75,0x6c,0x74,0x69,0x72,0x6f,0x77,0x20,0x74,0x64,0x7b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x33,0x30,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x3b,0x74,0x65,0x78,0x74,0x2d,0x61,0x6c,0x69,0x67,0x6e,0x3a,0x63,0x65,0x6e,0x74,0x65,0x72,0x7d,0x74,0x61,0x62,0x6c,0x65,0x2e,0x6d,0x75,0x6c,0x74,0x69,0x72,0x6f,0x77,0x20,0x74,0x72,0x3a,0x6e,0x74,0x68,0x2d,0x63,0x68,0x69,0x6c,0x64,0x28,0x65,0x76,0x65,0x6e,0x29,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x44,0x45,0x45,0x36,0x46,0x46,0x7d,0x2e,0x68,0x69,0x67,0x68,0x6c,0x69,0x67,0x68,0x74,0x20,0x74,0x64,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x64,0x62,0x66,0x66,0x30,0x30,0x37,0x35,0x7d,0x2e,0x61,0x70,0x68,0x65,0x61,0x64,0x65,0x72,0x2c,0x2e,0x68,0x65,0x61,0x64,0x65,0x72,0x6d,0x65,0x6e,0x75,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x38,0x46,0x38,0x46,0x38,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x38,0x70,0x78,0x20,0x31,0x32,0x70,0x78,0x7d,0x2e,0x6e,0x6f,0x74,0x65,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x34,0x34,0x34,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x74,0x79,0x6c,0x65,0x3a,0x69,0x74,0x61,0x6c,0x69,0x63,0x7d,0x2e,0x68,0x65,0x61,0x64,0x65,0x72,0x6d,0x65,0x6e,0x75,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x31,0x70,0x78,0x20,0x73,0x6f,0x6c,0x69,0x64,0x20,0x23,0x44,0x44,0x44,0x3b,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x39,0x30,0x70,0x78,0x3b,0x6c,0x65,0x66,0x74,0x3a,0x30,0x3b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x66,0x69,0x78,0x65,0x64,0x3b,0x72,0x69,0x67,0x68,0x74,0x3a,0x30,0x3b,0x74,0x6f,0x70,0x3a,0x30,0x3b,0x7a,0x2d,0x69,0x6e,0x64,0x65,0x78,0x3a,0x31,0x7d,0x2e,0x62,0x6f,0x64,0x79,0x6d,0x65,0x6e,0x75,0x7b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x74,0x6f,0x70,0x3a,0x39,0x36,0x70,0x78,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x62,0x61,0x72,0x7b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x69,0x6e,0x68,0x65,0x72,0x69,0x74,0x3b,0x74,0x6f,0x70,0x3a,0x35,0x35,0x70,0x78,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x7b,0x62,0x6f,0x72,0x64,0x65,0x72,0x3a,0x73,0x6f,0x6c,0x69,0x64,0x20,0x74,0x72,0x61,0x6e,0x73,0x70,0x61,0x72,0x65,0x6e,0x74,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x34,0x70,0x78,0x20,0x34,0x70,0x78,0x20,0x30,0x20,0x30,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x34,0x70,0x78,0x20,0x31,0x70,0x78,0x20,0x31,0x70,0x78,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x34,0x34,0x34,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x34,0x70,0x78,0x20,0x31,0x36,0x70,0x78,0x20,0x38,0x70,0x78,0x3b,0x77,0x68,0x69,0x74,0x65,0x2d,0x73,0x70,0x61,0x63,0x65,0x3a,0x6e,0x6f,0x77,0x72,0x61,0x70,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x2e,0x61,0x63,0x74,0x69,0x76,0x65,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x46,0x46,0x46,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x37,0x44,0x20,0x23,0x44,0x44,0x44,0x20,0x23,0x46,0x46,0x46,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x30,0x30,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x3a,0x68,0x6f,0x76,0x65,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x3a,0x23,0x44,0x45,0x46,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x30,0x30,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x5f,0x62,0x75,0x74,0x74,0x6f,0x6e,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x6e,0x6f,0x6e,0x65,0x7d,0x2e,0x6f,0x6e,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x67,0x72,0x65,0x65,0x6e,0x7d,0x2e,0x6f,0x66,0x66,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x72,0x65,0x64,0x7d,0x2e,0x64,0x69,0x76,0x5f,0x72,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x38,0x30,0x3b,0x62,0x6f,0x72,0x64,0x65,0x72,0x2d,0x72,0x61,0x64,0x69,0x75,0x73,0x3a,0x34,0x70,0x78,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x3a,0x32,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x31,0x70,0x78,0x20,0x31,0x30,0x70,0x78,0x7d,0x2e,0x61,0x6c,0x65,0x72,0x74,0x2c,0x2e,0x77,0x61,0x72,0x6e,0x69,0x6e,0x67,0x7b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x3a,0x31,0x35,0x70,0x78,0x3b,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x3a,0x32,0x30,0x70,0x78,0x3b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x66,0x66,0x66,0x7d,0x2e,0x64,0x69,0x76,0x5f,0x62,0x72,0x7b,0x63,0x6c,0x65,0x61,0x72,0x3a,0x62,0x6f,0x74,0x68,0x7d,0x2e,0x61,0x6c,0x65,0x72,0x74,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x66,0x34,0x34,0x33,0x33,0x36,0x7d,0x2e,0x77,0x61,0x72,0x6e,0x69,0x6e,0x67,0x7b,0x62,0x61,0x63,0x6b,0x67,0x72,0x6f,0x75,0x6e,0x64,0x2d,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x66,0x66,0x63,0x61,0x31,0x37,0x7d,0x2e,0x63,0x6c,0x6f,0x73,0x65,0x62,0x74,0x6e,0x7b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x3b,0x66,0x6f,0x6e,0x74,0x2d,0x73,0x69,0x7a,0x65,0x3a,0x32,0x32,0x70,0x78,0x3b,0x6c,0x69,0x6e,0x65,0x2d,0x68,0x65,0x69,0x67,0x68,0x74,0x3a,0x32,0x30,0x70,0x78,0x3b,0x6d,0x61,0x72,0x67,0x69,0x6e,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x31,0x35,0x70,0x78,0x3b,0x74,0x72,0x61,0x6e,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3a,0x2e,0x33,0x73,0x7d,0x2e,0x63,0x6c,0x6f,0x73,0x65,0x62,0x74,0x6e,0x3a,0x68,0x6f,0x76,0x65,0x72,0x7b,0x63,0x6f,0x6c,0x6f,0x72,0x3a,0x23,0x30,0x30,0x30,0x7d,0x73,0x65,0x63,0x74,0x69,0x6f,0x6e,0x7b,0x6f,0x76,0x65,0x72,0x66,0x6c,0x6f,0x77,0x2d,0x78,0x3a,0x61,0x75,0x74,0x6f,0x3b,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x30,0x30,0x25,0x7d,0x40,0x6d,0x65,0x64,0x69,0x61,0x20,0x73,0x63,0x72,0x65,0x65,0x6e,0x20,0x61,0x6e,0x64,0x20,0x28,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x39,0x36,0x30,0x70,0x78,0x29,0x7b,0x2e,0x73,0x68,0x6f,0x77,0x6d,0x65,0x6e,0x75,0x6c,0x61,0x62,0x65,0x6c,0x7b,0x64,0x69,0x73,0x70,0x6c,0x61,0x79,0x3a,0x6e,0x6f,0x6e,0x65,0x7d,0x2e,0x6d,0x65,0x6e,0x75,0x7b,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x31,0x31,0x76,0x77,0x3b,0x6d,0x61,0x78,0x2d,0x77,0x69,0x64,0x74,0x68,0x3a,0x34,0x38,0x70,0x78,0x7d,0x7d,0x0a, 0}; #endif // WEBSERVER_CSS From 18c89b622a5075d0c0a7a8ff1d89050d7ea3615a Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 18 Apr 2021 19:49:43 +0200 Subject: [PATCH 136/404] [ESPEasy-NOW] Only start ESPEasy-NOW when not trying to connect to WiFi --- src/src/DataStructs/NodesHandler.cpp | 12 ++++++++++++ src/src/DataStructs/NodesHandler.h | 4 +--- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 4 +++- src/src/Helpers/ESPEasy_now_handler.cpp | 8 ++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 500bffffe5..dc6e49f3f3 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -378,6 +378,18 @@ const NodeStruct * NodesHandler::getThisNode() { return getNodeByMac(this_mac.mac); } +uint8_t NodesHandler::getDistance() const { + // Perform extra check since _distance is only updated once every 30 seconds. + // And we don't want to tell other nodes we have distance 0 when we haven't. + if (isEndpoint()) return 0; + if (_distance == 0) { + // Outdated info, so return "we don't know" + return 255; + } + return _distance; +} + + NodesMap::const_iterator NodesHandler::begin() const { return _nodes.begin(); } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 1fcab6a73b..6790660477 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -60,9 +60,7 @@ class NodesHandler { const NodeStruct * getThisNode(); - uint8_t getDistance() const { - return _distance; - } + uint8_t getDistance() const; bool lastTimeValidDistanceExpired() const; diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index af8f1b004e..10879845e5 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -49,7 +49,9 @@ void setNetworkMedium(NetworkMedium_t new_medium) { case NetworkMedium_t::WIFI: WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); WiFiEventData.timerAPstart.clear(); - WifiDisconnect(); + if (new_medium == NetworkMedium_t::Ethernet) { + WifiDisconnect(); + } break; case NetworkMedium_t::ESPEasyNOW_only: WiFiEventData.clearAll(); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d3ce886c3d..e387e1ad44 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -89,6 +89,14 @@ bool ESPEasy_now_handler_t::begin() if (!Settings.UseESPEasyNow()) { return false; } if (use_EspEasy_now) { return true; } if (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { return false;} + if (WiFiEventData.wifiConnectInProgress) { + return false; + } + if (temp_disable_EspEasy_now_timer != 0) { + if (!timeOutReached(temp_disable_EspEasy_now_timer)) { + return false; + } + } _last_traceroute_sent = 0; _last_traceroute_received = 0; From 5fc2ab5605702bfeeab047812236233b4c8278a2 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 19 Apr 2021 00:25:02 +0200 Subject: [PATCH 137/404] [ESPEasy-NOW] Fix WiFi reconnect after disconnect with mesh active --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 ++----- src/src/ESPEasyCore/ESPEasyWifi.h | 6 ++--- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 15 +++++++++---- src/src/Helpers/ESPEasy_now_handler.cpp | 22 ++++++++++++++++++- src/src/Helpers/Networking.cpp | 6 +---- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 2d0c7f0242..5a31de60e7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -323,7 +323,7 @@ bool checkAndResetWiFi() { switch(status) { case STATION_GOT_IP: - if (WiFi.RSSI() < 0) { + if (WiFi.RSSI() < 0 && NetworkLocalIP().isSet()) { //if (WiFi.channel() == WiFiEventData.usedChannel || WiFiEventData.usedChannel == 0) { // This is a valid status, no need to reset return false; @@ -370,7 +370,7 @@ bool checkAndResetWiFi() { void resetWiFi() { - if (wifiAPmodeActivelyUsed()) return; + //if (wifiAPmodeActivelyUsed()) return; if (WiFiEventData.lastWiFiResetMoment.isSet() && !WiFiEventData.lastWiFiResetMoment.timeoutReached(1000)) { // Don't reset WiFi too often return; @@ -646,10 +646,6 @@ void WiFiScanPeriodical() { } bool WiFiScanAllowed() { - if (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { - // Scan still busy - return false; - } if (!WiFiEventData.processedScanDone) { processScanDone(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index 5def0d4170..9efde39f30 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -14,11 +14,11 @@ #include "../DataTypes/WiFiConnectionProtocol.h" -#define WIFI_RECONNECT_WAIT 20000 // in milliSeconds -#define WIFI_AP_OFF_TIMER_DURATION 300000 // in milliSeconds +#define WIFI_RECONNECT_WAIT 20000 // in milliSeconds +#define WIFI_AP_OFF_TIMER_DURATION 300000 // in milliSeconds #define WIFI_CONNECTION_CONSIDERED_STABLE 300000 // in milliSeconds #define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes -#define WIFI_SCAN_INTERVAL_AP_USED 180000 // in milliSeconds +#define WIFI_SCAN_INTERVAL_AP_USED 125000 // in milliSeconds #define WIFI_SCAN_INTERVAL_MINIMAL 60000 // in milliSeconds bool WiFiConnected(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 78813853cb..4011e62172 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -229,15 +229,22 @@ void processDisconnect() { addLog(LOG_LEVEL_INFO, log); } - // FIXME TD-er: Disconnect processing is done in several places. + + bool mustRestartWiFi = Settings.WiFiRestart_connection_lost(); #ifdef USES_ESPEASY_NOW - //if (isESPEasy_now_only()) return; - //ESPEasy_now_handler.end(); + if (use_EspEasy_now) { + mustRestartWiFi = true; + } #endif - if (Settings.WiFiRestart_connection_lost()) { + if (mustRestartWiFi) { initWiFi(); delay(100); + if (WiFiEventData.unprocessedWifiEvents()) { + handle_unprocessedNetworkEvents(); + } + + WifiScan(false); } logConnectionStatus(); } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index e387e1ad44..db052e87de 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -88,7 +88,7 @@ bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } if (use_EspEasy_now) { return true; } - if (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { return false;} + if (WiFi.scanComplete() == WIFI_SCAN_RUNNING || !WiFiEventData.processedScanDone) { return false;} if (WiFiEventData.wifiConnectInProgress) { return false; } @@ -197,6 +197,26 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() } } + if (use_EspEasy_now) { + const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); + if (traceroute_received_timeout || traceroute_sent_timeout) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Inactive due to not receiving trace routes"); + addLog(LOG_LEVEL_INFO, log); + } + } + end(); + temp_disable_EspEasy_now_timer = millis() + 10000; + WifiScan(true); + return; + } + } + + if (temp_disable_EspEasy_now_timer != 0) { if (timeOutReached(temp_disable_EspEasy_now_timer)) { if (begin()) { diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index f6b51b2602..4ef4aed9fe 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -400,11 +400,7 @@ void refreshNodeList() Nodes.refreshNodeList(max_age_allowed, max_age); #ifdef USES_ESPEASY_NOW - const uint8_t channel = Nodes.getESPEasyNOW_channel(); - - if (channel != 0) { - WifiScan(true, channel); - } + WifiScan(true, Nodes.getESPEasyNOW_channel()); #endif if (max_age > (0.75 * max_age_allowed)) { From 3d4d0ccf1d2679c86644f9c5705ef77cc8892aac Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 19 Apr 2021 10:22:38 +0200 Subject: [PATCH 138/404] [ESPEasy-NOW] Fix long reconnect delay when disconnected during scan When the ESP got disconnected during a periodical WiFi scan, it would receive events in an unexpected order, which could lead to a reconnect delay of a few minutes due to the rate limiter on WiFi scans. --- src/src/DataStructs/TimingStats.cpp | 2 ++ src/src/DataStructs/TimingStats.h | 2 ++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 10 +++++++--- src/src/ESPEasyCore/ESPEasyWifi.cpp | 13 +++++++++++++ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 17 ++++++++--------- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index ffe2592132..e05f873b0e 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -239,6 +239,8 @@ String getMiscStatsName(int stat) { case ESPEASY_NOW_SEND_MSG_FAIL: return String(F(ESPEASY_NOW_NAME)) + F(" send Message Fail"); case ESPEASY_NOW_SEND_PCKT: return String(F(ESPEASY_NOW_NAME)) + F(" send Packet"); case ESPEASY_NOW_DEDUP_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" DuplicateCheck loop"); + case WIFI_SCAN_ASYNC: return F("WiFi Scan Async"); + case WIFI_SCAN_SYNC: return F("WiFi Scan Sync (blocking)"); case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time"); case C001_DELAY_QUEUE: case C002_DELAY_QUEUE: diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 094f1b2520..2ff184aa12 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -89,6 +89,8 @@ # define ESPEASY_NOW_SEND_MSG_FAIL 68 # define ESPEASY_NOW_SEND_PCKT 69 # define ESPEASY_NOW_DEDUP_LOOP 70 +# define WIFI_SCAN_ASYNC 71 +# define WIFI_SCAN_SYNC 72 diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 10879845e5..579dbe806b 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -68,10 +68,14 @@ void setNetworkMedium(NetworkMedium_t new_medium) { bool isESPEasy_now_only() { #ifdef USES_EASPEASY_NOW - return active_network_medium == NetworkMedium_t::ESPEasyNOW_only; - #else - return false; + if (active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { + return true; + } + if (use_EspEasy_now) { + return !NetworkConnected(); + } #endif + return false; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 5a31de60e7..1be3d38643 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -649,6 +649,9 @@ bool WiFiScanAllowed() { if (!WiFiEventData.processedScanDone) { processScanDone(); } + if (WiFiEventData.unprocessedWifiEvents()) { + handle_unprocessedNetworkEvents(); + } if (WiFiEventData.unprocessedWifiEvents()) { return false; } @@ -660,6 +663,14 @@ bool WiFiScanAllowed() { if (WiFi_AP_Candidates.scanComplete() <= 0) { return true; } + if (WiFi_AP_Candidates.getBestCandidate().usable()) { + return false; + } + if (WiFiEventData.lastDisconnectMoment.isSet() && WiFiEventData.lastDisconnectMoment.millisPassedSince() < WIFI_RECONNECT_WAIT) { + if (!NetworkConnected()) { + return true; + } + } if (WiFiEventData.lastScanMoment.isSet()) { const LongTermTimer::Duration scanInterval = wifiAPmodeActivelyUsed() ? WIFI_SCAN_INTERVAL_AP_USED : WIFI_SCAN_INTERVAL_MINIMAL; if (WiFiEventData.lastScanMoment.millisPassedSince() < scanInterval) { @@ -674,6 +685,7 @@ void WifiScan(bool async, uint8_t channel) { if (!WiFiScanAllowed()) { return; } + START_TIMER; WiFiEventData.lastScanMoment.setNow(); if (loglevelActiveFor(LOG_LEVEL_INFO)) { if (channel == 0) { @@ -710,6 +722,7 @@ void WifiScan(bool async, uint8_t channel) { processScanDone(); } } + STOP_TIMER(async ? WIFI_SCAN_ASYNC : WIFI_SCAN_SYNC); } // ******************************************************************************** diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 4011e62172..57cdff565b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -410,15 +410,14 @@ void processGotIP() { if (WiFiEventData.wifiSetup) { // Wifi setup was active, Apparently these settings work. WiFiEventData.wifiSetup = false; - SaveSettings(); + SaveSecuritySettings(); } - refreshNodeList(); - logConnectionStatus(); - if ((WiFiEventData.WiFiConnected() || WiFi.isConnected()) && hasIPaddr()) { WiFiEventData.processedGotIP = true; WiFiEventData.setWiFiGotIP(); } + refreshNodeList(); + logConnectionStatus(); } // A client disconnected from the AP on this node. @@ -540,12 +539,12 @@ void processScanDone() { WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); #ifdef USES_ESPEASY_NOW - ESPEasy_now_handler.addPeerFromWiFiScan(); - if (use_EspEasy_now) { - if (!WiFiConnected()) { + if (Settings.UseESPEasyNow()) { + ESPEasy_now_handler.addPeerFromWiFiScan(); + if (!NetworkConnected()) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); - if (isESPEasy_now_only() || !ESPEasy_now_handler.active()) { + // if (isESPEasy_now_only() || !ESPEasy_now_handler.active()) { WifiDisconnect(); setAP(false); ESPEasy_now_handler.end(); @@ -556,7 +555,7 @@ void processScanDone() { setSTA(false); setNetworkMedium(Settings.NetworkMedium); NetworkConnectRelaxed(); - } + // } } else { setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); } From 3c1d9c0a0ef60f518ba474f1281354336e7f6d9e Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 19 Apr 2021 11:59:39 +0200 Subject: [PATCH 139/404] [ESPEasy-NOW] Reduce load when not connected to WiFi --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 1be3d38643..13cf4d4044 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -193,7 +193,7 @@ bool WiFiConnected() { //} WiFiEventData.wifiConnectInProgress = false; } - delay(1); + delay(0); STOP_TIMER(WIFI_NOTCONNECTED_STATS); recursiveCall = false; return false; From b084a9075a1717291c736cc37ea03f4b78615fd1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Apr 2021 10:42:54 +0200 Subject: [PATCH 140/404] [Customize Build] Allow to disable Node List columns on root page --- src/Custom-sample.h | 4 ++++ src/src/WebServer/RootPage.cpp | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index c807fbd8ae..9e4e7f2a36 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -194,6 +194,10 @@ #define MAIN_PAGE_SHOW_SYSINFO_BUTTON true #define MAIN_PAGE_SHOW_WiFi_SETUP_BUTTON true #define MAIN_PAGE_SHOW_BASIC_INFO_NOT_LOGGED_IN false + +#define MAIN_PAGE_SHOW_NODE_LIST_BUILD true +#define MAIN_PAGE_SHOW_NODE_LIST_TYPE true + #define SETUP_PAGE_SHOW_CONFIG_BUTTON true diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 9f75cabe05..9ec4df3126 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -44,6 +44,13 @@ #define MAIN_PAGE_SHOW_WiFi_SETUP_BUTTON false #endif +#ifndef MAIN_PAGE_SHOW_NODE_LIST_BUILD + #define MAIN_PAGE_SHOW_NODE_LIST_BUILD true +#endif +#ifndef MAIN_PAGE_SHOW_NODE_LIST_TYPE + #define MAIN_PAGE_SHOW_NODE_LIST_TYPE true +#endif + // ******************************************************************************** // Web Interface root page @@ -274,8 +281,12 @@ void handle_root() { html_TR(); html_table_header(F("Node List")); html_table_header(F("Name")); - html_table_header(getLabel(LabelType::BUILD_DESC)); - html_table_header(F("Type")); + if (MAIN_PAGE_SHOW_NODE_LIST_BUILD) { + html_table_header(getLabel(LabelType::BUILD_DESC)); + } + if (MAIN_PAGE_SHOW_NODE_LIST_TYPE) { + html_table_header(F("Type")); + } html_table_header(F("IP"), 160); // Should fit "255.255.255.255" html_table_header(F("Load")); html_table_header(F("Age (s)")); @@ -309,12 +320,16 @@ void handle_root() { } html_TD(); - if (it->second.build) { - addHtmlInt(it->second.build); + if (MAIN_PAGE_SHOW_NODE_LIST_BUILD) { + if (it->second.build) { + addHtmlInt(it->second.build); + } + html_TD(); + } + if (MAIN_PAGE_SHOW_NODE_LIST_TYPE) { + addHtml(it->second.getNodeTypeDisplayString()); + html_TD(); } - html_TD(); - addHtml(it->second.getNodeTypeDisplayString()); - html_TD(); if (it->second.ip[0] != 0) { html_add_wide_button_prefix(); From f754319c4397e53b36f0a43f7abd73249f735d81 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Apr 2021 11:17:59 +0200 Subject: [PATCH 141/404] [WiFi Setup] Hide password on Setup page ("*****") --- src/src/WebServer/SetupPage.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index d2b4d30f68..9cf4163cd7 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -79,9 +79,12 @@ void handle_setup() { String ssid = web_server.arg(F("ssid")); String other = web_server.arg(F("other")); - String password = web_server.arg(F("pass")); - - bool emptyPass = isFormItemChecked(F("emptypass")); + String password; + bool passwordGiven = getFormPassword(F("pass"), password); + if (passwordGiven) { + passwordGiven = password.length() != 0; + } + const bool emptyPassAllowed = isFormItemChecked(F("emptypass")); const bool performRescan = web_server.hasArg(F("performrescan")); if (performRescan) { WiFiEventData.lastScanMoment.clear(); @@ -99,7 +102,7 @@ void handle_setup() { { if (clearButtonPressed) { addHtmlError(F("Warning: Need to confirm to clear WiFi credentials")); - } else if (password.length() == 0 && !emptyPass) { + } else if (!passwordGiven && !emptyPassAllowed) { addHtmlError(F("No password entered")); } else { safe_strncpy(SecuritySettings.WifiKey, password.c_str(), sizeof(SecuritySettings.WifiKey)); @@ -336,16 +339,7 @@ void handle_setup_scan_and_show(const String& ssid, const String& other, const S html_BR(); - html_TR_TD(); - addHtml(F("Password:")); - html_TD(); - addHtml(F("'); - + addFormPasswordBox(F("Password"), F("pass"), password, 63); addFormCheckBox(F("Allow Empty Password"), F("emptypass"), false); /* From 5a013423f96589000818f2a20c227fc6d05871b4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Apr 2021 11:18:43 +0200 Subject: [PATCH 142/404] [ESPEasy-NOW] Hide ESPEasy-NOW data from nodes table when not enabled --- src/src/WebServer/RootPage.cpp | 48 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 9ec4df3126..00abe8b3a1 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -291,8 +291,10 @@ void handle_root() { html_table_header(F("Load")); html_table_header(F("Age (s)")); #ifdef USES_ESPEASY_NOW - html_table_header(F("Dist")); - html_table_header(F("Peer Info"), 160); + if (Settings.UseESPEasyNow()) { + html_table_header(F("Dist")); + html_table_header(F("Peer Info"), 160); + } #endif for (auto it = Nodes.begin(); it != Nodes.end(); ++it) @@ -356,27 +358,29 @@ void handle_root() { html_TD(); addHtml(String(it->second.getAge()/1000)); // time in seconds #ifdef USES_ESPEASY_NOW - html_TD(); - if (it->second.distance != 255) { - addHtml(String(it->second.distance)); - } - html_TD(); - if (it->second.ESPEasyNowPeer) { - addHtml(String(F(ESPEASY_NOW_NAME)) + F(" ")); - addHtml(it->second.ESPEasy_Now_MAC().toString()); - addHtml(F(" (ch: ")); - addHtml(String(it->second.channel)); - int8_t rssi = it->second.getRSSI(); - if (rssi < 0) { - addHtml(' '); - addHtml(String(rssi)); + if (Settings.UseESPEasyNow()) { + html_TD(); + if (it->second.distance != 255) { + addHtml(String(it->second.distance)); + } + html_TD(); + if (it->second.ESPEasyNowPeer) { + addHtml(String(F(ESPEASY_NOW_NAME)) + F(" ")); + addHtml(it->second.ESPEasy_Now_MAC().toString()); + addHtml(F(" (ch: ")); + addHtml(String(it->second.channel)); + int8_t rssi = it->second.getRSSI(); + if (rssi < 0) { + addHtml(' '); + addHtml(String(rssi)); + } + addHtml(')'); + const ESPEasy_now_traceroute_struct* trace = Nodes.getDiscoveryRoute(it->second.unit); + if (trace != nullptr) { + addHtml(' '); + addHtml(trace->toString()); + } } - addHtml(')'); - const ESPEasy_now_traceroute_struct* trace = Nodes.getDiscoveryRoute(it->second.unit); - if (trace != nullptr) { - addHtml(' '); - addHtml(trace->toString()); - } } #endif } From 9089fe2232d9f204d1710fd9ce262e11116787f4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 22 Apr 2021 12:51:41 +0200 Subject: [PATCH 143/404] [CUL reader] Only keep valid characters in the received sentence --- src/src/PluginStructs/P094_data_struct.cpp | 22 +++++++++++----------- src/src/PluginStructs/P094_data_struct.h | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 15abe8f599..eba0c06213 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -111,19 +111,15 @@ bool P094_data_struct::loop() { case 13: { const size_t length = sentence_part.length(); - bool valid = length > 0; - - for (size_t i = 0; i < length && valid; ++i) { - if ((sentence_part[i] > 127) || (sentence_part[i] < 32)) { - sentence_part = ""; + if (length > 0) { + if (current_sentence_errored) { ++sentences_received_error; - valid = false; + sentence_part = ""; + } else { + fullSentenceReceived = true; } } - - if (valid) { - fullSentenceReceived = true; - } + current_sentence_errored = false; break; } case 10: @@ -131,7 +127,11 @@ bool P094_data_struct::loop() { // Ignore LF break; default: - sentence_part += c; + if (c >= 32 && c < 127) { + sentence_part += c; + } else { + current_sentence_errored = true; + } break; } diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index c2dd9b9702..778633ad73 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -128,6 +128,7 @@ struct P094_data_struct : public PluginTaskData_base { uint16_t max_length = 550; uint32_t sentences_received = 0; uint32_t sentences_received_error = 0; + bool current_sentence_errored = false; uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; uint32_t debug_counter = 0; From cbf5ea6b7879f87f122c069ab6034122379c326d Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 23 Apr 2021 09:35:19 +0200 Subject: [PATCH 144/404] [CUL reader] Reduce memory usage on log + web stats --- src/_P094_CULReader.ino | 23 +++++++++++++++------- src/src/PluginStructs/P094_data_struct.cpp | 6 +++++- src/src/PluginStructs/P094_data_struct.h | 4 +++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index c55a2c45e1..cd95305856 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -219,9 +219,20 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { if (event->String2.length() > 0) { if (Plugin_094_match_all(event->TaskIndex, event->String2)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("CUL Reader: Sending: "); - log += event->String2; - addLog(LOG_LEVEL_INFO, log); + String log; + if (log.reserve(128)) { + log = F("CUL Reader: Sending: "); + const size_t messageLength = event->String2.length(); + if (messageLength < 100) { + log += event->String2; + } else { + // Split string so we get start and end + log += event->String2.substring(0, 40); + log += F("..."); + log += event->String2.substring(messageLength - 40); + } + addLog(LOG_LEVEL_INFO, log); + } } // Filter length options: // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit sending meters, which normaly is a fault) @@ -288,7 +299,7 @@ boolean Plugin_094(byte function, struct EventStruct *event, String& string) { return success; } -bool Plugin_094_match_all(taskIndex_t taskIndex, String& received) +bool Plugin_094_match_all(taskIndex_t taskIndex, const String& received) { P094_data_struct *P094_data = static_cast(getPluginTaskData(taskIndex)); @@ -440,9 +451,7 @@ void P094_html_show_stats(struct EventStruct *event) { } { addRowLabel(F("Current Sentence")); - String sentencePart; - P094_data->getSentence(sentencePart, false); - addHtml(sentencePart); + addHtml(P094_data->peekSentence()); } { diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index eba0c06213..69bd3cd16c 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -146,6 +146,10 @@ bool P094_data_struct::loop() { return fullSentenceReceived; } +const String& P094_data_struct::peekSentence() const { + return sentence_part; +} + void P094_data_struct::getSentence(String& string, bool appendSysTime) { if (appendSysTime) { // Unix timestamp = 10 decimals + separator @@ -239,7 +243,7 @@ bool P094_data_struct::disableFilterWindowActive() const { return false; } -bool P094_data_struct::parsePacket(String& received) const { +bool P094_data_struct::parsePacket(const String& received) const { size_t strlength = received.length(); if (strlength == 0) { diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 778633ad73..736163dce0 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -75,6 +75,8 @@ struct P094_data_struct : public PluginTaskData_base { bool loop(); + const String& peekSentence() const; + void getSentence(String& string, bool appendSysTime); void getSentencesReceived(uint32_t& succes, @@ -104,7 +106,7 @@ struct P094_data_struct : public PluginTaskData_base { bool disableFilterWindowActive() const; - bool parsePacket(String& received) const; + bool parsePacket(const String& received) const; static String MatchType_toString(P094_Match_Type matchType); static String P094_FilterValueType_toString(P094_Filter_Value_Type valueType); From 4a77eba157f14cf1d2ac8b9e815461188f1496d1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 23 Apr 2021 09:36:37 +0200 Subject: [PATCH 145/404] [Memory Usage] Check success memory allocation string type value events --- src/_C001.ino | 7 +++-- src/src/DataStructs/Web_StreamingBuffer.cpp | 3 ++- src/src/ESPEasyCore/ESPEasyRules.cpp | 30 ++++++++++++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/_C001.ino b/src/_C001.ino index 0affffb1d9..be8ce7bcd9 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -57,13 +57,12 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& if (event->idx != 0) { // We now create a URI for the request + const Sensor_VType sensorType = event->getSensorType(); String url; - if (url.reserve(128)) { + const size_t expectedSize = sensorType == Sensor_VType::SENSOR_TYPE_STRING ? 64 + event->String2.length() : 128; + if (url.reserve(expectedSize)) { url = F("/json.htm?type=command¶m="); - const Sensor_VType sensorType = event->getSensorType(); - - switch (sensorType) { case Sensor_VType::SENSOR_TYPE_SWITCH: diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index 5571b035f5..55a75acc4b 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -240,7 +240,8 @@ void Web_StreamingBuffer::sendContentBlocking(String& data) { #endif // if defined(ESP8266) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) sentBytes += length; - data = ""; + data = ""; + data.reserve(CHUNKED_BUFFER_SIZE); delay(0); } diff --git a/src/src/ESPEasyCore/ESPEasyRules.cpp b/src/src/ESPEasyCore/ESPEasyRules.cpp index 98e7185fd0..9099e2490c 100644 --- a/src/src/ESPEasyCore/ESPEasyRules.cpp +++ b/src/src/ESPEasyCore/ESPEasyRules.cpp @@ -1440,7 +1440,35 @@ void createRuleEvents(struct EventStruct *event) { const byte valueCount = getValueCountForTask(event->TaskIndex); - if (Settings.CombineTaskValues_SingleEvent(event->TaskIndex)) { + // Small optimization as sensor type string may result in large strings + // These also only yield a single value, so no need to check for combining task values. + if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { + size_t expectedSize = 2 + getTaskDeviceName(event->TaskIndex).length(); + expectedSize += strlen(ExtraTaskSettings.TaskDeviceValueNames[0]); + + bool appendCompleteStringvalue = false; + String eventString; + + if (eventString.reserve(expectedSize + event->String2.length())) { + appendCompleteStringvalue = true; + } else if (!eventString.reserve(expectedSize + 24)) { + // No need to continue as we can't even allocate the event, we probably also cannot process it + addLog(LOG_LEVEL_ERROR, F("Not enough memory for event")); + return; + } + eventString = getTaskDeviceName(event->TaskIndex); + eventString += F("#"); + eventString += ExtraTaskSettings.TaskDeviceValueNames[0]; + eventString += F("="); + if (appendCompleteStringvalue) { + eventString += event->String2; + } else { + eventString += event->String2.substring(0, 10); + eventString += F("..."); + eventString += event->String2.substring(event->String2.length() - 10); + } + eventQueue.addMove(std::move(eventString)); + } else if (Settings.CombineTaskValues_SingleEvent(event->TaskIndex)) { String eventString; eventString.reserve(128); // Enough for most use cases, prevent lots of memory allocations. eventString = getTaskDeviceName(event->TaskIndex); From 2cdfcd25030022c6651a9786772286cba4216771 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 24 Apr 2021 15:18:07 +0200 Subject: [PATCH 146/404] [CUL Reader] Fix sending received message + timestamp --- src/src/ESPEasyCore/ESPEasyRules.cpp | 2 ++ src/src/PluginStructs/P094_data_struct.cpp | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyRules.cpp b/src/src/ESPEasyCore/ESPEasyRules.cpp index 9099e2490c..8945b6d591 100644 --- a/src/src/ESPEasyCore/ESPEasyRules.cpp +++ b/src/src/ESPEasyCore/ESPEasyRules.cpp @@ -1460,6 +1460,7 @@ void createRuleEvents(struct EventStruct *event) { eventString += F("#"); eventString += ExtraTaskSettings.TaskDeviceValueNames[0]; eventString += F("="); + eventString += '`'; if (appendCompleteStringvalue) { eventString += event->String2; } else { @@ -1467,6 +1468,7 @@ void createRuleEvents(struct EventStruct *event) { eventString += F("..."); eventString += event->String2.substring(event->String2.length() - 10); } + eventString += '`'; eventQueue.addMove(std::move(eventString)); } else if (Settings.CombineTaskValues_SingleEvent(event->TaskIndex)) { String eventString; diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 69bd3cd16c..28d7de6320 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -151,17 +151,16 @@ const String& P094_data_struct::peekSentence() const { } void P094_data_struct::getSentence(String& string, bool appendSysTime) { + string = std::move(sentence_part); + sentence_part = ""; // FIXME TD-er: Should not be needed as move already cleared it. if (appendSysTime) { // Unix timestamp = 10 decimals + separator if (string.reserve(sentence_part.length() + 11)) { - string = sentence_part; string += ';'; string += node_time.getUnixTime(); } - sentence_part = ""; - } else { - string = std::move(sentence_part); } + sentence_part.reserve(string.length()); } void P094_data_struct::getSentencesReceived(uint32_t& succes, uint32_t& error, uint32_t& length_last) const { From 77e9b10ef3ebd394e5b86a17ad1141919f61a77c Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 24 Apr 2021 15:19:21 +0200 Subject: [PATCH 147/404] Change delay(1) into delay(0) to reduce load --- src/src/DataStructs/ControllerSettingsStruct.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 8 +++++++- src/src/Helpers/ESPEasy_Storage.cpp | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index e4a7d26da4..80574ce7b8 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -103,7 +103,7 @@ bool ControllerSettingsStruct::checkHostReachable(bool quick) { if (!NetworkConnected(10)) { return false; // Not connected, so no use in wasting time to connect to a host. } - delay(1); // Make sure the Watchdog will not trigger a reset. + delay(0); // Make sure the Watchdog will not trigger a reset. if (quick && ipSet()) { return true; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 57cdff565b..7939441fe4 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -93,7 +93,7 @@ void handle_unprocessedNetworkEvents() // WiFi connection is not yet available, so introduce some extra delays to // help the background tasks managing wifi connections - delay(1); + delay(0); NetworkConnectRelaxed(); @@ -231,6 +231,9 @@ void processDisconnect() { bool mustRestartWiFi = Settings.WiFiRestart_connection_lost(); + if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { + mustRestartWiFi = true; + } #ifdef USES_ESPEASY_NOW if (use_EspEasy_now) { mustRestartWiFi = true; @@ -238,6 +241,9 @@ void processDisconnect() { #endif if (mustRestartWiFi) { + WifiDisconnect(); // Needed or else node may not reconnect reliably. + delay(100); + setWifiMode(WIFI_OFF); initWiFi(); delay(100); if (WiFiEventData.unprocessedWifiEvents()) { diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index bad4b074d2..f1756d3785 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1184,7 +1184,7 @@ String LoadFromFile(const char *fname, int offset, byte *memAddress, int datasiz addLog(LOG_LEVEL_ERROR, log); return log; } - delay(1); + delay(0); START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadFromFile")); @@ -1196,7 +1196,7 @@ String LoadFromFile(const char *fname, int offset, byte *memAddress, int datasiz f.close(); STOP_TIMER(LOADFILE_STATS); - delay(1); + delay(0); return String(); } From 8afe370e3500d13ad61193ef6d25b8b1b7732344 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 24 Apr 2021 15:20:00 +0200 Subject: [PATCH 148/404] [WiFi] Add copy constructor to WiFi_AP_Candidate class --- src/src/DataStructs/WiFi_AP_Candidate.cpp | 10 ++++++++++ src/src/DataStructs/WiFi_AP_Candidate.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index 47715b652d..b5bced3d6e 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -46,6 +46,16 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { last_seen = millis(); } +WiFi_AP_Candidate::WiFi_AP_Candidate(const WiFi_AP_Candidate& other) +: ssid(other.ssid), key(other.key), last_seen(other.last_seen), + rssi(other.rssi), channel(other.channel), index(other.index), + enc_type(other.enc_type), isHidden(other.isHidden), + lowPriority(other.lowPriority), + isEmergencyFallback(other.isEmergencyFallback) +{ + setBSSID(other.bssid); +} + WiFi_AP_Candidate::WiFi_AP_Candidate() {} bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index bc49353707..f366dafca7 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -16,6 +16,8 @@ struct WiFi_AP_Candidate { // Construct using index from WiFi scan result WiFi_AP_Candidate(uint8_t networkItem); + WiFi_AP_Candidate(const WiFi_AP_Candidate& other); + // Default constructor WiFi_AP_Candidate(); From 7b2fcffa67420e28d320a16736054f329f373d3d Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 24 Apr 2021 15:20:59 +0200 Subject: [PATCH 149/404] [ESPEasy-NOW] Allow scan for WiFi when no traceroute received at all --- src/src/Helpers/ESPEasy_now_handler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index db052e87de..bc9ec464a5 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -200,7 +200,8 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() if (use_EspEasy_now) { const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); - if (traceroute_received_timeout || traceroute_sent_timeout) { + const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(64)) { @@ -364,7 +365,8 @@ bool ESPEasy_now_handler_t::active() const */ const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); - if (traceroute_received_timeout || traceroute_sent_timeout) { + const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(64)) { From c194692c80e4e8a9535654bb2a258b389c5bf515 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 25 Apr 2021 14:03:24 +0200 Subject: [PATCH 150/404] [ESPEasy-NOW] Try one channel at a time when searching for mesh. --- src/src/DataStructs/NodesHandler.cpp | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 52 ++++++++++++++++++++++--- src/src/Helpers/ESPEasy_now_handler.h | 1 + 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index dc6e49f3f3..edf7d9e9f5 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -462,7 +462,9 @@ uint8_t NodesHandler::getESPEasyNOW_channel() const } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { - return preferred->channel; + if (preferred->distance < 255) { + return preferred->channel; + } } return 0; } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index bc9ec464a5..3549f923c2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -33,7 +33,8 @@ # define ESPEASY_NOW_ACTIVITY_TIMEOUT 125000 // 2 minutes + 5 sec -# define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly +# define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly +# define ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT 35000 // Time to wait for announcement packets on a single channel # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" @@ -98,15 +99,25 @@ bool ESPEasy_now_handler_t::begin() } } + _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); + if (_usedWiFiChannel == 0) { + ++_lastScannedChannel; + if (_lastScannedChannel > 14) { + _lastScannedChannel = 1; + } + _usedWiFiChannel = _lastScannedChannel; + if (isESPEasy_now_only()) { + WifiScan(false, _usedWiFiChannel); + } + } + _last_traceroute_sent = 0; _last_traceroute_received = 0; _last_used = millis(); _last_started = millis(); - _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); _controllerIndex = INVALID_CONTROLLER_INDEX; if (isESPEasy_now_only()) { - WifiScan(false, 0); setConnectionSpeed(); } @@ -139,7 +150,6 @@ bool ESPEasy_now_handler_t::begin() ESPEasy_now_peermanager.removeAllPeers(); ESPEasy_now_peermanager.addKnownPeers(); - // FIXME TD-er: Must check in settings if enabled WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); sendDiscoveryAnnounce(); @@ -189,11 +199,41 @@ bool ESPEasy_now_handler_t::loop() void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() { - if (!WifiIsAP(WiFi.getMode()) || _usedWiFiChannel != Nodes.getESPEasyNOW_channel()) { + const uint8_t ESPEasyNOW_channel = Nodes.getESPEasyNOW_channel(); + if (!WifiIsAP(WiFi.getMode()) || _usedWiFiChannel != ESPEasyNOW_channel) { // AP mode may be turned off externally, or WiFi channel may have changed. // If so restart ESPEasy-now handler if (use_EspEasy_now) { - end(); + if (ESPEasyNOW_channel == 0) { + // We need to give it some time to receive announcement messages and maybe even a traceroute + if (timePassedSince(_last_started) > ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(80)) { + log = F(ESPEASY_NOW_NAME); + log += F(": No peers with set distance on channel "); + log += _usedWiFiChannel; + addLog(LOG_LEVEL_INFO, log); + } + } + + end(); + } + } else { + if (_usedWiFiChannel != ESPEasyNOW_channel) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Move to channel "); + log += ESPEasyNOW_channel; + addLog(LOG_LEVEL_INFO, log); + } + } + } + + end(); + } } } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index f3e8d978bb..d1c1e8e232 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -116,6 +116,7 @@ class ESPEasy_now_handler_t { unsigned int _ClientTimeout = 0; uint8_t _usedWiFiChannel = 0; + uint8_t _lastScannedChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; bool _enableESPEasyNowFallback = false; bool _mqtt_retainFlag = false; From 515562960ea79a8f59f906316d94a78b74b04e63 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 26 Apr 2021 02:46:13 +0200 Subject: [PATCH 151/404] [ESPEasy-NOW] Switch WiFi channel when gateway node does --- src/src/DataStructs/NodesHandler.cpp | 28 +++- src/src/DataStructs/NodesHandler.h | 2 + src/src/DataStructs/WiFiEventData.cpp | 4 +- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 15 ++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 12 +- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 125 ++++++++++++------ src/src/Helpers/ESPEasy_now_handler.h | 1 + src/src/WebServer/RootPage.cpp | 4 +- src/src/WebServer/SysInfoPage.cpp | 12 +- 10 files changed, 146 insertions(+), 61 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index edf7d9e9f5..f25000f43e 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -219,6 +219,20 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } } } + +/* + #ifdef USES_ESPEASY_NOW + if (res != nullptr) + { + uint8_t distance_res = 255; + const int successRate_res = getRouteSuccessRate(res->unit, distance_res); + if (distance_res == 255) { + return nullptr; + } + } + #endif +*/ + return res; } @@ -281,7 +295,10 @@ void NodesHandler::updateThisNode() { } } } - thisNode.channel = WiFi.channel(); + thisNode.channel = WiFiEventData.usedChannel; + if (thisNode.channel == 0) { + thisNode.channel = WiFi.channel(); + } thisNode.unit = Settings.Unit; thisNode.build = Settings.Build; @@ -455,19 +472,24 @@ bool NodesHandler::isEndpoint() const return false; } +#ifdef USES_ESPEASY_NOW uint8_t NodesHandler::getESPEasyNOW_channel() const { - if (isEndpoint() == 0) { + if (isEndpoint()) { return WiFi.channel(); } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { - if (preferred->distance < 255) { + uint8_t distance = 255; + getRouteSuccessRate(preferred->unit, distance); + + if (distance < 255) { return preferred->channel; } } return 0; } +#endif bool NodesHandler::recentlyBecameDistanceZero() { if (!_recentlyBecameDistanceZero) { diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 6790660477..8b9ebfaf6c 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -70,7 +70,9 @@ class NodesHandler { bool isEndpoint() const; +#ifdef USES_ESPEASY_NOW uint8_t getESPEasyNOW_channel() const; +#endif bool recentlyBecameDistanceZero(); diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index ea4ef6fc7d..3c2e781525 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -58,6 +58,7 @@ void WiFiEventData_t::clearAll() { processedScanDone = true; processedProbeRequestAPmode = true; wifiConnectAttemptNeeded = true; + wifiConnectInProgress = false; wifi_TX_pwr = 0; usedChannel = 0; } @@ -94,7 +95,8 @@ bool WiFiEventData_t::WiFiServicesInitialized() const { } void WiFiEventData_t::setWiFiDisconnected() { - wifiStatus = ESPEASY_WIFI_DISCONNECTED; + wifiConnectInProgress = false; + wifiStatus = ESPEASY_WIFI_DISCONNECTED; } void WiFiEventData_t::setWiFiGotIP() { diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 579dbe806b..7fe4fc2fbc 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -24,6 +24,13 @@ void setNetworkMedium(NetworkMedium_t new_medium) { if (!Settings.UseESPEasyNow()) { return; } + if (WiFiEventData.unprocessedWifiEvents() || + WiFiEventData.wifiConnectInProgress) { + return; + } + if (WiFiEventData.WiFiServicesInitialized()) { + return; + } if (active_network_medium != NetworkMedium_t::WIFI) { // Only allow to set to ESPEasyNOW_only from WiFi return; @@ -54,7 +61,13 @@ void setNetworkMedium(NetworkMedium_t new_medium) { } break; case NetworkMedium_t::ESPEasyNOW_only: - WiFiEventData.clearAll(); + #ifdef USES_EASPEASY_NOW + if (use_EspEasy_now) { + ESPEasy_now_handler.end(); + } + #endif + + //WiFiEventData.clearAll(); break; case NetworkMedium_t::NotSet: break; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e731055b0f..3d3fcb8c3f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -326,6 +326,10 @@ bool checkAndResetWiFi() { if (WiFi.RSSI() < 0 && NetworkLocalIP().isSet()) { //if (WiFi.channel() == WiFiEventData.usedChannel || WiFiEventData.usedChannel == 0) { // This is a valid status, no need to reset + if (!WiFiEventData.WiFiServicesInitialized()) { + WiFiEventData.setWiFiServicesInitialized(); + } + return false; //} } @@ -647,6 +651,9 @@ void WiFiScanPeriodical() { } bool WiFiScanAllowed() { + if (WiFi_AP_Candidates.scanComplete() == WIFI_SCAN_RUNNING) { + return false; + } if (!WiFiEventData.processedScanDone) { processScanDone(); } @@ -654,6 +661,7 @@ bool WiFiScanAllowed() { handle_unprocessedNetworkEvents(); } if (WiFiEventData.unprocessedWifiEvents()) { + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not allowed, unprocessed WiFi events")); return false; } /* @@ -661,10 +669,8 @@ bool WiFiScanAllowed() { return true; } */ - if (WiFi_AP_Candidates.scanComplete() <= 0) { - return true; - } if (WiFi_AP_Candidates.getBestCandidate().usable()) { + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not needed, good candidate present")); return false; } if (WiFiEventData.lastDisconnectMoment.isSet() && WiFiEventData.lastDisconnectMoment.millisPassedSince() < WIFI_RECONNECT_WAIT) { diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 097628b769..290f6d6b7f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -461,7 +461,7 @@ void processProbeRequestAPmode() { // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery #ifdef USES_ESPEASY_NOW - ESPEasy_now_handler.sendDiscoveryAnnounce(); + ESPEasy_now_handler.sendDiscoveryAnnounce(mac, WiFiEventData.usedChannel); #endif APModeProbeRequestReceived_list.pop_front(); @@ -619,7 +619,7 @@ void markWiFi_services_initialized() { } } WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) - WiFiEventData.setWiFiServicesInitialized(); + setNetworkMedium(NetworkMedium_t::WIFI); CheckRunningServices(); } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 3549f923c2..fccf8e35ec 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -34,7 +34,9 @@ # define ESPEASY_NOW_ACTIVITY_TIMEOUT 125000 // 2 minutes + 5 sec # define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly -# define ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT 35000 // Time to wait for announcement packets on a single channel +# define ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT 5000 // Time to wait for announcement packets on a single channel + +# define ESPEASY_NOW_MAX_CHANNEL 13 # define ESPEASY_NOW_TMP_SSID "ESPEASY_NOW" # define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" @@ -91,24 +93,36 @@ bool ESPEasy_now_handler_t::begin() if (use_EspEasy_now) { return true; } if (WiFi.scanComplete() == WIFI_SCAN_RUNNING || !WiFiEventData.processedScanDone) { return false;} if (WiFiEventData.wifiConnectInProgress) { + /* + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": wifiConnectInProgress"); + addLog(LOG_LEVEL_INFO, log); + } + } +*/ return false; } if (temp_disable_EspEasy_now_timer != 0) { if (!timeOutReached(temp_disable_EspEasy_now_timer)) { return false; + } else { + temp_disable_EspEasy_now_timer = 0; } } _usedWiFiChannel = Nodes.getESPEasyNOW_channel(); if (_usedWiFiChannel == 0) { + _scanChannelsMode = true; ++_lastScannedChannel; - if (_lastScannedChannel > 14) { + if (_lastScannedChannel > ESPEASY_NOW_MAX_CHANNEL) { _lastScannedChannel = 1; } _usedWiFiChannel = _lastScannedChannel; - if (isESPEasy_now_only()) { - WifiScan(false, _usedWiFiChannel); - } + } else { + _scanChannelsMode = false; } _last_traceroute_sent = 0; @@ -152,10 +166,30 @@ bool ESPEasy_now_handler_t::begin() WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); - sendDiscoveryAnnounce(); - use_EspEasy_now = true; addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" enabled")); + + if (_scanChannelsMode) { + WiFiEventData.lastScanMoment.clear(); + } + WifiScan(false, _usedWiFiChannel); + if (_scanChannelsMode) { + // Send discovery announce to all found hidden APs using the current channel + for (auto it = WiFi_AP_Candidates.scanned_begin(); it != WiFi_AP_Candidates.scanned_end(); ++it) { + if (it->isHidden && it->channel == _usedWiFiChannel) { + const MAC_address mac(it->bssid); + sendDiscoveryAnnounce(mac, _usedWiFiChannel); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = String(F(ESPEASY_NOW_NAME)) + F(": Send discovery to "); + log += mac.toString(); + addLog(LOG_LEVEL_INFO, log); + } + } + } + } else { + sendDiscoveryAnnounce(); + } + return true; } @@ -200,7 +234,9 @@ bool ESPEasy_now_handler_t::loop() void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() { const uint8_t ESPEasyNOW_channel = Nodes.getESPEasyNOW_channel(); - if (!WifiIsAP(WiFi.getMode()) || _usedWiFiChannel != ESPEasyNOW_channel) { + const bool channelChanged = _usedWiFiChannel != ESPEasyNOW_channel; + + if (!WifiIsAP(WiFi.getMode()) || (channelChanged && !Nodes.isEndpoint())) { // AP mode may be turned off externally, or WiFi channel may have changed. // If so restart ESPEasy-now handler if (use_EspEasy_now) { @@ -211,7 +247,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() String log; if (log.reserve(80)) { log = F(ESPEASY_NOW_NAME); - log += F(": No peers with set distance on channel "); + log += F(": No peers with distance set on channel "); log += _usedWiFiChannel; addLog(LOG_LEVEL_INFO, log); } @@ -220,7 +256,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() end(); } } else { - if (_usedWiFiChannel != ESPEasyNOW_channel) { + if (channelChanged) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(64)) { @@ -238,43 +274,33 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() } if (use_EspEasy_now) { - const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); - const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); - const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); - if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(64)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Inactive due to not receiving trace routes"); - addLog(LOG_LEVEL_INFO, log); + if (!Nodes.isEndpoint()) { + const bool traceroute_received_timeout = _last_traceroute_received != 0 && (timePassedSince(_last_traceroute_received) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); + const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); + if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(64)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Inactive due to not receiving trace routes"); + addLog(LOG_LEVEL_INFO, log); + } } + end(); + temp_disable_EspEasy_now_timer = millis() + 10000; + WifiScan(true); + return; } - end(); - temp_disable_EspEasy_now_timer = millis() + 10000; - WifiScan(true); - return; } } - if (temp_disable_EspEasy_now_timer != 0) { - if (timeOutReached(temp_disable_EspEasy_now_timer)) { - if (begin()) { - temp_disable_EspEasy_now_timer = 0; - } + if (Settings.UseESPEasyNow() != use_EspEasy_now) { + if (!use_EspEasy_now) { + begin(); } else { - if (use_EspEasy_now) { - end(); - } - } - } else { - if (Settings.UseESPEasyNow() != use_EspEasy_now) { - if (!use_EspEasy_now) { - begin(); - } else { - end(); - } + end(); } } } @@ -601,7 +627,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch const unsigned long start = millis(); // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. - for (int ch = 1; ch < 11; ++ch) { + for (int ch = 1; ch < ESPEASY_NOW_MAX_CHANNEL; ++ch) { msg.send(mac, ch); delay(0); } @@ -701,6 +727,21 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m } } + if (received.distance == 255 && Nodes.isEndpoint()) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + if (log.reserve(80)) { + log = F(ESPEASY_NOW_NAME); + log += F(": Send announce back to unit: "); + log += String(received.unit); + addLog(LOG_LEVEL_INFO, log); + } + } + + sendDiscoveryAnnounce(received.ESPEasy_Now_MAC(), received.channel); + sendTraceRoute(); + } + const uint8_t new_distance = Nodes.getDistance(); if (new_distance != cur_distance || isNewNode) { if (new_distance == 0) { @@ -763,7 +804,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy const unsigned long start = millis(); // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. - for (int ch = 1; ch < 11; ++ch) { + for (int ch = 1; ch < ESPEASY_NOW_MAX_CHANNEL; ++ch) { msg.send(mac, ch); delay(0); } diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index d1c1e8e232..15f5e70e49 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -118,6 +118,7 @@ class ESPEasy_now_handler_t { uint8_t _usedWiFiChannel = 0; uint8_t _lastScannedChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; + bool _scanChannelsMode = true; bool _enableESPEasyNowFallback = false; bool _mqtt_retainFlag = false; diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index e62ad23f4b..fa607d0923 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -199,9 +199,7 @@ void handle_root() { addRowLabelValue(LabelType::ETH_WIFI_MODE); #endif - if ( - active_network_medium == NetworkMedium_t::WIFI && - NetworkConnected()) + if (!WiFiEventData.WiFiDisconnected()) { addRowLabelValue(LabelType::IP_ADDRESS); addRowLabel(LabelType::WIFI_RSSI); diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 3e738856c7..cb77117af8 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -17,6 +17,7 @@ #include "../Globals/CRCValues.h" #include "../Globals/ESPEasy_time.h" +#include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" #include "../Globals/RTC.h" @@ -402,9 +403,9 @@ void handle_sysinfo_Ethernet() { void handle_sysinfo_Network() { addTableSeparator(F("Network"), 2, 3); - # ifdef HAS_ETHERNET + # if defined(HAS_ETHERNET) || defined(USES_ESPEASY_NOW) addRowLabelValue(LabelType::ETH_WIFI_MODE); - # endif // ifdef HAS_ETHERNET + # endif addRowLabelValue(LabelType::IP_CONFIG); addRowLabelValue(LabelType::IP_ADDRESS_SUBNET); @@ -417,11 +418,10 @@ void handle_sysinfo_Network() { addTableSeparator(F("WiFi"), 2, 3, F("Wifi")); - const bool showWiFiConnectionInfo = - active_network_medium == NetworkMedium_t::WIFI && - NetworkConnected(); + const bool showWiFiConnectionInfo = !WiFiEventData.WiFiDisconnected(); - addRowLabel(F("Wifi Connection")); + + addRowLabel(LabelType::WIFI_CONNECTION); if (showWiFiConnectionInfo) { String html; From 5fc08dd86573cf46dcd4b6df30df99776007cdb0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 29 Apr 2021 20:29:16 +0200 Subject: [PATCH 152/404] [ESPEasy-NOW] Fix interoperability between ESP32/ESP8266 A node may sometimes receive an ESP-NOW message on a different channel, but sending back a reply may get lost if the sender is on a different channel. No idea why this does happen, but it may happen especially when searching for the channel other nodes are using. If a node sends out an announcement of itself on channel 2, while the (receiving) gateway node is on channel 1, the gateway node may receive the announcement and since the announcement states the node does not (yet) have a distance, the gateway node may help that searching node by sending an announcement back including a traceroute. By sending that traceroute specific to that searching node, on the channel stated by that node, the searching node does know what would be the best channel to use and restart the mesh layer on that channel. --- src/src/DataStructs/NodesHandler.cpp | 4 ++-- src/src/Helpers/ESPEasy_now_handler.cpp | 27 +++++++++++++++++++++---- src/src/Helpers/Networking.cpp | 7 ++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index f25000f43e..1b6640b45a 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -463,11 +463,11 @@ bool NodesHandler::isEndpoint() const if (validControllerIndex(enabledMqttController)) { // FIXME TD-er: Must call updateMQTTclient_connected() and see what effect // the MQTTclient_connected state has when using ESPEasy-NOW. - return MQTTclient.connected(); + return MQTTclient_connected; } #endif - if (!WiFiConnected()) return false; + if (!NetworkConnected()) return false; return false; } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index fccf8e35ec..4f4da304fa 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -172,8 +172,9 @@ bool ESPEasy_now_handler_t::begin() if (_scanChannelsMode) { WiFiEventData.lastScanMoment.clear(); } - WifiScan(false, _usedWiFiChannel); + if (_scanChannelsMode) { + WifiScan(false, _usedWiFiChannel); // Send discovery announce to all found hidden APs using the current channel for (auto it = WiFi_AP_Candidates.scanned_begin(); it != WiFi_AP_Candidates.scanned_end(); ++it) { if (it->isHidden && it->channel == _usedWiFiChannel) { @@ -739,7 +740,15 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m } sendDiscoveryAnnounce(received.ESPEasy_Now_MAC(), received.channel); - sendTraceRoute(); + { + if (Nodes.isEndpoint()) { + ESPEasy_now_traceroute_struct thisTraceRoute; + thisTraceRoute.addUnit(Settings.Unit); + // Since we're the end node, claim highest success rate + thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); + sendTraceRoute(received.ESPEasy_Now_MAC(), thisTraceRoute, received.channel); + } + } } const uint8_t new_distance = Nodes.getDistance(); @@ -761,12 +770,18 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m // ************************************************************* void ESPEasy_now_handler_t::sendTraceRoute() { - if (Nodes.getDistance() == 0) { + if (Nodes.isEndpoint()) { ESPEasy_now_traceroute_struct thisTraceRoute; thisTraceRoute.addUnit(Settings.Unit); // Since we're the end node, claim highest success rate thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); - sendTraceRoute(thisTraceRoute); + + int channel = WiFiEventData.usedChannel; + if (channel == 0) { + channel = WiFi.channel(); + } + + sendTraceRoute(thisTraceRoute, channel); _last_traceroute_sent = millis(); } } @@ -793,9 +808,11 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::TraceRoute, len); if (sizeof(uint8_t) != msg.addBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t))) { + addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute error adding route size"));; return; } if (traceroute_size != msg.addBinaryData(traceroute_data, traceroute_size)) { + addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute error adding trace route"));; return; } if (channel < 0) { @@ -815,6 +832,8 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy addLog(LOG_LEVEL_INFO, log); } } else { + addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute ") + traceRoute.toString() + F(" ch: ") + String(channel)); + msg.send(mac, channel); } } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 5424c0f653..9f60d89f38 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -407,7 +407,12 @@ void refreshNodeList() Nodes.refreshNodeList(max_age_allowed, max_age); #ifdef USES_ESPEASY_NOW - WifiScan(true, Nodes.getESPEasyNOW_channel()); + #ifdef ESP8266 + // FIXME TD-er: Do not perform regular scans on ESP32 as long as we cannot scan per channel + if (!Nodes.isEndpoint()) { + WifiScan(true, Nodes.getESPEasyNOW_channel()); + } + #endif #endif if (max_age > (0.75 * max_age_allowed)) { From 6c3e78f73ff4f700e85fe746376c3205e469da77 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 30 Apr 2021 16:04:25 +0200 Subject: [PATCH 153/404] [ESPEasy-NOW] Allow preferred node without a traceroute, but with distance This is needed for nodes far away from a gateway node to find the correct channel to connect to. --- src/src/DataStructs/NodesHandler.cpp | 20 ++++++++++++++------ src/src/Helpers/ESPEasy_now_handler.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 1b6640b45a..a0c6f9df4e 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -195,8 +195,19 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& const int successRate_new = getRouteSuccessRate(it->second.unit, distance_new); const int successRate_res = getRouteSuccessRate(res->unit, distance_res); + if (successRate_new == 0 || successRate_res == 0) { + // One of the nodes does not (yet) have a route. + if (successRate_new == 0 && successRate_res == 0) { + distance_new = it->second.distance; + distance_res = res->distance; + } else if (successRate_res == 0) { + // The new one has a route, so must set the new one. + mustSet = true; + } + } + if (distance_new == distance_res) { - if (successRate_new > successRate_res) { + if (successRate_new > successRate_res && distance_new < 255) { mustSet = true; } } else if (distance_new < distance_res) { @@ -210,7 +221,7 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } if (mustSet) { #ifdef USES_ESPEASY_NOW - if (it->second.ESPEasyNowPeer && hasTraceRoute(it->second.unit)) { + if (it->second.ESPEasyNowPeer) { res = &(it->second); } #else @@ -480,10 +491,7 @@ uint8_t NodesHandler::getESPEasyNOW_channel() const } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { - uint8_t distance = 255; - getRouteSuccessRate(preferred->unit, distance); - - if (distance < 255) { + if (preferred->distance < 255) { return preferred->channel; } } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4f4da304fa..75e3d59d73 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -728,7 +728,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m } } - if (received.distance == 255 && Nodes.isEndpoint()) { + if (received.distance == 255 && Nodes.getDistance() < 255) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(80)) { From 2707331abae4ebd712cf55babbcdc65ffcd7201c Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 3 May 2021 17:22:58 +0200 Subject: [PATCH 154/404] [Controllers] Optimize memory usage by using std::move Controllers now use the move operator where possible to prevent memory allocation when a move is possible. Also started implementation of checking for message count per unit to see if we received the exact message twice. --- src/_C001.ino | 2 +- src/_C002.ino | 3 +- src/_C003.ino | 2 +- src/_C004.ino | 2 +- src/_C005.ino | 12 +++-- src/_C007.ino | 2 +- src/_C008.ino | 4 +- src/_C009.ino | 4 +- src/_C010.ino | 4 +- src/_C011.ino | 2 +- src/_C012.ino | 4 +- src/_C015.ino | 4 +- src/_C016.ino | 2 +- src/_C017.ino | 3 +- src/_C018.ino | 2 +- src/_C019.ino | 2 +- src/src/ControllerQueue/C011_queue_element.h | 2 + src/src/ControllerQueue/C015_queue_element.h | 2 + src/src/ControllerQueue/C016_queue_element.h | 2 + src/src/ControllerQueue/C018_queue_element.h | 2 + src/src/ControllerQueue/C019_queue_element.h | 2 + .../ControllerDelayHandlerStruct.h | 42 ++++++++-------- .../ControllerQueue/MQTT_queue_element.cpp | 27 +++++++--- src/src/ControllerQueue/MQTT_queue_element.h | 10 ++++ .../SimpleQueueElement_string_only.cpp | 4 +- .../SimpleQueueElement_string_only.h | 4 +- .../queue_element_formatted_uservar.h | 2 + .../queue_element_single_value_base.h | 2 + src/src/DataStructs/ESPEasy_now_merger.cpp | 4 +- src/src/DataStructs/UnitMessageCount.cpp | 16 ++++++ src/src/DataStructs/UnitMessageCount.h | 30 +++++++++++ src/src/ESPEasyCore/Controller.cpp | 50 +++++++++++++------ src/src/ESPEasyCore/Controller.h | 3 ++ 33 files changed, 189 insertions(+), 69 deletions(-) create mode 100644 src/src/DataStructs/UnitMessageCount.cpp create mode 100644 src/src/DataStructs/UnitMessageCount.h diff --git a/src/_C001.ino b/src/_C001.ino index be8ce7bcd9..fe3050b614 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -111,7 +111,7 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& url += mapVccToDomoticz(); # endif // if FEATURE_ADC_VCC - success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, event->TaskIndex, url)); + success = C001_DelayHandler->addToQueue(std::move(C001_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url)))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C001_DELAY_QUEUE, C001_DelayHandler->getNextScheduleTime()); } diff --git a/src/_C002.ino b/src/_C002.ino index a53adf66b6..41a56de9bb 100644 --- a/src/_C002.ino +++ b/src/_C002.ino @@ -267,7 +267,8 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& String pubname = CPlugin_002_pubname; parseControllerVariables(pubname, event, false); - success = MQTTpublish(event->ControllerIndex, event->TaskIndex, pubname.c_str(), json.c_str(), CPlugin_002_mqtt_retainFlag); + // Publish using move operator, thus pubname and json are empty after this call + success = MQTTpublish(event->ControllerIndex, event->TaskIndex, std::move(pubname), std::move(json), CPlugin_002_mqtt_retainFlag); } // if ixd !=0 else { diff --git a/src/_C003.ino b/src/_C003.ino index f0455b9cf5..d9bb7e07b4 100644 --- a/src/_C003.ino +++ b/src/_C003.ino @@ -56,7 +56,7 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& url += ","; url += formatUserVarNoCheck(event, 0); url += "\n"; - success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, event->TaskIndex, url)); + success = C003_DelayHandler->addToQueue(std::move(C003_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url)))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C004.ino b/src/_C004.ino index 0e14d9c628..46cef34251 100644 --- a/src/_C004.ino +++ b/src/_C004.ino @@ -67,7 +67,7 @@ bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& if (C004_DelayHandler == nullptr) { break; } - success = C004_DelayHandler->addToQueue(C004_queue_element(event)); + success = C004_DelayHandler->addToQueue(std::move(C004_queue_element(event))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C004_DELAY_QUEUE, C004_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C005.ino b/src/_C005.ino index baf1dcd556..0af8059827 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -149,14 +149,10 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& String tmppubname = pubname; parseSingleControllerVariable(tmppubname, event, x, false); String value; - - // Small optimization so we don't try to copy potentially large strings if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { - MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); value = event->String2.substring(0, 20); // For the log } else { value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); } # ifndef BUILD_NO_DEBUG @@ -168,6 +164,14 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_DEBUG, log); } # endif // ifndef BUILD_NO_DEBUG + + // Small optimization so we don't try to copy potentially large strings + if (event->sensorType == Sensor_VType::SENSOR_TYPE_STRING) { + MQTTpublish(event->ControllerIndex, event->TaskIndex, tmppubname.c_str(), event->String2.c_str(), mqtt_retainFlag); + } else { + // Publish using move operator, thus tmppubname and value are empty after this call + MQTTpublish(event->ControllerIndex, event->TaskIndex, std::move(tmppubname), std::move(value), mqtt_retainFlag); + } } break; } diff --git a/src/_C007.ino b/src/_C007.ino index 3cd69456c1..f0d95e52e4 100644 --- a/src/_C007.ino +++ b/src/_C007.ino @@ -63,7 +63,7 @@ bool CPlugin_007(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_ERROR, F("emoncms : Unknown sensortype or too many sensor values")); break; } - success = C007_DelayHandler->addToQueue(C007_queue_element(event)); + success = C007_DelayHandler->addToQueue(std::move(C007_queue_element(event))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C007_DELAY_QUEUE, C007_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C008.ino b/src/_C008.ino index 7fb460b1f6..9e095a38c6 100644 --- a/src/_C008.ino +++ b/src/_C008.ino @@ -74,9 +74,9 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& pubname = ControllerSettings.Publish; } - // FIXME TD-er must define a proper move operator + byte valueCount = getValueCountForTask(event->TaskIndex); - success = C008_DelayHandler->addToQueue(C008_queue_element(event, valueCount)); + success = C008_DelayHandler->addToQueue(std::move(C008_queue_element(event, valueCount))); if (success) { // Element was added. diff --git a/src/_C009.ino b/src/_C009.ino index 48d14016bc..ae6161adc9 100644 --- a/src/_C009.ino +++ b/src/_C009.ino @@ -76,8 +76,8 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& break; } - // FIXME TD-er must define a proper move operator - success = C009_DelayHandler->addToQueue(C009_queue_element(event)); + + success = C009_DelayHandler->addToQueue(std::move(C009_queue_element(event))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C010.ino b/src/_C010.ino index 7cff1d73fa..b840180442 100644 --- a/src/_C010.ino +++ b/src/_C010.ino @@ -95,8 +95,8 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& } } - // FIXME TD-er must define a proper move operator - success = C010_DelayHandler->addToQueue(C010_queue_element(element)); + + success = C010_DelayHandler->addToQueue(std::move(element)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C010_DELAY_QUEUE, C010_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C011.ino b/src/_C011.ino index c8d9ef138d..c5b5bc52bb 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -237,7 +237,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) LoadTaskSettings(event->TaskIndex); // Add a new element to the queue with the minimal payload - bool success = C011_DelayHandler->addToQueue(C011_queue_element(event)); + bool success = C011_DelayHandler->addToQueue(std::move(C011_queue_element(event))); if (success) { // Element was added. diff --git a/src/_C012.ino b/src/_C012.ino index 0749d9a66c..6f27198008 100644 --- a/src/_C012.ino +++ b/src/_C012.ino @@ -74,8 +74,8 @@ bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& } } - // FIXME TD-er must define a proper move operator - success = C012_DelayHandler->addToQueue(C012_queue_element(element)); + + success = C012_DelayHandler->addToQueue(std::move(element)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C012_DELAY_QUEUE, C012_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C015.ino b/src/_C015.ino index cb21f63304..8ce36108a0 100644 --- a/src/_C015.ino +++ b/src/_C015.ino @@ -167,8 +167,8 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& // Collect the values at the same run, to make sure all are from the same sample byte valueCount = getValueCountForTask(event->TaskIndex); - // FIXME TD-er must define a proper move operator - success = C015_DelayHandler->addToQueue(C015_queue_element(event, valueCount)); + + success = C015_DelayHandler->addToQueue(std::move(C015_queue_element(event, valueCount))); if (success) { // Element was added. diff --git a/src/_C016.ino b/src/_C016.ino index a4cd949287..758c8d40c0 100644 --- a/src/_C016.ino +++ b/src/_C016.ino @@ -108,7 +108,7 @@ bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& MakeControllerSettings(ControllerSettings); LoadControllerSettings(event->ControllerIndex, ControllerSettings); - success = C016_DelayHandler->addToQueue(element); + success = C016_DelayHandler->addToQueue(std::move(element)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C016_DELAY_QUEUE, C016_DelayHandler->getNextScheduleTime()); */ diff --git a/src/_C017.ino b/src/_C017.ino index dd8938f088..01502b1b3e 100644 --- a/src/_C017.ino +++ b/src/_C017.ino @@ -64,8 +64,7 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String& break; } - // FIXME TD-er must define a proper move operator - success = C017_DelayHandler->addToQueue(C017_queue_element(event)); + success = C017_DelayHandler->addToQueue(std::move(C017_queue_element(event))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C017_DELAY_QUEUE, C017_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C018.ino b/src/_C018.ino index 01f850051d..a34593281d 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -745,7 +745,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& if (C018_data != nullptr) { success = C018_DelayHandler->addToQueue( - C018_queue_element(event, C018_data->getSampleSetCount(event->TaskIndex))); + std::move(C018_queue_element(event, C018_data->getSampleSetCount(event->TaskIndex)))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C018_DELAY_QUEUE, C018_DelayHandler->getNextScheduleTime()); diff --git a/src/_C019.ino b/src/_C019.ino index 4b124e4e59..d1f43b229e 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -63,7 +63,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - success = C019_DelayHandler->addToQueue(C019_queue_element(event)); + success = C019_DelayHandler->addToQueue(std::move(C019_queue_element(event))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C019_DELAY_QUEUE, C019_DelayHandler->getNextScheduleTime()); break; diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index e348c6d4af..06c6c126a7 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -35,6 +36,7 @@ class C011_queue_element { taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; + UnitMessageCount_t UnitMessageCount; }; #endif //USES_C011 diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index 0bcb070256..00cbef1b01 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -36,6 +37,7 @@ class C015_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() byte valueCount = 0; + UnitMessageCount_t UnitMessageCount; }; #endif //USES_C015 diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 132189bdc4..d377b5385c 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/Plugins.h" struct EventStruct; @@ -36,6 +37,7 @@ class C016_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; byte valueCount = 0; + UnitMessageCount_t UnitMessageCount; }; #endif //USES_C016 diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 29d2d4f9eb..d0c3e2f36f 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" @@ -31,6 +32,7 @@ class C018_queue_element { unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; + UnitMessageCount_t UnitMessageCount; }; #endif //USES_C018 diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 0be765b23b..672483da08 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/ESPEasy_EventStruct.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" @@ -32,6 +33,7 @@ class C019_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; EventStruct event; + UnitMessageCount_t UnitMessageCount; }; // #endif //USES_C019 diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index ddfaac975c..0b38b6beaf 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -3,6 +3,7 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../DataStructs/TimingStats.h" +#include "../DataStructs/UnitMessageCount.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/CPlugins.h" #include "../Globals/ESPEasy_Scheduler.h" @@ -103,15 +104,23 @@ struct ControllerDelayHandlerStruct { return true; } - // Return true if last element was removed - bool removeLastIfDuplicate() { + // Return true if message is already present in the queue + bool isDuplicate(const T& element) const { + // Some controllers may receive duplicate messages, due to lost acknowledgement + // This is actually the same message, so this should not be processed. + if (!unitLastMessageCount.isNew(element.UnitMessageCount)) { + return true; + } + // The unit message count is still stored to make sure a new one with the same count + // is considered a duplicate, even when the queue is empty. + unitLastMessageCount.add(element.UnitMessageCount); + + // the setting 'deduplicate' does look at the content of the message and only compares it to messages in the queue. if (deduplicate && !sendQueue.empty()) { - auto back = sendQueue.back(); // Use reverse iterator here, as it is more likely a duplicate is added shortly after another. auto it = sendQueue.rbegin(); // Same as back() - ++it; // The last element before back() for (; it != sendQueue.rend(); ++it) { - if (back.isDuplicate(*it)) { + if (element.isDuplicate(*it)) { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { const cpluginID_t cpluginID = getCPluginID_from_ControllerIndex(it->controller_idx); @@ -120,8 +129,6 @@ struct ControllerDelayHandlerStruct { addLog(LOG_LEVEL_DEBUG, log); } #endif // ifndef BUILD_NO_DEBUG - - sendQueue.pop_back(); return true; } } @@ -130,8 +137,12 @@ struct ControllerDelayHandlerStruct { } // Try to add to the queue, if permitted by "delete_oldest" - // Return false when no item was added. - bool addToQueue(T&& element, bool checkDuplicate = true) { + // Return true when item was added, or skipped as it was considered a duplicate + bool addToQueue(T&& element) { + if (isDuplicate(element)) { + return true; + } + if (delete_oldest) { // Force add to the queue. // If max buffer is reached, the oldest in the queue (first to be served) will be removed. @@ -139,20 +150,10 @@ struct ControllerDelayHandlerStruct { sendQueue.pop_front(); attempt = 0; } - sendQueue.emplace_back(element); - if (checkDuplicate) { - // If message is already present consider adding to be a success. - removeLastIfDuplicate(); - } - return true; } if (!queueFull(element)) { - sendQueue.emplace_back(element); - if (checkDuplicate) { - // If message is already present consider adding to be a success. - removeLastIfDuplicate(); - } + sendQueue.push_back(element); return true; } #ifndef BUILD_NO_DEBUG @@ -239,6 +240,7 @@ struct ControllerDelayHandlerStruct { } std::list sendQueue; + mutable UnitLastMessageCount_map unitLastMessageCount; unsigned long lastSend; unsigned int minTimeBetweenMessages; unsigned long expire_timeout = 0; diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index f5c4fbc2f4..b0d575accc 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -8,12 +8,18 @@ MQTT_queue_element::MQTT_queue_element(int ctrl_idx, const String& topic, const String& payload, bool retained) : _topic(topic), _payload(payload), TaskIndex(TaskIndex), controller_idx(ctrl_idx), _retained(retained) { - // some parts of the topic may have been replaced by empty strings, - // or "/status" may have been appended to a topic ending with a "/" - // Get rid of "//" - while (_topic.indexOf(F("//")) != -1) { - _topic.replace(F("//"), F("/")); - } + removeEmptyTopics(); +} + +MQTT_queue_element::MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, + String&& topic, + String&& payload, + bool retained) + : + _topic(std::move(topic)), _payload(std::move(payload)), TaskIndex(TaskIndex), controller_idx(ctrl_idx), _retained(retained) +{ + removeEmptyTopics(); } size_t MQTT_queue_element::getSize() const { @@ -35,3 +41,12 @@ bool MQTT_queue_element::isDuplicate(const MQTT_queue_element& other) const { } return true; } + +void MQTT_queue_element::removeEmptyTopics() { + // some parts of the topic may have been replaced by empty strings, + // or "/status" may have been appended to a topic ending with a "/" + // Get rid of "//" + while (_topic.indexOf(F("//")) != -1) { + _topic.replace(F("//"), F("/")); + } +} \ No newline at end of file diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index e59cf658ca..8d488dbb8f 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -2,6 +2,7 @@ #define CONTROLLERQUEUE_MQTT_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" @@ -19,16 +20,25 @@ class MQTT_queue_element { const String& payload, bool retained); + explicit MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, + String&& topic, + String&& payload, + bool retained); + size_t getSize() const; bool isDuplicate(const MQTT_queue_element& other) const; + void removeEmptyTopics(); + String _topic; String _payload; unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; bool _retained = false; + UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp index 0bfab48a52..dccbebe887 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp @@ -2,8 +2,8 @@ simple_queue_element_string_only::simple_queue_element_string_only() {} -simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, const String& req) : - txt(req), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} +simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, String&& req) : + txt(std::move(req)), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} size_t simple_queue_element_string_only::getSize() const { return sizeof(*this) + txt.length(); diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 68763fb7f7..39ed7f9b5d 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -2,6 +2,7 @@ #define CONTROLLERQUEUE_SIMPLE_QUEUE_ELEMENT_STRING_ONLY_H #include "../../ESPEasy_common.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" @@ -15,7 +16,7 @@ class simple_queue_element_string_only { explicit simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, - const String& req); + String&& req); size_t getSize() const; @@ -26,6 +27,7 @@ class simple_queue_element_string_only { unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; + UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index b900df5831..863406d46c 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../DataStructs/DeviceStruct.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -30,6 +31,7 @@ class queue_element_formatted_uservar { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; byte valueCount = 0; + UnitMessageCount_t UnitMessageCount; }; #endif // CONTROLLERQUEUE_QUEUE_ELEMENT_FORMATTED_USERVAR_H diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 683f79b841..2c464d7aa2 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -36,6 +37,7 @@ class queue_element_single_value_base { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() byte valueCount = 0; + UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 1a5bb590bb..7f75afca60 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -149,7 +149,9 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const if (stringLength == 0) { return false; } - string.reserve(stringLength); + if (!string.reserve(stringLength)) { + return false; + } } const size_t bufsize = 128; diff --git a/src/src/DataStructs/UnitMessageCount.cpp b/src/src/DataStructs/UnitMessageCount.cpp new file mode 100644 index 0000000000..59dd4452ac --- /dev/null +++ b/src/src/DataStructs/UnitMessageCount.cpp @@ -0,0 +1,16 @@ +#include "../DataStructs/UnitMessageCount.h" + +bool UnitLastMessageCount_map::isNew(const UnitMessageCount_t& count) const { + auto it = _map.find(count.unit); + + if (it != _map.end()) { + return it->second != count.count; + } + return true; +} + +void UnitLastMessageCount_map::add(const UnitMessageCount_t& count) { + if ((count.unit != 0) && (count.unit != 255)) { + _map[count.unit] = count.count; + } +} diff --git a/src/src/DataStructs/UnitMessageCount.h b/src/src/DataStructs/UnitMessageCount.h new file mode 100644 index 0000000000..8fb6f11106 --- /dev/null +++ b/src/src/DataStructs/UnitMessageCount.h @@ -0,0 +1,30 @@ +#ifndef DATASTRUCTS_UNITMESSAGECOUNT_H +#define DATASTRUCTS_UNITMESSAGECOUNT_H + +#include "../../ESPEasy_common.h" + +#include + +// For deduplication, some controllers may add a unit ID and current counter. +// This count will wrap around, so it is just to detect if a message is received multiple times. +// The unit ID is the unit where the message originates from and thus should be kept along when forwarding. +struct UnitMessageCount_t { + UnitMessageCount_t() {} + + UnitMessageCount_t(byte unitnr, byte messageCount) : unit(unitnr), count(messageCount) {} + + byte unit = 0; // Initialize to "not set" + byte count = 0; +}; + +struct UnitLastMessageCount_map { + bool isNew(const UnitMessageCount_t& count) const; + + void add(const UnitMessageCount_t& count); + +private: + + std::map_map; +}; + +#endif // ifndef DATASTRUCTS_UNITMESSAGECOUNT_H diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 2fe73906e3..108fd13d52 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -524,20 +524,28 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes bool success = false; if (!MQTT_queueFull(controller_idx)) { - success = MQTTDelayHandler->addToQueue(MQTT_queue_element(), false); - if (success) { + { + MQTT_queue_element element; size_t pos = 0; - MQTTDelayHandler->sendQueue.back().controller_idx = controller_idx; - MQTTDelayHandler->sendQueue.back()._retained = retained; - message.getString(MQTTDelayHandler->sendQueue.back()._topic, pos); - message.getString(MQTTDelayHandler->sendQueue.back()._payload, pos); - // Check to see if it was successful. - size_t payloadSize = message.getPayloadSize(); - if ((MQTTDelayHandler->sendQueue.back()._topic.length() + MQTTDelayHandler->sendQueue.back()._payload.length() + 2) < payloadSize) { - success = false; - MQTTDelayHandler->sendQueue.pop_back(); - } else { - MQTTDelayHandler->removeLastIfDuplicate(); + element.controller_idx = controller_idx; + element._retained = retained; + const size_t payloadSize = message.getPayloadSize(); + if (message.getString(element._topic, pos) && message.getString(element._payload, pos)) { + success = true; + const size_t bytesLeft = payloadSize - pos; + if (bytesLeft >= 2) { + // There is some UnitMessageCount left + if (!(message.getBinaryData(&element.UnitMessageCount.unit, 1, pos) == 1 && + message.getBinaryData(&element.UnitMessageCount.count, 1, pos) == 1)) + { + // Whatever may have been present, it could not be loaded, so clear just to be sure. + element.UnitMessageCount.unit = 0; + element.UnitMessageCount.count = 0; + } + } + } + if (success) { + success = MQTTDelayHandler->addToQueue(std::move(element)); } } } @@ -556,7 +564,21 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const if (MQTT_queueFull(controller_idx)) { return false; } - const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained)); + const bool success = MQTTDelayHandler->addToQueue(std::move(MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained))); + + scheduleNextMQTTdelayQueue(); + return success; +} + +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, String&& topic, String&& payload, bool retained) { + if (MQTTDelayHandler == nullptr) { + return false; + } + + if (MQTT_queueFull(controller_idx)) { + return false; + } + const bool success = MQTTDelayHandler->addToQueue(std::move(MQTT_queue_element(controller_idx, taskIndex, std::move(topic), std::move(payload), retained))); scheduleNextMQTTdelayQueue(); return success; diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 38d02ed242..1459cd4dcd 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -76,6 +76,9 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained); +// Publish using the move operator for topic and message +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, String&& topic, String&& payload, bool retained); + /*********************************************************************************************\ * Send status info back to channel where request came from From e49d45da0b7b9485e364a843f6c322c6e01ed972 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 3 May 2021 20:24:55 +0200 Subject: [PATCH 155/404] [Controller] Do not keep unitMessageCount as member when not needed --- src/src/ControllerQueue/C011_queue_element.h | 3 ++- src/src/ControllerQueue/C015_queue_element.h | 3 ++- src/src/ControllerQueue/C016_queue_element.cpp | 1 + src/src/ControllerQueue/C016_queue_element.h | 3 ++- src/src/ControllerQueue/C018_queue_element.h | 3 ++- src/src/ControllerQueue/C019_queue_element.h | 1 + .../ControllerDelayHandlerStruct.h | 10 +++++----- src/src/ControllerQueue/MQTT_queue_element.h | 3 +++ .../SimpleQueueElement_string_only.h | 2 +- .../queue_element_formatted_uservar.h | 3 ++- .../queue_element_single_value_base.h | 3 ++- src/src/DataStructs/UnitMessageCount.cpp | 15 +++++++++------ src/src/DataStructs/UnitMessageCount.h | 4 ++-- src/src/Helpers/PeriodicalActions.cpp | 2 +- 14 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 06c6c126a7..7ee5c97002 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -25,6 +25,8 @@ class C011_queue_element { bool isDuplicate(const C011_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + size_t getSize() const; String uri; @@ -36,7 +38,6 @@ class C011_queue_element { taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; - UnitMessageCount_t UnitMessageCount; }; #endif //USES_C011 diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index 00cbef1b01..0b49602a0f 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -29,6 +29,8 @@ class C015_queue_element { bool isDuplicate(const C015_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + String txt[VARS_PER_TASK]; int vPin[VARS_PER_TASK] = { 0 }; int idx = 0; @@ -37,7 +39,6 @@ class C015_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() byte valueCount = 0; - UnitMessageCount_t UnitMessageCount; }; #endif //USES_C015 diff --git a/src/src/ControllerQueue/C016_queue_element.cpp b/src/src/ControllerQueue/C016_queue_element.cpp index 8b783e04bf..a4878c5d3e 100644 --- a/src/src/ControllerQueue/C016_queue_element.cpp +++ b/src/src/ControllerQueue/C016_queue_element.cpp @@ -44,4 +44,5 @@ bool C016_queue_element::isDuplicate(const C016_queue_element& other) const { return true; } + #endif diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index d377b5385c..bf76da72a4 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -31,13 +31,14 @@ class C016_queue_element { bool isDuplicate(const C016_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + float values[VARS_PER_TASK] = { 0 }; unsigned long _timestamp = 0; // Unix timestamp taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; byte valueCount = 0; - UnitMessageCount_t UnitMessageCount; }; #endif //USES_C016 diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index d0c3e2f36f..3ab47d22cb 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -28,11 +28,12 @@ class C018_queue_element { bool isDuplicate(const C018_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + String packed; unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; - UnitMessageCount_t UnitMessageCount; }; #endif //USES_C018 diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 672483da08..21a9b6d912 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -26,6 +26,7 @@ class C019_queue_element { bool isDuplicate(const C019_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } String packed; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 0b38b6beaf..769751c604 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -108,12 +108,12 @@ struct ControllerDelayHandlerStruct { bool isDuplicate(const T& element) const { // Some controllers may receive duplicate messages, due to lost acknowledgement // This is actually the same message, so this should not be processed. - if (!unitLastMessageCount.isNew(element.UnitMessageCount)) { + if (!unitLastMessageCount.isNew(element.getUnitMessageCount())) { return true; } // The unit message count is still stored to make sure a new one with the same count // is considered a duplicate, even when the queue is empty. - unitLastMessageCount.add(element.UnitMessageCount); + unitLastMessageCount.add(element.getUnitMessageCount()); // the setting 'deduplicate' does look at the content of the message and only compares it to messages in the queue. if (deduplicate && !sendQueue.empty()) { @@ -171,7 +171,7 @@ struct ControllerDelayHandlerStruct { // Get the next element. // Remove front element when max_retries is reached. T* getNext() { - if (sendQueue.empty()) { return NULL; } + if (sendQueue.empty()) { return nullptr; } if (attempt > max_retries) { sendQueue.pop_front(); @@ -190,7 +190,7 @@ struct ControllerDelayHandlerStruct { } } - if (sendQueue.empty()) { return NULL; } + if (sendQueue.empty()) { return nullptr; } return &sendQueue.front(); } @@ -291,7 +291,7 @@ struct ControllerDelayHandlerStruct { void process_c##NNN####M##_delay_queue() { \ if (C##NNN####M##_DelayHandler == nullptr) return; \ C##NNN####M##_queue_element *element(C##NNN####M##_DelayHandler->getNext()); \ - if (element == NULL) return; \ + if (element == nullptr) return; \ MakeControllerSettings(ControllerSettings); \ bool ready = true; \ if (!AllocatedControllerSettings()) { \ diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index 8d488dbb8f..1c3037c122 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -30,6 +30,9 @@ class MQTT_queue_element { bool isDuplicate(const MQTT_queue_element& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return &UnitMessageCount; } + UnitMessageCount_t* getUnitMessageCount() { return &UnitMessageCount; } + void removeEmptyTopics(); String _topic; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 39ed7f9b5d..7923e7000c 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -22,12 +22,12 @@ class simple_queue_element_string_only { bool isDuplicate(const simple_queue_element_string_only& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } String txt; unsigned long _timestamp = millis(); taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; - UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index 863406d46c..902b767ee5 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -24,6 +24,8 @@ class queue_element_formatted_uservar { bool isDuplicate(const queue_element_formatted_uservar& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + String txt[VARS_PER_TASK]; int idx = 0; unsigned long _timestamp = millis(); @@ -31,7 +33,6 @@ class queue_element_formatted_uservar { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; Sensor_VType sensorType = Sensor_VType::SENSOR_TYPE_NONE; byte valueCount = 0; - UnitMessageCount_t UnitMessageCount; }; #endif // CONTROLLERQUEUE_QUEUE_ELEMENT_FORMATTED_USERVAR_H diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 2c464d7aa2..7e0d20c1a3 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -30,6 +30,8 @@ class queue_element_single_value_base { bool isDuplicate(const queue_element_single_value_base& other) const; + const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + String txt[VARS_PER_TASK]; int idx = 0; unsigned long _timestamp = millis(); @@ -37,7 +39,6 @@ class queue_element_single_value_base { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; mutable byte valuesSent = 0; // Value must be set by const function checkDone() byte valueCount = 0; - UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/DataStructs/UnitMessageCount.cpp b/src/src/DataStructs/UnitMessageCount.cpp index 59dd4452ac..7ceaf696be 100644 --- a/src/src/DataStructs/UnitMessageCount.cpp +++ b/src/src/DataStructs/UnitMessageCount.cpp @@ -1,16 +1,19 @@ #include "../DataStructs/UnitMessageCount.h" -bool UnitLastMessageCount_map::isNew(const UnitMessageCount_t& count) const { - auto it = _map.find(count.unit); +bool UnitLastMessageCount_map::isNew(const UnitMessageCount_t *count) const { + if (count == nullptr) { return true; } + auto it = _map.find(count->unit); if (it != _map.end()) { - return it->second != count.count; + return it->second != count->count; } return true; } -void UnitLastMessageCount_map::add(const UnitMessageCount_t& count) { - if ((count.unit != 0) && (count.unit != 255)) { - _map[count.unit] = count.count; +void UnitLastMessageCount_map::add(const UnitMessageCount_t *count) { + if (count == nullptr) { return; } + + if ((count->unit != 0) && (count->unit != 255)) { + _map[count->unit] = count->count; } } diff --git a/src/src/DataStructs/UnitMessageCount.h b/src/src/DataStructs/UnitMessageCount.h index 8fb6f11106..734d6cbe3e 100644 --- a/src/src/DataStructs/UnitMessageCount.h +++ b/src/src/DataStructs/UnitMessageCount.h @@ -18,9 +18,9 @@ struct UnitMessageCount_t { }; struct UnitLastMessageCount_map { - bool isNew(const UnitMessageCount_t& count) const; + bool isNew(const UnitMessageCount_t *count) const; - void add(const UnitMessageCount_t& count); + void add(const UnitMessageCount_t *count); private: diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index b9122298b4..bbd0f1dbac 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -314,7 +314,7 @@ void processMQTTdelayQueue() { START_TIMER; MQTT_queue_element *element(MQTTDelayHandler->getNext()); - if (element == NULL) { return; } + if (element == nullptr) { return; } #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { From b93603d6cc0e535a64bba3f29468e22ffa37557b Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 3 May 2021 23:49:40 +0200 Subject: [PATCH 156/404] [ESPEasy-NOW] Fix unit not getting out of "ESPeasy-NOW-only" mode --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 3d3fcb8c3f..60200a913d 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -328,6 +328,7 @@ bool checkAndResetWiFi() { // This is a valid status, no need to reset if (!WiFiEventData.WiFiServicesInitialized()) { WiFiEventData.setWiFiServicesInitialized(); + setNetworkMedium(NetworkMedium_t::WIFI); } return false; From a6c79aebd3548a68ae01c6d9a8cf814ab70a364b Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 01:17:37 +0200 Subject: [PATCH 157/404] [ESPEasy-NOW] Add force WiFi channel setting --- src/src/DataStructs/NodesHandler.cpp | 17 +++++++++++++++-- src/src/DataStructs/SettingsStruct.h | 1 + src/src/Helpers/ESPEasy_checks.cpp | 4 ++-- src/src/Helpers/StringProvider.cpp | 2 ++ src/src/Helpers/StringProvider.h | 1 + src/src/WebServer/AdvancedConfigPage.cpp | 9 +++++++++ src/src/WebServer/JSON.cpp | 1 + src/src/WebServer/SysInfoPage.cpp | 1 + 8 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index a0c6f9df4e..22fed9f847 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -13,10 +13,13 @@ #include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" +#include "../Globals/NetworkState.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" +#define ESPEASY_NOW_ALLOWED_AGE_NO_TRACEROUTE 35000 + bool NodesHandler::addNode(const NodeStruct& node) { int8_t rssi = 0; @@ -211,7 +214,11 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& mustSet = true; } } else if (distance_new < distance_res) { - mustSet = true; + if (it->second.getAge() < ESPEASY_NOW_ALLOWED_AGE_NO_TRACEROUTE) { + // Only allow this new one if it was seen recently + // as it does not (yet) have a traceroute. + mustSet = true; + } } #else if (it->second < *res) { @@ -487,7 +494,13 @@ bool NodesHandler::isEndpoint() const uint8_t NodesHandler::getESPEasyNOW_channel() const { if (isEndpoint()) { - return WiFi.channel(); + if (active_network_medium == NetworkMedium_t::WIFI || + Settings.ForceESPEasyNOWchannel == 0) { + return WiFi.channel(); + } + } + if (Settings.ForceESPEasyNOWchannel > 0) { + return Settings.ForceESPEasyNOWchannel; } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 6293d736f0..d7bdb6531b 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -274,6 +274,7 @@ class SettingsStruct_tmpl uint8_t WiFi_TX_power = 70; // 70 = 17.5dBm. unit: 0.25 dBm int8_t WiFi_sensitivity_margin = 3; // Margin in dBm on top of sensitivity. uint8_t NumberExtraWiFiScans = 0; + int8_t ForceESPEasyNOWchannel = 0; }; /* diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 13511ba44d..3e0a08044e 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -71,10 +71,10 @@ void run_compiletime_checks() { check_size(); check_size(); #ifdef ESP32 - const unsigned int SettingsStructSize = (312 + 84 * TASKS_MAX); + const unsigned int SettingsStructSize = (316 + 84 * TASKS_MAX); #endif #ifdef ESP8266 - const unsigned int SettingsStructSize = (288 + 84 * TASKS_MAX); + const unsigned int SettingsStructSize = (292 + 84 * TASKS_MAX); #endif check_size(); check_size(); diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 792123b75e..ad9aa03304 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -124,6 +124,7 @@ String getLabel(LabelType::Enum label) { #ifdef USES_ESPEASY_NOW case LabelType::USE_ESPEASY_NOW: return String(F("Enable ")) + F(ESPEASY_NOW_NAME); case LabelType::TEMP_DISABLE_ESPEASY_NOW: return String(F("Temporary disable ")) + F(ESPEASY_NOW_NAME); + case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(F("Force Channel ")) + F(ESPEASY_NOW_NAME); #endif @@ -214,6 +215,7 @@ String getValue(LabelType::Enum label) { case LabelType::WIFI_SENS_MARGIN: return String(Settings.WiFi_sensitivity_margin); case LabelType::WIFI_SEND_AT_MAX_TX_PWR:return jsonBool(Settings.UseMaxTXpowerForSending()); case LabelType::WIFI_NR_EXTRA_SCANS: return String(Settings.NumberExtraWiFiScans); + case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); case LabelType::WIFI_PERIODICAL_SCAN: return jsonBool(Settings.PeriodicalScanWiFi()); case LabelType::FREE_MEM: return String(ESP.getFreeHeap()); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 0ecb6bc5ae..c551595b3d 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -92,6 +92,7 @@ struct LabelType { #ifdef USES_ESPEASY_NOW USE_ESPEASY_NOW, TEMP_DISABLE_ESPEASY_NOW, + FORCE_ESPEASY_NOW_CHANNEL, #endif BUILD_DESC, diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index e0f319a67b..dc3d9a43aa 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -98,6 +98,7 @@ void handle_advanced() { #ifdef USES_ESPEASY_NOW Settings.UseESPEasyNow(isFormItemChecked(getInternalLabel(LabelType::USE_ESPEASY_NOW))); + Settings.ForceESPEasyNOWchannel = getFormItemInt(getInternalLabel(LabelType::FORCE_ESPEASY_NOW_CHANNEL)); #endif addHtmlError(SaveSettings()); @@ -255,6 +256,14 @@ void handle_advanced() { #ifdef USES_ESPEASY_NOW addFormCheckBox(LabelType::USE_ESPEASY_NOW, Settings.UseESPEasyNow()); + { + addFormNumericBox(LabelType::FORCE_ESPEASY_NOW_CHANNEL, Settings.ForceESPEasyNOWchannel, 0, 14); + String note = F("Force channel to use for "); + note += F(ESPEASY_NOW_NAME); + note += F("-only mode (0 = use any channel)"); + addFormNote(note); + } + #endif addFormSeparator(2); diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 74cd26633e..d2369c008a 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -208,6 +208,7 @@ void handle_json() #endif // ifdef SUPPORT_ARP #ifdef USES_ESPEASY_NOW stream_next_json_object_value(LabelType::USE_ESPEASY_NOW); + stream_next_json_object_value(LabelType::FORCE_ESPEASY_NOW_CHANNEL); #endif stream_next_json_object_value(LabelType::CONNECTION_FAIL_THRESH); stream_next_json_object_value(LabelType::WIFI_TX_MAX_PWR); diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index cb77117af8..94b83c0b78 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -489,6 +489,7 @@ void handle_sysinfo_WiFiSettings() { addRowLabelValue(LabelType::WIFI_PERIODICAL_SCAN); #ifdef USES_ESPEASY_NOW addRowLabelValue(LabelType::USE_ESPEASY_NOW); + addRowLabelValue(LabelType::FORCE_ESPEASY_NOW_CHANNEL); #endif } From af17ffbc9182ec68552b285747375fe93241b135 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 01:18:44 +0200 Subject: [PATCH 158/404] [ESPEasy-NOW] switch to 802.11b for ESPEasy-NOW-only mode --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 60200a913d..90f8021473 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1087,7 +1087,13 @@ void setConnectionSpeed() { if (!Settings.ForceWiFi_bg_mode() || (WiFiEventData.wifi_connect_attempt > 10)) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } else { - WiFi.setPhyMode(WIFI_PHY_MODE_11G); + WiFiPhyMode_t phyMode = WIFI_PHY_MODE_11G; + #ifdef USE_ESPEASY_NOW + if (active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { + phyMode = WIFI_PHY_MODE_11B; + } + #endif + WiFi.setPhyMode(phyMode); } #endif // ifdef ESP8266 From 92edb3ef83fa981f61c5099f12ece14bc255025b Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 10:52:40 +0200 Subject: [PATCH 159/404] [ESPEasy-NOW] Detect duplicate MQTT messages from peer node Peer nodes may try to re-send an ESPEasy-NOW message if no acknowledgement was received. However the receiving end may still process the message, resulting in duplicates. For now this dedup is only implemented for MQTT messages, but it may be used later on all message types. --- src/src/DataStructs/ESPEasy_now_merger.cpp | 11 +++++++++++ src/src/DataStructs/ESPEasy_now_merger.h | 3 +++ src/src/ESPEasyCore/Controller.cpp | 6 +++--- src/src/ESPEasyCore/Controller.h | 3 ++- src/src/Helpers/ESPEasy_now_handler.cpp | 22 ++++++++++++++++------ 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 7f75afca60..0db0a1b5b7 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -83,6 +83,17 @@ unsigned long ESPEasy_now_merger::getFirstPacketTimestamp() const return _firstPacketTimestamp; } +bool ESPEasy_now_merger::getMessageCount(uint8_t& count) const +{ + auto it = _queue.find(0); + + if (it == _queue.end()) { + return false; + } + count = it->second.getHeader().message_count; + return true; +} + bool ESPEasy_now_merger::getMac(uint8_t *mac) const { auto it = _queue.find(0); diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index ca3736faf5..84cb0be59f 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -62,6 +62,9 @@ class ESPEasy_now_merger { unsigned long getFirstPacketTimestamp() const; + bool getMessageCount(uint8_t& count) const; + + private: // Find packet + payload position in packet for payload_pos of entire message diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 108fd13d52..664bb9b656 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -519,7 +519,7 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained) +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const UnitMessageCount_t& unitMessageCount, bool retained) { bool success = false; if (!MQTT_queueFull(controller_idx)) @@ -529,6 +529,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes size_t pos = 0; element.controller_idx = controller_idx; element._retained = retained; + element.UnitMessageCount = unitMessageCount; const size_t payloadSize = message.getPayloadSize(); if (message.getString(element._topic, pos) && message.getString(element._payload, pos)) { success = true; @@ -539,8 +540,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes message.getBinaryData(&element.UnitMessageCount.count, 1, pos) == 1)) { // Whatever may have been present, it could not be loaded, so clear just to be sure. - element.UnitMessageCount.unit = 0; - element.UnitMessageCount.count = 0; + element.UnitMessageCount = unitMessageCount; } } } diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 1459cd4dcd..719cdd6123 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -5,6 +5,7 @@ #include "../DataTypes/EventValueSource.h" #include "../DataStructs/ESPEasy_now_merger.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" // ******************************************************************************** @@ -71,7 +72,7 @@ void SendStatus(struct EventStruct *event, const String& status); bool MQTT_queueFull(controllerIndex_t controller_idx); #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, bool retained); +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const UnitMessageCount_t& unitMessageCount, bool retained); #endif bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 75e3d59d73..edd9c4b225 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1028,15 +1028,25 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge if (validControllerIndex(controllerIndex)) { load_ControllerSettingsCache(controllerIndex); - bool success = MQTTpublish(controllerIndex, message, _mqtt_retainFlag); - if (!success) { - mustKeep = false; - return success; - } - MAC_address mac; + bool success = false; + if (message.getMac(mac)) { + UnitMessageCount_t UnitMessageCount; + const NodeStruct* node = Nodes.getNodeByMac(mac); + if (node != nullptr) { + if (message.getMessageCount(UnitMessageCount.count)) { + UnitMessageCount.unit = node->unit; + } + } + + success = MQTTpublish(controllerIndex, message, UnitMessageCount, _mqtt_retainFlag); + if (!success) { + mustKeep = false; + return success; + } + ESPEasy_Now_MQTT_queue_check_packet query; const bool queue_full = MQTT_queueFull(controllerIndex); query.setState(queue_full); From ddc21afcd0fef1c812efd79d3ab59af0f69ba645 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 13:18:24 +0200 Subject: [PATCH 160/404] [ESPEasy-NOW] Do not process duplicate packets in multipart messages --- src/src/DataStructs/ESPEasy_now_merger.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 0db0a1b5b7..4d3cb49555 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -28,9 +28,16 @@ void ESPEasy_now_merger::addPacket( } #endif - _queue.emplace(std::make_pair(packet_nr, ESPEasy_Now_packet())); - _queue[packet_nr].setReceivedPacket(mac, buf, packetSize); - _firstPacketTimestamp = millis(); + if (_queue.find(packet_nr) == _queue.end()) { + // Not yet present. + // Wwe might receive some packets several times if the sender does not receive our acknowledgement + ESPEasy_Now_packet packet; + packet.setReceivedPacket(mac, buf, packetSize); + if (packet.valid()) { + _queue[packet_nr] = std::move(packet); + _firstPacketTimestamp = millis(); + } + } } bool ESPEasy_now_merger::messageComplete() const From 6424745368b4bba75400ba6f8e8607699f3fa553 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 15:49:40 +0200 Subject: [PATCH 161/404] Add move assignment to EventStruct --- src/src/DataStructs/ESPEasy_EventStruct.cpp | 58 +++++++++++++++++++++ src/src/DataStructs/ESPEasy_EventStruct.h | 2 + src/src/Helpers/Scheduler.cpp | 22 ++++---- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_EventStruct.cpp b/src/src/DataStructs/ESPEasy_EventStruct.cpp index ec65394c79..aaf8942b0c 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.cpp +++ b/src/src/DataStructs/ESPEasy_EventStruct.cpp @@ -29,6 +29,36 @@ EventStruct::EventStruct(const struct EventStruct& event) : , OriginTaskIndex(event.OriginTaskIndex) {} +EventStruct::EventStruct(struct EventStruct&& event) : + String1(std::move(event.String1)) + , String2(std::move(event.String2)) + , String3(std::move(event.String3)) + , String4(std::move(event.String4)) + , String5(std::move(event.String5)) + , Data(event.Data) + , idx(event.idx) + , Par1(event.Par1), Par2(event.Par2), Par3(event.Par3), Par4(event.Par4), Par5(event.Par5) + , Source(event.Source), TaskIndex(event.TaskIndex), ControllerIndex(event.ControllerIndex) + , NotificationIndex(event.NotificationIndex) + , BaseVarIndex(event.BaseVarIndex), sensorType(event.sensorType) + , OriginTaskIndex(event.OriginTaskIndex) { + event.Data = nullptr; + event.idx = 0; + event.Par1 = 0; + event.Par2 = 0; + event.Par3 = 0; + event.Par4 = 0; + event.Par5 = 0; + Source = EventValueSource::Enum::VALUE_SOURCE_NOT_SET; + TaskIndex = INVALID_TASK_INDEX; + ControllerIndex = INVALID_CONTROLLER_INDEX; + NotificationIndex = INVALID_NOTIFIER_INDEX; // index position in Settings.Notification, 0-3 + BaseVarIndex = 0; + sensorType = Sensor_VType::SENSOR_TYPE_NOT_SET; + OriginTaskIndex = 0; + + } + EventStruct& EventStruct::operator=(const struct EventStruct& other) { // check for self-assignment if (&other == this) { @@ -56,6 +86,34 @@ EventStruct& EventStruct::operator=(const struct EventStruct& other) { return *this; } +EventStruct& EventStruct::operator=(struct EventStruct&& other) { + // check for self-assignment + if (&other == this) { + return *this; + } + String1 = std::move(other.String1); + String2 = std::move(other.String2); + String3 = std::move(other.String3); + String4 = std::move(other.String4); + String5 = std::move(other.String5); + Data = other.Data; + idx = other.idx; + Par1 = other.Par1; + Par2 = other.Par2; + Par3 = other.Par3; + Par4 = other.Par4; + Par5 = other.Par5; + Source = other.Source; + TaskIndex = other.TaskIndex; + ControllerIndex = other.ControllerIndex; + NotificationIndex = other.NotificationIndex; + BaseVarIndex = other.BaseVarIndex; + sensorType = other.sensorType; + OriginTaskIndex = other.OriginTaskIndex; + return *this; +} + + void EventStruct::setTaskIndex(taskIndex_t taskIndex) { TaskIndex = taskIndex; BaseVarIndex = taskIndex * VARS_PER_TASK; diff --git a/src/src/DataStructs/ESPEasy_EventStruct.h b/src/src/DataStructs/ESPEasy_EventStruct.h index f0efde5f56..0e29a99b0f 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.h +++ b/src/src/DataStructs/ESPEasy_EventStruct.h @@ -20,7 +20,9 @@ struct EventStruct EventStruct(); explicit EventStruct(taskIndex_t taskIndex); explicit EventStruct(const struct EventStruct& event); + explicit EventStruct(struct EventStruct&& event); EventStruct& operator=(const struct EventStruct& other); + EventStruct& operator=(struct EventStruct&& other); void setTaskIndex(taskIndex_t taskIndex); diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index 1f00b6dfe2..5806366b33 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -1011,21 +1011,23 @@ void ESPEasy_Scheduler::schedule_mqtt_plugin_import_event_timer(deviceIndex_t byte *b_payload, unsigned int length) { if (validDeviceIndex(DeviceIndex)) { - // Emplace empty event in the queue first and the fill it. - // This makes sure the relatively large event will not be in memory twice. const unsigned long mixedId = createSystemEventMixedId(PluginPtrType::TaskPlugin, DeviceIndex, static_cast(Function)); - ScheduledEventQueue.emplace_back(mixedId, EventStruct(TaskIndex)); - ScheduledEventQueue.back().event.String1 = c_topic; - - String& payload = ScheduledEventQueue.back().event.String2; - if (!payload.reserve(length)) { + EventStruct event(TaskIndex); + const size_t topic_length = strlen_P(c_topic); + if (!(event.String1.reserve(topic_length) && event.String2.reserve(length))) { addLog(LOG_LEVEL_ERROR, F("MQTT : Out of Memory! Cannot process MQTT message")); + return; + } + for (size_t i = 0; i < topic_length; ++i) { + event.String1 += c_topic[i]; } - for (unsigned int i = 0; i < length; ++i) { - char c = static_cast(*(b_payload + i)); - payload += c; + const char c = static_cast(*(b_payload + i)); + event.String2 += c; } + // Emplace using move. + // This makes sure the relatively large event will not be in memory twice. + ScheduledEventQueue.emplace_back(mixedId, std::move(event)); } } From 37512317a87f00bbf248afc96866f2bad1fc9449 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 15:50:26 +0200 Subject: [PATCH 162/404] [ESPEasy-NOW] Add more allocation checks + detect forwarding loops --- src/src/DataStructs/ESPEasy_now_merger.cpp | 34 +++++++++++++++------- src/src/DataStructs/ESPEasy_now_merger.h | 4 +++ src/src/DataStructs/NodesHandler.cpp | 20 +++++++++++-- src/src/DataStructs/NodesHandler.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 6 ++-- src/src/Helpers/ESPEasy_now_handler.h | 4 ++- src/src/Helpers/PeriodicalActions.cpp | 14 +++++---- src/src/Helpers/PeriodicalActions.h | 4 ++- 8 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 4d3cb49555..6976eb2445 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -11,6 +11,22 @@ ESPEasy_now_merger::ESPEasy_now_merger() { _firstPacketTimestamp = millis(); } +ESPEasy_now_merger::ESPEasy_now_merger(ESPEasy_now_merger&& other) : + _firstPacketTimestamp(other._firstPacketTimestamp), + _queue(std::move(other._queue)), + _nr_packets(other._nr_packets) { + other._firstPacketTimestamp = 0; + other._nr_packets = 255; + } + +ESPEasy_now_merger& ESPEasy_now_merger::operator=(ESPEasy_now_merger&& other) +{ + _firstPacketTimestamp = other._firstPacketTimestamp; + _queue = std::move(other._queue); + _nr_packets = other._nr_packets; + return *this; +} + void ESPEasy_now_merger::addPacket( uint8_t packet_nr, const MAC_address& mac, @@ -28,16 +44,14 @@ void ESPEasy_now_merger::addPacket( } #endif - if (_queue.find(packet_nr) == _queue.end()) { - // Not yet present. - // Wwe might receive some packets several times if the sender does not receive our acknowledgement - ESPEasy_Now_packet packet; - packet.setReceivedPacket(mac, buf, packetSize); - if (packet.valid()) { - _queue[packet_nr] = std::move(packet); - _firstPacketTimestamp = millis(); - } - } + // FIXME TD-er: How to handle duplicates? + // We might receive some packets several times if the sender does not receive our acknowledgement + ESPEasy_Now_packet packet; + packet.setReceivedPacket(mac, buf, packetSize); + if (packet.valid()) { + _queue[packet_nr] = std::move(packet); + _firstPacketTimestamp = millis(); + } } bool ESPEasy_now_merger::messageComplete() const diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 84cb0be59f..64036fc97f 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -19,6 +19,10 @@ class ESPEasy_now_merger { ESPEasy_now_merger(); + ESPEasy_now_merger(ESPEasy_now_merger&& other); + + ESPEasy_now_merger& operator=(ESPEasy_now_merger&& other); + void addPacket( uint8_t packet_nr, const MAC_address& mac, diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 22fed9f847..8b008d046f 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -79,8 +79,8 @@ bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_ log = F(ESPEASY_NOW_NAME); log += F(": Node: "); log += String(node.unit); - log += F(" Traceroute received: "); - log += _nodeStats[node.unit].latestRoute().toString(); + log += F(" DiscoveryRoute received: "); + log += traceRoute.toString(); addLog(LOG_LEVEL_INFO, log); } } @@ -175,6 +175,17 @@ const NodeStruct * NodesHandler::getPreferredNode() const { return getPreferredNode_notMatching(dummy); } +const NodeStruct* NodesHandler::getPreferredNode_notMatching(uint8_t unit_nr) const { + MAC_address not_matching; + if (unit_nr != 0 && unit_nr != 255) { + const NodeStruct* node = getNode(unit_nr); + if (node != nullptr) { + not_matching = node->ESPEasy_Now_MAC(); + } + } + return getPreferredNode_notMatching(not_matching); +} + const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching) const { MAC_address this_mac; @@ -205,7 +216,10 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& distance_res = res->distance; } else if (successRate_res == 0) { // The new one has a route, so must set the new one. - mustSet = true; + distance_res = res->distance; + if (distance_new < 255) { + mustSet = true; + } } } diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 8b9ebfaf6c..3dc72d05d1 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -46,6 +46,7 @@ class NodesHandler { const NodeStruct* getPreferredNode() const; + const NodeStruct* getPreferredNode_notMatching(uint8_t unit_nr) const; const NodeStruct* getPreferredNode_notMatching(const MAC_address& not_matching) const; #ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index edd9c4b225..153887a53b 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -945,7 +945,7 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // * MQTT controller forwarder // ************************************************************* -bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload) +bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const UnitMessageCount_t* unitMessageCount) { if (!use_EspEasy_now) { return false; } @@ -965,7 +965,9 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const bool processed = false; if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { - const NodeStruct *preferred = Nodes.getPreferredNode(); + // Must make sure we don't forward it to the unit we received the message from. + const uint8_t unit_nr = (unitMessageCount == nullptr) ? 0 : unitMessageCount->unit; + const NodeStruct *preferred = Nodes.getPreferredNode_notMatching(unit_nr); if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { MAC_address mac = preferred->ESPEasy_Now_MAC(); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 15f5e70e49..cddc77ad03 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -14,6 +14,7 @@ # include "../DataStructs/ESPEasy_Now_p2p_data.h" # include "../DataStructs/ESPEasy_now_traceroute.h" # include "../DataStructs/MAC_address.h" +# include "../DataStructs/UnitMessageCount.h" # include "../DataStructs/WiFi_AP_Candidate.h" # include "../Globals/CPlugins.h" @@ -70,7 +71,8 @@ class ESPEasy_now_handler_t { bool sendToMQTT(controllerIndex_t controllerIndex, const String & topic, - const String & payload); + const String & payload, + const UnitMessageCount_t* unitMessageCount); bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); bool sendMQTTCheckControllerQueue(const MAC_address& mac, diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index bbd0f1dbac..e2afa0b32a 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -340,11 +340,12 @@ void processMQTTdelayQueue() { message = replacement; message += ';'; message += element->_payload; - processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained); + + processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, element->getUnitMessageCount()); } else #endif { - processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained); + processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, element->getUnitMessageCount()); } @@ -368,15 +369,16 @@ void processMQTTdelayQueue() { } bool processMQTT_message(controllerIndex_t controllerIndex, - const String & topic, - const String & payload, - bool retained) + const String & topic, + const String & payload, + bool retained, + const UnitMessageCount_t* unitMessageCount) { bool processed = false; #ifdef USES_ESPEASY_NOW if (!MQTTclient_connected) { - processed = ESPEasy_now_handler.sendToMQTT(controllerIndex, topic, payload); + processed = ESPEasy_now_handler.sendToMQTT(controllerIndex, topic, payload, unitMessageCount); } #endif diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 8da731dc3c..fe1fad668e 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -4,6 +4,7 @@ #include #include "../../ESPEasy_common.h" +#include "../DataStructs/UnitMessageCount.h" #include "../Globals/CPlugins.h" #include "../Helpers/Scheduler.h" @@ -39,7 +40,8 @@ void processMQTTdelayQueue(); bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, - bool retained); + bool retained, + const UnitMessageCount_t* unitMessageCount); void updateMQTTclient_connected(); From 026b9f19e55ba7063f6641c8fe60b6263d7ebd5a Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 20:21:48 +0200 Subject: [PATCH 163/404] [Events] Make sure events are not copied unless absolutely needed --- src/src/Commands/Notifications.cpp | 2 +- .../ControllerQueue/C019_queue_element.cpp | 4 +- src/src/CustomBuild/define_plugin_sets.h | 4 +- src/src/DataStructs/ESPEasy_EventStruct.cpp | 42 +++++++------------ src/src/DataStructs/ESPEasy_EventStruct.h | 10 ++++- src/src/DataStructs/ESPEasy_Now_packet.cpp | 21 ++++++++++ src/src/DataStructs/ESPEasy_Now_packet.h | 8 +++- src/src/DataStructs/ESPEasy_now_merger.h | 2 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 16 +++++-- src/src/DataStructs/ESPEasy_now_splitter.h | 3 +- .../DataStructs/EventStructCommandWrapper.h | 2 +- .../SendData_DuplicateChecker_data.cpp | 4 +- src/src/Globals/Plugins.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 4 +- src/src/Helpers/PeriodicalActions.cpp | 2 +- src/src/Helpers/Scheduler.cpp | 16 +++---- src/src/Helpers/Scheduler.h | 13 ++++-- src/src/Helpers/StringConverter.cpp | 4 +- src/src/WebServer/NotificationPage.cpp | 2 +- 19 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/src/Commands/Notifications.cpp b/src/src/Commands/Notifications.cpp index 3a9355deab..2abd684d89 100644 --- a/src/src/Commands/Notifications.cpp +++ b/src/src/Commands/Notifications.cpp @@ -26,7 +26,7 @@ String Command_Notifications_Notify(struct EventStruct *event, const char* Line) // TempEvent.NotificationProtocolIndex = NotificationProtocolIndex; TempEvent.NotificationIndex = index; TempEvent.String1 = message; - Scheduler.schedule_notification_event_timer(NotificationProtocolIndex, NPlugin::Function::NPLUGIN_NOTIFY, &TempEvent); + Scheduler.schedule_notification_event_timer(NotificationProtocolIndex, NPlugin::Function::NPLUGIN_NOTIFY, std::move(TempEvent)); } } } diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 80ca2e6af5..562753f1c7 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -12,9 +12,9 @@ String getPackedFromPlugin(struct EventStruct *event, C019_queue_element::C019_queue_element() {} C019_queue_element::C019_queue_element(struct EventStruct *event_p) : - controller_idx(event_p->ControllerIndex), - event(*event_p) + controller_idx(event_p->ControllerIndex) { + event.deep_copy(event_p); #ifdef USES_PACKED_RAW_DATA packed = getPackedFromPlugin(event_p, 0); diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 59b4a44e19..2d89acd50b 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1484,7 +1484,9 @@ To create/register a plugin, you have to : #endif #if defined(USES_C019) || defined(USES_P098) - #define USES_ESPEASY_NOW + #ifndef USES_ESPEASY_NOW + #define USES_ESPEASY_NOW + #endif #endif #if defined(USES_P085) || defined (USES_P052) || defined(USES_P078) || defined(USES_P108) diff --git a/src/src/DataStructs/ESPEasy_EventStruct.cpp b/src/src/DataStructs/ESPEasy_EventStruct.cpp index aaf8942b0c..bc01a4c155 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.cpp +++ b/src/src/DataStructs/ESPEasy_EventStruct.cpp @@ -14,21 +14,6 @@ EventStruct::EventStruct(taskIndex_t taskIndex) : TaskIndex(taskIndex), BaseVarIndex(taskIndex * VARS_PER_TASK) {} -EventStruct::EventStruct(const struct EventStruct& event) : - String1(event.String1) - , String2(event.String2) - , String3(event.String3) - , String4(event.String4) - , String5(event.String5) - , Data(event.Data) - , idx(event.idx) - , Par1(event.Par1), Par2(event.Par2), Par3(event.Par3), Par4(event.Par4), Par5(event.Par5) - , Source(event.Source), TaskIndex(event.TaskIndex), ControllerIndex(event.ControllerIndex) - , NotificationIndex(event.NotificationIndex) - , BaseVarIndex(event.BaseVarIndex), sensorType(event.sensorType) - , OriginTaskIndex(event.OriginTaskIndex) -{} - EventStruct::EventStruct(struct EventStruct&& event) : String1(std::move(event.String1)) , String2(std::move(event.String2)) @@ -49,20 +34,19 @@ EventStruct::EventStruct(struct EventStruct&& event) : event.Par3 = 0; event.Par4 = 0; event.Par5 = 0; - Source = EventValueSource::Enum::VALUE_SOURCE_NOT_SET; - TaskIndex = INVALID_TASK_INDEX; - ControllerIndex = INVALID_CONTROLLER_INDEX; - NotificationIndex = INVALID_NOTIFIER_INDEX; // index position in Settings.Notification, 0-3 - BaseVarIndex = 0; - sensorType = Sensor_VType::SENSOR_TYPE_NOT_SET; - OriginTaskIndex = 0; - + event.Source = EventValueSource::Enum::VALUE_SOURCE_NOT_SET; + event.TaskIndex = INVALID_TASK_INDEX; + event.ControllerIndex = INVALID_CONTROLLER_INDEX; + event.NotificationIndex = INVALID_NOTIFIER_INDEX; // index position in Settings.Notification, 0-3 + event.BaseVarIndex = 0; + event.sensorType = Sensor_VType::SENSOR_TYPE_NOT_SET; + event.OriginTaskIndex = 0; } -EventStruct& EventStruct::operator=(const struct EventStruct& other) { +void EventStruct::deep_copy(const struct EventStruct& other) { // check for self-assignment if (&other == this) { - return *this; + return; } String1 = other.String1; String2 = other.String2; @@ -83,9 +67,15 @@ EventStruct& EventStruct::operator=(const struct EventStruct& other) { BaseVarIndex = other.BaseVarIndex; sensorType = other.sensorType; OriginTaskIndex = other.OriginTaskIndex; - return *this; } +void EventStruct::deep_copy(const struct EventStruct* other) { + if (other != nullptr) { + deep_copy(*other); + } +} + + EventStruct& EventStruct::operator=(struct EventStruct&& other) { // check for self-assignment if (&other == this) { diff --git a/src/src/DataStructs/ESPEasy_EventStruct.h b/src/src/DataStructs/ESPEasy_EventStruct.h index 0e29a99b0f..d91e90d613 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.h +++ b/src/src/DataStructs/ESPEasy_EventStruct.h @@ -19,11 +19,17 @@ struct EventStruct { EventStruct(); explicit EventStruct(taskIndex_t taskIndex); - explicit EventStruct(const struct EventStruct& event); explicit EventStruct(struct EventStruct&& event); - EventStruct& operator=(const struct EventStruct& other); EventStruct& operator=(struct EventStruct&& other); + // Explicit deep_copy function to make sure this object is not accidentally copied using the copy-constructor + // Copy constructor and assignment operator should not be used. + void deep_copy(const struct EventStruct& other); + void deep_copy(const struct EventStruct* other); + // explicit EventStruct(const struct EventStruct& event); + // EventStruct& operator=(const struct EventStruct& other); + + void setTaskIndex(taskIndex_t taskIndex); // Check (and update) sensorType if not set, plus return (corrected) sensorType diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index b52201bf35..50ccf12930 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -17,6 +17,27 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t pay ESPEasy_Now_packet::ESPEasy_Now_packet() : _valid(false) {} +ESPEasy_Now_packet::ESPEasy_Now_packet(ESPEasy_Now_packet&& other) +: _buf(std::move(other._buf)), _valid(other._valid) +{ + for (size_t i = 0; i < 6; ++i) { + _mac[i] = other._mac[i]; + other._mac[i] = 0; + } + other._valid = false; +} + +ESPEasy_Now_packet& ESPEasy_Now_packet::operator=(ESPEasy_Now_packet&& other) +{ + for (size_t i = 0; i < 6; ++i) { + _mac[i] = other._mac[i]; + other._mac[i] = 0; + } + _buf = std::move(other._buf); + _valid = other._valid; + other._valid = false; +} + bool ESPEasy_Now_packet::setReceivedPacket(const MAC_address& mac, const uint8_t *buf, size_t packetSize) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index c62bebdbd5..0d222acefc 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -21,12 +21,16 @@ class ESPEasy_Now_packet { ESPEasy_Now_packet(); - bool setReceivedPacket(const MAC_address& mac, + ESPEasy_Now_packet(ESPEasy_Now_packet&& other); + + ESPEasy_Now_packet& operator=(ESPEasy_Now_packet&& other); + + bool ICACHE_FLASH_ATTR setReceivedPacket(const MAC_address& mac, const uint8_t *buf, size_t packetSize); // A packet may become invalid if it was not possible to allocate enough memory for the buffer - bool valid() const; + bool ICACHE_FLASH_ATTR valid() const; bool checksumValid() const; diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 64036fc97f..529fa8f739 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -23,7 +23,7 @@ class ESPEasy_now_merger { ESPEasy_now_merger& operator=(ESPEasy_now_merger&& other); - void addPacket( + void ICACHE_FLASH_ATTR addPacket( uint8_t packet_nr, const MAC_address& mac, const uint8_t *buf, diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 8cebe45639..080882c739 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -26,7 +26,9 @@ size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) size_t data_left = length; while ((data_left > 0) && (_totalSize > _bytesStored)) { - createNextPacket(); + if (!createNextPacket()) { + return length - data_left; + } const size_t bytesAdded = _queue.back().addBinaryData(data, data_left, _payload_pos); if (bytesAdded == 0) { return length - data_left; @@ -45,7 +47,7 @@ size_t ESPEasy_now_splitter::addString(const String& string) return addBinaryData(reinterpret_cast(string.c_str()), length); } -void ESPEasy_now_splitter::createNextPacket() +bool ESPEasy_now_splitter::createNextPacket() { size_t current_PayloadSize = ESPEasy_Now_packet::getMaxPayloadSize(); @@ -62,18 +64,24 @@ void ESPEasy_now_splitter::createNextPacket() log += data_left; addLog(LOG_LEVEL_INFO, log); */ - return; + return true; } // Determine size of next packet size_t message_bytes_left = _totalSize - _bytesStored; _header.payload_size = message_bytes_left - sizeof(ESPEasy_now_hdr); - _queue.emplace_back(_header, message_bytes_left); + + ESPEasy_Now_packet newPacket(_header, message_bytes_left); + if (!newPacket.valid()) { + return false; + } + _queue.push_back(std::move(newPacket)); _payload_pos = 0; // Set the packet number for the next packet. // Total packet count will be set right before sending them. _header.packet_nr++; + return true; } bool ESPEasy_now_splitter::sendToBroadcast() diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 71accb876c..918e6c7787 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -27,7 +27,8 @@ class ESPEasy_now_splitter { private: // Create next packet when needed. - void createNextPacket(); + // return false when it was needed, but failed to do so. + bool createNextPacket(); size_t getPayloadPos() const; diff --git a/src/src/DataStructs/EventStructCommandWrapper.h b/src/src/DataStructs/EventStructCommandWrapper.h index 8d486ab173..ef3cd5c31e 100644 --- a/src/src/DataStructs/EventStructCommandWrapper.h +++ b/src/src/DataStructs/EventStructCommandWrapper.h @@ -7,7 +7,7 @@ struct EventStructCommandWrapper { EventStructCommandWrapper() : id(0) {} - EventStructCommandWrapper(unsigned long i, const EventStruct& e) : id(i), event(e) {} + EventStructCommandWrapper(unsigned long i, EventStruct&& e) : id(i), event(std::move(e)) {} unsigned long id; String cmd; diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp index 016c7484a2..40ac492d0a 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp @@ -7,9 +7,7 @@ #define TIMEOUT_ASK_FOR_DUPLICATE 100 SendData_DuplicateChecker_data::SendData_DuplicateChecker_data(EventStruct *event) { - if (event != nullptr) { - _event = *event; - } + _event.deep_copy(event); } bool SendData_DuplicateChecker_data::doSend() diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index ee667927d0..9d4522f11d 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -328,7 +328,7 @@ bool PluginCall(byte Function, struct EventStruct *event, String& str) event = &TempEvent; } else { - TempEvent = (*event); + TempEvent.deep_copy(*event); } #ifndef BUILD_NO_RAM_TRACKER diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 153887a53b..71a8406540 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -62,7 +62,7 @@ std::list ESPEasy_now_MQTT_check_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; - size_t payload_length = count - sizeof(ESPEasy_now_hdr); + const size_t payload_length = count - sizeof(ESPEasy_now_hdr); if (count < sizeof(ESPEasy_now_hdr) || (payload_length > ESPEasy_Now_packet::getMaxPayloadSize())) { STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; // Too small @@ -82,7 +82,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; } - uint64_t key = mac_to_key(mac, header.message_type, header.message_count); + const uint64_t key = mac_to_key(mac, header.message_type, header.message_count); ESPEasy_now_in_queue[key].addPacket(header.packet_nr, mac, buf, count); STOP_TIMER(RECEIVE_ESPEASY_NOW_LOOP); } diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index e2afa0b32a..1eeb24b413 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -283,7 +283,7 @@ void schedule_all_tasks_using_MQTT_controller() { // Schedule a call to each MQTT import plugin to notify the broker connection state EventStruct event(task); event.Par1 = MQTTclient_connected ? 1 : 0; - Scheduler.schedule_plugin_task_event_timer(DeviceIndex, PLUGIN_MQTT_CONNECTION_STATE, &event); + Scheduler.schedule_plugin_task_event_timer(DeviceIndex, PLUGIN_MQTT_CONNECTION_STATE, std::move(event)); } } } diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index 5806366b33..a927e828d6 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -998,9 +998,9 @@ void ESPEasy_Scheduler::process_task_device_timer(unsigned long task_index, unsi * Thus only use these when the result is not needed immediately. * Proper use case is calling from a callback function, since those cannot use yield() or delay() \*********************************************************************************************/ -void ESPEasy_Scheduler::schedule_plugin_task_event_timer(deviceIndex_t DeviceIndex, byte Function, struct EventStruct *event) { +void ESPEasy_Scheduler::schedule_plugin_task_event_timer(deviceIndex_t DeviceIndex, byte Function, struct EventStruct &&event) { if (validDeviceIndex(DeviceIndex)) { - schedule_event_timer(PluginPtrType::TaskPlugin, DeviceIndex, Function, event); + schedule_event_timer(PluginPtrType::TaskPlugin, DeviceIndex, Function, std::move(event)); } } @@ -1031,9 +1031,9 @@ void ESPEasy_Scheduler::schedule_mqtt_plugin_import_event_timer(deviceIndex_t } } -void ESPEasy_Scheduler::schedule_controller_event_timer(protocolIndex_t ProtocolIndex, byte Function, struct EventStruct *event) { +void ESPEasy_Scheduler::schedule_controller_event_timer(protocolIndex_t ProtocolIndex, byte Function, struct EventStruct &&event) { if (validProtocolIndex(ProtocolIndex)) { - schedule_event_timer(PluginPtrType::ControllerPlugin, ProtocolIndex, Function, event); + schedule_event_timer(PluginPtrType::ControllerPlugin, ProtocolIndex, Function, std::move(event)); } } @@ -1076,16 +1076,16 @@ void ESPEasy_Scheduler::schedule_mqtt_controller_event_timer(protocolIndex_t Pro } } -void ESPEasy_Scheduler::schedule_notification_event_timer(byte NotificationProtocolIndex, NPlugin::Function Function, struct EventStruct *event) { - schedule_event_timer(PluginPtrType::NotificationPlugin, NotificationProtocolIndex, static_cast(Function), event); +void ESPEasy_Scheduler::schedule_notification_event_timer(byte NotificationProtocolIndex, NPlugin::Function Function, struct EventStruct &&event) { + schedule_event_timer(PluginPtrType::NotificationPlugin, NotificationProtocolIndex, static_cast(Function), std::move(event)); } -void ESPEasy_Scheduler::schedule_event_timer(PluginPtrType ptr_type, byte Index, byte Function, struct EventStruct *event) { +void ESPEasy_Scheduler::schedule_event_timer(PluginPtrType ptr_type, byte Index, byte Function, struct EventStruct &&event) { const unsigned long mixedId = createSystemEventMixedId(ptr_type, Index, Function); // EventStructCommandWrapper eventWrapper(mixedId, *event); // ScheduledEventQueue.push_back(eventWrapper); - ScheduledEventQueue.emplace_back(mixedId, *event); + ScheduledEventQueue.emplace_back(mixedId, std::move(event)); } void ESPEasy_Scheduler::process_system_event_queue() { diff --git a/src/src/Helpers/Scheduler.h b/src/src/Helpers/Scheduler.h index 32b40e95a4..f28b624d30 100644 --- a/src/src/Helpers/Scheduler.h +++ b/src/src/Helpers/Scheduler.h @@ -230,9 +230,11 @@ class ESPEasy_Scheduler { * Thus only use these when the result is not needed immediately. * Proper use case is calling from a callback function, since those cannot use yield() or delay() \*********************************************************************************************/ + + // Note: event will be moved void schedule_plugin_task_event_timer(deviceIndex_t DeviceIndex, byte Function, - struct EventStruct *event); + struct EventStruct &&event); void schedule_mqtt_plugin_import_event_timer(deviceIndex_t DeviceIndex, taskIndex_t TaskIndex, @@ -242,9 +244,10 @@ class ESPEasy_Scheduler { unsigned int length); + // Note: the event will be moved void schedule_controller_event_timer(protocolIndex_t ProtocolIndex, byte Function, - struct EventStruct *event); + struct EventStruct &&event); void schedule_mqtt_controller_event_timer(protocolIndex_t ProtocolIndex, CPlugin::Function Function, @@ -252,9 +255,10 @@ class ESPEasy_Scheduler { byte *b_payload, unsigned int length); + // Note: The event will be moved void schedule_notification_event_timer(byte NotificationProtocolIndex, NPlugin::Function Function, - struct EventStruct *event); + struct EventStruct &&event); static unsigned long createSystemEventMixedId(PluginPtrType ptr_type, @@ -264,10 +268,11 @@ class ESPEasy_Scheduler { byte Index, byte Function); + // Note, the event will be moved void schedule_event_timer(PluginPtrType ptr_type, byte Index, byte Function, - struct EventStruct *event); + struct EventStruct &&event); void process_system_event_queue(); diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index 1a5cd57465..7bf19614f5 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -237,6 +237,7 @@ void addNewLine(String& line) { Format a value to the set number of decimals \*********************************************************************************************/ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck, bool& isvalid) { + if (event == nullptr) return ""; isvalid = true; const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); @@ -249,7 +250,8 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck { // First try to format using the plugin specific formatting. String result; - EventStruct tempEvent(*event); + EventStruct tempEvent; + tempEvent.deep_copy(event); tempEvent.idx = rel_index; PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, result); if (result.length() > 0) { diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index ac979a9d7f..551b571949 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -92,7 +92,7 @@ void handle_notifications() { { // TempEvent.NotificationProtocolIndex = NotificationProtocolIndex; TempEvent.NotificationIndex = notificationindex; - Scheduler.schedule_notification_event_timer(NotificationProtocolIndex, NPlugin::Function::NPLUGIN_NOTIFY, &TempEvent); + Scheduler.schedule_notification_event_timer(NotificationProtocolIndex, NPlugin::Function::NPLUGIN_NOTIFY, std::move(TempEvent)); } } } From f1dd1b2efbc8b3674a14dac56f00a7e20eeb2e71 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 21:20:33 +0200 Subject: [PATCH 164/404] [Controllers] Implement move constructor to guarantee no copy is made --- .../ControllerQueue/C011_queue_element.cpp | 32 +++++++++++----- src/src/ControllerQueue/C011_queue_element.h | 2 + .../ControllerQueue/C015_queue_element.cpp | 26 +++++++++---- src/src/ControllerQueue/C015_queue_element.h | 2 + .../ControllerQueue/C016_queue_element.cpp | 24 +++++++++--- src/src/ControllerQueue/C016_queue_element.h | 2 + .../ControllerQueue/C018_queue_element.cpp | 25 +++++++------ src/src/ControllerQueue/C018_queue_element.h | 2 + .../ControllerQueue/C019_queue_element.cpp | 22 ++++++++--- src/src/ControllerQueue/C019_queue_element.h | 2 + .../ControllerDelayHandlerStruct.h | 2 +- .../ControllerQueue/MQTT_queue_element.cpp | 37 ++++++++++--------- src/src/ControllerQueue/MQTT_queue_element.h | 14 ++++--- .../SimpleQueueElement_string_only.cpp | 18 ++++----- .../SimpleQueueElement_string_only.h | 2 + .../queue_element_formatted_uservar.cpp | 24 ++++++++++-- .../queue_element_formatted_uservar.h | 1 + .../queue_element_single_value_base.cpp | 20 +++++----- .../queue_element_single_value_base.h | 2 +- 19 files changed, 170 insertions(+), 89 deletions(-) diff --git a/src/src/ControllerQueue/C011_queue_element.cpp b/src/src/ControllerQueue/C011_queue_element.cpp index ca58a27057..90dd4ebe29 100644 --- a/src/src/ControllerQueue/C011_queue_element.cpp +++ b/src/src/ControllerQueue/C011_queue_element.cpp @@ -6,6 +6,18 @@ C011_queue_element::C011_queue_element() {} +C011_queue_element::C011_queue_element(C011_queue_element&& other) + : uri(std::move(other.uri)) + , HttpMethod(std::move(other.HttpMethod)) + , header(std::move(other.header)) + , postStr(std::move(other.postStr)) + , idx(other.idx) + , _timestamp(other._timestamp) + , TaskIndex(other.TaskIndex) + , controller_idx(other.controller_idx) + , sensorType(other.sensorType) +{} + C011_queue_element::C011_queue_element(const struct EventStruct *event) : idx(event->idx), TaskIndex(event->TaskIndex), @@ -14,6 +26,7 @@ C011_queue_element::C011_queue_element(const struct EventStruct *event) : size_t C011_queue_element::getSize() const { size_t total = sizeof(*this); + total += uri.length(); total += HttpMethod.length(); total += header.length(); @@ -22,17 +35,16 @@ size_t C011_queue_element::getSize() const { } bool C011_queue_element::isDuplicate(const C011_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.sensorType != sensorType || - other.idx != idx) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.sensorType != sensorType) || + (other.idx != idx)) { return false; } - return (other.uri.equals(uri) && - other.HttpMethod.equals(HttpMethod) && - other.header.equals(header) && - other.postStr.equals(postStr)); + return other.uri.equals(uri) && + other.HttpMethod.equals(HttpMethod) && + other.header.equals(header) && + other.postStr.equals(postStr); } - -#endif +#endif // ifdef USES_C011 diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 7ee5c97002..d65e06cb6a 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -21,6 +21,8 @@ class C011_queue_element { C011_queue_element(); + C011_queue_element(C011_queue_element&& other); + C011_queue_element(const struct EventStruct *event); bool isDuplicate(const C011_queue_element& other) const; diff --git a/src/src/ControllerQueue/C015_queue_element.cpp b/src/src/ControllerQueue/C015_queue_element.cpp index 4b2971845b..093168f665 100644 --- a/src/src/ControllerQueue/C015_queue_element.cpp +++ b/src/src/ControllerQueue/C015_queue_element.cpp @@ -6,6 +6,17 @@ C015_queue_element::C015_queue_element() {} +C015_queue_element::C015_queue_element(C015_queue_element&& other) + : idx(other.idx), _timestamp(other._timestamp), TaskIndex(other.TaskIndex) + , controller_idx(other.controller_idx), valuesSent(other.valuesSent) + , valueCount(other.valueCount) +{ + for (byte i = 0; i < VARS_PER_TASK; ++i) { + txt[i] = std::move(other.txt[i]); + vPin[i] = other.vPin[i]; + } +} + C015_queue_element::C015_queue_element(const struct EventStruct *event, byte value_count) : idx(event->idx), TaskIndex(event->TaskIndex), @@ -28,17 +39,19 @@ size_t C015_queue_element::getSize() const { } bool C015_queue_element::isDuplicate(const C015_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.sensorType != sensorType || - other.valueCount != valueCount || - other.idx != idx) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.sensorType != sensorType) || + (other.valueCount != valueCount) || + (other.idx != idx)) { return false; } + for (byte i = 0; i < VARS_PER_TASK; ++i) { if (other.txt[i] != txt[i]) { return false; } + if (other.vPin[i] != vPin[i]) { return false; } @@ -46,5 +59,4 @@ bool C015_queue_element::isDuplicate(const C015_queue_element& other) const { return true; } - -#endif +#endif // ifdef USES_C015 diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index 0b49602a0f..b222537c4d 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -21,6 +21,8 @@ class C015_queue_element { C015_queue_element(); + C015_queue_element(C015_queue_element&& other); + C015_queue_element(const struct EventStruct *event, byte value_count); bool checkDone(bool succesfull) const; diff --git a/src/src/ControllerQueue/C016_queue_element.cpp b/src/src/ControllerQueue/C016_queue_element.cpp index a4878c5d3e..96b54ef455 100644 --- a/src/src/ControllerQueue/C016_queue_element.cpp +++ b/src/src/ControllerQueue/C016_queue_element.cpp @@ -9,6 +9,18 @@ C016_queue_element::C016_queue_element() : _timestamp(0), TaskIndex(INVALID_TASK_INDEX), controller_idx(0), sensorType( Sensor_VType::SENSOR_TYPE_NONE) {} +C016_queue_element::C016_queue_element(C016_queue_element&& other) + : _timestamp(other._timestamp) + , TaskIndex(other.TaskIndex) + , controller_idx(other.controller_idx) + , sensorType(other.sensorType) + , valueCount(other.valueCount) +{ + for (byte i = 0; i < VARS_PER_TASK; ++i) { + values[i] = other.values[i]; + } +} + C016_queue_element::C016_queue_element(const struct EventStruct *event, byte value_count, unsigned long unixTime) : _timestamp(unixTime), TaskIndex(event->TaskIndex), @@ -30,12 +42,13 @@ size_t C016_queue_element::getSize() const { } bool C016_queue_element::isDuplicate(const C016_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.sensorType != sensorType || - other.valueCount != valueCount) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.sensorType != sensorType) || + (other.valueCount != valueCount)) { return false; } + for (byte i = 0; i < VARS_PER_TASK; ++i) { if (other.values[i] != values[i]) { return false; @@ -44,5 +57,4 @@ bool C016_queue_element::isDuplicate(const C016_queue_element& other) const { return true; } - -#endif +#endif // ifdef USES_C016 diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index bf76da72a4..b0c4054141 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -23,6 +23,8 @@ class C016_queue_element { C016_queue_element(); + C016_queue_element(C016_queue_element&& other); + C016_queue_element(const struct EventStruct *event, byte value_count, unsigned long unixTime); diff --git a/src/src/ControllerQueue/C018_queue_element.cpp b/src/src/ControllerQueue/C018_queue_element.cpp index 032de24f11..efc1f4bf4f 100644 --- a/src/src/ControllerQueue/C018_queue_element.cpp +++ b/src/src/ControllerQueue/C018_queue_element.cpp @@ -10,18 +10,26 @@ C018_queue_element::C018_queue_element() {} +C018_queue_element::C018_queue_element(C018_queue_element&& other) + : packed(std::move(other.packed)) + , _timestamp(other._timestamp) + , TaskIndex(other.TaskIndex) + , controller_idx(other.controller_idx) +{} + C018_queue_element::C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount) : TaskIndex(event->TaskIndex), controller_idx(event->ControllerIndex) { - #ifdef USES_PACKED_RAW_DATA + # ifdef USES_PACKED_RAW_DATA packed = getPackedFromPlugin(event, sampleSetCount); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("C018 queue element: "); log += packed; addLog(LOG_LEVEL_INFO, log); } - #endif // USES_PACKED_RAW_DATA + # endif // USES_PACKED_RAW_DATA } size_t C018_queue_element::getSize() const { @@ -29,17 +37,12 @@ size_t C018_queue_element::getSize() const { } bool C018_queue_element::isDuplicate(const C018_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.packed != packed)) { return false; } - for (byte i = 0; i < VARS_PER_TASK; ++i) { - if (other.packed[i] != packed[i]) { - return false; - } - } return true; } - -#endif +#endif // ifdef USES_C018 diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 3ab47d22cb..15eda87839 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -21,6 +21,8 @@ class C018_queue_element { C018_queue_element(); + C018_queue_element(C018_queue_element&& other); + C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount); diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 562753f1c7..0c3251ad07 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -11,6 +11,16 @@ String getPackedFromPlugin(struct EventStruct *event, C019_queue_element::C019_queue_element() {} +C019_queue_element::C019_queue_element(C019_queue_element&& other) + : packed(std::move(other.packed)) + , _timestamp(other._timestamp) + , TaskIndex(other.TaskIndex) + , controller_idx(other.controller_idx) + , plugin_id(other.plugin_id) + , event(std::move(other.event)) + , UnitMessageCount(other.UnitMessageCount) +{} + C019_queue_element::C019_queue_element(struct EventStruct *event_p) : controller_idx(event_p->ControllerIndex) { @@ -33,14 +43,14 @@ size_t C019_queue_element::getSize() const { return sizeof(*this) + packed.length(); } - bool C019_queue_element::isDuplicate(const C019_queue_element& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.plugin_id != plugin_id || - other.packed != packed) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.plugin_id != plugin_id) || + (other.packed != packed)) { return false; } + // FIXME TD-er: Must check event too? return false; -} \ No newline at end of file +} diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 21a9b6d912..ccb31d17d9 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -20,6 +20,8 @@ class C019_queue_element { C019_queue_element(); + C019_queue_element(C019_queue_element&& other); + C019_queue_element(struct EventStruct *event); size_t getSize() const; diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 769751c604..4ff0579bf0 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -153,7 +153,7 @@ struct ControllerDelayHandlerStruct { } if (!queueFull(element)) { - sendQueue.push_back(element); + sendQueue.push_back(std::move(element)); return true; } #ifndef BUILD_NO_DEBUG diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index b0d575accc..a26c3e0c03 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -3,6 +3,15 @@ MQTT_queue_element::MQTT_queue_element() {} +MQTT_queue_element::MQTT_queue_element(MQTT_queue_element&& other) + : _topic(std::move(other._topic)), + _payload(std::move(other._payload)), + _timestamp(other._timestamp), + TaskIndex(other.TaskIndex), + controller_idx(other.controller_idx), + _retained(other._retained), + UnitMessageCount(other.UnitMessageCount) {} + MQTT_queue_element::MQTT_queue_element(int ctrl_idx, taskIndex_t TaskIndex, const String& topic, const String& payload, bool retained) : @@ -11,12 +20,12 @@ MQTT_queue_element::MQTT_queue_element(int ctrl_idx, removeEmptyTopics(); } -MQTT_queue_element::MQTT_queue_element(int ctrl_idx, - taskIndex_t TaskIndex, - String&& topic, - String&& payload, - bool retained) - : +MQTT_queue_element::MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, + String && topic, + String && payload, + bool retained) + : _topic(std::move(topic)), _payload(std::move(payload)), TaskIndex(TaskIndex), controller_idx(ctrl_idx), _retained(retained) { removeEmptyTopics(); @@ -27,18 +36,12 @@ size_t MQTT_queue_element::getSize() const { } bool MQTT_queue_element::isDuplicate(const MQTT_queue_element& other) const { - if (other.controller_idx != controller_idx || - other._retained != _retained) { + if ((other.controller_idx != controller_idx) || + (other._retained != _retained) || + other._topic != _topic || + other._payload != _payload) { return false; } - for (byte i = 0; i < VARS_PER_TASK; ++i) { - if (other._topic[i] != _topic[i]) { - return false; - } - if (other._payload[i] != _payload[i]) { - return false; - } - } return true; } @@ -49,4 +52,4 @@ void MQTT_queue_element::removeEmptyTopics() { while (_topic.indexOf(F("//")) != -1) { _topic.replace(F("//"), F("/")); } -} \ No newline at end of file +} diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index 1c3037c122..ed493f6bf3 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -14,17 +14,19 @@ class MQTT_queue_element { MQTT_queue_element(); + MQTT_queue_element(MQTT_queue_element&& other); + explicit MQTT_queue_element(int ctrl_idx, taskIndex_t TaskIndex, const String& topic, const String& payload, bool retained); - explicit MQTT_queue_element(int ctrl_idx, - taskIndex_t TaskIndex, - String&& topic, - String&& payload, - bool retained); + explicit MQTT_queue_element(int ctrl_idx, + taskIndex_t TaskIndex, + String && topic, + String && payload, + bool retained); size_t getSize() const; @@ -41,7 +43,7 @@ class MQTT_queue_element { taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; bool _retained = false; - UnitMessageCount_t UnitMessageCount; + UnitMessageCount_t UnitMessageCount; }; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp index dccbebe887..7d5010a8bc 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp @@ -2,22 +2,22 @@ simple_queue_element_string_only::simple_queue_element_string_only() {} +simple_queue_element_string_only::simple_queue_element_string_only(simple_queue_element_string_only&& other) + : txt(std::move(other.txt)), _timestamp(other._timestamp), TaskIndex(other.TaskIndex), controller_idx(other.controller_idx) +{} + simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, String&& req) : - txt(std::move(req)), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} + txt(std::move(req)), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} size_t simple_queue_element_string_only::getSize() const { return sizeof(*this) + txt.length(); } bool simple_queue_element_string_only::isDuplicate(const simple_queue_element_string_only& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.txt != txt)) { return false; } - for (byte i = 0; i < VARS_PER_TASK; ++i) { - if (other.txt[i] != txt[i]) { - return false; - } - } return true; -} \ No newline at end of file +} diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 7923e7000c..69c65c6a93 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -14,6 +14,8 @@ class simple_queue_element_string_only { simple_queue_element_string_only(); + simple_queue_element_string_only(simple_queue_element_string_only&& other); + explicit simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, String&& req); diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp index 93a61a2aa1..edcd7aa177 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp @@ -7,6 +7,20 @@ queue_element_formatted_uservar::queue_element_formatted_uservar() {} +queue_element_formatted_uservar::queue_element_formatted_uservar(queue_element_formatted_uservar&& other) + : + idx(other.idx), + _timestamp(other._timestamp), + TaskIndex(other.TaskIndex), + controller_idx(other.controller_idx), + sensorType(other.sensorType), + valueCount(other.valueCount) +{ + for (size_t i = 0; i < VARS_PER_TASK; ++i) { + txt[i] = std::move(other.txt[i]); + } +} + queue_element_formatted_uservar::queue_element_formatted_uservar(EventStruct *event) : idx(event->idx), TaskIndex(event->TaskIndex), @@ -14,6 +28,7 @@ queue_element_formatted_uservar::queue_element_formatted_uservar(EventStruct *ev sensorType(event->sensorType) { valueCount = getValueCountForTask(TaskIndex); + for (byte i = 0; i < valueCount; ++i) { txt[i] = formatUserVarNoCheck(event, i); } @@ -29,12 +44,13 @@ size_t queue_element_formatted_uservar::getSize() const { } bool queue_element_formatted_uservar::isDuplicate(const queue_element_formatted_uservar& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.sensorType != sensorType || - other.valueCount != valueCount) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.sensorType != sensorType) || + (other.valueCount != valueCount)) { return false; } + for (byte i = 0; i < VARS_PER_TASK; ++i) { if (other.txt[i] != txt[i]) { return false; diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index 902b767ee5..e8f07e446b 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -17,6 +17,7 @@ class queue_element_formatted_uservar { public: queue_element_formatted_uservar(); + queue_element_formatted_uservar(queue_element_formatted_uservar&& other); queue_element_formatted_uservar(struct EventStruct *event); diff --git a/src/src/ControllerQueue/queue_element_single_value_base.cpp b/src/src/ControllerQueue/queue_element_single_value_base.cpp index c2740ddaaf..6657acb42f 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.cpp +++ b/src/src/ControllerQueue/queue_element_single_value_base.cpp @@ -11,18 +11,15 @@ queue_element_single_value_base::queue_element_single_value_base(const struct Ev valuesSent(0), valueCount(value_count) {} -/* -queue_element_single_value_base::queue_element_single_value_base(queue_element_single_value_base &&rval) -: idx(rval.idx), TaskIndex(rval.TaskIndex), - controller_idx(rval.controller_idx), +queue_element_single_value_base::queue_element_single_value_base(queue_element_single_value_base&& rval) + : idx(rval.idx), _timestamp(rval._timestamp), TaskIndex(rval.TaskIndex), + controller_idx(rval.controller_idx), valuesSent(rval.valuesSent), valueCount(rval.valueCount) { for (byte i = 0; i < VARS_PER_TASK; ++i) { - String tmp(std::move(rval.txt[i])); - txt[i] = tmp; + txt[i] = std::move(rval.txt[i]); } } -*/ bool queue_element_single_value_base::checkDone(bool succesfull) const { if (succesfull) { ++valuesSent; } @@ -39,12 +36,13 @@ size_t queue_element_single_value_base::getSize() const { } bool queue_element_single_value_base::isDuplicate(const queue_element_single_value_base& other) const { - if (other.controller_idx != controller_idx || - other.TaskIndex != TaskIndex || - other.valueCount != valueCount || - other.idx != idx) { + if ((other.controller_idx != controller_idx) || + (other.TaskIndex != TaskIndex) || + (other.valueCount != valueCount) || + (other.idx != idx)) { return false; } + for (byte i = 0; i < VARS_PER_TASK; ++i) { if (other.txt[i] != txt[i]) { return false; diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 7e0d20c1a3..31b220950e 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -22,7 +22,7 @@ class queue_element_single_value_base { queue_element_single_value_base(const struct EventStruct *event, byte value_count); -// queue_element_single_value_base(queue_element_single_value_base &&rval); + queue_element_single_value_base(queue_element_single_value_base &&rval); bool checkDone(bool succesfull) const; From 16b3a51b2943259bf19486daf5926da54fed649d Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 May 2021 22:42:03 +0200 Subject: [PATCH 165/404] [MQTT] Fix MQTT controller may not connect when re-enabled after a while --- src/src/ControllerQueue/DelayQueueElements.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/src/ControllerQueue/DelayQueueElements.cpp b/src/src/ControllerQueue/DelayQueueElements.cpp index 253835989a..9b684626d6 100644 --- a/src/src/ControllerQueue/DelayQueueElements.cpp +++ b/src/src/ControllerQueue/DelayQueueElements.cpp @@ -3,6 +3,7 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../DataStructs/TimingStats.h" #include "../Globals/ESPEasy_Scheduler.h" +#include "../Helpers/PeriodicalActions.h" #ifdef USES_MQTT ControllerDelayHandlerStruct *MQTTDelayHandler = nullptr; @@ -22,6 +23,8 @@ bool init_mqtt_delay_queue(controllerIndex_t ControllerIndex, String& pubname, b MQTTDelayHandler->configureControllerSettings(ControllerSettings); pubname = ControllerSettings.Publish; retainFlag = ControllerSettings.mqtt_retainFlag(); + Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible. + scheduleNextMQTTdelayQueue(); return true; } From ecf49cef234a579e3e0c4ec1159c2660007bb759 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 00:14:29 +0200 Subject: [PATCH 166/404] [ESPEasy-NOW] Check for max free block in RAM when processing mesh data --- src/src/DataStructs/ESPEasy_Now_packet.cpp | 16 +++++++++++----- src/src/DataStructs/ESPEasy_Now_packet.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 50ccf12930..d1411c8b57 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -4,16 +4,19 @@ # include "../../ESPEasy_fdwdecl.h" # include "../Helpers/CRC_functions.h" +# include "../Helpers/Memory.h" # define ESPEASY_NOW_MAX_PACKET_SIZE 200 ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { - setSize(payloadSize + sizeof(ESPEasy_now_hdr)); + const size_t requestedSize = payloadSize + sizeof(ESPEasy_now_hdr); + setSize(requestedSize); setHeader(header); } + ESPEasy_Now_packet::ESPEasy_Now_packet() : _valid(false) {} @@ -29,6 +32,10 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(ESPEasy_Now_packet&& other) ESPEasy_Now_packet& ESPEasy_Now_packet::operator=(ESPEasy_Now_packet&& other) { + if (&other == this) { + return *this; + } + for (size_t i = 0; i < 6; ++i) { _mac[i] = other._mac[i]; other._mac[i] = 0; @@ -36,6 +43,7 @@ ESPEasy_Now_packet& ESPEasy_Now_packet::operator=(ESPEasy_Now_packet&& other) _buf = std::move(other._buf); _valid = other._valid; other._valid = false; + return *this; } bool ESPEasy_Now_packet::setReceivedPacket(const MAC_address& mac, @@ -60,12 +68,10 @@ void ESPEasy_Now_packet::setSize(size_t packetSize) if (packetSize > ESPEASY_NOW_MAX_PACKET_SIZE) { packetSize = ESPEASY_NOW_MAX_PACKET_SIZE; } - #ifdef ESP8266 - const size_t maxFreeBlock = ESP.getMaxFreeBlockSize(); + const size_t maxFreeBlock = getMaxFreeBlock(); if (packetSize > maxFreeBlock) { packetSize = maxFreeBlock; } - #endif _buf.resize(packetSize); _valid = _buf.size() >= packetSize; @@ -97,7 +103,7 @@ size_t ESPEasy_Now_packet::getSize() const size_t ESPEasy_Now_packet::getPayloadSize() const { - size_t size = getSize(); + const size_t size = getSize(); if (size < sizeof(ESPEasy_now_hdr)) { // should not happen diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 0d222acefc..08d77fbc32 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -16,6 +16,7 @@ class ESPEasy_Now_packet { // Constructor for sending a packet + // Actual allocated size may be lower than requested. explicit ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize); From d7dcb058c13b21f98b23769a77752e767b63e271 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 00:15:05 +0200 Subject: [PATCH 167/404] [Memory] getMaxFreeBlock() should return valid value on ESP32 --- src/src/Helpers/Memory.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index 9572cf7343..b5d3831f4a 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -1,4 +1,4 @@ -#include "Memory.h" +#include "../Helpers/Memory.h" #ifdef ESP8266 @@ -77,14 +77,15 @@ unsigned long FreeMem(void) unsigned long getMaxFreeBlock() { - unsigned long freemem = FreeMem(); - - #ifdef CORE_POST_2_5_0 - + const unsigned long freemem = FreeMem(); // computing max free block is a rather extensive operation, so only perform when free memory is already low. if (freemem < 6144) { + #if defined(ESP32) + return ESP.getMaxAllocHeap(); + #endif // if defined(ESP32) + #ifdef CORE_POST_2_5_0 return ESP.getMaxFreeBlockSize(); - } #endif // ifdef CORE_POST_2_5_0 + } return freemem; } From ed72ad820b6d7e8d7bc1ea4ed42f19dfc718dd80 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 12:56:16 +0200 Subject: [PATCH 168/404] [Network] Properly switch between ETH and WiFi ESP32 does send events for connected/disconnected only once. So we cannot rely on the events. Also the WiFi disconnect was not handled well when switching between network media. --- src/src/Commands/MQTT.cpp | 1 + src/src/DataStructs/EthernetEventData.cpp | 2 + src/src/DataStructs/WiFiEventData.h | 5 ++ src/src/ESPEasyCore/ESPEasyEth.cpp | 30 +++++++- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 6 +- src/src/ESPEasyCore/ESPEasyWifi.cpp | 18 ++++- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 77 +++++++++++-------- src/src/Helpers/PeriodicalActions.cpp | 1 + 8 files changed, 106 insertions(+), 34 deletions(-) diff --git a/src/src/Commands/MQTT.cpp b/src/src/Commands/MQTT.cpp index 1dfb9adecd..5b453ecbe3 100644 --- a/src/src/Commands/MQTT.cpp +++ b/src/src/Commands/MQTT.cpp @@ -76,6 +76,7 @@ boolean MQTTsubscribe(controllerIndex_t controller_idx, const char* topic, boole { if (MQTTclient.subscribe(topic)) { Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible. + scheduleNextMQTTdelayQueue(); String log = F("Subscribed to: "); log += topic; addLog(LOG_LEVEL_INFO, log); return true; diff --git a/src/src/DataStructs/EthernetEventData.cpp b/src/src/DataStructs/EthernetEventData.cpp index 2151138ec1..65df1e49db 100644 --- a/src/src/DataStructs/EthernetEventData.cpp +++ b/src/src/DataStructs/EthernetEventData.cpp @@ -108,6 +108,7 @@ void EthernetEventData_t::markGotIP() { void EthernetEventData_t::markLostIP() { bitClear(ethStatus, ESPEASY_ETH_GOT_IP); bitClear(ethStatus, ESPEASY_ETH_SERVICES_INITIALIZED); + lastGetIPmoment.clear(); } void EthernetEventData_t::markDisconnect() { @@ -119,6 +120,7 @@ void EthernetEventData_t::markDisconnect() { } else { lastConnectedDuration_us = lastConnectMoment.timeDiff(lastDisconnectMoment); } + lastConnectMoment.clear(); setEthDisconnected(); processedDisconnect = false; } diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 3b855df338..3cb2330bfc 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -107,6 +107,11 @@ struct WiFiEventData_t { bool performedClearWiFiCredentials = false; + // processDisconnect() may clear all WiFi settings, resulting in clearing processedDisconnect + // This can cause recursion, so a semaphore is needed here. + bool processingDisconnect = false; + + unsigned long connectionFailures = 0; diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index 0cc6b65463..9303df4136 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -106,11 +106,39 @@ bool ETHConnectRelaxed() { Settings.ETH_Pin_mdio, (eth_phy_type_t)Settings.ETH_Phy_Type, (eth_clock_mode_t)Settings.ETH_Clock_Mode); + if (EthEventData.ethInitSuccess) { + EthEventData.ethConnectAttemptNeeded = false; + } return EthEventData.ethInitSuccess; } bool ETHConnected() { - return EthEventData.EthServicesInitialized(); + if (EthEventData.EthServicesInitialized()) { + if (EthLinkUp()) { + return true; + } + // Apparently we missed an event + EthEventData.processedDisconnect = false; + } else if (EthEventData.ethInitSuccess) { + if (EthLinkUp()) { + EthEventData.setEthConnected(); + if (NetworkLocalIP() != IPAddress(0, 0, 0, 0) && + !EthEventData.EthGotIP()) { + EthEventData.processedGotIP = false; + } + if (EthEventData.lastConnectMoment.isSet()) { + if (!EthEventData.EthServicesInitialized()) { + if (EthEventData.lastConnectMoment.millisPassedSince() > 10000 && + EthEventData.lastGetIPmoment.isSet()) { + EthEventData.processedGotIP = false; + EthEventData.markLostIP(); + } + } + } + return false; + } + } + return false; } #endif \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 7fe4fc2fbc..51d5680825 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -248,7 +248,11 @@ String WifiSoftAPmacAddress() { void CheckRunningServices() { set_mDNS(); - SetWiFiTXpower(); + if (active_network_medium == NetworkMedium_t::WIFI || + active_network_medium == NetworkMedium_t::ESPEasyNOW_only) + { + SetWiFiTXpower(); + } } #ifdef HAS_ETHERNET diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 90f8021473..1c236eaf2d 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -662,7 +662,23 @@ bool WiFiScanAllowed() { handle_unprocessedNetworkEvents(); } if (WiFiEventData.unprocessedWifiEvents()) { - addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not allowed, unprocessed WiFi events")); + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log = F("WiFi : Scan not allowed, unprocessed WiFi events: "); + if (!WiFiEventData.processedConnect) { + log += F(" conn"); + } + if (!WiFiEventData.processedDisconnect) { + log += F(" disconn"); + } + if (!WiFiEventData.processedGotIP) { + log += F(" gotIP"); + } + if (!WiFiEventData.processedDHCPTimeout) { + log += F(" DHCP_t/o"); + } + + addLog(LOG_LEVEL_ERROR, log); + } return false; } /* diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 290f6d6b7f..5bd7de3fe3 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -31,6 +31,7 @@ #include "../Helpers/Misc.h" #include "../Helpers/Network.h" #include "../Helpers/Networking.h" +#include "../Helpers/PeriodicalActions.h" #include "../Helpers/Scheduler.h" #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_WiFi.h" @@ -42,13 +43,23 @@ void handle_unprocessedNetworkEvents() { #ifdef HAS_ETHERNET - // Must process the Ethernet Connected event regardless the active network medium. - // It may happen by plugging in the cable while WiFi was active. - if (!EthEventData.processedConnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("Eth : Entering processConnect()")); - #endif // ifndef BUILD_NO_DEBUG - processEthernetConnected(); + if (EthEventData.unprocessedEthEvents()) { + // Process disconnect events before connect events. + if (!EthEventData.processedDisconnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("Eth : Entering processDisconnect()")); + #endif // ifndef BUILD_NO_DEBUG + processEthernetDisconnected(); + } + + // Must process the Ethernet Connected event regardless the active network medium. + // It may happen by plugging in the cable while WiFi was active. + if (!EthEventData.processedConnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("Eth : Entering processConnect()")); + #endif // ifndef BUILD_NO_DEBUG + processEthernetConnected(); + } } if (active_network_medium == NetworkMedium_t::Ethernet) { @@ -58,14 +69,6 @@ void handle_unprocessedNetworkEvents() NetworkConnectRelaxed(); } - // Process disconnect events before connect events. - if (!EthEventData.processedDisconnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("Eth : Entering processDisconnect()")); - #endif // ifndef BUILD_NO_DEBUG - processEthernetDisconnected(); - } - if (!EthEventData.processedGotIP) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("Eth : Entering processGotIP()")); @@ -85,6 +88,16 @@ void handle_unprocessedNetworkEvents() } #endif + if (WiFiEventData.unprocessedWifiEvents()) { + // Process disconnect events before connect events. + if (!WiFiEventData.processedDisconnect) { + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processDisconnect()")); + #endif // ifndef BUILD_NO_DEBUG + processDisconnect(); + } + } + if (active_network_medium == NetworkMedium_t::WIFI || active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents()) { if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { @@ -97,14 +110,6 @@ void handle_unprocessedNetworkEvents() NetworkConnectRelaxed(); - // Process disconnect events before connect events. - if (!WiFiEventData.processedDisconnect) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processDisconnect()")); - #endif // ifndef BUILD_NO_DEBUG - processDisconnect(); - } - if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); @@ -205,8 +210,9 @@ void handle_unprocessedNetworkEvents() // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** void processDisconnect() { - if (WiFiEventData.processedDisconnect) { return; } - WiFiEventData.processedDisconnect = true; + if (WiFiEventData.processedDisconnect || + WiFiEventData.processingDisconnect) { return; } + WiFiEventData.processingDisconnect = true; WiFiEventData.setWiFiDisconnected(); WiFiEventData.wifiConnectAttemptNeeded = true; delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 @@ -254,6 +260,8 @@ void processDisconnect() { WifiScan(false); } logConnectionStatus(); + WiFiEventData.processedDisconnect = true; + WiFiEventData.processingDisconnect = false; } void processConnect() { @@ -403,6 +411,7 @@ void processGotIP() { MQTTclient_should_reconnect = true; timermqtt_interval = 100; Scheduler.setIntervalTimer(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT); + scheduleNextMQTTdelayQueue(); #endif // USES_MQTT Scheduler.sendGratuitousARP_now(); @@ -641,11 +650,11 @@ void processEthernetConnected() { void processEthernetDisconnected() { EthEventData.setEthDisconnected(); EthEventData.processedDisconnect = true; + EthEventData.ethConnectAttemptNeeded = true; if (Settings.UseRules) { eventQueue.add(F("ETHERNET#Disconnected")); } - setNetworkMedium(NetworkMedium_t::WIFI); } void processEthernetGotIP() { @@ -659,15 +668,19 @@ void processEthernetGotIP() { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("ETH MAC: "); + String log; + log.reserve(160); + log = F("ETH MAC: "); log += NetworkMacAddress(); + log += ' '; if (useStaticIP()) { - log += F("Static IP: "); + log += F("Static"); } else { - log += F("DHCP IP: "); + log += F("DHCP"); } + log += F(" IP: "); log += NetworkLocalIP().toString(); - log += " ("; + log += F(" ("); log += NetworkGetHostname(); log += F(") GW: "); log += NetworkGatewayIP().toString(); @@ -677,7 +690,7 @@ void processEthernetGotIP() { if (EthFullDuplex()) { log += F(" FULL_DUPLEX"); } - log += F(" "); + log += ' '; log += EthLinkSpeed(); log += F("Mbps"); } else { @@ -703,6 +716,7 @@ void processEthernetGotIP() { MQTTclient_should_reconnect = true; timermqtt_interval = 100; Scheduler.setIntervalTimer(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT); + scheduleNextMQTTdelayQueue(); #endif // USES_MQTT Scheduler.sendGratuitousARP_now(); @@ -715,6 +729,7 @@ void processEthernetGotIP() { EthEventData.processedGotIP = true; EthEventData.setEthGotIP(); + CheckRunningServices(); } #endif \ No newline at end of file diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 1eeb24b413..2143a6cddc 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -424,6 +424,7 @@ void updateMQTTclient_connected() { timermqtt_interval = 250; } Scheduler.setIntervalTimer(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT); + scheduleNextMQTTdelayQueue(); } void runPeriodicalMQTT() { From d3f21cd366d0c082bb571245fa53f798d12c50f7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 13:23:35 +0200 Subject: [PATCH 169/404] [WiFi] Show WiFi STA MAC in sysinfo when eth is active --- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 8 ++++++++ src/src/ESPEasyCore/ESPEasyNetwork.h | 1 + src/src/Helpers/StringProvider.cpp | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 51d5680825..6e25d22866 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -246,6 +246,14 @@ String WifiSoftAPmacAddress() { return String(macaddress); } +String WifiSTAmacAddress() { + uint8_t mac[] = { 0, 0, 0, 0, 0, 0 }; + uint8_t *macread = WiFi.macAddress(mac); + char macaddress[20]; + formatMAC(macread, macaddress); + return String(macaddress); +} + void CheckRunningServices() { set_mDNS(); if (active_network_medium == NetworkMedium_t::WIFI || diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 6c4b5a8025..6833b7377c 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -23,6 +23,7 @@ String NetworkGetHostname(); String NetworkCreateRFCCompliantHostname(bool force_add_unitnr = false); String createRFCCompliantHostname(const String& oldString); String WifiSoftAPmacAddress(); +String WifiSTAmacAddress(); void CheckRunningServices(); diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index ad9aa03304..c2d2f6ef85 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -266,7 +266,7 @@ String getValue(LabelType::Enum label) { case LabelType::DNS_1: return NetworkDnsIP(0).toString(); case LabelType::DNS_2: return NetworkDnsIP(1).toString(); case LabelType::ALLOWED_IP_RANGE: return describeAllowedIPrange(); - case LabelType::STA_MAC: return NetworkMacAddress(); + case LabelType::STA_MAC: return WifiSTAmacAddress(); case LabelType::AP_MAC: return WifiSoftAPmacAddress(); case LabelType::SSID: return WiFi.SSID(); case LabelType::BSSID: return WiFi.BSSIDstr(); From e737d4c53b4062623f00d922c4cb93a227ec1aa5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 13:48:24 +0200 Subject: [PATCH 170/404] [Network] Allow fallback to WiFi when Ethernet not connected at boot --- src/src/ESPEasyCore/ESPEasyEth.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index 9303df4136..d66b64fe36 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -136,6 +136,8 @@ bool ETHConnected() { } } return false; + } else { + setNetworkMedium(NetworkMedium_t::WIFI); } } return false; diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 6e25d22866..57765d3dc0 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -51,6 +51,9 @@ void setNetworkMedium(NetworkMedium_t new_medium) { #ifdef HAS_ETHERNET // FIXME TD-er: How to 'end' ETH? // ETH.end(); + if (new_medium == NetworkMedium_t::WIFI) { + WiFiEventData.clearAll(); + } #endif break; case NetworkMedium_t::WIFI: From d51f0d0e3789018da90e66d2f4d67ee839dab43b Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 22:40:34 +0200 Subject: [PATCH 171/404] [Oopsie] Need to hide in other commits, deny this ever was committed! As reported on [the forum](https://www.letscontrolit.com/forum/viewtopic.php?f=6&t=8528&p=52439#p52439) --- src/src/Helpers/PeriodicalActions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 2143a6cddc..fb0002b600 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -268,7 +268,9 @@ void runEach30Seconds() void scheduleNextMQTTdelayQueue() { - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT_DELAY_QUEUE, MQTTDelayHandler->getNextScheduleTime()); + if (MQTTDelayHandler != nullptr) { + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT_DELAY_QUEUE, MQTTDelayHandler->getNextScheduleTime()); + } } void schedule_all_tasks_using_MQTT_controller() { From 47f947b6b811c3ffcdabfa449fd3a612b00fda5c Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 May 2021 23:53:20 +0200 Subject: [PATCH 172/404] [Cleanup] Remove unneeded std::move and copy/assignment constructors --- src/_C001.ino | 2 +- src/_C003.ino | 2 +- src/_C004.ino | 2 +- src/_C007.ino | 2 +- src/_C008.ino | 2 +- src/_C009.ino | 2 +- src/_C011.ino | 2 +- src/_C015.ino | 2 +- src/_C017.ino | 2 +- src/_C019.ino | 2 +- src/src/DataStructs/ESPEasy_EventStruct.cpp | 82 +-------------------- src/src/DataStructs/ESPEasy_EventStruct.h | 14 +++- src/src/ESPEasyCore/Controller.cpp | 4 +- 13 files changed, 25 insertions(+), 95 deletions(-) diff --git a/src/_C001.ino b/src/_C001.ino index fe3050b614..8acd3baed0 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -111,7 +111,7 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& url += mapVccToDomoticz(); # endif // if FEATURE_ADC_VCC - success = C001_DelayHandler->addToQueue(std::move(C001_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url)))); + success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C001_DELAY_QUEUE, C001_DelayHandler->getNextScheduleTime()); } diff --git a/src/_C003.ino b/src/_C003.ino index d9bb7e07b4..f7b2a9b79e 100644 --- a/src/_C003.ino +++ b/src/_C003.ino @@ -56,7 +56,7 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& url += ","; url += formatUserVarNoCheck(event, 0); url += "\n"; - success = C003_DelayHandler->addToQueue(std::move(C003_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url)))); + success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url))); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C004.ino b/src/_C004.ino index 46cef34251..0e14d9c628 100644 --- a/src/_C004.ino +++ b/src/_C004.ino @@ -67,7 +67,7 @@ bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& if (C004_DelayHandler == nullptr) { break; } - success = C004_DelayHandler->addToQueue(std::move(C004_queue_element(event))); + success = C004_DelayHandler->addToQueue(C004_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C004_DELAY_QUEUE, C004_DelayHandler->getNextScheduleTime()); break; diff --git a/src/_C007.ino b/src/_C007.ino index f0d95e52e4..3cd69456c1 100644 --- a/src/_C007.ino +++ b/src/_C007.ino @@ -63,7 +63,7 @@ bool CPlugin_007(CPlugin::Function function, struct EventStruct *event, String& addLog(LOG_LEVEL_ERROR, F("emoncms : Unknown sensortype or too many sensor values")); break; } - success = C007_DelayHandler->addToQueue(std::move(C007_queue_element(event))); + success = C007_DelayHandler->addToQueue(C007_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C007_DELAY_QUEUE, C007_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C008.ino b/src/_C008.ino index 9e095a38c6..44165f4700 100644 --- a/src/_C008.ino +++ b/src/_C008.ino @@ -76,7 +76,7 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& byte valueCount = getValueCountForTask(event->TaskIndex); - success = C008_DelayHandler->addToQueue(std::move(C008_queue_element(event, valueCount))); + success = C008_DelayHandler->addToQueue(C008_queue_element(event, valueCount)); if (success) { // Element was added. diff --git a/src/_C009.ino b/src/_C009.ino index ae6161adc9..0fbc3a8099 100644 --- a/src/_C009.ino +++ b/src/_C009.ino @@ -77,7 +77,7 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& } - success = C009_DelayHandler->addToQueue(std::move(C009_queue_element(event))); + success = C009_DelayHandler->addToQueue(C009_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C011.ino b/src/_C011.ino index c5b5bc52bb..c8d9ef138d 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -237,7 +237,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) LoadTaskSettings(event->TaskIndex); // Add a new element to the queue with the minimal payload - bool success = C011_DelayHandler->addToQueue(std::move(C011_queue_element(event))); + bool success = C011_DelayHandler->addToQueue(C011_queue_element(event)); if (success) { // Element was added. diff --git a/src/_C015.ino b/src/_C015.ino index 8ce36108a0..49d535b067 100644 --- a/src/_C015.ino +++ b/src/_C015.ino @@ -168,7 +168,7 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& byte valueCount = getValueCountForTask(event->TaskIndex); - success = C015_DelayHandler->addToQueue(std::move(C015_queue_element(event, valueCount))); + success = C015_DelayHandler->addToQueue(C015_queue_element(event, valueCount)); if (success) { // Element was added. diff --git a/src/_C017.ino b/src/_C017.ino index 01502b1b3e..36f086d70d 100644 --- a/src/_C017.ino +++ b/src/_C017.ino @@ -64,7 +64,7 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String& break; } - success = C017_DelayHandler->addToQueue(std::move(C017_queue_element(event))); + success = C017_DelayHandler->addToQueue(C017_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C017_DELAY_QUEUE, C017_DelayHandler->getNextScheduleTime()); break; } diff --git a/src/_C019.ino b/src/_C019.ino index d1f43b229e..4b124e4e59 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -63,7 +63,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - success = C019_DelayHandler->addToQueue(std::move(C019_queue_element(event))); + success = C019_DelayHandler->addToQueue(C019_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C019_DELAY_QUEUE, C019_DelayHandler->getNextScheduleTime()); break; diff --git a/src/src/DataStructs/ESPEasy_EventStruct.cpp b/src/src/DataStructs/ESPEasy_EventStruct.cpp index bc01a4c155..06f3490f4f 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.cpp +++ b/src/src/DataStructs/ESPEasy_EventStruct.cpp @@ -14,59 +14,8 @@ EventStruct::EventStruct(taskIndex_t taskIndex) : TaskIndex(taskIndex), BaseVarIndex(taskIndex * VARS_PER_TASK) {} -EventStruct::EventStruct(struct EventStruct&& event) : - String1(std::move(event.String1)) - , String2(std::move(event.String2)) - , String3(std::move(event.String3)) - , String4(std::move(event.String4)) - , String5(std::move(event.String5)) - , Data(event.Data) - , idx(event.idx) - , Par1(event.Par1), Par2(event.Par2), Par3(event.Par3), Par4(event.Par4), Par5(event.Par5) - , Source(event.Source), TaskIndex(event.TaskIndex), ControllerIndex(event.ControllerIndex) - , NotificationIndex(event.NotificationIndex) - , BaseVarIndex(event.BaseVarIndex), sensorType(event.sensorType) - , OriginTaskIndex(event.OriginTaskIndex) { - event.Data = nullptr; - event.idx = 0; - event.Par1 = 0; - event.Par2 = 0; - event.Par3 = 0; - event.Par4 = 0; - event.Par5 = 0; - event.Source = EventValueSource::Enum::VALUE_SOURCE_NOT_SET; - event.TaskIndex = INVALID_TASK_INDEX; - event.ControllerIndex = INVALID_CONTROLLER_INDEX; - event.NotificationIndex = INVALID_NOTIFIER_INDEX; // index position in Settings.Notification, 0-3 - event.BaseVarIndex = 0; - event.sensorType = Sensor_VType::SENSOR_TYPE_NOT_SET; - event.OriginTaskIndex = 0; - } - void EventStruct::deep_copy(const struct EventStruct& other) { - // check for self-assignment - if (&other == this) { - return; - } - String1 = other.String1; - String2 = other.String2; - String3 = other.String3; - String4 = other.String4; - String5 = other.String5; - Data = other.Data; - idx = other.idx; - Par1 = other.Par1; - Par2 = other.Par2; - Par3 = other.Par3; - Par4 = other.Par4; - Par5 = other.Par5; - Source = other.Source; - TaskIndex = other.TaskIndex; - ControllerIndex = other.ControllerIndex; - NotificationIndex = other.NotificationIndex; - BaseVarIndex = other.BaseVarIndex; - sensorType = other.sensorType; - OriginTaskIndex = other.OriginTaskIndex; + this->operator=(other); } void EventStruct::deep_copy(const struct EventStruct* other) { @@ -75,35 +24,6 @@ void EventStruct::deep_copy(const struct EventStruct* other) { } } - -EventStruct& EventStruct::operator=(struct EventStruct&& other) { - // check for self-assignment - if (&other == this) { - return *this; - } - String1 = std::move(other.String1); - String2 = std::move(other.String2); - String3 = std::move(other.String3); - String4 = std::move(other.String4); - String5 = std::move(other.String5); - Data = other.Data; - idx = other.idx; - Par1 = other.Par1; - Par2 = other.Par2; - Par3 = other.Par3; - Par4 = other.Par4; - Par5 = other.Par5; - Source = other.Source; - TaskIndex = other.TaskIndex; - ControllerIndex = other.ControllerIndex; - NotificationIndex = other.NotificationIndex; - BaseVarIndex = other.BaseVarIndex; - sensorType = other.sensorType; - OriginTaskIndex = other.OriginTaskIndex; - return *this; -} - - void EventStruct::setTaskIndex(taskIndex_t taskIndex) { TaskIndex = taskIndex; BaseVarIndex = taskIndex * VARS_PER_TASK; diff --git a/src/src/DataStructs/ESPEasy_EventStruct.h b/src/src/DataStructs/ESPEasy_EventStruct.h index d91e90d613..48965b8593 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.h +++ b/src/src/DataStructs/ESPEasy_EventStruct.h @@ -14,13 +14,23 @@ /*********************************************************************************************\ * EventStruct +* This should not be copied, only moved. +* When copy is really needed, use deep_copy \*********************************************************************************************/ struct EventStruct { EventStruct(); + // Delete the copy constructor + EventStruct(const struct EventStruct& event) = delete; +private: + // Hide the copy assignment operator by making it private + EventStruct& operator=(const EventStruct&) = default; + +public: + EventStruct(struct EventStruct&& event) = default; + EventStruct& operator=(struct EventStruct&& other) = default; + explicit EventStruct(taskIndex_t taskIndex); - explicit EventStruct(struct EventStruct&& event); - EventStruct& operator=(struct EventStruct&& other); // Explicit deep_copy function to make sure this object is not accidentally copied using the copy-constructor // Copy constructor and assignment operator should not be used. diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 664bb9b656..aa0f32e1e8 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -564,7 +564,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const if (MQTT_queueFull(controller_idx)) { return false; } - const bool success = MQTTDelayHandler->addToQueue(std::move(MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained))); + const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained)); scheduleNextMQTTdelayQueue(); return success; @@ -578,7 +578,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, Strin if (MQTT_queueFull(controller_idx)) { return false; } - const bool success = MQTTDelayHandler->addToQueue(std::move(MQTT_queue_element(controller_idx, taskIndex, std::move(topic), std::move(payload), retained))); + const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, taskIndex, std::move(topic), std::move(payload), retained)); scheduleNextMQTTdelayQueue(); return success; From cc11f85b5af22f66b5f95706d32e9b502f5e6754 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 6 May 2021 00:07:53 +0200 Subject: [PATCH 173/404] [Controller Queue] Remove unneeded constructors using =default and =delete --- src/src/ControllerQueue/C011_queue_element.cpp | 13 ------------- src/src/ControllerQueue/C011_queue_element.h | 6 ++++-- src/src/ControllerQueue/C015_queue_element.cpp | 2 -- src/src/ControllerQueue/C015_queue_element.h | 4 +++- src/src/ControllerQueue/C018_queue_element.cpp | 9 --------- src/src/ControllerQueue/C018_queue_element.h | 6 ++++-- src/src/ControllerQueue/C019_queue_element.cpp | 12 ------------ src/src/ControllerQueue/C019_queue_element.h | 6 ++++-- src/src/ControllerQueue/MQTT_queue_element.cpp | 11 ----------- src/src/ControllerQueue/MQTT_queue_element.h | 6 ++++-- .../SimpleQueueElement_string_only.cpp | 5 ----- .../SimpleQueueElement_string_only.h | 6 ++++-- .../queue_element_formatted_uservar.cpp | 2 -- .../queue_element_formatted_uservar.h | 3 ++- .../queue_element_single_value_base.cpp | 2 -- .../queue_element_single_value_base.h | 4 +++- src/src/DataStructs/ESPEasyControllerCache.h | 2 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 4 ---- src/src/DataStructs/ESPEasy_Now_packet.h | 5 ++++- src/src/DataStructs/ESPEasy_now_merger.cpp | 16 ---------------- src/src/DataStructs/ESPEasy_now_merger.h | 6 +++--- src/src/DataStructs/ESPEasy_now_traceroute.cpp | 4 ---- src/src/DataStructs/ESPEasy_now_traceroute.h | 2 +- src/src/DataStructs/ESPeasyControllerCache.cpp | 2 -- src/src/DataStructs/EventQueue.cpp | 2 -- src/src/DataStructs/EventQueue.h | 2 +- 26 files changed, 38 insertions(+), 104 deletions(-) diff --git a/src/src/ControllerQueue/C011_queue_element.cpp b/src/src/ControllerQueue/C011_queue_element.cpp index 90dd4ebe29..828f9f7985 100644 --- a/src/src/ControllerQueue/C011_queue_element.cpp +++ b/src/src/ControllerQueue/C011_queue_element.cpp @@ -4,19 +4,6 @@ #ifdef USES_C011 -C011_queue_element::C011_queue_element() {} - -C011_queue_element::C011_queue_element(C011_queue_element&& other) - : uri(std::move(other.uri)) - , HttpMethod(std::move(other.HttpMethod)) - , header(std::move(other.header)) - , postStr(std::move(other.postStr)) - , idx(other.idx) - , _timestamp(other._timestamp) - , TaskIndex(other.TaskIndex) - , controller_idx(other.controller_idx) - , sensorType(other.sensorType) -{} C011_queue_element::C011_queue_element(const struct EventStruct *event) : idx(event->idx), diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index d65e06cb6a..5b909d44bf 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -19,9 +19,11 @@ struct EventStruct; class C011_queue_element { public: - C011_queue_element(); + C011_queue_element() = default; - C011_queue_element(C011_queue_element&& other); + C011_queue_element(C011_queue_element&& other) = default; + + C011_queue_element(const C011_queue_element& other) = delete; C011_queue_element(const struct EventStruct *event); diff --git a/src/src/ControllerQueue/C015_queue_element.cpp b/src/src/ControllerQueue/C015_queue_element.cpp index 093168f665..984cb46bfc 100644 --- a/src/src/ControllerQueue/C015_queue_element.cpp +++ b/src/src/ControllerQueue/C015_queue_element.cpp @@ -4,8 +4,6 @@ #ifdef USES_C015 -C015_queue_element::C015_queue_element() {} - C015_queue_element::C015_queue_element(C015_queue_element&& other) : idx(other.idx), _timestamp(other._timestamp), TaskIndex(other.TaskIndex) , controller_idx(other.controller_idx), valuesSent(other.valuesSent) diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index b222537c4d..cee9083ec1 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -19,7 +19,9 @@ struct EventStruct; class C015_queue_element { public: - C015_queue_element(); + C015_queue_element() = default; + + C015_queue_element(const C015_queue_element& other) = delete; C015_queue_element(C015_queue_element&& other); diff --git a/src/src/ControllerQueue/C018_queue_element.cpp b/src/src/ControllerQueue/C018_queue_element.cpp index efc1f4bf4f..96911c9632 100644 --- a/src/src/ControllerQueue/C018_queue_element.cpp +++ b/src/src/ControllerQueue/C018_queue_element.cpp @@ -8,15 +8,6 @@ #ifdef USES_C018 -C018_queue_element::C018_queue_element() {} - -C018_queue_element::C018_queue_element(C018_queue_element&& other) - : packed(std::move(other.packed)) - , _timestamp(other._timestamp) - , TaskIndex(other.TaskIndex) - , controller_idx(other.controller_idx) -{} - C018_queue_element::C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount) : TaskIndex(event->TaskIndex), controller_idx(event->ControllerIndex) diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 15eda87839..b07a483061 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -19,9 +19,11 @@ struct EventStruct; class C018_queue_element { public: - C018_queue_element(); + C018_queue_element() = default; - C018_queue_element(C018_queue_element&& other); + C018_queue_element(const C018_queue_element& other) = delete; + + C018_queue_element(C018_queue_element&& other) = default; C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount); diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 0c3251ad07..9785453b79 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -9,18 +9,6 @@ String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount); #endif // USES_PACKED_RAW_DATA -C019_queue_element::C019_queue_element() {} - -C019_queue_element::C019_queue_element(C019_queue_element&& other) - : packed(std::move(other.packed)) - , _timestamp(other._timestamp) - , TaskIndex(other.TaskIndex) - , controller_idx(other.controller_idx) - , plugin_id(other.plugin_id) - , event(std::move(other.event)) - , UnitMessageCount(other.UnitMessageCount) -{} - C019_queue_element::C019_queue_element(struct EventStruct *event_p) : controller_idx(event_p->ControllerIndex) { diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index ccb31d17d9..187b0b62a9 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -18,9 +18,11 @@ class C019_queue_element { public: - C019_queue_element(); + C019_queue_element() = default; - C019_queue_element(C019_queue_element&& other); + C019_queue_element(const C019_queue_element& other) = delete; + + C019_queue_element(C019_queue_element&& other) = default; C019_queue_element(struct EventStruct *event); diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index a26c3e0c03..9acaa0cc9b 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -1,17 +1,6 @@ #include "../ControllerQueue/MQTT_queue_element.h" -MQTT_queue_element::MQTT_queue_element() {} - -MQTT_queue_element::MQTT_queue_element(MQTT_queue_element&& other) - : _topic(std::move(other._topic)), - _payload(std::move(other._payload)), - _timestamp(other._timestamp), - TaskIndex(other.TaskIndex), - controller_idx(other.controller_idx), - _retained(other._retained), - UnitMessageCount(other.UnitMessageCount) {} - MQTT_queue_element::MQTT_queue_element(int ctrl_idx, taskIndex_t TaskIndex, const String& topic, const String& payload, bool retained) : diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index ed493f6bf3..c6ec8471e2 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -12,9 +12,11 @@ class MQTT_queue_element { public: - MQTT_queue_element(); + MQTT_queue_element() = default; - MQTT_queue_element(MQTT_queue_element&& other); + MQTT_queue_element(const MQTT_queue_element& other) = delete; + + MQTT_queue_element(MQTT_queue_element&& other) = default; explicit MQTT_queue_element(int ctrl_idx, taskIndex_t TaskIndex, diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp index 7d5010a8bc..bc39a65f9c 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.cpp @@ -1,10 +1,5 @@ #include "../ControllerQueue/SimpleQueueElement_string_only.h" -simple_queue_element_string_only::simple_queue_element_string_only() {} - -simple_queue_element_string_only::simple_queue_element_string_only(simple_queue_element_string_only&& other) - : txt(std::move(other.txt)), _timestamp(other._timestamp), TaskIndex(other.TaskIndex), controller_idx(other.controller_idx) -{} simple_queue_element_string_only::simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, String&& req) : txt(std::move(req)), TaskIndex(TaskIndex), controller_idx(ctrl_idx) {} diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 69c65c6a93..235034a266 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -12,9 +12,11 @@ class simple_queue_element_string_only { public: - simple_queue_element_string_only(); + simple_queue_element_string_only() = default; - simple_queue_element_string_only(simple_queue_element_string_only&& other); + simple_queue_element_string_only(const simple_queue_element_string_only& other) = delete; + + simple_queue_element_string_only(simple_queue_element_string_only&& other) = default; explicit simple_queue_element_string_only(int ctrl_idx, taskIndex_t TaskIndex, diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp index edcd7aa177..ce88424364 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.cpp +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.cpp @@ -5,8 +5,6 @@ #include "../../_Plugin_Helper.h" -queue_element_formatted_uservar::queue_element_formatted_uservar() {} - queue_element_formatted_uservar::queue_element_formatted_uservar(queue_element_formatted_uservar&& other) : idx(other.idx), diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index e8f07e446b..f5553eb4ed 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -16,7 +16,8 @@ struct EventStruct; class queue_element_formatted_uservar { public: - queue_element_formatted_uservar(); + queue_element_formatted_uservar() = default; + queue_element_formatted_uservar(const queue_element_formatted_uservar& other) = delete; queue_element_formatted_uservar(queue_element_formatted_uservar&& other); queue_element_formatted_uservar(struct EventStruct *event); diff --git a/src/src/ControllerQueue/queue_element_single_value_base.cpp b/src/src/ControllerQueue/queue_element_single_value_base.cpp index 6657acb42f..5052a4df3f 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.cpp +++ b/src/src/ControllerQueue/queue_element_single_value_base.cpp @@ -2,8 +2,6 @@ #include "../DataStructs/ESPEasy_EventStruct.h" -queue_element_single_value_base::queue_element_single_value_base() {} - queue_element_single_value_base::queue_element_single_value_base(const struct EventStruct *event, byte value_count) : idx(event->idx), TaskIndex(event->TaskIndex), diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 31b220950e..69abbbdc8e 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -17,11 +17,13 @@ struct EventStruct; class queue_element_single_value_base { public: - queue_element_single_value_base(); + queue_element_single_value_base() = default; queue_element_single_value_base(const struct EventStruct *event, byte value_count); + queue_element_single_value_base(const queue_element_single_value_base &rval) = delete; + queue_element_single_value_base(queue_element_single_value_base &&rval); bool checkDone(bool succesfull) const; diff --git a/src/src/DataStructs/ESPEasyControllerCache.h b/src/src/DataStructs/ESPEasyControllerCache.h index 419fa28cf9..8189d468f4 100644 --- a/src/src/DataStructs/ESPEasyControllerCache.h +++ b/src/src/DataStructs/ESPEasyControllerCache.h @@ -6,7 +6,7 @@ #include "../DataStructs/RTC_cache_handler_struct.h" struct ControllerCache_struct { - ControllerCache_struct(); + ControllerCache_struct() = default; ~ControllerCache_struct(); diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index d1411c8b57..a614df88af 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -16,10 +16,6 @@ ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t pay setHeader(header); } - -ESPEasy_Now_packet::ESPEasy_Now_packet() : _valid(false) -{} - ESPEasy_Now_packet::ESPEasy_Now_packet(ESPEasy_Now_packet&& other) : _buf(std::move(other._buf)), _valid(other._valid) { diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 08d77fbc32..bb9d99f4f2 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -20,10 +20,13 @@ class ESPEasy_Now_packet { explicit ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize); - ESPEasy_Now_packet(); + ESPEasy_Now_packet() = default; + + ESPEasy_Now_packet(const ESPEasy_Now_packet& other) = delete; ESPEasy_Now_packet(ESPEasy_Now_packet&& other); + ESPEasy_Now_packet& operator=(const ESPEasy_Now_packet& other) = delete; ESPEasy_Now_packet& operator=(ESPEasy_Now_packet&& other); bool ICACHE_FLASH_ATTR setReceivedPacket(const MAC_address& mac, diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index 6976eb2445..d65fc27a64 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -11,22 +11,6 @@ ESPEasy_now_merger::ESPEasy_now_merger() { _firstPacketTimestamp = millis(); } -ESPEasy_now_merger::ESPEasy_now_merger(ESPEasy_now_merger&& other) : - _firstPacketTimestamp(other._firstPacketTimestamp), - _queue(std::move(other._queue)), - _nr_packets(other._nr_packets) { - other._firstPacketTimestamp = 0; - other._nr_packets = 255; - } - -ESPEasy_now_merger& ESPEasy_now_merger::operator=(ESPEasy_now_merger&& other) -{ - _firstPacketTimestamp = other._firstPacketTimestamp; - _queue = std::move(other._queue); - _nr_packets = other._nr_packets; - return *this; -} - void ESPEasy_now_merger::addPacket( uint8_t packet_nr, const MAC_address& mac, diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 529fa8f739..85ebd7164b 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -18,10 +18,10 @@ class ESPEasy_now_merger { public: ESPEasy_now_merger(); + ESPEasy_now_merger(const ESPEasy_now_merger& other) = delete; + ESPEasy_now_merger(ESPEasy_now_merger&& other) = default; - ESPEasy_now_merger(ESPEasy_now_merger&& other); - - ESPEasy_now_merger& operator=(ESPEasy_now_merger&& other); + ESPEasy_now_merger& operator=(ESPEasy_now_merger&& other) = default; void ICACHE_FLASH_ATTR addPacket( uint8_t packet_nr, diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index 31b5c2111d..fdfebb98cf 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -2,10 +2,6 @@ #include -ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct() { -// unit_vector.reserve(32); // prevent re-allocations -} - ESPEasy_now_traceroute_struct::ESPEasy_now_traceroute_struct(uint8_t size) { unit_vector.resize(size); } diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 75e7203eaa..82c28724f6 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -11,7 +11,7 @@ \*********************************************************************************************/ struct ESPEasy_now_traceroute_struct { - ESPEasy_now_traceroute_struct(); + ESPEasy_now_traceroute_struct() = default; ESPEasy_now_traceroute_struct(uint8_t size); diff --git a/src/src/DataStructs/ESPeasyControllerCache.cpp b/src/src/DataStructs/ESPeasyControllerCache.cpp index dc921651cb..3c47e3d463 100644 --- a/src/src/DataStructs/ESPeasyControllerCache.cpp +++ b/src/src/DataStructs/ESPeasyControllerCache.cpp @@ -1,8 +1,6 @@ #include "ESPEasyControllerCache.h" -ControllerCache_struct::ControllerCache_struct() {} - ControllerCache_struct::~ControllerCache_struct() { if (_RTC_cache_handler != nullptr) { delete _RTC_cache_handler; diff --git a/src/src/DataStructs/EventQueue.cpp b/src/src/DataStructs/EventQueue.cpp index ac93977906..e267b7878d 100644 --- a/src/src/DataStructs/EventQueue.cpp +++ b/src/src/DataStructs/EventQueue.cpp @@ -1,7 +1,5 @@ #include "EventQueue.h" -EventQueueStruct::EventQueueStruct() {} - void EventQueueStruct::add(const String& event) { _eventQueue.push_back(event); diff --git a/src/src/DataStructs/EventQueue.h b/src/src/DataStructs/EventQueue.h index bfd3724bfb..6af9c0bfe9 100644 --- a/src/src/DataStructs/EventQueue.h +++ b/src/src/DataStructs/EventQueue.h @@ -9,7 +9,7 @@ struct EventQueueStruct { - EventQueueStruct(); + EventQueueStruct() = default; void add(const String& event); From b9311385dda73d91b148eefaed77cd6e2d542833 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 6 May 2021 16:05:24 +0200 Subject: [PATCH 174/404] [Locking] Add mutex to access map structures --- lib/raburton_esp8266_mutex/keywords.txt | 23 ++++++ lib/raburton_esp8266_mutex/library.json | 30 ++++++++ lib/raburton_esp8266_mutex/library.properties | 10 +++ lib/raburton_esp8266_mutex/license.txt | 21 ++++++ .../src/esp8266_mutex.c | 44 +++++++++++ .../src/esp8266_mutex.h | 27 +++++++ platformio_esp82xx_base.ini | 12 ++- src/src/DataStructs/ESPEasy_now_merger.cpp | 1 + src/src/DataStructs/ESPEasy_now_merger.h | 1 - src/src/DataStructs/NodesHandler.cpp | 50 +++++++++---- src/src/DataStructs/NodesHandler.h | 5 ++ .../SendData_DuplicateChecker_struct.cpp | 28 +++++-- .../SendData_DuplicateChecker_struct.h | 7 +- src/src/Globals/Logging.h | 2 +- src/src/Helpers/ESPEasyMutex.h | 75 +++++++++++++++++++ src/src/Helpers/ESPEasy_now_handler.cpp | 17 ++++- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 16 +++- src/src/Helpers/WiFi_AP_CandidatesList.h | 3 + 18 files changed, 342 insertions(+), 30 deletions(-) create mode 100644 lib/raburton_esp8266_mutex/keywords.txt create mode 100644 lib/raburton_esp8266_mutex/library.json create mode 100644 lib/raburton_esp8266_mutex/library.properties create mode 100644 lib/raburton_esp8266_mutex/license.txt create mode 100644 lib/raburton_esp8266_mutex/src/esp8266_mutex.c create mode 100644 lib/raburton_esp8266_mutex/src/esp8266_mutex.h create mode 100644 src/src/Helpers/ESPEasyMutex.h diff --git a/lib/raburton_esp8266_mutex/keywords.txt b/lib/raburton_esp8266_mutex/keywords.txt new file mode 100644 index 0000000000..be8adeffe3 --- /dev/null +++ b/lib/raburton_esp8266_mutex/keywords.txt @@ -0,0 +1,23 @@ +####################################### +# Syntax Coloring Map for raburton_esp8266_mutex +# (esp8266) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +mutex_t KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +CreateMutux KEYWORD2 +GetMutex KEYWORD2 +ReleaseMutex KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/raburton_esp8266_mutex/library.json b/lib/raburton_esp8266_mutex/library.json new file mode 100644 index 0000000000..e1b7839c6c --- /dev/null +++ b/lib/raburton_esp8266_mutex/library.json @@ -0,0 +1,30 @@ +{ + "name": "RABurton ESP8266 Mutex", + "version": "1.0.2", + "keywords": [ + "esp8266", "mutex" + ], + "license": "MIT", + "description": "A mutex for the ESP8266.", + "repository": + { + "type": "git", + "url": "https://github.com/raburton/esp8266/tree/master/mutex" + }, + "authors": + [ + { + "name": "Richard A Burton", + "email": "richardaburton@gmail.com" + }, + { + "name": "Gijs Noorlander", + "email": "gijs.noorlander@gmail.com", + "maintainer": true + } + ], + "frameworks": "arduino", + "platforms": [ + "espressif8266" + ] +} diff --git a/lib/raburton_esp8266_mutex/library.properties b/lib/raburton_esp8266_mutex/library.properties new file mode 100644 index 0000000000..567562be8a --- /dev/null +++ b/lib/raburton_esp8266_mutex/library.properties @@ -0,0 +1,10 @@ +name=RABurton ESP8266 Mutex +version=1.0.2 +author=Richard A Burton +maintainer=Richard A Burton +sentence=A mutex for the ESP8266. +license=MIT +paragraph= +category= +url= +architectures=esp8266 diff --git a/lib/raburton_esp8266_mutex/license.txt b/lib/raburton_esp8266_mutex/license.txt new file mode 100644 index 0000000000..04903d79e3 --- /dev/null +++ b/lib/raburton_esp8266_mutex/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lib/raburton_esp8266_mutex/src/esp8266_mutex.c b/lib/raburton_esp8266_mutex/src/esp8266_mutex.c new file mode 100644 index 0000000000..4fc8c933ea --- /dev/null +++ b/lib/raburton_esp8266_mutex/src/esp8266_mutex.c @@ -0,0 +1,44 @@ +////////////////////////////////////////////////// +// Mutex support for ESP8266. +// Copyright 2015 Richard A Burton +// richardaburton@gmail.com +// https://github.com/raburton/esp8266/tree/master/mutex +// See license.txt for license terms. +////////////////////////////////////////////////// + +#include "esp8266_mutex.h" + +// setup a new mutex +void ICACHE_FLASH_ATTR CreateMutux(mutex_t *mutex) { + *mutex = 1; +} + +// try to get a mutex +// returns true if successful, false if mutex not free +// as the esp8266 doesn't support the atomic S32C1I instruction +// we have to make the code uninterruptable to produce the +// same overall effect +bool ICACHE_FLASH_ATTR GetMutex(mutex_t *mutex) { + + int iOld = 1, iNew = 0; + + asm volatile ( + "rsil a15, 1\n" // read and set interrupt level to 1 + "l32i %0, %1, 0\n" // load value of mutex + "bne %0, %2, 1f\n" // compare with iOld, branch if not equal + "s32i %3, %1, 0\n" // store iNew in mutex + "1:\n" // branch target + "wsr.ps a15\n" // restore program state + "rsync\n" + : "=&r" (iOld) + : "r" (mutex), "r" (iOld), "r" (iNew) + : "a15", "memory" + ); + + return (bool)iOld; +} + +// release a mutex +void ICACHE_FLASH_ATTR ReleaseMutex(mutex_t *mutex) { + *mutex = 1; +} diff --git a/lib/raburton_esp8266_mutex/src/esp8266_mutex.h b/lib/raburton_esp8266_mutex/src/esp8266_mutex.h new file mode 100644 index 0000000000..7dece3cb38 --- /dev/null +++ b/lib/raburton_esp8266_mutex/src/esp8266_mutex.h @@ -0,0 +1,27 @@ +////////////////////////////////////////////////// +// Mutex support for ESP8266. +// Copyright 2015 Richard A Burton +// richardaburton@gmail.com +// https://github.com/raburton/esp8266/tree/master/mutex +// See license.txt for license terms. +////////////////////////////////////////////////// + +#ifndef __MUTEX_H__ +#define __MUTEX_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +typedef int32 mutex_t; + +void ICACHE_FLASH_ATTR CreateMutux(mutex_t *mutex); +bool ICACHE_FLASH_ATTR GetMutex(mutex_t *mutex); +void ICACHE_FLASH_ATTR ReleaseMutex(mutex_t *mutex); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index a3490b2c3c..a1aa37fbdf 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -52,7 +52,17 @@ extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT -lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, bblanchon/ArduinoJson @ ^6.17.2, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, WifiEspNow +lib_deps = + https://github.com/TD-er/ESPEasySerial.git#v2.0.5 + adafruit/Adafruit ILI9341 @ ^1.5.6 + Adafruit GFX Library + LOLIN_EPD + Adafruit BusIO + bblanchon/ArduinoJson @ ^6.17.2 + VL53L0X @ 1.3.0 + SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9 + WifiEspNow + td-er/RABurton ESP8266 Mutex @ ^1.0.2 lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, SD(esp8266), SDFS, LittleFS(esp8266), ServoESP32 board = esp12e monitor_filters = esp8266_exception_decoder diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index d65fc27a64..dcdb14827b 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -7,6 +7,7 @@ # define ESPEASY_NOW_MESSAGE_TIMEOUT 5000 + ESPEasy_now_merger::ESPEasy_now_merger() { _firstPacketTimestamp = millis(); } diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 85ebd7164b..d0071e4cac 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -7,7 +7,6 @@ # include "MAC_address.h" - // Class to process all incoming messages from a single sender. // One or more packets form a complete message. // This class only contains packets which have the same: diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 8b008d046f..8fd9379158 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -6,8 +6,6 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" -#include "../Helpers/ESPEasy_time_calc.h" -#include "../Helpers/PeriodicalActions.h" #include "../Globals/ESPEasy_time.h" #include "../Globals/ESPEasy_now_peermanager.h" #include "../Globals/ESPEasy_now_state.h" @@ -17,6 +15,8 @@ #include "../Globals/RTC.h" #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" +#include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/PeriodicalActions.h" #define ESPEASY_NOW_ALLOWED_AGE_NO_TRACEROUTE 35000 @@ -43,22 +43,30 @@ bool NodesHandler::addNode(const NodeStruct& node) ESPEasy_NOW_MAC = it->second.ESPEasy_Now_MAC(); isNewNode = false; - it = _nodes.erase(it); + { + _nodes_mutex.lock(); + it = _nodes.erase(it); + _nodes_mutex.unlock(); + } } else { ++it; } } - _nodes[node.unit] = node; - _nodes[node.unit].lastUpdated = millis(); - if (node.getRSSI() >= 0 && rssi < 0) { - _nodes[node.unit].setRSSI(rssi); - } - const MAC_address node_ap(node.ap_mac); - if (node_ap.all_zero()) { - _nodes[node.unit].setAP_MAC(node_ap); - } - if (node.ESPEasy_Now_MAC().all_zero()) { - _nodes[node.unit].setESPEasyNow_mac(ESPEasy_NOW_MAC); + { + _nodes_mutex.lock(); + _nodes[node.unit] = node; + _nodes[node.unit].lastUpdated = millis(); + if (node.getRSSI() >= 0 && rssi < 0) { + _nodes[node.unit].setRSSI(rssi); + } + const MAC_address node_ap(node.ap_mac); + if (node_ap.all_zero()) { + _nodes[node.unit].setAP_MAC(node_ap); + } + if (node.ESPEasy_Now_MAC().all_zero()) { + _nodes[node.unit].setESPEasyNow_mac(ESPEasy_NOW_MAC); + } + _nodes_mutex.unlock(); } return isNewNode; } @@ -67,7 +75,11 @@ bool NodesHandler::addNode(const NodeStruct& node) bool NodesHandler::addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute) { const bool isNewNode = addNode(node); - _nodeStats[node.unit].setDiscoveryRoute(node.unit, traceRoute); + { + _nodeStats_mutex.lock(); + _nodeStats[node.unit].setDiscoveryRoute(node.unit, traceRoute); + _nodeStats_mutex.unlock(); + } ESPEasy_now_peermanager.addPeer(node.ESPEasy_Now_MAC(), node.channel); @@ -465,14 +477,20 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& auto route_it = _nodeStats.find(it->second.unit); if (route_it != _nodeStats.end()) { if (route_it->second.getAge() > max_age_allowed) { + _nodeStats_mutex.lock(); _nodeStats.erase(route_it); + _nodeStats_mutex.unlock(); } else { mustErase = false; } } #endif if (mustErase) { - it = _nodes.erase(it); + { + _nodes_mutex.lock(); + it = _nodes.erase(it); + _nodes_mutex.unlock(); + } nodeRemoved = true; } } else { diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 3dc72d05d1..ffb4785987 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -10,6 +10,9 @@ #include "../DataStructs/ESPEasy_now_Node_statistics.h" #endif +#include "../Helpers/ESPEasyMutex.h" + + class NodesHandler { public: @@ -109,9 +112,11 @@ class NodesHandler { uint8_t _distance = 255; // Cached value NodesMap _nodes; + ESPEasy_Mutex _nodes_mutex; #ifdef USES_ESPEASY_NOW ESPEasy_now_Node_statisticsMap _nodeStats; + ESPEasy_Mutex _nodeStats_mutex; #endif bool _recentlyBecameDistanceZero = false; diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index d654312e03..0fd4ee9cd8 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -7,7 +7,6 @@ #include "../../ESPEasy_fdwdecl.h" - #define HISTORIC_ELEMENT_LIFETIME 10000 // 10 seconds const uint32_t SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY = 0; @@ -38,9 +37,16 @@ uint32_t SendData_DuplicateChecker_struct::add(struct EventStruct *event, const // Item already exists in the queue, no need to ask around return DUPLICATE_CHECKER_INVALID_KEY; } - - _queue.emplace(std::make_pair(key, SendData_DuplicateChecker_data(event))); - _historic[key] = millis(); + { + _queue_mutex.lock(); + _queue.emplace(std::make_pair(key, SendData_DuplicateChecker_data(event))); + _queue_mutex.unlock(); + } + { + _historic_mutex.lock(); + _historic[key] = millis(); + _historic_mutex.unlock(); + } } return key; } @@ -54,7 +60,9 @@ bool SendData_DuplicateChecker_struct::historicKey(uint32_t key) if (it == _historic.end()) { // Someone asked about it, so mark it here + _historic_mutex.lock(); _historic[key] = millis(); + _historic_mutex.unlock(); return false; } @@ -73,7 +81,11 @@ void SendData_DuplicateChecker_struct::remove(uint32_t key) addLog(LOG_LEVEL_DEBUG, String(F(ESPEASY_NOW_NAME)) + F(": message not sent as processed elsewhere")); } #endif - _queue.erase(it); + { + _queue_mutex.lock(); + _queue.erase(it); + _queue_mutex.unlock(); + } } } @@ -83,7 +95,9 @@ void SendData_DuplicateChecker_struct::loop() for (auto it = _queue.begin(); it != _queue.end();) { if (it->second.doSend()) { - it = _queue.erase(it); + _queue_mutex.lock(); + _queue.erase(it); + _queue_mutex.unlock(); // Processed one, others will be processed later return; @@ -98,7 +112,9 @@ void SendData_DuplicateChecker_struct::purge_old_historic() for (auto it = _historic.begin(); it != _historic.end();) { if (timePassedSince(it->second) > HISTORIC_ELEMENT_LIFETIME) { + _historic_mutex.lock(); it = _historic.erase(it); + _historic_mutex.unlock(); } else { ++it; } diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.h b/src/src/DataStructs/SendData_DuplicateChecker_struct.h index cf7c3bc26a..79af19bdc0 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.h +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.h @@ -2,7 +2,9 @@ #define DATASTRUCTS_SENDDATA_DUPLICATECHECKER_STRUCT_H -#include "SendData_DuplicateChecker_data.h" +#include "../DataStructs/SendData_DuplicateChecker_data.h" + +#include "../Helpers/ESPEasyMutex.h" #include @@ -36,9 +38,12 @@ class SendData_DuplicateChecker_struct { // Map of key + event std::map_queue; + ESPEasy_Mutex _queue_mutex; // Map of key + timestamp last seen. std::map_historic; + ESPEasy_Mutex _historic_mutex; + }; #endif // DATASTRUCTS_SENDDATA_DUPLICATECHECKER_STRUCT_H diff --git a/src/src/Globals/Logging.h b/src/src/Globals/Logging.h index a225b004b2..ed2c431180 100644 --- a/src/src/Globals/Logging.h +++ b/src/src/Globals/Logging.h @@ -1,7 +1,6 @@ #ifndef GLOBALS_LOGGING_H #define GLOBALS_LOGGING_H - #include #include @@ -16,4 +15,5 @@ extern LogStruct Logging; \*********************************************************************************************/ extern std::deque serialWriteBuffer; + #endif // GLOBALS_LOGGING_H \ No newline at end of file diff --git a/src/src/Helpers/ESPEasyMutex.h b/src/src/Helpers/ESPEasyMutex.h new file mode 100644 index 0000000000..48655db2d1 --- /dev/null +++ b/src/src/Helpers/ESPEasyMutex.h @@ -0,0 +1,75 @@ +#ifndef HELPERS_ESPEASYMUTEX_H +#define HELPERS_ESPEASYMUTEX_H + + +// ESP8266 does not support std::mutex, so we need to implement our own. +// Used the ESP8266 mutex implemented here: https://github.com/raburton/esp8266/tree/master/mutex +// This library is just linked in, not part of ESPEasy. +// +// We just need to make a wrapper to make sure we can use the same code for ESP8266 and ESP32. + + +#ifdef ESP8266 +# include +#endif // ifdef ESP8266 + +#ifdef ESP32 +# include +#endif // ifdef ESP32 + +struct ESPEasy_Mutex { + // Don't allow to copy or move the mutex + ESPEasy_Mutex(const ESPEasy_Mutex& other) = delete; + ESPEasy_Mutex(ESPEasy_Mutex&& other) = delete; + ESPEasy_Mutex& operator=(const ESPEasy_Mutex& other) = delete; + ESPEasy_Mutex& operator=(ESPEasy_Mutex&& other) = delete; + +#ifdef ESP8266 + + ESPEasy_Mutex() { + CreateMutux(&_mutex); + } + + // May cause deadlock, perhaps add a timeout? + void lock() { + while (!GetMutex(&_mutex)) {} + } + + bool try_lock() { + return GetMutex(&_mutex); + } + + void unlock() { + ReleaseMutex(&_mutex); + } + +private: + + mutex_t _mutex = 0; +#endif // ifdef ESP8266 + +#ifdef ESP32 + ESPEasy_Mutex() = default; + + void lock() { + _mutex.lock(); + } + + bool try_lock() { + return _mutex.try_lock(); + } + + void unlock() { + _mutex.unlock(); + } + +private: + + std::mutex _mutex; + + +#endif // ifdef ESP32 +}; + + +#endif // ifndef HELPERS_ESPEASYMUTEX_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 71a8406540..80ebf344db 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -25,6 +25,7 @@ # include "../Helpers/CRC_functions.h" # include "../Helpers/ESPEasy_Storage.h" # include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/ESPEasyMutex.h" # include "../Helpers/PeriodicalActions.h" # include "../Helpers/_CPlugin_Helper.h" @@ -55,6 +56,7 @@ static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr return key; } +ESPEasy_Mutex ESPEasy_now_in_queue_mutex; std::map ESPEasy_now_in_queue; std::list ESPEasy_now_traceroute_queue; @@ -83,7 +85,12 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t return; } const uint64_t key = mac_to_key(mac, header.message_type, header.message_count); - ESPEasy_now_in_queue[key].addPacket(header.packet_nr, mac, buf, count); + + { + ESPEasy_now_in_queue_mutex.lock(); + ESPEasy_now_in_queue[key].addPacket(header.packet_nr, mac, buf, count); + ESPEasy_now_in_queue_mutex.unlock(); + } STOP_TIMER(RECEIVE_ESPEASY_NOW_LOOP); } @@ -199,7 +206,6 @@ void ESPEasy_now_handler_t::end() _controllerIndex = INVALID_CONTROLLER_INDEX; _usedWiFiChannel = 0; use_EspEasy_now = false; - ESPEasy_now_in_queue.clear(); RTC.clearLastWiFi(); // Force a WiFi scan if (_last_used != 0) { // Only call WifiEspNow.end() if it was started. @@ -207,6 +213,11 @@ void ESPEasy_now_handler_t::end() _last_used = 0; _last_started = 0; } + { + ESPEasy_now_in_queue_mutex.lock(); + ESPEasy_now_in_queue.clear(); + ESPEasy_now_in_queue_mutex.unlock(); + } addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" disabled")); } @@ -354,7 +365,9 @@ bool ESPEasy_now_handler_t::loop_process_ESPEasyNOW_in_queue() } if (removeMessage) { + ESPEasy_now_in_queue_mutex.lock(); it = ESPEasy_now_in_queue.erase(it); + ESPEasy_now_in_queue_mutex.unlock(); /* // FIXME TD-er: For now only process one item and then wait for the next loop. diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 5e34bc46e3..7230ef6088 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -5,6 +5,7 @@ #include "../Globals/RTC.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" + #include "../../ESPEasy_common.h" #include "../../ESPEasy_fdwdecl.h" @@ -18,7 +19,6 @@ #define ESPEASY_NOW_TMP_PASSPHRASE "random_passphrase" #endif - WiFi_AP_CandidatesList::WiFi_AP_CandidatesList() { known.clear(); candidates.clear(); @@ -84,7 +84,9 @@ void WiFi_AP_CandidatesList::begin_sync_scan() { void WiFi_AP_CandidatesList::purge_expired() { for (auto it = scanned.begin(); it != scanned.end(); ) { if (it->expired()) { + scanned_mutex.lock(); it = scanned.erase(it); + scanned_mutex.unlock(); } else { ++it; } @@ -98,13 +100,17 @@ void WiFi_AP_CandidatesList::process_WiFiscan(uint8_t scancount) { // Remove previous scan result if present for (auto it = scanned.begin(); it != scanned.end(); ) { if (tmp == *it || it->expired()) { + scanned_mutex.lock(); it = scanned.erase(it); + scanned_mutex.unlock(); } else { ++it; } } // if (Settings.IncludeHiddenSSID() || !tmp.isHidden) { + scanned_mutex.lock(); scanned.push_back(tmp); + scanned_mutex.unlock(); #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("WiFi : Scan result: "); @@ -114,7 +120,11 @@ void WiFi_AP_CandidatesList::process_WiFiscan(uint8_t scancount) { #endif // ifndef BUILD_NO_DEBUG // } } - scanned.sort(); + { + scanned_mutex.lock(); + scanned.sort(); + scanned_mutex.unlock(); + } loadCandidatesFromScanned(); WiFi.scanDelete(); } @@ -247,7 +257,9 @@ void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { for (auto scan = scanned.begin(); scan != scanned.end();) { if (scan->expired()) { + scanned_mutex.lock(); scan = scanned.erase(scan); + scanned_mutex.unlock(); } else { if (scan->isHidden) { if (Settings.IncludeHiddenSSID()) { diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index d14e3dedb2..5497a889eb 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -2,6 +2,7 @@ #define HELPERS_WIFI_AP_CANDIDATESLIST_H #include "../DataStructs/WiFi_AP_Candidate.h" +#include "../Helpers/ESPEasyMutex.h" #include "../../ESPEasy_common.h" #include @@ -73,6 +74,8 @@ struct WiFi_AP_CandidatesList { std::list known; std::list scanned; + ESPEasy_Mutex scanned_mutex; + WiFi_AP_Candidate_const_iterator known_it; From bd7766b1a0c472de3bee0c471de6fff1dc626182 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 9 May 2021 01:16:14 +0200 Subject: [PATCH 175/404] [ESPEasy-NOW] Fix compile issue, missing #ifdef --- src/src/Helpers/StringProvider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index c2d2f6ef85..99ffaa17e7 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -215,7 +215,6 @@ String getValue(LabelType::Enum label) { case LabelType::WIFI_SENS_MARGIN: return String(Settings.WiFi_sensitivity_margin); case LabelType::WIFI_SEND_AT_MAX_TX_PWR:return jsonBool(Settings.UseMaxTXpowerForSending()); case LabelType::WIFI_NR_EXTRA_SCANS: return String(Settings.NumberExtraWiFiScans); - case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); case LabelType::WIFI_PERIODICAL_SCAN: return jsonBool(Settings.PeriodicalScanWiFi()); case LabelType::FREE_MEM: return String(ESP.getFreeHeap()); @@ -293,6 +292,7 @@ String getValue(LabelType::Enum label) { #ifdef USES_ESPEASY_NOW case LabelType::USE_ESPEASY_NOW: return jsonBool(Settings.UseESPEasyNow()); case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); + case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); #endif case LabelType::BUILD_DESC: return String(BUILD); From 497f61c5ef2c10d317be354cd8712b7a4e9e0459 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 May 2021 23:07:55 +0200 Subject: [PATCH 176/404] [ESPEasy-NOW] Make mesh compatible with older builds (no traceroute) --- .../ESPEasy_now_Node_statistics.cpp | 2 +- src/src/DataStructs/NodesHandler.cpp | 46 +++++++++---------- src/src/DataStructs/NodesHandler.h | 4 -- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 522541f94a..5741594b73 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -99,7 +99,7 @@ const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() const int successRate = routes[i].computeSuccessRate(); if (distance == bestDistance) { - if (successRate > bestSuccessRate) { + if (successRate > bestSuccessRate && distance < 255) { bestSuccessRate = successRate; bestIndex = i; } diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 8fd9379158..6cbeb1a7e0 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -216,7 +216,7 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } else { #ifdef USES_ESPEASY_NOW - uint8_t distance_new, distance_res = 0; + uint8_t distance_new, distance_res = 255; const int successRate_new = getRouteSuccessRate(it->second.unit, distance_new); const int successRate_res = getRouteSuccessRate(res->unit, distance_res); @@ -254,7 +254,7 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } if (mustSet) { #ifdef USES_ESPEASY_NOW - if (it->second.ESPEasyNowPeer) { + if (it->second.ESPEasyNowPeer && it->second.distance < 255) { res = &(it->second); } #else @@ -397,24 +397,29 @@ void NodesHandler::updateThisNode() { if (preferred != nullptr) { if (!preferred->isExpired()) { - const ESPEasy_now_traceroute_struct* tracert_ptr = getTraceRoute(preferred->unit); - if (tracert_ptr != nullptr && tracert_ptr->getDistance() < 255) { - // Make a copy of the traceroute - thisTraceRoute = *tracert_ptr; - thisTraceRoute.addUnit(thisNode.unit); - - _distance = thisTraceRoute.getDistance(); // This node is already included in the traceroute. - } -/* - if (_distance != lastDistance) { - if (isESPEasy_now_only() && WiFiConnected()) { - // We are connected to a 'fake AP' for ESPEasy-NOW, but found a known AP - // Try to reconnect to it. - RTC.clearLastWiFi(); // Force a WiFi scan - WifiDisconnect(); + // Only take the distance of another node if it is running a build which does not send out traceroute + // If it is a build sending traceroute, only consider having a distance if you know how to reach the gateway node + // This does impose an issue when a gateway node is running an older version, as the next hops never will have a traceroute too. + // Therefore the reported build for those units will be faked to be an older version. + if (preferred->build < 20113) { + if (preferred->distance != 255) { + _distance = preferred->distance + 1; + thisNode.build = 20112; + } + } else { + const ESPEasy_now_traceroute_struct* tracert_ptr = getTraceRoute(preferred->unit); + if (tracert_ptr != nullptr && tracert_ptr->getDistance() < 255) { + // Make a copy of the traceroute + thisTraceRoute = *tracert_ptr; + thisTraceRoute.addUnit(thisNode.unit); + if (preferred->distance != 255) { + // Traceroute is only updated when a node is connected. + // Thus the traceroute may be outdated, while the node info will already indicate if a node has lost its route to the gateway node. + // So we only must set the distance of this node if the preferred node has a distance. + _distance = thisTraceRoute.getDistance(); // This node is already included in the traceroute. + } } } - */ } } #endif @@ -576,11 +581,6 @@ bool NodesHandler::lastTimeValidDistanceExpired() const } #ifdef USES_ESPEASY_NOW -bool NodesHandler::hasTraceRoute(uint8_t unit) const -{ - return _nodeStats.find(unit) != _nodeStats.end(); -} - void NodesHandler::updateSuccessRate(byte unit, bool success) { auto it = _nodeStats.find(unit); diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index ffb4785987..8d7e262c77 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -103,10 +103,6 @@ class NodesHandler { void setRSSI(NodeStruct * node, int rssi); -#ifdef USES_ESPEASY_NOW - bool hasTraceRoute(uint8_t unit) const; -#endif - unsigned long _lastTimeValidDistance = 0; uint8_t _distance = 255; // Cached value From e04353ede674a111106a32323274035f422c6530 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 14 May 2021 16:49:06 +0200 Subject: [PATCH 177/404] [Provisioning] Allow to fetch config via commands from HTTP server To ease provisioning a number of nodes, an administrator should be able to configure some host + credentials to fetch files from a server and allow to update a node via rules. The commands do not allow to fetch files from just anywhere, since the user must explicitly enable and configure it. Therefore it is controlled by the administrator whether a file may be fetched and what file to fetch. It is also possible to include some system variable in the URL, like `%mac%` which will be URL encoded when fetching the file. --- src/Custom-sample.h | 9 +- src/ESPEasy_common.h | 8 - src/src/Commands/InternalCommands.cpp | 8 + src/src/Commands/Provisioning.cpp | 42 +++++ src/src/Commands/Provisioning.h | 24 +++ src/src/CustomBuild/define_plugin_sets.h | 5 + src/src/DataStructs/FactoryDefaultPref.cpp | 33 ++++ src/src/DataStructs/FactoryDefaultPref.h | 13 +- src/src/DataStructs/ProvisioningStruct.cpp | 40 ++++ src/src/DataStructs/ProvisioningStruct.h | 47 +++++ src/src/DataStructs/SecurityStruct.h | 2 +- src/src/DataTypes/ESPEasyFileType.cpp | 80 ++++++++ src/src/DataTypes/ESPEasyFileType.h | 35 ++++ src/src/DataTypes/SettingsType.cpp | 7 +- src/src/Helpers/ESPEasy_FactoryDefault.cpp | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 183 ++++++++++++++++++- src/src/Helpers/ESPEasy_Storage.h | 44 ++++- src/src/Helpers/ESPEasy_checks.cpp | 6 + src/src/Helpers/Networking.cpp | 38 ++-- src/src/Helpers/Networking.h | 4 +- src/src/Helpers/StringParser.cpp | 2 +- src/src/Helpers/StringProvider.cpp | 39 ---- src/src/Helpers/StringProvider.h | 24 +-- src/src/WebServer/DownloadPage.cpp | 2 +- src/src/WebServer/FileList.cpp | 4 +- src/src/WebServer/SettingsArchive.cpp | 202 ++++++++++++--------- src/src/WebServer/SettingsArchive.h | 9 +- src/src/WebServer/UploadPage.cpp | 2 +- tools/pio/pre_custom_esp82xx.py | 1 + 29 files changed, 718 insertions(+), 197 deletions(-) create mode 100644 src/src/Commands/Provisioning.cpp create mode 100644 src/src/Commands/Provisioning.h create mode 100644 src/src/DataStructs/ProvisioningStruct.cpp create mode 100644 src/src/DataStructs/ProvisioningStruct.h create mode 100644 src/src/DataTypes/ESPEasyFileType.cpp create mode 100644 src/src/DataTypes/ESPEasyFileType.h diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 614feea451..232925d5aa 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -167,13 +167,18 @@ #define CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME 10 -#define USES_SSDP - +// Allow for remote provisioning of a node. +// This is only allowed for custom builds. +// To setup the configuration of the provisioning file, one must also define USE_SETTINGS_ARCHIVE +// Default setting is to not allow to configure a node remotely, unless explicitly enabled. +// #define USE_CUSTOM_PROVISIONING // #define USE_SETTINGS_ARCHIVE // #define FEATURE_I2CMULTIPLEXER // #define USE_TRIGONOMETRIC_FUNCTIONS_RULES +#define USES_SSDP + /* ####################################################################################################### Defining web interface diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index 0e3cb06c84..0dff196f5a 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -66,10 +66,6 @@ namespace std #if defined(ESP8266) #include "core_version.h" #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD - #define FILE_CONFIG "config.dat" - #define FILE_SECURITY "security.dat" - #define FILE_NOTIFICATION "notification.dat" - #define FILE_RULES "rules1.txt" #include #ifndef LWIP_VERSION_MAJOR #error @@ -104,10 +100,6 @@ namespace std #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32_STD #define ICACHE_RAM_ATTR IRAM_ATTR - #define FILE_CONFIG "/config.dat" - #define FILE_SECURITY "/security.dat" - #define FILE_NOTIFICATION "/notification.dat" - #define FILE_RULES "/rules1.txt" #include // #include "esp32_ping.h" #include diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index a870f6ce76..fa970a0b2c 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -24,6 +24,7 @@ #include "../Commands/Networks.h" #include "../Commands/Notifications.h" +#include "../Commands/Provisioning.h" #include "../Commands/RTC.h" #include "../Commands/Rules.h" #include "../Commands/SDCARD.h" @@ -320,6 +321,13 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_A( "pcfpulse", Command_GPIO_Pulse, 3); // GPIO.h } COMMAND_CASE_R("password", Command_Settings_Password, 1); // Settings.h +#ifdef USE_CUSTOM_PROVISIONING + COMMAND_CASE_A( "provisionconfig", Command_Provisioning_Config, 0); // Provisioning.h + COMMAND_CASE_A( "provisionsecurity", Command_Provisioning_Security, 0); // Provisioning.h + COMMAND_CASE_A( "provisionnotification", Command_Provisioning_Notification, 0); // Provisioning.h + COMMAND_CASE_A( "provisionprovision", Command_Provisioning_Provision, 0); // Provisioning.h + COMMAND_CASE_A( "provisionrules", Command_Provisioning_Rules, 1); // Provisioning.h +#endif COMMAND_CASE_A( "pulse", Command_GPIO_Pulse, 3); // GPIO.h #ifdef USES_MQTT COMMAND_CASE_A( "publish", Command_MQTT_Publish, 2); // MQTT.h diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp new file mode 100644 index 0000000000..5c4ac77916 --- /dev/null +++ b/src/src/Commands/Provisioning.cpp @@ -0,0 +1,42 @@ +#include "../Commands/Provisioning.h" + + +#ifdef USE_CUSTOM_PROVISIONING + +# include "../Commands/Common.h" + +# include "../../ESPEasy_common.h" +# include "../DataTypes/ESPEasyFileType.h" +# include "../DataStructs/ESPEasy_EventStruct.h" +# include "../Helpers/ESPEasy_Storage.h" + + +String Command_Provisioning_Config(struct EventStruct *event, const char *Line) +{ + return downloadFileType(FileType::CONFIG_DAT); +} + +String Command_Provisioning_Security(struct EventStruct *event, const char *Line) +{ + return downloadFileType(FileType::SECURITY_DAT); +} + +String Command_Provisioning_Notification(struct EventStruct *event, const char *Line) +{ + return downloadFileType(FileType::NOTIFICATION_DAT); +} + +String Command_Provisioning_Provision(struct EventStruct *event, const char *Line) +{ + return downloadFileType(FileType::PROVISIONING_DAT); +} + +String Command_Provisioning_Rules(struct EventStruct *event, const char *Line) +{ + if ((event->Par1 <= 0) || (event->Par1 > 4)) { + return F("ProvisionRules: rules index out of range"); + } + return downloadFileType(FileType::RULES_TXT, event->Par1 - 1); +} + +#endif // ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/Commands/Provisioning.h b/src/src/Commands/Provisioning.h new file mode 100644 index 0000000000..16b448acb0 --- /dev/null +++ b/src/src/Commands/Provisioning.h @@ -0,0 +1,24 @@ +#ifndef COMMANDS_PROVISIONING_H +#define COMMANDS_PROVISIONING_H + +#include "../../ESPEasy_common.h" + +#ifdef USE_CUSTOM_PROVISIONING + +class String; + +String Command_Provisioning_Config(struct EventStruct *event, + const char *Line); +String Command_Provisioning_Security(struct EventStruct *event, + const char *Line); +String Command_Provisioning_Notification(struct EventStruct *event, + const char *Line); +String Command_Provisioning_Provision(struct EventStruct *event, + const char *Line); +String Command_Provisioning_Rules(struct EventStruct *event, + const char *Line); + + +#endif // ifdef USE_CUSTOM_PROVISIONING + +#endif // ifndef COMMANDS_PROVISIONING_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index e32207f1c2..40da740a35 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1699,5 +1699,10 @@ To create/register a plugin, you have to : #endif +#if defined(USE_SETTINGS_ARCHIVE) || defined(USE_CUSTOM_PROVISIONING) + #ifndef USE_DOWNLOAD + #define USE_DOWNLOAD + #endif +#endif #endif // DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataStructs/FactoryDefaultPref.cpp b/src/src/DataStructs/FactoryDefaultPref.cpp index 137e28ea28..71b2c24e90 100644 --- a/src/src/DataStructs/FactoryDefaultPref.cpp +++ b/src/src/DataStructs/FactoryDefaultPref.cpp @@ -94,6 +94,39 @@ void ResetFactoryDefaultPreference_struct::deleteFirst(bool checked) { bitWrite(_preference, 21, checked); } +bool ResetFactoryDefaultPreference_struct::saveURL() const { + return bitRead(_preference, 22); +} + +void ResetFactoryDefaultPreference_struct::saveURL(bool checked) { + bitWrite(_preference, 22, checked); +} + +bool ResetFactoryDefaultPreference_struct::allowFetchByCommand() const { + return bitRead(_preference, 23); +} + +void ResetFactoryDefaultPreference_struct::allowFetchByCommand(bool checked) { + bitWrite(_preference, 23, checked); +} + +bool ResetFactoryDefaultPreference_struct::storeCredentials() const { + return bitRead(_preference, 24); +} + +void ResetFactoryDefaultPreference_struct::storeCredentials(bool checked) { + bitWrite(_preference, 24, checked); +} + +bool ResetFactoryDefaultPreference_struct::fetchProvisioningDat() const { + return bitRead(_preference, 25); +} + +void ResetFactoryDefaultPreference_struct::fetchProvisioningDat(bool checked) { + bitWrite(_preference, 25, checked); +} + + uint32_t ResetFactoryDefaultPreference_struct::getPreference() { return _preference; } diff --git a/src/src/DataStructs/FactoryDefaultPref.h b/src/src/DataStructs/FactoryDefaultPref.h index 30ce3f504d..580e39708d 100644 --- a/src/src/DataStructs/FactoryDefaultPref.h +++ b/src/src/DataStructs/FactoryDefaultPref.h @@ -40,16 +40,27 @@ struct ResetFactoryDefaultPreference_struct { bool fetchConfigDat() const; void fetchConfigDat(bool fetch); + bool fetchProvisioningDat() const; + void fetchProvisioningDat(bool fetch); + bool deleteFirst() const; void deleteFirst(bool checked); + bool saveURL() const; + void saveURL(bool checked); + + bool allowFetchByCommand() const; + void allowFetchByCommand(bool checked); + + bool storeCredentials() const; + void storeCredentials(bool checked); uint32_t getPreference(); // TODO TD-er: Add extra flags for settings to keep/set when reset to default. private: - uint32_t _preference; + uint32_t _preference = 0; }; diff --git a/src/src/DataStructs/ProvisioningStruct.cpp b/src/src/DataStructs/ProvisioningStruct.cpp new file mode 100644 index 0000000000..43f2eeddd8 --- /dev/null +++ b/src/src/DataStructs/ProvisioningStruct.cpp @@ -0,0 +1,40 @@ +#include "../DataStructs/ProvisioningStruct.h" + +#ifdef USE_CUSTOM_PROVISIONING + +# include "../Helpers/StringConverter.h" +# include "../Helpers/Hardware.h" + +ProvisioningStruct::ProvisioningStruct() { + ZERO_FILL(user); + ZERO_FILL(pass); + ZERO_FILL(url); +} + +void ProvisioningStruct::validate() { + ZERO_TERMINATE(user); + ZERO_TERMINATE(pass); + ZERO_TERMINATE(url); +} + +bool ProvisioningStruct::matchingFlashSize() const +{ + return modelMatchingFlashSize(ResetFactoryDefaultPreference.getDeviceModel()); +} + +bool ProvisioningStruct::setUser(const String& username) +{ + return safe_strncpy(user, username, sizeof(user)); +} + +bool ProvisioningStruct::setPass(const String& password) +{ + return safe_strncpy(pass, password, sizeof(pass)); +} + +bool ProvisioningStruct::setUrl(const String& url_str) +{ + return safe_strncpy(url, url_str, sizeof(url)); +} + +#endif // ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/DataStructs/ProvisioningStruct.h b/src/src/DataStructs/ProvisioningStruct.h new file mode 100644 index 0000000000..4036e7a45f --- /dev/null +++ b/src/src/DataStructs/ProvisioningStruct.h @@ -0,0 +1,47 @@ +#ifndef DATASTRUCTS_PROVISIONINGSTRUCT_H +#define DATASTRUCTS_PROVISIONINGSTRUCT_H + +#include "../../ESPEasy_common.h" + +#ifdef USE_CUSTOM_PROVISIONING +# include "../CustomBuild/ESPEasyLimits.h" +# include "../DataStructs/FactoryDefaultPref.h" + +/*********************************************************************************************\ +* ProvisioningStruct +\*********************************************************************************************/ +struct ProvisioningStruct +{ + ProvisioningStruct(); + + void validate(); + + bool matchingFlashSize() const; + + bool setUser(const String& username); + bool setPass(const String& password); + bool setUrl(const String& url_str); + + // its safe to extend this struct, up to 4096 bytes, default values in config are 0. + uint8_t md5[16] = { 0 }; + uint8_t ProgmemMd5[16] = { 0 }; // crc of the binary that last saved the struct to file. + + ResetFactoryDefaultPreference_struct ResetFactoryDefaultPreference; + + // Credentials + URL for fetching configuration from HTTP server + char user[26] = { 0 }; + char pass[64] = { 0 }; + char url[128] = { 0 }; +}; + +typedef std::shared_ptr ProvisioningStruct_ptr_type; +# define MakeProvisioningSettings(T) ProvisioningStruct_ptr_type ProvisioningStruct_ptr(new (std::nothrow) ProvisioningStruct()); \ + ProvisioningStruct& T = *ProvisioningStruct_ptr; + +// Check to see if MakeProvisioningSettings was successful +# define AllocatedProvisioningSettings() (ProvisioningStruct_ptr.get() != nullptr) + + +#endif // ifdef USE_CUSTOM_PROVISIONING + +#endif // ifndef DATASTRUCTS_PROVISIONINGSTRUCT_H diff --git a/src/src/DataStructs/SecurityStruct.h b/src/src/DataStructs/SecurityStruct.h index 91d1e7c768..658be467e2 100644 --- a/src/src/DataStructs/SecurityStruct.h +++ b/src/src/DataStructs/SecurityStruct.h @@ -39,7 +39,7 @@ struct SecurityStruct char Password[26]; byte AllowedIPrangeLow[4] = {0}; // TD-er: Use these byte AllowedIPrangeHigh[4] = {0}; - byte IPblockLevel = 0; + byte IPblockLevel = 0; //its safe to extend this struct, up to 4096 bytes, default values in config are 0. Make sure crc is last uint8_t ProgmemMd5[16] = {0}; // crc of the binary that last saved the struct to file. diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp new file mode 100644 index 0000000000..38e066f62c --- /dev/null +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -0,0 +1,80 @@ +#include "../DataTypes/ESPEasyFileType.h" + +#include "../Globals/ResetFactoryDefaultPref.h" + +bool matchFileType(const String& filename, FileType::Enum filetype) +{ + if (filename.startsWith(F("/"))) { + return matchFileType(filename.substring(1), filetype); + } + return filename.equalsIgnoreCase(getFileName(filetype)); +} + +bool isProtectedFileType(const String& filename) +{ + return matchFileType(filename, FileType::CONFIG_DAT) || + matchFileType(filename, FileType::SECURITY_DAT) || + matchFileType(filename, FileType::NOTIFICATION_DAT) || + matchFileType(filename, FileType::PROVISIONING_DAT); +} + +String getFileName(FileType::Enum filetype) { + String result; + + switch (filetype) + { + case FileType::CONFIG_DAT: + result += F("config.dat"); + break; + case FileType::NOTIFICATION_DAT: + result += F("notification.dat"); + break; + case FileType::SECURITY_DAT: + result += F("security.dat"); + break; + case FileType::PROVISIONING_DAT: + result += F("provisioning.dat"); + case FileType::RULES_TXT: + // Use getRulesFileName + break; + + case FileType::MAX_FILETYPE: + break; + } + return result; +} + +String getFileName(FileType::Enum filetype, unsigned int filenr) { + if (filetype == FileType::RULES_TXT) { + return getRulesFileName(filenr); + } + return getFileName(filetype); +} + +// filenr = 0...3 for files rules1.txt ... rules4.txt +String getRulesFileName(unsigned int filenr) { + String result; + + if (filenr < 4) { + result += F("rules"); + result += filenr + 1; + result += F(".txt"); + } + return result; +} + +bool getDownloadFiletypeChecked(FileType::Enum filetype, unsigned int filenr) { + bool isChecked = false; + + switch (filetype) { + case FileType::CONFIG_DAT: isChecked = ResetFactoryDefaultPreference.fetchConfigDat(); break; + case FileType::SECURITY_DAT: isChecked = ResetFactoryDefaultPreference.fetchSecurityDat(); break; + case FileType::NOTIFICATION_DAT: isChecked = ResetFactoryDefaultPreference.fetchNotificationDat(); break; + case FileType::RULES_TXT: isChecked = ResetFactoryDefaultPreference.fetchRulesTXT(filenr); break; + case FileType::PROVISIONING_DAT: isChecked = ResetFactoryDefaultPreference.fetchProvisioningDat(); break; + + case FileType::MAX_FILETYPE: + break; + } + return isChecked; +} diff --git a/src/src/DataTypes/ESPEasyFileType.h b/src/src/DataTypes/ESPEasyFileType.h new file mode 100644 index 0000000000..52cde62a9f --- /dev/null +++ b/src/src/DataTypes/ESPEasyFileType.h @@ -0,0 +1,35 @@ +#ifndef DATATYPES_ESPEASYFILETYPE_H +#define DATATYPES_ESPEASYFILETYPE_H + +#include + +struct FileType { + enum Enum : short { + CONFIG_DAT, + SECURITY_DAT, + RULES_TXT, + NOTIFICATION_DAT, + PROVISIONING_DAT, + + + MAX_FILETYPE + }; +}; + +bool matchFileType(const String& filename, FileType::Enum filetype); + +bool isProtectedFileType(const String& filename); + +String getFileName(FileType::Enum filetype); +String getFileName(FileType::Enum filetype, + unsigned int filenr); + + +// filenr = 0...3 for files rules1.txt ... rules4.txt +String getRulesFileName(unsigned int filenr); + +bool getDownloadFiletypeChecked(FileType::Enum filetype, + unsigned int filenr); + + +#endif // ifndef DATATYPES_ESPEASYFILETYPE_H diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index ee8edd5f4b..f0971ef345 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -4,6 +4,7 @@ #include "../DataStructs/NotificationSettingsStruct.h" #include "../DataStructs/SecurityStruct.h" #include "../DataStructs/ControllerSettingsStruct.h" +#include "../DataTypes/ESPEasyFileType.h" #include "../Globals/ExtraTaskSettings.h" #include "../Globals/Settings.h" @@ -206,9 +207,9 @@ String SettingsType::getSettingsFileName(Enum settingsType) { String SettingsType::getSettingsFileName(SettingsType::SettingsFileEnum file_type) { switch (file_type) { - case SettingsFileEnum::FILE_CONFIG_type: return F(FILE_CONFIG); - case SettingsFileEnum::FILE_NOTIFICATION_type: return F(FILE_NOTIFICATION); - case SettingsFileEnum::FILE_SECURITY_type: return F(FILE_SECURITY); + case SettingsFileEnum::FILE_CONFIG_type: return getFileName(FileType::CONFIG_DAT); + case SettingsFileEnum::FILE_NOTIFICATION_type: return getFileName(FileType::NOTIFICATION_DAT); + case SettingsFileEnum::FILE_SECURITY_type: return getFileName(FileType::SECURITY_DAT); case SettingsFileEnum::FILE_UNKNOWN_type: break; } return ""; diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 19587553fe..a63973e71a 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -82,7 +82,7 @@ void ResetFactory() InitFile(SettingsType::SettingsFileEnum::FILE_NOTIFICATION_type); #endif - String fname = F(FILE_RULES); + String fname = getRulesFileName(0); InitFile(fname.c_str(), 0); Settings.clearMisc(); diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 9f2176e060..8e637e2633 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -6,6 +6,8 @@ #include "../DataStructs/TimingStats.h" +#include "../DataTypes/ESPEasyFileType.h" + #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" @@ -31,9 +33,11 @@ #include "../Helpers/Hardware.h" #include "../Helpers/Memory.h" #include "../Helpers/Misc.h" +#include "../Helpers/Networking.h" #include "../Helpers/Numerical.h" #include "../Helpers/PeriodicalActions.h" #include "../Helpers/StringConverter.h" +#include "../Helpers/StringParser.h" #include "ESPEasy_checks.h" @@ -417,7 +421,7 @@ String SaveSecuritySettings() { if (memcmp(tmp_md5, SecuritySettings.md5, 16) != 0) { // Settings have changed, save to file. memcpy(SecuritySettings.md5, tmp_md5, 16); - err = SaveToFile((char *)FILE_SECURITY, 0, (byte *)&SecuritySettings, sizeof(SecuritySettings)); + err = SaveToFile(getFileName(FileType::SECURITY_DAT).c_str(), 0, (byte *)&SecuritySettings, sizeof(SecuritySettings)); if (WifiIsAP(WiFi.getMode())) { // Security settings are saved, may be update of WiFi settings or hostname. @@ -432,14 +436,28 @@ String SaveSecuritySettings() { void afterloadSettings() { ExtraTaskSettings.clear(); // make sure these will not contain old settings. - ResetFactoryDefaultPreference_struct pref(Settings.ResetFactoryDefaultPreference); - DeviceModel model = pref.getDeviceModel(); + + // Load ResetFactoryDefaultPreference from provisioning.dat if available. + uint32_t pref_temp = Settings.ResetFactoryDefaultPreference; + #ifdef USE_CUSTOM_PROVISIONING + if (fileExists(getFileName(FileType::PROVISIONING_DAT))) { + MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { + loadProvisioningSettings(ProvisioningSettings); + if (ProvisioningSettings.matchingFlashSize()) { + pref_temp = ProvisioningSettings.ResetFactoryDefaultPreference.getPreference(); + } + } + } + #endif // TODO TD-er: Try to get the information from more locations to make it more persistent // Maybe EEPROM location? - if (modelMatchingFlashSize(model)) { - ResetFactoryDefaultPreference = Settings.ResetFactoryDefaultPreference; + + ResetFactoryDefaultPreference_struct pref(pref_temp); + if (modelMatchingFlashSize(pref.getDeviceModel())) { + ResetFactoryDefaultPreference = pref_temp; } Scheduler.setEcoMode(Settings.EcoPowerMode()); @@ -487,7 +505,7 @@ String LoadSettings() } */ - err = LoadFromFile((char *)FILE_SECURITY, 0, (byte *)&SecuritySettings, sizeof(SecurityStruct)); + err = LoadFromFile(getFileName(FileType::SECURITY_DAT).c_str(), 0, (byte *)&SecuritySettings, sizeof(SecurityStruct)); md5.begin(); md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings) - 16); md5.calculate(); @@ -513,6 +531,8 @@ String LoadSettings() return err; } + + /********************************************************************************************\ Disable Plugin, based on bootFailedCount \*********************************************************************************************/ @@ -942,6 +962,62 @@ String LoadCustomControllerSettings(controllerIndex_t ControllerIndex, byte *mem return LoadFromFile(SettingsType::Enum::CustomControllerSettings_Type, ControllerIndex, memAddress, datasize); } + +#ifdef USE_CUSTOM_PROVISIONING +/********************************************************************************************\ + Save Provisioning Settings + \*********************************************************************************************/ +String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings) +{ + MD5Builder md5; + uint8_t tmp_md5[16] = { 0 }; + String err; + + ProvisioningSettings.validate(); + memcpy(ProvisioningSettings.ProgmemMd5, CRCValues.runTimeMD5, 16); + md5.begin(); + md5.add((uint8_t *)&ProvisioningSettings + 16, sizeof(ProvisioningSettings) - 16); + md5.calculate(); + md5.getBytes(tmp_md5); + + if (memcmp(tmp_md5, ProvisioningSettings.md5, 16) != 0) { + // Settings have changed, save to file. + memcpy(ProvisioningSettings.md5, tmp_md5, 16); + err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (byte *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + } + return err; +} + +/********************************************************************************************\ + Load Provisioning Settings + \*********************************************************************************************/ +String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) +{ + uint8_t calculatedMd5[16] = { 0 }; + MD5Builder md5; + + String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (byte *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + md5.begin(); + md5.add(((uint8_t *)&ProvisioningSettings) + 16, sizeof(ProvisioningSettings) - 16); + md5.calculate(); + md5.getBytes(calculatedMd5); + + if (memcmp(calculatedMd5, ProvisioningSettings.md5, 16) == 0) { + addLog(LOG_LEVEL_INFO, F("CRC : ProvisioningSettings CRC ...OK ")); + + if (memcmp(ProvisioningSettings.ProgmemMd5, CRCValues.runTimeMD5, 16) != 0) { + addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings")); + } + } + else { + addLog(LOG_LEVEL_ERROR, F("CRC : ProvisioningSettings CRC ...FAIL")); + } + ProvisioningSettings.validate(); + return err; +} + +#endif + /********************************************************************************************\ Save Controller settings to file system \*********************************************************************************************/ @@ -1009,6 +1085,11 @@ String SaveToFile(const char *fname, int index, const byte *memAddress, int data return doSaveToFile(fname, index, memAddress, datasize, "r+"); } +String SaveToFile_trunc(const char *fname, int index, const byte *memAddress, int datasize) +{ + return doSaveToFile(fname, index, memAddress, datasize, "w+"); +} + // See for mode description: https://github.com/esp8266/Arduino/blob/master/doc/filesystem.rst String doSaveToFile(const char *fname, int index, const byte *memAddress, int datasize, const char *mode) { @@ -1564,3 +1645,93 @@ String getPartitionTable(byte pType, const String& itemSep, const String& lineEn } #endif // ifdef ESP32 + +#ifdef USE_DOWNLOAD +String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr) +{ + if (!ResetFactoryDefaultPreference.allowFetchByCommand() || !getDownloadFiletypeChecked(filetype, filenr)) { + // Not selected, so not downloaded + return F("Not Allowed"); + } + + String filename = getFileName(filetype, filenr); + String fullUrl; + fullUrl.reserve(url.length() + filename.length() + 1); // May need to add an extra slash + fullUrl = url; + fullUrl = parseTemplate(fullUrl, true); // URL encode + + // URLEncode may also encode the '/' into "%2f" + // FIXME TD-er: Can this really occur? + fullUrl.replace(F("%2f"), F("/")); + + while (filename.startsWith(F("/"))) { + filename = filename.substring(1); + } + if (!fullUrl.endsWith(F("/"))) { + fullUrl += F("/"); + } + fullUrl += filename; + + String error; + if (ResetFactoryDefaultPreference.deleteFirst()) { + if (fileExists(filename) && !tryDeleteFile(filename)) { + return F("Could not delete existing file"); + } + if (!downloadFile(fullUrl, filename, user, pass, error)) { + return error; + } + } else { + if (fileExists(filename)) { + // Must download it to a tmp file. + String tmpfile = filename; + tmpfile += F(".tmp"); + if (!downloadFile(fullUrl, tmpfile, user, pass, error)) { + return error; + } + String filename_bak = filename; + filename_bak += F("_bak"); + + if (fileExists(filename) && !tryRenameFile(filename, filename_bak)) { + return F("Could not rename to _bak"); + } else { + // File does not exist (anymore) + if (!tryRenameFile(tmpfile, filename)) { + error = F("Could not rename tmp file"); + + if (tryRenameFile(filename_bak, filename)) { + error += F("... reverted"); + } else { + error += F(" Not reverted!"); + } + return error; + } + } + } else { + if (!downloadFile(fullUrl, filename, user, pass, error)) { + return error; + } + } + } + return error; +} +#endif + +#ifdef USE_CUSTOM_PROVISIONING + +String downloadFileType(FileType::Enum filetype, unsigned int filenr) +{ + String url, user, pass; + + { + MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { + loadProvisioningSettings(ProvisioningSettings); + url = ProvisioningSettings.url; + user = ProvisioningSettings.user; + pass = ProvisioningSettings.pass; + } + } + return downloadFileType(url, user, pass, filetype, filenr); +} + +#endif \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index c9d32af4b0..1f564fce41 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -3,7 +3,8 @@ #include - +#include "../DataStructs/ProvisioningStruct.h" +#include "../DataTypes/ESPEasyFileType.h" #include "../DataTypes/SettingsType.h" #include "../Globals/Plugins.h" #include "../Globals/CPlugins.h" @@ -159,6 +160,22 @@ String SaveCustomControllerSettings(controllerIndex_t ControllerIndex, byte *mem \*********************************************************************************************/ String LoadCustomControllerSettings(controllerIndex_t ControllerIndex, byte *memAddress, int datasize); + +#ifdef USE_CUSTOM_PROVISIONING +/********************************************************************************************\ + Save Provisioning Settings + \*********************************************************************************************/ +String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings); + +/********************************************************************************************\ + Load Provisioning Settings + \*********************************************************************************************/ +String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings); +#endif + + + + /********************************************************************************************\ Save Controller settings to file system \*********************************************************************************************/ @@ -182,8 +199,17 @@ String InitFile(SettingsType::SettingsFileEnum file_type); /********************************************************************************************\ Save data into config file on file system \*********************************************************************************************/ +// Save to file in r+ mode +// Open for reading and writing. +// The stream is positioned at the beginning of the file. String SaveToFile(const char *fname, int index, const byte *memAddress, int datasize); +// Save to file in w+ mode +// Open for reading and writing. +// The file is created if it does not exist, otherwise it is truncated. +// The stream is positioned at the beginning of the file. +String SaveToFile_trunc(const char *fname, int index, const byte *memAddress, int datasize); + // See for mode description: https://github.com/esp8266/Arduino/blob/master/doc/filesystem.rst String doSaveToFile(const char *fname, int index, const byte *memAddress, int datasize, const char *mode); @@ -258,4 +284,20 @@ String getPartitionTable(byte pType, const String& itemSep, const String& lineEn #endif // ifdef ESP32 +/********************************************************************************************\ + Download ESPEasy file types from HTTP server + \*********************************************************************************************/ +#ifdef USE_DOWNLOAD +String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr = 0); + +#endif +#ifdef USE_CUSTOM_PROVISIONING +// Download file type based on settings stored in provisioning.dat file. +String downloadFileType(FileType::Enum filetype, unsigned int filenr = 0); + +#endif + + + + #endif // HELPERS_ESPEASY_STORAGE_H \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 3e0a08044e..37d7f9d0f0 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -16,6 +16,9 @@ #include "../DataStructs/NodeStruct.h" #include "../DataStructs/PortStatusStruct.h" #include "../DataStructs/ProtocolStruct.h" +#ifdef USE_CUSTOM_PROVISIONING +#include "../DataStructs/ProvisioningStruct.h" +#endif #include "../DataStructs/RTCStruct.h" #include "../DataStructs/SecurityStruct.h" #include "../DataStructs/SettingsStruct.h" @@ -76,6 +79,9 @@ void run_compiletime_checks() { #ifdef ESP8266 const unsigned int SettingsStructSize = (292 + 84 * TASKS_MAX); #endif + #ifdef USE_CUSTOM_PROVISIONING + check_size(); + #endif check_size(); check_size(); #ifdef USES_NOTIFIER diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 3cf6a48823..092a18c150 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -57,14 +57,14 @@ void etharp_gratuitous_r(struct netif *netif) { #endif // ifdef SUPPORT_ARP -#ifdef USE_SETTINGS_ARCHIVE +#ifdef USE_DOWNLOAD # ifdef ESP8266 # include # endif // ifdef ESP8266 # ifdef ESP32 # include "HTTPClient.h" # endif // ifdef ESP32 -#endif // USE_SETTINGS_ARCHIVE +#endif /*********************************************************************************************\ @@ -1117,7 +1117,7 @@ String splitURL(const String& fullURL, String& host, uint16_t& port, String& fil return fullURL.substring(endhost); } -#ifdef USE_SETTINGS_ARCHIVE +#ifdef USE_DOWNLOAD // Download a file from a given URL and save to a local file named "file_save" // If the URL ends with a /, the file part will be assumed the same as file_save. @@ -1159,7 +1159,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const } if (fileExists(file_save)) { - error = F("File exists"); + error = F("File exists: "); + error += file_save; addLog(LOG_LEVEL_ERROR, error); return false; } @@ -1186,7 +1187,10 @@ bool downloadFile(const String& url, String file_save, const String& user, const if (httpCode != HTTP_CODE_OK) { error = F("HTTP code: "); error += httpCode; + error += ' '; + error += file_save; addLog(LOG_LEVEL_ERROR, error); + http.end(); return false; } @@ -1194,7 +1198,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const File f = tryOpenFile(file_save, "w"); if (f) { - uint8_t buff[128]; + const size_t downloadBuffSize = 256; + uint8_t buff[downloadBuffSize]; size_t bytesWritten = 0; // get tcp stream @@ -1202,14 +1207,16 @@ bool downloadFile(const String& url, String file_save, const String& user, const // read all data from server while (http.connected() && (len > 0 || len == -1)) { - // read up to 128 byte - size_t c = stream->readBytes(buff, std::min((size_t)len, sizeof(buff))); + // read up to downloadBuffSize at a time. + const size_t c = stream->readBytes(buff, std::min((size_t)len, downloadBuffSize)); if (c > 0) { timeout = millis() + 2000; if (f.write(buff, c) != c) { - error = F("Error saving file, "); + error = F("Error saving file: "); + error += file_save; + error += ' '; error += bytesWritten; error += F(" Bytes written"); addLog(LOG_LEVEL_ERROR, error); @@ -1222,7 +1229,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const } if (timeOutReached(timeout)) { - error = F("Timeout"); + error = F("Timeout: "); + error += file_save; addLog(LOG_LEVEL_ERROR, error); delay(0); http.end(); @@ -1232,12 +1240,18 @@ bool downloadFile(const String& url, String file_save, const String& user, const } f.close(); http.end(); - addLog(LOG_LEVEL_INFO, F("downloadFile: Success")); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("downloadFile: "); + log += file_save; + log += F(" Success"); + addLog(LOG_LEVEL_INFO, log); + } return true; } - error = F("Failed to open file for writing"); + error = F("Failed to open file for writing: "); + error += file_save; addLog(LOG_LEVEL_ERROR, error); return false; } -#endif // USE_SETTINGS_ARCHIVE +#endif diff --git a/src/src/Helpers/Networking.h b/src/src/Helpers/Networking.h index 69de5c3beb..eccf7753f7 100644 --- a/src/src/Helpers/Networking.h +++ b/src/src/Helpers/Networking.h @@ -153,7 +153,7 @@ bool splitHostPortString(const String& hostPortString, String& host, uint16_t& p // Return value is everything after the hostname:port section (including /) String splitURL(const String& fullURL, String& host, uint16_t& port, String& file); -#ifdef USE_SETTINGS_ARCHIVE +#ifdef USE_DOWNLOAD // Download a file from a given URL and save to a local file named "file_save" // If the URL ends with a /, the file part will be assumed the same as file_save. @@ -163,7 +163,7 @@ bool downloadFile(const String& url, String file_save); bool downloadFile(const String& url, String file_save, const String& user, const String& pass, String& error); -#endif // USE_SETTINGS_ARCHIVE +#endif diff --git a/src/src/Helpers/StringParser.cpp b/src/src/Helpers/StringParser.cpp index 3d85bf7bd7..5b27275e8e 100644 --- a/src/src/Helpers/StringParser.cpp +++ b/src/src/Helpers/StringParser.cpp @@ -3,10 +3,10 @@ #include "../../_Plugin_Helper.h" +#include "../Commands/GPIO.h" #include "../DataStructs/TimingStats.h" #include "../ESPEasyCore/ESPEasyRules.h" -#include "../Commands/GPIO.h" #include "../Globals/Cache.h" #include "../Globals/Plugins_other.h" diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 86811bc9ce..381de41c94 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -419,42 +419,3 @@ String getExtendedValue(LabelType::Enum label) { return ""; } -String getFileName(FileType::Enum filetype) { - String result; - - switch (filetype) - { - case FileType::CONFIG_DAT: - result += F("config.dat"); - break; - case FileType::NOTIFICATION_DAT: - result += F("notification.dat"); - break; - case FileType::SECURITY_DAT: - result += F("security.dat"); - break; - case FileType::RULES_TXT: - // Use getRulesFileName - break; - } - return result; -} - -String getFileName(FileType::Enum filetype, unsigned int filenr) { - if (filetype == FileType::RULES_TXT) { - return getRulesFileName(filenr); - } - return getFileName(filetype); -} - -// filenr = 0...3 for files rules1.txt ... rules4.txt -String getRulesFileName(unsigned int filenr) { - String result; - - if (filenr < 4) { - result += F("rules"); - result += filenr + 1; - result += F(".txt"); - } - return result; -} diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index c551595b3d..4578dd4da4 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -171,31 +171,9 @@ String getValue(LabelType::Enum label); String getExtendedValue(LabelType::Enum label); -struct FileType { - enum Enum : short { - CONFIG_DAT, - SECURITY_DAT, - RULES_TXT, - NOTIFICATION_DAT - }; -}; -String getFileName(FileType::Enum filetype); -String getFileName(FileType::Enum filetype, - unsigned int filenr); - -// filenr = 0...3 for files rules1.txt ... rules4.txt -String getRulesFileName(unsigned int filenr); -void addDownloadFiletypeCheckbox(FileType::Enum filetype, - unsigned int filenr = 0); -void storeDownloadFiletypeCheckbox(FileType::Enum filetype, - unsigned int filenr = 0); -bool tryDownloadFileType(const String & url, - const String & user, - const String & pass, - FileType::Enum filetype, - unsigned int filenr = 0); + #endif // STRING_PROVIDER_TYPES_H diff --git a/src/src/WebServer/DownloadPage.cpp b/src/src/WebServer/DownloadPage.cpp index 1db42de834..0c333f68e4 100644 --- a/src/src/WebServer/DownloadPage.cpp +++ b/src/src/WebServer/DownloadPage.cpp @@ -24,7 +24,7 @@ void handle_download() // sendHeadandTail_stdtemplate(); - fs::File dataFile = tryOpenFile(F(FILE_CONFIG), "r"); + fs::File dataFile = tryOpenFile(getFileName(FileType::CONFIG_DAT), "r"); if (!dataFile) { return; diff --git a/src/src/WebServer/FileList.cpp b/src/src/WebServer/FileList.cpp index 96a9895f73..9114cfe6ef 100644 --- a/src/src/WebServer/FileList.cpp +++ b/src/src/WebServer/FileList.cpp @@ -243,7 +243,7 @@ void handle_filelist() { void handle_filelist_add_file(const String& filename, int filesize, int startIdx) { html_TR_TD(); - if ((filename != F(FILE_CONFIG)) && (filename != F(FILE_SECURITY)) && (filename != F(FILE_NOTIFICATION))) + if (!isProtectedFileType(filename)) { html_add_button_prefix(); addHtml(F("filelist?delete=")); @@ -454,7 +454,7 @@ void handle_SDfilelist() { else { - if ((entry.name() != String(F(FILE_CONFIG)).c_str()) && (entry.name() != String(F(FILE_SECURITY)).c_str())) + if (isProtectedFileType(String(entry.name()))) { addHtml(F("(i); + if (ft == FileType::RULES_TXT) { + for (int i = 0; i < 4; ++i) { + storeDownloadFiletypeCheckbox(FileType::RULES_TXT, i); + } + } else { + storeDownloadFiletypeCheckbox(ft); + } } - ResetFactoryDefaultPreference.deleteFirst(isFormItemChecked("del")); - + ResetFactoryDefaultPreference.deleteFirst(isFormItemChecked(F("del"))); + ResetFactoryDefaultPreference.saveURL(isFormItemChecked(F("saveurl"))); + ResetFactoryDefaultPreference.allowFetchByCommand(isFormItemChecked(F("allowcommand"))); + ResetFactoryDefaultPreference.storeCredentials(isFormItemChecked(F("savecred"))); applyFactoryDefaultPref(); - addHtmlError(SaveSettings()); + + String error; + #ifdef USE_CUSTOM_PROVISIONING + { + MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { + ProvisioningSettings.ResetFactoryDefaultPreference = ResetFactoryDefaultPreference.getPreference(); + if (ResetFactoryDefaultPreference.saveURL()) { + ProvisioningSettings.setUrl(web_server.arg(F("url"))); + } + if (ResetFactoryDefaultPreference.storeCredentials()) { + ProvisioningSettings.setUser(web_server.arg(F("user"))); + ProvisioningSettings.setPass(web_server.arg(F("pass"))); + } + } + error += saveProvisioningSettings(ProvisioningSettings); + } + #endif + + error += SaveSettings(); + addHtmlError(error); } bool showOptions = true; if (web_server.hasArg(F("download"))) { // Try downloading files. + // Don't use the ProvisioningSettings, as not all may be stored. String url = web_server.arg(F("url")); String user = web_server.arg(F("user")); String pass = web_server.arg(F("pass")); @@ -59,14 +87,23 @@ void handle_settingsarchive() { addTableSeparator(F("Download result"), 2, 3); bool somethingDownloaded = false; - if (tryDownloadFileType(url, user, pass, FileType::CONFIG_DAT)) { somethingDownloaded = true; } - - if (tryDownloadFileType(url, user, pass, FileType::SECURITY_DAT)) { somethingDownloaded = true; } - - if (tryDownloadFileType(url, user, pass, FileType::NOTIFICATION_DAT)) { somethingDownloaded = true; } + for (int i = 0; i < FileType::MAX_FILETYPE; ++i) { + const FileType::Enum ft = static_cast(i); + if (ft != FileType::RULES_TXT) { + if (getDownloadFiletypeChecked(ft, 0)) { + if (tryDownloadFileType(url, user, pass, ft)) { + somethingDownloaded = true; + } + } + } + } for (int i = 0; i < 4; ++i) { - if (tryDownloadFileType(url, user, pass, FileType::RULES_TXT, i)) { somethingDownloaded = true; } + if (getDownloadFiletypeChecked(FileType::RULES_TXT, i)) { + if (tryDownloadFileType(url, user, pass, FileType::RULES_TXT, i)) { + somethingDownloaded = true; + } + } } if (somethingDownloaded) { @@ -83,14 +120,45 @@ void handle_settingsarchive() { if (showOptions) { // Nothing chosen yet, show options. + addTableSeparator(F("Archive Location"), 2, 3); - addTableSeparator(F("Files to Download"), 2, 3); - addDownloadFiletypeCheckbox(FileType::CONFIG_DAT); - addDownloadFiletypeCheckbox(FileType::SECURITY_DAT); - addDownloadFiletypeCheckbox(FileType::NOTIFICATION_DAT); + { + String url, user, pass; + + { + #ifdef USE_CUSTOM_PROVISIONING + { + MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { + loadProvisioningSettings(ProvisioningSettings); + url = ProvisioningSettings.url; + user = ProvisioningSettings.user; + pass = ProvisioningSettings.pass; + } + } + #endif - for (int i = 0; i < 4; ++i) { - addDownloadFiletypeCheckbox(FileType::RULES_TXT, i); + if (web_server.arg(F("url")).length() != 0) { + url = web_server.arg(F("url")); + } + if (web_server.arg(F("user")).length() != 0) { + user = web_server.arg(F("user")); + } + if (web_server.arg(F("pass")).length() != 0) { + pass = web_server.arg(F("pass")); + } + } + + addFormTextBox(F("URL with settings"), F("url"), url, 256); + addFormNote(F("Only HTTP supported. Do not include filename. URL is allowed to contain system variables.")); + #ifdef USE_CUSTOM_PROVISIONING + addFormCheckBox(F("Store URL"), F("saveurl"), ResetFactoryDefaultPreference.saveURL()); + #endif + addFormTextBox(F("User"), F("user"), user, 64); + addFormPasswordBox(F("Pass"), F("pass"), pass, 64); + #ifdef USE_CUSTOM_PROVISIONING + addFormCheckBox(F("Store Credentials"), F("savecred"), ResetFactoryDefaultPreference.storeCredentials()); + #endif } addTableSeparator(F("Download Settings"), 2, 3); @@ -98,20 +166,27 @@ void handle_settingsarchive() { addRowLabel(F("Delete First")); addCheckBox("del", ResetFactoryDefaultPreference.deleteFirst()); addFormNote(F("Needed on filesystem with not enough free space. Use with care!")); + addFormCheckBox(F("Allow Fetch by Command"), F("allowcommand"), ResetFactoryDefaultPreference.allowFetchByCommand()); + addFormNote(F("Fetch files via a command does need a stored URL and credentials")); + addTableSeparator(F("Files to Download"), 2, 3); + for (int i = 0; i < FileType::MAX_FILETYPE; ++i) { + const FileType::Enum ft = static_cast(i); + if (ft != FileType::RULES_TXT) { + addDownloadFiletypeCheckbox(ft); + } + } + + for (int i = 0; i < 4; ++i) { + addDownloadFiletypeCheckbox(FileType::RULES_TXT, i); + } + + addFormSeparator(2); html_TR_TD(); html_TD(); addSubmitButton(F("Save Preferences"), F("savepref")); - addTableSeparator(F("Archive Location"), 2, 3); - - addFormTextBox(F("URL with settings"), F("url"), web_server.arg(F("url")), 256); - addFormNote(F("Only HTTP supported. Do not include filename")); - addFormTextBox(F("User"), F("user"), web_server.arg(F("user")), 64); - addFormPasswordBox(F("Pass"), F("pass"), web_server.arg(F("pass")), 64); - addFormNote(F("URL, user and pass will not be stored")); - addRowLabel(F("Try download files")); addSubmitButton(F("Download"), F("download"), F("red")); } @@ -125,18 +200,6 @@ void handle_settingsarchive() { // ******************************************************************************** // download filetype selectors // ******************************************************************************** -bool getDownloadFiletypeChecked(FileType::Enum filetype, unsigned int filenr) { - bool isChecked = false; - - switch (filetype) { - case FileType::CONFIG_DAT: isChecked = ResetFactoryDefaultPreference.fetchConfigDat(); break; - case FileType::SECURITY_DAT: isChecked = ResetFactoryDefaultPreference.fetchSecurityDat(); break; - case FileType::NOTIFICATION_DAT: isChecked = ResetFactoryDefaultPreference.fetchNotificationDat(); break; - case FileType::RULES_TXT: isChecked = ResetFactoryDefaultPreference.fetchRulesTXT(filenr); break; - } - return isChecked; -} - void addDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr) { String filetype_str = getFileName(filetype, filenr); String label = F("Fetch "); @@ -155,60 +218,23 @@ void storeDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr) case FileType::SECURITY_DAT: ResetFactoryDefaultPreference.fetchSecurityDat(isChecked); break; case FileType::NOTIFICATION_DAT: ResetFactoryDefaultPreference.fetchNotificationDat(isChecked); break; case FileType::RULES_TXT: { ResetFactoryDefaultPreference.fetchRulesTXT(filenr, isChecked); break; } + case FileType::PROVISIONING_DAT: { ResetFactoryDefaultPreference.fetchProvisioningDat(isChecked); break; } + case FileType::MAX_FILETYPE: + break; + } } bool tryDownloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr) { - if (!getDownloadFiletypeChecked(filetype, filenr)) { - // Not selected, so not downloaded - return false; - } - String filename = getFileName(filetype, filenr); - bool res = false; - String error; - + const String filename = getFileName(filetype, filenr); addRowLabel(filename); - - if (ResetFactoryDefaultPreference.deleteFirst()) { - if (!fileExists(filename) || tryDeleteFile(filename)) { - res = downloadFile(url + filename, filename, user, pass, error); - } else { - error = F("Could not delete existing file"); - } - } else { - String tmpfile = filename; - tmpfile += F(".tmp"); - res = downloadFile(url + filename, tmpfile, user, pass, error); - - if (res) { - String filename_bak = filename; - filename_bak += F("_bak"); - - if (fileExists(filename) && !tryRenameFile(filename, filename_bak)) { - res = false; - error = F("Could not rename to _bak"); - } else { - // File does not exist (anymore) - if (!tryRenameFile(tmpfile, filename)) { - res = false; - error = F("Could not rename tmp file"); - - if (tryRenameFile(filename_bak, filename)) { - error += F("... reverted"); - } else { - error += F(" Not reverted!"); - } - } - } - } - } - - if (!res) { - addHtml(error); - } else { + const String error = downloadFileType(url, user, pass, filetype, filenr); + if (error.length() == 0) { addHtml(F("Success")); + return true; } - return res; + addHtml(error); + return false; } #endif // ifdef USE_SETTINGS_ARCHIVE diff --git a/src/src/WebServer/SettingsArchive.h b/src/src/WebServer/SettingsArchive.h index af97972769..8264415eee 100644 --- a/src/src/WebServer/SettingsArchive.h +++ b/src/src/WebServer/SettingsArchive.h @@ -5,7 +5,7 @@ #ifdef USE_SETTINGS_ARCHIVE -#include "../Helpers/StringProvider.h" +#include "../DataTypes/ESPEasyFileType.h" // ******************************************************************************** // Web Interface to manage archived settings @@ -15,13 +15,12 @@ void handle_settingsarchive(); // ******************************************************************************** // download filetype selectors // ******************************************************************************** -bool getDownloadFiletypeChecked(FileType::Enum filetype, unsigned int filenr); +void addDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr = 0); -void addDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr); +void storeDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr = 0); -void storeDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr); -bool tryDownloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr); +bool tryDownloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr = 0); #endif // ifdef USE_SETTINGS_ARCHIVE diff --git a/src/src/WebServer/UploadPage.cpp b/src/src/WebServer/UploadPage.cpp index ad03c577c0..b36bd14db2 100644 --- a/src/src/WebServer/UploadPage.cpp +++ b/src/src/WebServer/UploadPage.cpp @@ -123,7 +123,7 @@ void handleFileUpload() { // first data block, if this is the config file, check PID/Version if (upload.totalSize == 0) { - if (strcasecmp(upload.filename.c_str(), FILE_CONFIG) == 0) + if (matchFileType(upload.filename, FileType::CONFIG_DAT)) { struct TempStruct { unsigned long PID; diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 3e38909252..bcf0600462 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -59,6 +59,7 @@ "-DFEATURE_SD", "-DFEATURE_I2CMULTIPLEXER", "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", +# "-DUSE_CUSTOM_PROVISIONING", "-DUSE_SETTINGS_ARCHIVE" ] From 2ca05aefca4c0343e933c613d0e16b9fbe2d4d45 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 May 2021 12:54:10 +0200 Subject: [PATCH 178/404] [Provisioning] Add factory default defines to ease deployment of nodes --- src/Custom-sample.h | 27 ++++++++++++ src/src/CustomBuild/ESPEasyDefaults.h | 48 ++++++++++++++++++++++ src/src/Helpers/ESPEasy_FactoryDefault.cpp | 31 ++++++++++++++ tools/pio/pre_custom_esp82xx.py | 2 +- 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 232925d5aa..bbd05f94a1 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -177,6 +177,33 @@ // #define FEATURE_I2CMULTIPLEXER // #define USE_TRIGONOMETRIC_FUNCTIONS_RULES + +#ifdef USE_CUSTOM_PROVISIONING +// For device models, see src/src/DataTypes/DeviceModel.h +// #ifdef ESP32 +// #define DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL 0 // DeviceModel_default +// #endif +// #ifdef ESP8266 +// #define DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL 0 // DeviceModel_default +// #endif +// #define DEFAULT_PROVISIONING_FETCH_RULES1 false +// #define DEFAULT_PROVISIONING_FETCH_RULES2 false +// #define DEFAULT_PROVISIONING_FETCH_RULES3 false +// #define DEFAULT_PROVISIONING_FETCH_RULES4 false +// #define DEFAULT_PROVISIONING_FETCH_NOTIFICATIONS false +// #define DEFAULT_PROVISIONING_FETCH_SECURITY false +// #define DEFAULT_PROVISIONING_FETCH_CONFIG false +// #define DEFAULT_PROVISIONING_FETCH_PROVISIONING false +// #define DEFAULT_PROVISIONING_SAVE_URL false +// #define DEFAULT_PROVISIONING_SAVE_CREDENTIALS false +// #define DEFAULT_PROVISIONING_ALLOW_FETCH_COMMAND false +// #define DEFAULT_PROVISIONING_URL "" +// #define DEFAULT_PROVISIONING_USER "" +// #define DEFAULT_PROVISIONING_PASS "" +#endif + + + #define USES_SSDP /* diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index f782a9255e..c195966f4d 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -311,6 +311,54 @@ #define DEFAULT_SYNC_UDP_PORT 0 // Used for ESPEasy p2p. (IANA registered port: 8266) #endif +// --- Defaults to be used for custom automatic provisioning builds ------------------------------------ +#ifdef USE_CUSTOM_PROVISIONING + #ifndef DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL + #define DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL 0 // DeviceModel_default + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_RULES1 + #define DEFAULT_PROVISIONING_FETCH_RULES1 false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_RULES2 + #define DEFAULT_PROVISIONING_FETCH_RULES2 false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_RULES3 + #define DEFAULT_PROVISIONING_FETCH_RULES3 false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_RULES4 + #define DEFAULT_PROVISIONING_FETCH_RULES4 false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_NOTIFICATIONS + #define DEFAULT_PROVISIONING_FETCH_NOTIFICATIONS false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_SECURITY + #define DEFAULT_PROVISIONING_FETCH_SECURITY false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_CONFIG + #define DEFAULT_PROVISIONING_FETCH_CONFIG false + #endif + #ifndef DEFAULT_PROVISIONING_FETCH_PROVISIONING + #define DEFAULT_PROVISIONING_FETCH_PROVISIONING false + #endif + #ifndef DEFAULT_PROVISIONING_SAVE_URL + #define DEFAULT_PROVISIONING_SAVE_URL false + #endif + #ifndef DEFAULT_PROVISIONING_SAVE_CREDENTIALS + #define DEFAULT_PROVISIONING_SAVE_CREDENTIALS false + #endif + #ifndef DEFAULT_PROVISIONING_ALLOW_FETCH_COMMAND + #define DEFAULT_PROVISIONING_ALLOW_FETCH_COMMAND false + #endif + #ifndef DEFAULT_PROVISIONING_URL + #define DEFAULT_PROVISIONING_URL "" + #endif + #ifndef DEFAULT_PROVISIONING_USER + #define DEFAULT_PROVISIONING_USER "" + #endif + #ifndef DEFAULT_PROVISIONING_PASS + #define DEFAULT_PROVISIONING_PASS "" + #endif +#endif /* // --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------ diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index a63973e71a..86d4e9a8d0 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -27,6 +27,25 @@ \*********************************************************************************************/ void ResetFactory() { + #ifdef USE_CUSTOM_PROVISIONING + if (ResetFactoryDefaultPreference.getPreference() == 0) + { + ResetFactoryDefaultPreference.setDeviceModel(static_cast(DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL)); + ResetFactoryDefaultPreference.fetchRulesTXT(0, DEFAULT_PROVISIONING_FETCH_RULES1); + ResetFactoryDefaultPreference.fetchRulesTXT(1, DEFAULT_PROVISIONING_FETCH_RULES2); + ResetFactoryDefaultPreference.fetchRulesTXT(2, DEFAULT_PROVISIONING_FETCH_RULES3); + ResetFactoryDefaultPreference.fetchRulesTXT(3, DEFAULT_PROVISIONING_FETCH_RULES4); + ResetFactoryDefaultPreference.fetchNotificationDat(DEFAULT_PROVISIONING_FETCH_NOTIFICATIONS); + ResetFactoryDefaultPreference.fetchSecurityDat(DEFAULT_PROVISIONING_FETCH_SECURITY); + ResetFactoryDefaultPreference.fetchConfigDat(DEFAULT_PROVISIONING_FETCH_CONFIG); + ResetFactoryDefaultPreference.fetchProvisioningDat(DEFAULT_PROVISIONING_FETCH_PROVISIONING); + ResetFactoryDefaultPreference.saveURL(DEFAULT_PROVISIONING_SAVE_URL); + ResetFactoryDefaultPreference.storeCredentials(DEFAULT_PROVISIONING_SAVE_CREDENTIALS); + ResetFactoryDefaultPreference.allowFetchByCommand(DEFAULT_PROVISIONING_ALLOW_FETCH_COMMAND); + } + #endif + + const GpioFactorySettingsStruct gpio_settings(ResetFactoryDefaultPreference.getDeviceModel()); #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("ResetFactory")); @@ -74,6 +93,18 @@ void ResetFactory() return; } +#ifdef USE_CUSTOM_PROVISIONING + { + MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { + ProvisioningSettings.setUser(F(DEFAULT_PROVISIONING_USER)); + ProvisioningSettings.setPass(F(DEFAULT_PROVISIONING_PASS)); + ProvisioningSettings.setUrl(F(DEFAULT_PROVISIONING_URL)); + ProvisioningSettings.ResetFactoryDefaultPreference = ResetFactoryDefaultPreference.getPreference(); + saveProvisioningSettings(ProvisioningSettings); + } + } +#endif // pad files with extra zeros for future extensions InitFile(SettingsType::SettingsFileEnum::FILE_CONFIG_type); diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index bcf0600462..02ab60e772 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -59,7 +59,7 @@ "-DFEATURE_SD", "-DFEATURE_I2CMULTIPLEXER", "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", -# "-DUSE_CUSTOM_PROVISIONING", + "-DUSE_CUSTOM_PROVISIONING", "-DUSE_SETTINGS_ARCHIVE" ] From 7f54718e4df632716d3d40da56b650c54c33d331 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 15 May 2021 19:13:24 +0200 Subject: [PATCH 179/404] [Provisioning] Add documentation --- docs/source/Plugin/P000_commands.repl | 30 +++++++ docs/source/Tools/Tools.rst | 74 ++++++++++++++++++ .../images/SettingsArchive_download1.png | Bin 114793 -> 65288 bytes .../images/SettingsArchive_download2.png | Bin 55075 -> 33076 bytes .../images/SettingsArchive_provisioning.png | Bin 0 -> 78778 bytes src/src/Helpers/ESPEasy_Storage.cpp | 32 +++++--- src/src/Helpers/Networking.cpp | 3 +- src/src/WebServer/SettingsArchive.cpp | 9 ++- 8 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 docs/source/Tools/images/SettingsArchive_provisioning.png diff --git a/docs/source/Plugin/P000_commands.repl b/docs/source/Plugin/P000_commands.repl index bac971ac81..f6f90f4472 100644 --- a/docs/source/Plugin/P000_commands.repl +++ b/docs/source/Plugin/P000_commands.repl @@ -282,6 +282,36 @@ ``Password,``" " + ProvisionConfig"," + :red:`Internal`"," + Fetch ``config.dat`` as configured in the Provisioning configuration (see Settings Archive) + + ``ProvisionConfig``" + " + ProvisionSecurity"," + :red:`Internal`"," + Fetch ``security.dat`` as configured in the Provisioning configuration (see Settings Archive) + + ``ProvisionSecurity``" + " + ProvisionNotification"," + :red:`Internal`"," + Fetch ``notification.dat`` as configured in the Provisioning configuration (see Settings Archive) + + ``ProvisionNotification``" + " + ProvisionProvision"," + :red:`Internal`"," + Fetch ``provisioning.dat`` as configured in the Provisioning configuration (see Settings Archive) + + ``ProvisionProvision``" + " + ProvisionRules"," + :red:`Internal`"," + Fetch ``rulesN.txt`` as configured in the Provisioning configuration (see Settings Archive) + + ``ProvisionRules,1`` to fetch ``rules1.txt`` " + " Publish"," :green:`Rules`"," Send command using MQTT broker service diff --git a/docs/source/Tools/Tools.rst b/docs/source/Tools/Tools.rst index d857908d5e..b6e6555ee0 100644 --- a/docs/source/Tools/Tools.rst +++ b/docs/source/Tools/Tools.rst @@ -590,14 +590,44 @@ Especially if the node is hard to reach for a proper clean setup. .. image:: images/SettingsArchive_download2.png After downloading the files, a summary is given. + A returned error can be something like 404 (file not available) or 401 (not authorized). These are the standard HTTP error codes. +The error will be ``-1`` if the host is unreachable. + +If a file already exists, the new file is downloaded with ``_tmp`` appended to the filename. +If successful, the original file will be renamed to one with ``_bak`` appended to the filename and then the ``_tmp`` version is renamed to the original filename. +However, if the ``_bak`` is present, it may fail to rename the original one, so the operation fails. +The presence of the ``_bak`` file is also some protection to not being able to fetch a new version, unless the "Delete First" option is checked. If ''config.dat'' or ''security.dat'' was downloaded, it is very important to do a reboot and not try to change (and save) anything on the ESPeasy node. The old settings are still active in memory and if something will be saved, only the changed part may be saved. This would corrupt the settings file. +With only ``USE_SETTINGS_ARCHIVE`` defined during build, the URL and credentials cannot be stored. +For this the build must be made with ``USE_CUSTOM_PROVISIONING`` defined. + +N.B. ``USE_CUSTOM_PROVISIONING`` is added on 2021-05-16. + + +URL with Settings +^^^^^^^^^^^^^^^^^ + +This holds the full URL without file name where the files must be fetched from. + +Since builds made after 2021-05-16, the URL may also contain system variables. +This allows for an URL like: ``http://192.168.10.127/%mac%`` + +System variables will be converted into an URL encoded form, which may end up like this: + +* ``http://192.168.10.127/A0%3a20%3aA6%3a14%3a84%3a81/rules4.txt`` MAC address: ``A0:20:A6:14:84:81`` + +The URL will not be stored, unless the build is made with ``USE_CUSTOM_PROVISIONING`` defined and the option is checked to save the URL. (option only present when ``USE_CUSTOM_PROVISIONING`` defined) + +Using system variables may allow for multi stage setup of a node, as you could for example fetch a rule which may set a variable to a new value and thus new files may be fetched from a different URL. + + Side Effects on cloning ----------------------- @@ -611,3 +641,47 @@ If the original node is configured to use static IP, the clone will use the same This can render both inaccessible. +Provisioning +============ + +Added: 2021-05-16 + +When the build is made with ``USE_CUSTOM_PROVISIONING`` defined, this Settings Archive screen does allow for more settings helping deployment and remote administration of ESPEasy nodes. + +All Settings on the Settings Archive page can be stored in a file named ``provisioning.dat``. +This file also can store the factory default settings like the device model to ease deployment of a large number of nodes. + +N.B. The ``USE_SETTINGS_ARCHIVE`` define is needed to allow to edit the ``provisioning.dat`` file, but it is not needed to use the provisioning feature. + + +.. image:: images/SettingsArchive_provisioning.png + +As can be seen, the URL and credentials can be stored. +This will be stored in a file named ``provisioning.dat`` +Such a file may also be fetched from a server. + +The ``provisioning.dat`` file can also be automatically generated when performing a factory reset. +For this the (custom) build must be prepared via a number of defined defaults. +See the ``Custom-sample.h`` file for some examples. + + +Allow Fetch by Command +^^^^^^^^^^^^^^^^^^^^^^ + +This checkbox allows provisioning via commands. +These commands are not restricted, so they can also be given via HTTP or MQTT. + +However, they can only be executed when: + +* Allow Fetch by Command is enabled +* the file to download is checked +* URL (+ optional credentials) is stored + +The commands are: + + +* ``ProvisionConfig`` Fetch ``config.dat`` +* ``ProvisionSecurity`` Fetch ``security.dat`` +* ``ProvisionNotification`` Fetch ``notification.dat`` +* ``ProvisionProvision`` Fetch ``provisioning.dat`` +* ``ProvisionRules,1`` Fetch ``rules1.txt`` diff --git a/docs/source/Tools/images/SettingsArchive_download1.png b/docs/source/Tools/images/SettingsArchive_download1.png index fbe81dec4ed18704113903a2cb8cab2636add58d..0e53d4ac63c8d8b6e2bba6c73e48e1a7b5743b8b 100644 GIT binary patch literal 65288 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 b?)^bGQq;At5g=wU-ma%(aJ%#t^4Wg?{EVrD literal 114793 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 YxsL5!7I0U9OW%@}RFWuvZ|wKq08p3k%K!iX literal 55075 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 diff --git a/docs/source/Tools/images/SettingsArchive_provisioning.png b/docs/source/Tools/images/SettingsArchive_provisioning.png new file mode 100644 index 0000000000000000000000000000000000000000..662be22a9ea0ed9de72105bd9ad973f0b0fca65a GIT binary patch literal 78778 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⪼_<<-`eh-OV35<9cB{xz4Y1g& zlffqoU+xr_qEC#YgA!$+R%@1`J1C-4Ur4LA;$veuu)+1;Gf>L4F8%1UN}HZqg3H=T zMGfUgTl0uX=Oi%(w{ZKD?U`%~pj)E?UcvP)Nh}6tG=ljlkbrTWS?D%S=*3)_F?}^Ydg=)6!@^^iRK`s`iR!;nh)u|ND1f&`vQ*mij+n^ zWytK|7xe0|5`@3b)uCJ3%qVY%Y`@DKt@@Lt)8}+1azUB;fz%(X4S| z_u$#M=(Z2OehAM4ccvJxNMU3!ySrBi4(Pot!iwx>@l3BFvhwy|kl5F|a!Ou`xkeA2 zPA)y)R-M=YPYF%cO?qQJ6@lj6G1&85b3mN}ks3FoF>Jw}76U74u4zK!4JYv0l8w%| z*zJ`Y_|b8^^z*B;9!&jqO%UweQKN>kabw{4xd)#k{4)u>6rG$g&74;R6^v!k&g){X zKYPUIFBx>^gnV?iqgFp4x?AV)y>51@f)kzKj})9fX`Ot$v<|)DshBi+)LummQyB5M zr;GD;=+ZmteMq!&YsSlEZFXWP14cku`|OBi{*scdmtxYvaUl~CF7n`hqU%HcH=U=G zd?uHijAF{+fi?qiUUpwC$t$qDhe402ILPe^^SYYB<}3HfHgarAQlMgWZVjbc$kT*te^Dr(35#MyP~3(WuY9iekyPqIo$y?*ukIry2C1WQ5c zo?v?Cuj4E*cb8TTU)=b8Q2!j~3E>Ilsu}l3IsOiUN$}8#AJUq~n zl0Mno8d|5WfA74&2}n2$>%8{tGSboE2qtcF3~HFdEjo}$gOb-Tr`Bnr05lRm zri}+2nj;XoE-9y}8M83BK2>XNWXctQpe^rAYF`5mev;UEct@nVx;liELs>~FSzib^ z+LCf!6zVSX|MVqSlBiMa{5_e)^Y*96f`Wo;_#|u7^|d7>zf7WiozkDoe0 z47?5MzBxBl>qbrua{GI5lsYIeysQGYnh8!Ok0H}q-bTvuYWJ;^0^JU9ah~LWcEC>{ zZk%JLDm8U=jO%h7&EF40e0TI0u}tVh#K9>p4jATqpl6%>CTPUO%=lcHC5jBQs}w1G8|-l-MN9GX`*uBi z@bpwoB*tm(N95-K!RJalbaXCgF*~JoSbK}z`G{^4FU>ILP$@a6{fcjcx<|gcjGOhyD>I8h;{}9^mqM7#EfTT5IW%=K6%3I>D6`W@ zVtXkM89)x;(FWDGgM{GBJBTuaHsTJP~@T_Lh$@rHsp| zJH};OX4i62ZcXqg;GRc8*{>IsZcQcmWR(;=@I>s%&WcX;pjO$@*hEo`W33;0K+%3F zGG{$1#|_~1cnS8J1M4de;_u30wTtYYF?Vky3iGpCCYww`M&&VtZzC4%wrh z;MwRrLbO3}Rb@H>zCa265rc@13ZA9|@md|cod1bW%1l@s{pjC8G?etLPl4p&vpw3A zCM(=%qcf%-_tD>Jda~|aTS)#{@ucVJ=;vOTDbi1Jx*b4TTV{T04%4u6h~rz_NKvs? zvV}cKEfTXk>|^GZKaqDst}yo2pELZGS@VSCOSI;lrZiK@T95 zyXkego)OaLg?MAh&s^@$h~+N_&AUsn$)W+hTM2yL#UIuZir{)&PP;?Ki-nggn4ghLu* z>#J@qcH|U}IWx&m^T}}^Rr|wFEO)d+f5+QfW5z`zTF*I(s%*zOl8x3wV3{5FQ^zz4 zrb=*e_V)6LEXhIKvme*}WJi2O$J8XF^qNOvZDBfaI}lZVPOUU8g;|y=*D`c zB70WHa#NVoyNt=NpOw5MRbap6@v~59Hw9wrhx1%BV$dbJc6-Ly%03SFRf_Eu(i_ST zV60u3xbC}ij741MktF8Y`8$4JK&-I;1hFcXfKXQ)9wQ+#5m}^qbL7$e` z{!!jN_2hN1~4>IaMxGYAdRL9UXd8S4PWTlEc82_cz}(oC)?Eq zERenI_FZ1}YCFjaarI%3OAWELM81p02Qb}H*Hi7bH{0I4Y%rT(T1ff470P(40tdDZ zW<9m-J##*Jm#YwMK~CkJb?1%9n~nYUn_Sx^S^f$EpZ>#*U`p}nYt7t>QXRayYW)?C zqZgGMPZ<4;1_!Jm2J%nbE4sDzIX)H3it9(sde|fn+w)9`xz6H_Y_+Ue&yJzMpyhR_ zTJA(qZ*O-a7)cAfca~#%`iqN4y>qd*!cMR4%vPLo#c}v;b`aj(8LdbL-b7d?`PU#H zCE#a!SS3$9qf*)z$U!sr*}1Rif#d%M_iZ1BLEr_&gr!pFd+!gXX39Z!DzU<1R+60~ z<6)}(t;I%fmB_2TA7C(TKR?8omr*;%$9RRPvmscwmX6gthJD?=3DoC z{nmg9dU4Bhl!FvgH4cdPJ!*t%Zw*Nh!89s?tHePHTPbZ zhr5Y!x&>Ezv3=Nvd*^J$D3U>nmiyCeVZk{K5pK*Yfu(=AfXqV^e_j#k9(~w|E2jkJ zcF(nQw1^Pl%k7kDEXk;HgxRRzyc8pG86HF~770)7d)B~L@TkTKSs(OJ-mirE6`V~c z=%_~rQT4v!P^#Y^Gs^pm&?JRJ%y__O{Ib^Vv3+PA+rI;o<0_}V#`u`gFfH}w$-e+u z2)ohg9G-5~$=XA9poaz6-;-8KpE7lN(AsK_S5fnM+^ZcgO8&HQ<@c)E(f;;r5rOG@ zUg}$0n|hjm7Rk6T`Y&|&PndT>Y`wn^fV3+YyCfrkny&vj$HO}Wd3kw&&yuwGKS>`6 z04J9GK{LevL^J15Pr}Y_{lhhUv@2;m0JQ!I9M9P-x>VPVX@eu?s7EH0@k&e2%>an_ zf+8LM9+1628q~SJv$8@jj7I=RcSFy~ETM}#`9Eg*0i5f(e{!A;0I>CoZziUufU(+Z zfV~2~3!}A+*;fw$?G47AqojAA&ao~ZpVn61F1;B&fK1oUt(-p@v5RO{T30ewR1kHC zE<)4*wr6Jt97YZrS2cSGnzEQ<>=sJcsL;4S#rp^2(oW40`JoS-22Py9qULYY|uhA46 z6*-i7=zlkgvfGHKdC*}tk=nDsd&U~rf%nQUMRC^w`}CQxUQTD`v{-2YBc}NXXL^asB<)WfV2LNmqeBnEeLZO;z2?f28<-!m^FNga%eL^%pwH zOpYrv*z{FStmx=mGkqzgrL#Zw;j=_7)Oy8ep5g5BIoI~xHYq*l^=#Tp5r(i}=d$!4 z8GmqPe&@u_Ljk8Lplj-GSe<}z@UgTP8>I?>A>DMQsjzJcJ5QYB>lV5j8=hsuP7OO1 zyxh^`9y!cm@SR6Rlv{_fjQK~dOy;6~*1!3_+?n$P-4Mhx9jr2spx(v_%H5$+V!#blYw!iRmg2VimM_0y;sP_;P^S-zn#LpVZcd3;A88W%v9La>U4yFOCAEA?Pb<%h8lL`UiZA86s9O}twyww;*_Dpi$xqp>Di7Z@|$;>RR-D1!<~{*-)hyD5H4*97$s7zl@E3vM1% z794>08P76j>*%k!pz9+$;RyYhc&q`pTY>Nio=CgRVRP=2Lb$KfSsx|aQMe~l3#M=j zdyihA+}`q4vE1Ho5UhXPnk+{C{Is!9M03zKMhKJ%WS<28!QSz0Y^f}F#vV%+y1CM?yK*8NPv>f$bEY8roc{ zdTHKL)VWYhl`dWLbkjVAA)}rVcOu(x9DBq^U^v^n>6Q|)u!2eD27sdtoaMS0q&WZQ zi|&Q24dJo2LHE`PH4f9-oEcO#Rw5t4_23*bmWO$^e4?5t^=pcXZP<1u<+h97>NNt0 zz;vBN9-rEw+KBybIRV`evb|i9Kxr__JMo%`rqA!#EWR6u!4V@vSnLva6_#IG1JuyM z=UyA;VY^XJ1dJ~W8GX((RxM&0Bs<=d*PKxs9O3A&i9Y|N@pOqUKhJw#Dv|)Rsj3D+ zRIb-2wY$!)0zNi#ZJBQD}E*<-eS*fb&*8@_$D|D zn$d{oKazZmuKgA4o#q%9jmgVF;E(mylrv% zArQ3wKwwqys?mw*BQ5D($v)#s42xz4+=kqejYLl=K7G*GT-0bAm{L)u&uIYGDj)HP|Hc+&^Tar(cvkw12ljH7!=-zJ_K!#GuI>TK zJnv59CIuRBy?%-5$xlJcB1^tLAvJ=2if1qYNPcN)Uv*&iwRveOq{E^J&fA7l$WRLQ zoL?ZTt83S;gI9JxPwC6+MAbjk5Y2C-sDPbJ*|JM})CIi1oZg?m93b8s;L7Cxw!f(O zp*QlyK@Eq`+zxj4Kicgjw23WuS0LPFhRPce3$it^C`xHYpyo2RZJ}9>Hh!AqRce?Cnbd8t)9RHq_{fHL$E`?_QHeiDYk-IG&zrhloZYtsC-h zRC9ZLp5KE%f8)jatQt4c8;akT`Wwi-S}h)`VkcIP>zV{a8QP#&}gAUxRgUe;#fX{J9K_oq{{9 z+&d@s-oNRGnn)E=g4KePX4EXg6{+#^_?;#VA)xZu4W ztrMn~NBwod09o?wnwg*eI+ussGjVRMv@8~=9C_kfy`w!=G?vmgAj--elP|wm ziX9vjN)&HZ?Nu;QvQVL8*%RTC>*@cqTTaeO?Zh_? z-W(D_sh*mICOz8g`j(gHQtPBh@EN`ld3TFHc>cz{cgPw){ulC+Ms;O<^7v0;s6&1?{1T<_#L8$@) zQUY5M5b4ru#L%RQGzlekEI<^bHF*5+EVTo56n0`M!J39q)VN z-Z9?4fg~$yt-0oJ{@Sd7wO-w=VPN@;G~-5-m5c5F9cnAaX*s$C0zfFJi^q-{mY6 zb3}LG&~7hwoXr+d&Sp#l`I)V>$TFX z*~xlF;`($;t3pia&5LVFr`rAKeJ=tLC7F>rHKU`Af;Zb`5%a^<$atd8xXS{UEUb`> z(Dd|vIc@V*PJ0KmMrReI+EebG+9uKEHq905ywqai39oqC`N#5xCb#|?uDm*6u-7ak zX0nwWfLO^MnG+nO%{v=4N3Q*f-h$UUF|Gd!yt)0+%U?4;#+zY6C=ktAvbB>}T$w2x ztcj*SS8ObXP$ONS6=P>^w8h2(Nz0AIXw**`27(G=PR=3Kvxt9#^pgJKZ^WFmCnDKG zal#^6>f941b7xl-=aeUAaG^^g_6bSV8Ok0|-O%zANUVyJNuoAVyT^C}MWEzZY9QHu z(7Q*S(=u;(*dU*XvRILHV9Ab_BS$>c^z~raL|qYRjP?hzyk-R|jxo*dI{gu7V}mc3 z7|sg?lLU=t`jr?)*@~yxr}hf4%En*T_QMD}(s_yehXIasCG&5eDOoT~JgHt6fb7L! zhZH02DpfcAR(}O-%CN8OnKCS4u{6brbsj~WQfJ)Cja{RgK>s>|6aR&P(B%>jFPb$ zCG!OwrEC~Ry-ELxB&G=S(dZ`?*PL8zKlgFzu-v1s3T{(YU{!$pXB$h$px>oE7)ljn zyqf9N9>SFN>3D^ELt<0Oly_wN`d2ogJL!C#zD)YCO-+y~j?Oe;gRiaV#X@m=4UWnb z#z!cztB*(bj0I`fp=ciO&HuwGahA19Lq*k5y8&Qe!9zJb@0gs2|8Q*fHr zNPfJl!JG2I6^D+y(Y58R*UOg*_k<@j94=5*aN6azYXY>>Ln=~>(u_yz9@V?@D5Lm0 zz8+}jZt^66k!Z~D<)hgH^)!Q7tl*RT$!#<&rpzx%R;c^W*#d`bBib-p;taC)4|hg_ zGp|y$g^F55Z{C39OqCXw_DP4Ih&;&8iYGiB6+ z18%5jF+RhE(}hrh&2j$-c7PN`?}bIU+4#w!USgg4jj~lxgOp=yr%h4Yq0o2t(aw51 z=}@$moVD)od25-Eol63jSusVmWv?IS+9bL;Zg5BztQhy=4H)R^8B^5yaswJCFqXUD zv4?L@C%n%y+R4noWUW9}O*`z_%CejaUyYPMc#O2>yvDwHl#R^{660h}#eZ*nRhU;d z1ZMS*%RzUwxZ*-W3!Y|U=eaX@ie?mtItJmrLyD>KYM$Cxx&sa4$?^UB42!E;bn@PK zV`g1>a)I1(+mLjy%)Nqsr_w0u+QnCB0ykMWGSU+DTK-9k0e;Q8?aL2{b%L*7B zBLWDaJ^c`0siMCm@ns8I?)v-<)|+r?NstL-i!zUl&jZT)EPjA`-BT>+1EkwUmgPJ# zqr~m^AYf9H57pVFu&b#Pj>{GpwhBNmV?B0S*1*_@Lu)jzy+!PKCHbW3Ci`e-bq=YC z=M4f7tJutfG1#Ze`%H%??Ci@U4EdOxk5uZpdl9pk#k-XkFE+e= zS3fXc%u%)Zg;Qlh^KY{Kb7z?S=hWXW{1DMU_HOLlOdC zfprM*SEeoOMkxBPKLw3vin|1=bA6qvr=IXC3-a{tgPj#sdaWQszIW-BJ9*%te_Am1 zh?*hoaM&iP_%81cUyUIp>Um-9&ji%T6Tzk~8!sbdaoU)1(Qg8{fg(pl`B@SjT%(~q z(g?mn2>{ww6hXQ%=f)JpbTs{ zYRl=~wHx*M7`lZyy^x$>Ru7nx{S{x_?pJ1 zi5Lve>Lil(y^x<@YnX#Dz~B7$)(~sv70XBPH#Qe!XxkO31YfnM7gn>U&u;e zZQJ-f+1r;x4F4n?eJ)+8`=aCo5Dtsdoi8q~ihjt}kLsQXp~5eBp6IV+?7sr`8qqNbf1-lf<=%kzapFYT8zfcf~09jC(dx9VM)HM623{$pjAq;&Fc<)4Fie-Th>u1MFJg zvHy&wg&o1A7%)!u+;%0b3?s$;>JLoX{sE+E^%>`LmJ3EENvr!K3%{N&mdu||*DwA? zfuN~3%TviGB+HqazpcT?D&W!6#0yFo^}?Avr5ov4f7UQu(vQ{cbgZ~!iHmng#<3q1 z_yw|YcqJn9GZa_w+QNMYEbOmC-S9uI6F)VgUu0$-`{AT;NFff8X9DRXU|OMC)g)o} ze=+{2nUV&;kj3tq&0gTT{BJ1u;<`U6_%Ghf^&m%LMqGmfj|!l`cF^}I*X8!vXjJ4G zRNr@$Lz$x)L5?ma>h0yX3Hr>1>*$cAhf8SgDQWohBeUVgBqEn9U|N_in*+gpM!<0K8dxVGUKOq09kGzL0?ZQv`&C2 zTh8etNl(L?pHER%-;w@#(&&@8+LYQzcDQ%**1hy?#=gP*|S(CYEEAk5u zMeR1Uxl7e|Rc(VUwP9T->#o2vR^?D5;Hxonv+6aOFP%SAI)A;RmV9nZ2_Y2FTZpwB zFV8?u0NR%hj^=ze@)RY%3v8s1-ON^^dDks>_D-@R8-xSB4PaoHm z{4S4YrBbTtH#@{%DZC{eGXJQW4k>B~P1i+ba8?WqHAFIqP_9 zdUXP@gblh+g;mm8tH#5=P)h-I>+s0uLn~45qGH}jHZo~}+iPsVaY*se3s$Ydkq|{& z;d+#?g+qsSR6ER@7ozV!Nj!7?m4RMZ=U7+-vD5AkPZEpds{)Z4K-*AOp{KKQMC)SX z*Ec#Gp+*Y1gsELwR|<{vq4>k3d%wO%#0EZ?=qpv zXjPl9fax`)Tkbpyo3x4|AS3Ax;`&T7(j}NPAdab?@F)`_ADuxp#!s4YM`F|8LW;~8I((gNJKYxwz}<|H%AE0{4`@Pn zv~}k8MHS74EIK>aO(QJ&P9%}{ogrd4sTmE;zV%#||UG3j+I$-Q8nq1W%!Fvu}+U4 zntCv6HM{mCr;Qv?4cbevK}8?9_L;j3p7cBcuW||%ds`lV$kdU0{~yULDV&o-1MTkJ z1~u4RN_&ohG6~;;lSC9rOb0FUOH(T>?v9f*^|-J5?4ktJzsn7abTzC|Ox+@M zV<@Vk@3l|Q>q)4-qZP_T{w9DZ0RHNJhrjQjsWKIwuiSE2XuI#Tc<;cdKG~!!M=qpN z>OGLPFF2}VrBc1qrf=GP=PYwV5E_}HuAaC@`!o;PgvpZnbE{ujl=5Cg?HWIA65vtl zwRegR$P}nNDOesEbXv8v?dV{d-Umrrq>cRkYy^~Vd)eG$U)lGe{d>S=eJV+`r@?l{ z1K;UD>&R(4U)H&TwW*;^ zYG_s~_#_IaI4J(`(J__hw;RfH06(C6^%nwvAuO2`pg#Z?o|R8E0HFAp4O{`d-|wM#_B@X!9k zc*j0cS0>|Nrv7&|^;EZ%{jl@<`zJT$&yh8)DdG6iiCZNwo8U1e^QLLh%QZ4SMZ)Pn zpVVK?iDx2M+LZ3g{e10K=RZ6W%qhE2vmY@}1veAZEd3ul9e=?|KRX@wg{$_H z8Ru!mM+3$AM*A}@-;~6wiVPzgBuleXX3T571;9A8_uLZY9Oj{1&MCoEvmxRAw}w9y zuz0g`p~_eW;STpod^}8T)`_si@t&{&PY}F-zhdDa8is_fx_{2{IX15J4wx*tTPhEw-LDT7`iEm; z$j0>(d*8}!)FQVS{{)Q==>0P^iuZfKJ!Me2`1^9a==;XDs2&0=4<`o{-%;}Vu5!Jj z<3AwL3waBd3QV8_b@1OnM67YArkeY`_F70U(TWge=R!(`!~3v$dCkQ~P4iFhwB#08 zP5;=H**ID5?r`;ji87d8yf@}}C%w+Vy}R=gBKJrv-W;Z#ys&Dl+mJ*)RQqH+mQV0# zXhPcP=cypZ^+_O_MSc(*TOZI=WH?_=?|#d)7M`q=qUTID9Q6{x3Ocyn&4iJ5NbztD zK(M}-Q1yAH!RwNsHLBba)>&2d5q-VpMW~O&+J(EDqHe8aB`k(My@9$ zH_%p&8X`7nyU&sN(o-~Lxt@F)Zv#Y8+GPfnk;HBmq!sH^Q#_JBwKJHyeFkNr;?NC9 z6o-S~Nk*nnYp3?BP^)oxC9}Z2ap<5xz?JV%R`Sc=!krFxabIewuy#-;L?>% zwDA*JclClHm3|jT;I=`J4Sb(Cp_;z3ITxX+-gnsrT!I1~0lqD=E*8E-Nt2@>%$nF!*4xr!&f5O@5T+wE_h_vdqj5A zw^=CfJwiy)|AzZ;xtUkwWmGsuBBPp0FIc6k(vMQi^ZvptDRx0;#pPCALIyN zKT$_Ym$9314uK

hCqN>+qX1YkdtAx^6sBFU#$wYh$S&{M1s5nl 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 literal 0 HcmV?d00001 diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 8e637e2633..ae9c0e65e2 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1649,16 +1649,17 @@ String getPartitionTable(byte pType, const String& itemSep, const String& lineEn #ifdef USE_DOWNLOAD String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr) { - if (!ResetFactoryDefaultPreference.allowFetchByCommand() || !getDownloadFiletypeChecked(filetype, filenr)) { + if (!getDownloadFiletypeChecked(filetype, filenr)) { // Not selected, so not downloaded return F("Not Allowed"); } String filename = getFileName(filetype, filenr); String fullUrl; + fullUrl.reserve(url.length() + filename.length() + 1); // May need to add an extra slash fullUrl = url; - fullUrl = parseTemplate(fullUrl, true); // URL encode + fullUrl = parseTemplate(fullUrl, true); // URL encode // URLEncode may also encode the '/' into "%2f" // FIXME TD-er: Can this really occur? @@ -1667,29 +1668,37 @@ String downloadFileType(const String& url, const String& user, const String& pas while (filename.startsWith(F("/"))) { filename = filename.substring(1); } + if (!fullUrl.endsWith(F("/"))) { fullUrl += F("/"); } fullUrl += filename; String error; + if (ResetFactoryDefaultPreference.deleteFirst()) { if (fileExists(filename) && !tryDeleteFile(filename)) { return F("Could not delete existing file"); } + if (!downloadFile(fullUrl, filename, user, pass, error)) { return error; } } else { if (fileExists(filename)) { + String filename_bak = filename; + filename_bak += F("_bak"); + if (fileExists(filename_bak)) { + return F("Could not rename to _bak"); + } + // Must download it to a tmp file. String tmpfile = filename; - tmpfile += F(".tmp"); + tmpfile += F("_tmp"); + if (!downloadFile(fullUrl, tmpfile, user, pass, error)) { return error; } - String filename_bak = filename; - filename_bak += F("_bak"); if (fileExists(filename) && !tryRenameFile(filename, filename_bak)) { return F("Could not rename to _bak"); @@ -1714,19 +1723,24 @@ String downloadFileType(const String& url, const String& user, const String& pas } return error; } -#endif + +#endif // ifdef USE_DOWNLOAD #ifdef USE_CUSTOM_PROVISIONING String downloadFileType(FileType::Enum filetype, unsigned int filenr) { - String url, user, pass; + if (!ResetFactoryDefaultPreference.allowFetchByCommand()) { + return F("Not Allowed"); + } + String url, user, pass; { MakeProvisioningSettings(ProvisioningSettings); + if (AllocatedProvisioningSettings()) { loadProvisioningSettings(ProvisioningSettings); - url = ProvisioningSettings.url; + url = ProvisioningSettings.url; user = ProvisioningSettings.user; pass = ProvisioningSettings.pass; } @@ -1734,4 +1748,4 @@ String downloadFileType(FileType::Enum filetype, unsigned int filenr) return downloadFileType(url, user, pass, filetype, filenr); } -#endif \ No newline at end of file +#endif // ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 092a18c150..1579e86326 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -1188,7 +1188,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const error = F("HTTP code: "); error += httpCode; error += ' '; - error += file_save; + error += url; + addLog(LOG_LEVEL_ERROR, error); http.end(); return false; diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index b4dd398017..2fe9475e04 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -48,9 +48,11 @@ void handle_settingsarchive() { } ResetFactoryDefaultPreference.deleteFirst(isFormItemChecked(F("del"))); +#ifdef USE_CUSTOM_PROVISIONING ResetFactoryDefaultPreference.saveURL(isFormItemChecked(F("saveurl"))); ResetFactoryDefaultPreference.allowFetchByCommand(isFormItemChecked(F("allowcommand"))); ResetFactoryDefaultPreference.storeCredentials(isFormItemChecked(F("savecred"))); +#endif applyFactoryDefaultPref(); String error; @@ -166,8 +168,10 @@ void handle_settingsarchive() { addRowLabel(F("Delete First")); addCheckBox("del", ResetFactoryDefaultPreference.deleteFirst()); addFormNote(F("Needed on filesystem with not enough free space. Use with care!")); + #ifdef USE_CUSTOM_PROVISIONING addFormCheckBox(F("Allow Fetch by Command"), F("allowcommand"), ResetFactoryDefaultPreference.allowFetchByCommand()); - addFormNote(F("Fetch files via a command does need a stored URL and credentials")); + addFormNote(F("Fetch files via a command does need stored URL (+ credentials)")); + #endif addTableSeparator(F("Files to Download"), 2, 3); for (int i = 0; i < FileType::MAX_FILETYPE; ++i) { @@ -181,12 +185,11 @@ void handle_settingsarchive() { addDownloadFiletypeCheckbox(FileType::RULES_TXT, i); } - addFormSeparator(2); - html_TR_TD(); html_TD(); addSubmitButton(F("Save Preferences"), F("savepref")); + addFormSeparator(2); addRowLabel(F("Try download files")); addSubmitButton(F("Download"), F("download"), F("red")); } From 8d2a35f68f9829c854579d4885c0de388f7aa607 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 May 2021 13:02:27 +0200 Subject: [PATCH 180/404] [ESPEasy-NOW] Do not change WiFi TX power when ESPEasy-NOW is used Not sure why, but the experienced range per hop differs quite a lot per test, so do not change WiFi TX power with ESPEasy-NOW enabled. --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 1c236eaf2d..0d269b6283 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -450,6 +450,11 @@ void SetWiFiTXpower(float dBm, float rssi) { return; } + if (Settings.UseESPEasyNow()) { + // Do not mess with WiFi TX power when ESPEasy-now is used. + return; + } + // Range ESP32 : 2dBm - 20dBm // Range ESP8266: 0dBm - 20.5dBm float maxTXpwr; From f3b17140dd8b5ce148fccf61ac0e311b1df18336 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 May 2021 22:01:51 +0200 Subject: [PATCH 181/404] [ESPEasy-NOW] Fix merge issues --- src/src/Commands/ESPEasy_Now_cmd.cpp | 1 - src/src/DataStructs/NodesHandler.cpp | 2 +- .../DataStructs/SendData_DuplicateChecker_data.cpp | 1 - .../SendData_DuplicateChecker_struct.cpp | 1 - src/src/ESPEasyCore/ESPEasy_setup.cpp | 13 +++++++++++++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 1 + 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index 1b6d326593..cf21841892 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -6,7 +6,6 @@ #ifdef USES_ESPEASY_NOW #include "../Commands/Common.h" -#include "../../ESPEasy_fdwdecl.h" #include "../../ESPEasy_common.h" #include "../Globals/ESPEasy_now_handler.h" diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 6cbeb1a7e0..327de383e0 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -2,7 +2,6 @@ #include "../../ESPEasy_common.h" #include "../../ESPEasy-Globals.h" -#include "../../ESPEasy_fdwdecl.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" @@ -16,6 +15,7 @@ #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/Misc.h" #include "../Helpers/PeriodicalActions.h" #define ESPEASY_NOW_ALLOWED_AGE_NO_TRACEROUTE 35000 diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp index 40ac492d0a..201dcead32 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp @@ -2,7 +2,6 @@ #include "../ESPEasyCore/Controller.h" #include "../Helpers/ESPEasy_time_calc.h" -#include "../../ESPEasy_fdwdecl.h" #define TIMEOUT_ASK_FOR_DUPLICATE 100 diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 0fd4ee9cd8..a0253a4598 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -4,7 +4,6 @@ #include "../Globals/Plugins.h" #include "../Helpers/CRC_functions.h" #include "../Helpers/ESPEasy_time_calc.h" -#include "../../ESPEasy_fdwdecl.h" #define HISTORIC_ELEMENT_LIFETIME 10000 // 10 seconds diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 49efd627c8..b6d6658742 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -297,6 +297,19 @@ void ESPEasy_setup() clearAllCaches(); + #ifdef USES_ESPEASY_NOW + if (isESPEasy_now_only() || Settings.UseESPEasyNow()) { + RTC.lastWiFiSettingsIndex = 0; // Force to load the first settings. + RTC.lastWiFiChannel = 0; // Force slow connect + } +#endif + + #ifdef USES_ESPEASY_NOW + // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + temp_disable_EspEasy_now_timer = millis() + 10000; + #endif + + if (Settings.UseRules && isDeepSleepEnabled()) { String event = F("System#NoSleep="); diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 7fd9ea8bf8..679553058e 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -5,6 +5,7 @@ #include "../Globals/RTC.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" +#include "../Helpers/Misc.h" #include "../../ESPEasy_common.h" From a56b67ed7533c494bd2c4fe9c045d43bd75364ec Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 May 2021 22:54:46 +0200 Subject: [PATCH 182/404] [WiFi] Allow for unprocessed WiFi events to timeout Fixes nodes not being able to reconnect. --- src/src/DataStructs/WiFiEventData.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 3c2e781525..afa75a221b 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -15,6 +15,7 @@ #define ESPEASY_WIFI_SERVICES_INITIALIZED 2 #define WIFI_RECONNECT_WAIT 20000 // in milliSeconds +#define WIFI_CONNECT_TIMEOUT 20000 // in milliSeconds bool WiFiEventData_t::WiFiConnectAllowed() const { if (!wifiConnectAttemptNeeded) return false; @@ -33,6 +34,24 @@ bool WiFiEventData_t::unprocessedWifiEvents() const { { return false; } + if (!processedConnect) { + if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + return false; + } + } + if (!processedGotIP) { + if (lastGetIPmoment.isSet() && lastGetIPmoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + return false; + } + } + if (!processedDisconnect) { + if (lastDisconnectMoment.isSet() && lastDisconnectMoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + return false; + } + } + if (!processedDHCPTimeout) { + return false; + } return true; } From d5292167b2457152d6177f54b56a30be838f816d Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 May 2021 22:58:16 +0200 Subject: [PATCH 183/404] [WiFi] Change unprocessed event timeout to 10 sec. --- src/src/DataStructs/WiFiEventData.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index afa75a221b..11e9a6c74f 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -15,7 +15,7 @@ #define ESPEASY_WIFI_SERVICES_INITIALIZED 2 #define WIFI_RECONNECT_WAIT 20000 // in milliSeconds -#define WIFI_CONNECT_TIMEOUT 20000 // in milliSeconds +#define WIFI_PROCESS_EVENTS_TIMEOUT 10000 // in milliSeconds bool WiFiEventData_t::WiFiConnectAllowed() const { if (!wifiConnectAttemptNeeded) return false; @@ -35,17 +35,17 @@ bool WiFiEventData_t::unprocessedWifiEvents() const { return false; } if (!processedConnect) { - if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } if (!processedGotIP) { - if (lastGetIPmoment.isSet() && lastGetIPmoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + if (lastGetIPmoment.isSet() && lastGetIPmoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } if (!processedDisconnect) { - if (lastDisconnectMoment.isSet() && lastDisconnectMoment.timeoutReached(WIFI_CONNECT_TIMEOUT)) { + if (lastDisconnectMoment.isSet() && lastDisconnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { return false; } } From 93983d768ea4a20f2ed14220fae4e5e87d0e8a2a Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 18 May 2021 13:15:00 +0200 Subject: [PATCH 184/404] [WiFi AP] Add flag to prevent starting WiFi AP. --- docs/source/Config/Config.rst | 22 ++++++++++++++++++++++ docs/source/Plugin/P000_commands.repl | 6 ++++++ src/Custom-sample.h | 3 ++- src/src/Commands/InternalCommands.cpp | 1 + src/src/Commands/WiFi.cpp | 6 ++++++ src/src/Commands/WiFi.h | 1 + src/src/CustomBuild/ESPEasyDefaults.h | 6 +++++- src/src/DataStructs/SettingsStruct.cpp | 11 +++++++++++ src/src/DataStructs/SettingsStruct.h | 2 ++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 ++++++-- src/src/WebServer/ConfigPage.cpp | 11 +++++++++++ 11 files changed, 73 insertions(+), 4 deletions(-) diff --git a/docs/source/Config/Config.rst b/docs/source/Config/Config.rst index 38939050cc..c3041f5f15 100644 --- a/docs/source/Config/Config.rst +++ b/docs/source/Config/Config.rst @@ -111,6 +111,28 @@ This is often used to perform the initial configuration like connecting to the l Can also be set via the command ``WiFiAPKey``. +Don't force /setup in AP-Mode +----------------------------- + +Allow optional usage of ESPEasy without WIFI avaiable. + +When checked you can use ESPEasy in AP-Mode without beeing forced to ``/setup``. + + +Don't Allow AP +-------------- + +Usually the AP will be started when no WiFi is defined, or the defined one cannot be found. +This flag may prevent to start an AP. + +Since this flag can lock out a user, there is a restricted command to uncheck this. + +``WifiAllowAP`` will uncheck this flag in the settings until a reboot. +If the settings are saved, this flag will remain unchecked. + +N.B. Restricted means, not accepted from a remote source, only local or via serial. + + Custom Build WiFi credentials ----------------------------- diff --git a/docs/source/Plugin/P000_commands.repl b/docs/source/Plugin/P000_commands.repl index f6f90f4472..c689d5ca7d 100644 --- a/docs/source/Plugin/P000_commands.repl +++ b/docs/source/Plugin/P000_commands.repl @@ -516,6 +516,12 @@ ``WifiAPKey,``" " + WifiAllowAP"," + :red:`Internal`"," + Uncheck the setting to prevent starting AP when unable to connect to a network. + + ``WifiAllowAP``" + " WifiAPMode"," :red:`Internal`"," Force the unit into AP mode. diff --git a/src/Custom-sample.h b/src/Custom-sample.h index bbd05f94a1..648dfbe908 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -67,7 +67,8 @@ // See: https://github.com/letscontrolit/ESPEasy/issues/2724 #define DEFAULT_SEND_TO_HTTP_ACK false // Wait for ack with SendToHttp command. -#define DEFAULT_AP_DONT_FORCE_SETUP false // Allow optional usage of Sensor without WIFI avaiable // When set you can use the Sensor in AP-Mode without beeing forced to /setup +#define DEFAULT_AP_DONT_FORCE_SETUP false // Allow optional usage of Sensor without WIFI avaiable // When set you can use the Sensor in AP-Mode without beeing forced to /setup +#define DEFAULT_DONT_ALLOW_START_AP false // Usually the AP will be started when no WiFi is defined, or the defined one cannot be found. This flag may prevent it. // --- Default Controller ------------------------------------------------------------------------------ #define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index fa970a0b2c..3a7580d8b8 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -409,6 +409,7 @@ bool executeInternalCommand(command_case_data & data) #endif if (data.cmd_lc[1] == 'i') { + COMMAND_CASE_R( "wifiallowap", Command_Wifi_AllowAP, 0); // WiFi.h COMMAND_CASE_R( "wifiapmode", Command_Wifi_APMode, 0); // WiFi.h COMMAND_CASE_A( "wificonnect", Command_Wifi_Connect, 0); // WiFi.h COMMAND_CASE_A("wifidisconnect", Command_Wifi_Disconnect, 0); // WiFi.h diff --git a/src/src/Commands/WiFi.cpp b/src/src/Commands/WiFi.cpp index 6b24b55c53..ba3cc45dea 100644 --- a/src/src/Commands/WiFi.cpp +++ b/src/src/Commands/WiFi.cpp @@ -118,6 +118,12 @@ String Command_Wifi_Mode(struct EventStruct *event, const char *Line) return return_command_success(); } +String Command_Wifi_AllowAP(struct EventStruct *event, const char* Line) +{ + Settings.DoNotStartAP(false); + return return_command_success(); +} + // FIXME: TD-er This is not an erase, but actually storing the current settings // in the wifi settings of the core library String Command_WiFi_Erase(struct EventStruct *event, const char *Line) diff --git a/src/src/Commands/WiFi.h b/src/src/Commands/WiFi.h index 71de4ff13a..18bfa661ba 100644 --- a/src/src/Commands/WiFi.h +++ b/src/src/Commands/WiFi.h @@ -15,6 +15,7 @@ String Command_Wifi_Disconnect(struct EventStruct *event, const char* Line); String Command_Wifi_APMode(struct EventStruct *event, const char* Line); String Command_Wifi_STAMode(struct EventStruct *event, const char* Line); String Command_Wifi_Mode(struct EventStruct *event, const char* Line); +String Command_Wifi_AllowAP(struct EventStruct *event, const char* Line); // FIXME: TD-er This is not an erase, but actually storing the current settings // in the wifi settings of the core library diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index c195966f4d..ff2a6ede93 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -118,7 +118,11 @@ #endif #ifndef DEFAULT_AP_DONT_FORCE_SETUP -#define DEFAULT_AP_DONT_FORCE_SETUP false // Allow optional usage of Sensor without WIFI avaiable // When set you can use the Sensor in AP-Mode without beeing forced to /setup +#define DEFAULT_AP_DONT_FORCE_SETUP false // Allow optional usage of Sensor without WIFI avaiable // When set you can use the Sensor in AP-Mode without beeing forced to /setup +#endif + +#ifndef DEFAULT_DONT_ALLOW_START_AP +#define DEFAULT_DONT_ALLOW_START_AP false // Usually the AP will be started when no WiFi is defined, or the defined one cannot be found. This flag may prevent it. #endif // --- Default Controller ------------------------------------------------------------------------------ diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index 0e606ea53f..b2fae50d6e 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -195,6 +195,16 @@ void SettingsStruct_tmpl::CombineTaskValues_SingleEvent(taskIndex_t tas } } +template +bool SettingsStruct_tmpl::DoNotStartAP() const { + return bitRead(VariousBits1, 17); +} + +template +void SettingsStruct_tmpl::DoNotStartAP(bool value) { + bitWrite(VariousBits1, 17, value); +} + template void SettingsStruct_tmpl::validate() { if (UDPPort > 65535) { UDPPort = 0; } @@ -361,6 +371,7 @@ void SettingsStruct_tmpl::clearMisc() { SendToHttp_ack(DEFAULT_SEND_TO_HTTP_ACK); UseESPEasyNow(DEFAULT_USE_ESPEASYNOW); ApDontForceSetup(DEFAULT_AP_DONT_FORCE_SETUP); + DoNotStartAP(DEFAULT_DONT_ALLOW_START_AP); } template diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index d7bdb6531b..337df5d945 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -115,6 +115,8 @@ class SettingsStruct_tmpl bool CombineTaskValues_SingleEvent(taskIndex_t taskIndex) const; void CombineTaskValues_SingleEvent(taskIndex_t taskIndex, bool value); + bool DoNotStartAP() const; + void DoNotStartAP(bool value); void validate(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e412d92e7c..5a10cbe5d4 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -167,7 +167,9 @@ bool WiFiConnected() { if ((WiFiEventData.timerAPstart.isSet()) && WiFiEventData.timerAPstart.timeReached()) { // Timer reached, so enable AP mode. if (!WifiIsAP(WiFi.getMode())) { - setAP(true); + if (!Settings.DoNotStartAP()) { + setAP(true); + } } WiFiEventData.timerAPstart.clear(); } @@ -294,7 +296,9 @@ bool prepareWiFi() { WiFiEventData.wifiConnectAttemptNeeded = false; // No need to wait longer to start AP mode. - setAP(true); + if (!Settings.DoNotStartAP()) { + setAP(true); + } return false; } WiFiEventData.warnedNoValidWiFiSettings = false; diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index d7de760e04..ba1e78fd2e 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -85,6 +85,9 @@ void handle_config() { // When set you can use the Sensor in AP-Mode without being forced to /setup Settings.ApDontForceSetup(isFormItemChecked(F("ApDontForceSetup"))); + // Usually the AP will be started when no WiFi is defined, or the defined one cannot be found. This flag may prevent it. + Settings.DoNotStartAP(isFormItemChecked(F("DoNotStartAP"))); + // TD-er Read access control from form. SecuritySettings.IPblockLevel = getFormItemInt(F("ipblocklevel")); @@ -173,6 +176,14 @@ void handle_config() { addFormCheckBox(F("Don't force /setup in AP-Mode"), F("ApDontForceSetup"), Settings.ApDontForceSetup()); addFormNote(F("When set you can use the Sensor in AP-Mode without being forced to /setup. /setup can still be called.")); + addFormCheckBox(F("Don't Allow AP"), F("DoNotStartAP"), Settings.DoNotStartAP()); + #ifdef HAS_ETHERNET + addFormNote(F("Do not allow to start an AP when unable to connect to configured LAN/WiFi")); + #else + addFormNote(F("Do not allow to start an AP when configured WiFi cannot be found")); + #endif + + // TD-er add IP access box F("ipblocklevel") addFormSubHeader(F("Client IP filtering")); { From 5eb49450d27fde633bb0016aa660bb41f821f7ce Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 28 May 2021 23:01:58 +0200 Subject: [PATCH 185/404] [ESPEasy-NOW] Fix merge issues --- src/_C014.ino | 2 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 2 +- src/src/DataStructs/NodeStruct.cpp | 6 ++- src/src/DataStructs/NodeStruct.h | 2 +- .../SendData_DuplicateChecker_struct.cpp | 2 +- src/src/DataStructs/TimingStats.cpp | 16 +++---- src/src/DataTypes/ESPEasyTimeSource.cpp | 4 +- src/src/DataTypes/ESPEasyTimeSource.h | 3 +- src/src/DataTypes/NetworkMedium.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 43 +++++++++++-------- src/src/Helpers/StringProvider.cpp | 6 +-- src/src/Helpers/_CPlugin_Helper_webform.cpp | 2 +- src/src/WebServer/RootPage.cpp | 3 +- src/src/WebServer/SettingsArchive.cpp | 8 +--- 14 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/_C014.ino b/src/_C014.ino index f1fdb094c8..038c0a0807 100644 --- a/src/_C014.ino +++ b/src/_C014.ino @@ -268,7 +268,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$fw/version",toString(Settings.Build,0).c_str(),errorCounter); // $fw/name Device → Controller Name of the firmware running on the device. Allowed characters are the same as the device ID Yes Yes - CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$fw/name",getNodeTypeDisplayString(NODE_TYPE_ID).c_str(),errorCounter); + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$fw/name",String(NodeStruct::getNodeTypeDisplayString(NODE_TYPE_ID)).c_str(),errorCounter); // $stats/interval Device → Controller Interval in seconds at which the device refreshes its $stats/+: See next section for details about statistical attributes Yes Yes CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex,"$stats/interval",CPLUGIN_014_INTERVAL,errorCounter); diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 080882c739..7aca296c3b 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -233,7 +233,7 @@ bool ESPEasy_now_splitter::prepareForSend(const MAC_address& mac) _queue[i].setMac(mac); if (!_queue[i].valid()) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": Could not prepare for send")); + addLog(LOG_LEVEL_ERROR, F(ESPEASY_NOW_NAME ": Could not prepare for send")); } return false; } diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 9c43422542..183168635c 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -88,7 +88,7 @@ bool NodeStruct::operator<(const NodeStruct &other) const { } -const __FlashStringHelper * getNodeTypeDisplayString(byte nodeType) { +const __FlashStringHelper * NodeStruct::getNodeTypeDisplayString(byte nodeType) { switch (nodeType) { case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); @@ -101,6 +101,10 @@ const __FlashStringHelper * getNodeTypeDisplayString(byte nodeType) { return F(""); } +String NodeStruct::getNodeTypeDisplayString() const { + return NodeStruct::getNodeTypeDisplayString(nodeType); +} + String NodeStruct::getNodeName() const { String res; size_t length = strnlen(reinterpret_cast(nodeName), sizeof(nodeName)); diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index f69daabeab..19eaebd0d4 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -16,7 +16,6 @@ #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 #define NODE_TYPE_ID_NANO_EASY_STD 81 -const __FlashStringHelper * getNodeTypeDisplayString(byte nodeType); /*********************************************************************************************\ * NodeStruct @@ -36,6 +35,7 @@ struct __attribute__((__packed__)) NodeStruct // - lower load (TODO TD-er) bool operator<(const NodeStruct &other) const; + static const __FlashStringHelper * getNodeTypeDisplayString(byte nodeType); String getNodeTypeDisplayString() const; String getNodeName() const; diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index a0253a4598..544a84d3d8 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -77,7 +77,7 @@ void SendData_DuplicateChecker_struct::remove(uint32_t key) if (it != _queue.end()) { #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - addLog(LOG_LEVEL_DEBUG, String(F(ESPEASY_NOW_NAME)) + F(": message not sent as processed elsewhere")); + addLog(LOG_LEVEL_DEBUG, F(ESPEASY_NOW_NAME ": message not sent as processed elsewhere")); } #endif { diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index d2b273f3e6..ea4bed62b3 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -231,14 +231,14 @@ String getMiscStatsName(int stat) { case PARSE_SYSVAR: return F("parseSystemVariables()"); case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); - case HANDLE_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" handle received message"); - case EXPIRED_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" incomplete expired"); - case INVALID_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" incomplete invalid"); - case RECEIVE_ESPEASY_NOW_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" onReceive()"); - case ESPEASY_NOW_SEND_MSG_SUC: return String(F(ESPEASY_NOW_NAME)) + F(" send Message Success"); - case ESPEASY_NOW_SEND_MSG_FAIL: return String(F(ESPEASY_NOW_NAME)) + F(" send Message Fail"); - case ESPEASY_NOW_SEND_PCKT: return String(F(ESPEASY_NOW_NAME)) + F(" send Packet"); - case ESPEASY_NOW_DEDUP_LOOP: return String(F(ESPEASY_NOW_NAME)) + F(" DuplicateCheck loop"); + case HANDLE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " handle received message"); + case EXPIRED_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete expired"); + case INVALID_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete invalid"); + case RECEIVE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " onReceive()"); + case ESPEASY_NOW_SEND_MSG_SUC: return F(ESPEASY_NOW_NAME " send Message Success"); + case ESPEASY_NOW_SEND_MSG_FAIL: return F(ESPEASY_NOW_NAME " send Message Fail"); + case ESPEASY_NOW_SEND_PCKT: return F(ESPEASY_NOW_NAME " send Packet"); + case ESPEASY_NOW_DEDUP_LOOP: return F(ESPEASY_NOW_NAME " DuplicateCheck loop"); case WIFI_SCAN_ASYNC: return F("WiFi Scan Async"); case WIFI_SCAN_SYNC: return F("WiFi Scan Sync (blocking)"); case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time"); diff --git a/src/src/DataTypes/ESPEasyTimeSource.cpp b/src/src/DataTypes/ESPEasyTimeSource.cpp index 1538a8e0fd..962691d3fe 100644 --- a/src/src/DataTypes/ESPEasyTimeSource.cpp +++ b/src/src/DataTypes/ESPEasyTimeSource.cpp @@ -5,14 +5,14 @@ #include "../../ESPEasy_common.h" -String toString(timeSource_t timeSource) +const __FlashStringHelper* toString(timeSource_t timeSource) { switch (timeSource) { case timeSource_t::GPS_PPS_time_source: return F("GPS PPS"); case timeSource_t::GPS_time_source: return F("GPS"); case timeSource_t::NTP_time_source: return F("NTP"); case timeSource_t::Manual_set: return F("Manual"); - case timeSource_t::ESP_now_peer: return String(F(ESPEASY_NOW_NAME)) + F(" peer"); + case timeSource_t::ESP_now_peer: return F(ESPEASY_NOW_NAME " peer"); case timeSource_t::Restore_RTC_time_source: return F("RTC at boot"); case timeSource_t::No_time_source: return F("No time set"); } diff --git a/src/src/DataTypes/ESPEasyTimeSource.h b/src/src/DataTypes/ESPEasyTimeSource.h index ef0545c2d5..1d9565cde0 100644 --- a/src/src/DataTypes/ESPEasyTimeSource.h +++ b/src/src/DataTypes/ESPEasyTimeSource.h @@ -3,6 +3,7 @@ #include +#include class String; @@ -25,7 +26,7 @@ enum class timeSource_t : uint8_t { No_time_source = 255 // No time set }; -String toString(timeSource_t timeSource); +const __FlashStringHelper* toString(timeSource_t timeSource); bool isExternalTimeSource(timeSource_t timeSource); diff --git a/src/src/DataTypes/NetworkMedium.cpp b/src/src/DataTypes/NetworkMedium.cpp index 7ac66decf5..1cc6a13ccd 100644 --- a/src/src/DataTypes/NetworkMedium.cpp +++ b/src/src/DataTypes/NetworkMedium.cpp @@ -26,7 +26,7 @@ const __FlashStringHelper * toString(NetworkMedium_t medium) { switch (medium) { case NetworkMedium_t::WIFI: return F("WiFi"); case NetworkMedium_t::Ethernet: return F("Ethernet"); - case NetworkMedium_t::ESPEasyNOW_only: return String(F(ESPEASY_NOW_NAME)) + F(" only"); + case NetworkMedium_t::ESPEasyNOW_only: return F(ESPEASY_NOW_NAME " only"); case NetworkMedium_t::NotSet: return F("Not Set"); // Do not use default: as this allows the compiler to detect any missing cases. diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 80ebf344db..f3b494c5d9 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -159,13 +159,13 @@ bool ESPEasy_now_handler_t::begin() // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": begin on channel "); + String log = F(ESPEASY_NOW_NAME ": begin on channel "); log += _usedWiFiChannel; addLog(LOG_LEVEL_INFO, log); } if (!WifiEspNow.begin()) { - addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": Failed to initialize ESPEasy-NOW")); + addLog(LOG_LEVEL_ERROR, F(ESPEASY_NOW_NAME ": Failed to initialize ESPEasy-NOW")); return false; } ESPEasy_now_peermanager.removeAllPeers(); @@ -174,7 +174,7 @@ bool ESPEasy_now_handler_t::begin() WifiEspNow.onReceive(ESPEasy_now_onReceive, nullptr); use_EspEasy_now = true; - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" enabled")); + addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME " enabled")); if (_scanChannelsMode) { WiFiEventData.lastScanMoment.clear(); @@ -188,7 +188,7 @@ bool ESPEasy_now_handler_t::begin() const MAC_address mac(it->bssid); sendDiscoveryAnnounce(mac, _usedWiFiChannel); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": Send discovery to "); + String log = F(ESPEASY_NOW_NAME ": Send discovery to "); log += mac.toString(); addLog(LOG_LEVEL_INFO, log); } @@ -218,7 +218,7 @@ void ESPEasy_now_handler_t::end() ESPEasy_now_in_queue.clear(); ESPEasy_now_in_queue_mutex.unlock(); } - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(" disabled")); + addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME " disabled")); } bool ESPEasy_now_handler_t::loop() @@ -506,7 +506,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(const WiFi_AP_Candidate& peer) tmpNodeInfo.setESPEasyNow_mac(peer_mac); if (Nodes.addNode(tmpNodeInfo)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": Found node via WiFi scan: "); + String log = F(ESPEASY_NOW_NAME ": Found node via WiFi scan: "); log += peer_mac.toString(); log += F(" "); log += tmpNodeInfo.getRSSI(); @@ -646,7 +646,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": Sent discovery to all channels in "); + String log = F(ESPEASY_NOW_NAME ": Sent discovery to all channels in "); log += String(timePassedSince(start)); log += F(" ms"); addLog(LOG_LEVEL_INFO, log); @@ -692,7 +692,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (!received.setESPEasyNow_mac(mac)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - log = String(F(ESPEASY_NOW_NAME)) + F(": Received discovery message from MAC not stated in message: "); + log = F(ESPEASY_NOW_NAME ": Received discovery message from MAC not stated in message: "); log += mac.toString(); addLog(LOG_LEVEL_ERROR, log); } @@ -726,7 +726,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log.reserve(128); - log = String(F(ESPEASY_NOW_NAME)) + F(": discovery: "); + log = F(ESPEASY_NOW_NAME ": discovery: "); log += message.getLogString(); log += '\n'; log += received.getSummary(); @@ -821,11 +821,11 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::TraceRoute, len); if (sizeof(uint8_t) != msg.addBinaryData(reinterpret_cast(&traceroute_size), sizeof(uint8_t))) { - addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute error adding route size"));; + addLog(LOG_LEVEL_ERROR, F(ESPEASY_NOW_NAME ": sendTraceRoute error adding route size"));; return; } if (traceroute_size != msg.addBinaryData(traceroute_data, traceroute_size)) { - addLog(LOG_LEVEL_ERROR, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute error adding trace route"));; + addLog(LOG_LEVEL_ERROR, F(ESPEASY_NOW_NAME ": sendTraceRoute error adding trace route"));; return; } if (channel < 0) { @@ -839,13 +839,20 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": Sent Traceroute to all channels in "); - log += String(timePassedSince(start)); + String log = F(ESPEASY_NOW_NAME ": Sent Traceroute to all channels in "); + log += timePassedSince(start); log += F(" ms"); addLog(LOG_LEVEL_INFO, log); } } else { - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": sendTraceRoute ") + traceRoute.toString() + F(" ch: ") + String(channel)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + log += F(ESPEASY_NOW_NAME ": sendTraceRoute "); + log += traceRoute.toString(); + log += F(" ch: "); + log += channel; + addLog(LOG_LEVEL_INFO, log); + } msg.send(mac, channel); } @@ -895,7 +902,7 @@ void ESPEasy_now_handler_t::sendNTPquery() if (!_best_NTP_candidate.getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = String(F(ESPEASY_NOW_NAME)) + F(": Send NTP query to: "); + String log = F(ESPEASY_NOW_NAME ": Send NTP query to: "); log += mac.toString(); addLog(LOG_LEVEL_INFO, log); } @@ -1067,7 +1074,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge query.setState(queue_full); if (loglevelActiveFor(LOG_LEVEL_INFO) && queue_full) { - addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": After MQTT message received: Full")); + addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME ": After MQTT message received: Full")); } sendMQTTCheckControllerQueue(mac, 0, query.state); } @@ -1155,7 +1162,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { String log; - log = String(F(ESPEASY_NOW_NAME)) + F(": Received Queue state: "); + log = F(ESPEASY_NOW_NAME ": Received Queue state: "); log += query.isFull() ? F("Full") : F("not Full"); addLog(LOG_LEVEL_DEBUG_MORE, log); } @@ -1169,7 +1176,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me // We have to give our own queue state and reply query.setState(MQTT_queueFull(controllerIndex)); - // addLog(LOG_LEVEL_INFO, String(F(ESPEASY_NOW_NAME)) + F(": reply to queue state query")); + // addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME ": reply to queue state query")); const size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); if (len == msg.addBinaryData(reinterpret_cast(&query), len)) { diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index b6176f6bf5..60580bff8c 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -123,9 +123,9 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); #ifdef USES_ESPEASY_NOW - case LabelType::USE_ESPEASY_NOW: return String(F("Enable ")) + F(ESPEASY_NOW_NAME); - case LabelType::TEMP_DISABLE_ESPEASY_NOW: return String(F("Temporary disable ")) + F(ESPEASY_NOW_NAME); - case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(F("Force Channel ")) + F(ESPEASY_NOW_NAME); + case LabelType::USE_ESPEASY_NOW: return F("Enable " ESPEASY_NOW_NAME); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable " ESPEASY_NOW_NAME); + case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return F("Force Channel " ESPEASY_NOW_NAME); #endif diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index 75eded81a7..15d666d42b 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -48,7 +48,7 @@ const __FlashStringHelper * toString(ControllerSettingsStruct::VarType parameter case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: return F("Send Binary"); case ControllerSettingsStruct::CONTROLLER_TIMEOUT: return F("Client Timeout"); case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: return F("Sample Set Initiator"); - case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: return F("Enable " + ESPEASY_NOW_NAME + " Fallback"); + case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: return F("Enable " ESPEASY_NOW_NAME " Fallback"); case ControllerSettingsStruct::CONTROLLER_ENABLED: diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index f583e7c0e2..c241a56f82 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -362,7 +362,8 @@ void handle_root() { } html_TD(); if (it->second.ESPEasyNowPeer) { - addHtml(String(F(ESPEASY_NOW_NAME)) + F(" ")); + addHtml(F(ESPEASY_NOW_NAME)); + addHtml(' '); addHtml(it->second.ESPEasy_Now_MAC().toString()); addHtml(F(" (ch: ")); addHtml(String(it->second.channel)); diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index 1bc3e5b240..b9b0221d3c 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -189,13 +189,7 @@ void handle_settingsarchive() { html_TD(); addSubmitButton(F("Save Preferences"), F("savepref")); - addTableSeparator(F("Archive Location"), 2, 3); - - addFormTextBox(F("URL with settings"), F("url"), webArg(F("url")), 256); - addFormNote(F("Only HTTP supported. Do not include filename")); - addFormTextBox(F("User"), F("user"), webArg(F("user")), 64); - addFormPasswordBox(F("Pass"), F("pass"), webArg(F("pass")), 64); - addFormNote(F("URL, user and pass will not be stored")); + addFormSeparator(2); addRowLabel(F("Try download files")); addSubmitButton(F("Download"), F("download"), F("red")); From adab09e41dbaac32908c9ae13f1213e1c40002e7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 2 Jul 2021 16:30:44 +0200 Subject: [PATCH 186/404] [ESP32] Disable DHCP server on fake AP to suppress logs to Serial0 See: [invalid-event-when-client-connect-ap-debug-output](https://community.platformio.org/t/invalid-event-when-client-connect-ap-debug-output/11539) Apparently the ESP32 IDF code does not have a wrapper around this log entry so it is logging it always regardless of the desired settings. What happens is that we're having a hidden AP active and if it is scanned, it might output this log. --- src/src/ESPEasyCore/ESPEasyEth.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 15 +++++++++++++++ src/src/ESPEasyCore/ESPEasyNetwork.h | 1 + src/src/Helpers/ESPEasy_now_handler.cpp | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index fc3284e0a8..a1d6fcd854 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -120,12 +120,14 @@ bool ETHConnectRelaxed() { bool ETHConnected() { if (EthEventData.EthServicesInitialized()) { if (EthLinkUp()) { + stop_eth_dhcps(); return true; } // Apparently we missed an event EthEventData.processedDisconnect = false; } else if (EthEventData.ethInitSuccess) { if (EthLinkUp()) { + stop_eth_dhcps(); EthEventData.setEthConnected(); if (NetworkLocalIP() != IPAddress(0, 0, 0, 0) && !EthEventData.EthGotIP()) { diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 1a5b763f3f..43fc60d067 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -266,4 +266,19 @@ uint8_t EthLinkSpeed() return ETH.linkSpeed(); return 0; } + + +void stop_eth_dhcps() { + esp_err_t err = tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_ETH); + if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED){ +/* + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log = F("ETH : DHCP server could not be stopped! Error: "); + log += err; + addLog(LOG_LEVEL_ERROR, log); + } +*/ + } +} + #endif diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 3bdcecc5fa..0b27408482 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -32,6 +32,7 @@ void CheckRunningServices(); bool EthFullDuplex(); bool EthLinkUp(); uint8_t EthLinkSpeed(); +void stop_eth_dhcps(); #endif diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index f3b494c5d9..e32f1cb810 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -146,6 +146,10 @@ bool ESPEasy_now_handler_t::begin() const String passphrase = F(ESPEASY_NOW_TMP_PASSPHRASE); setAP(true); + #ifdef ESP32 + // We're running a dummy AP, so don't run DHCP server. + tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP); + #endif // Make sure AP will not be turned off. WiFiEventData.timerAPoff.clear(); From 5ac5ba57b3f443cc8ddc7c58cd3eeb059a37658b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 3 Jul 2021 22:09:11 +0200 Subject: [PATCH 187/404] Fix merge issues --- src/src/Helpers/ESPEasy_time.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 706286e2be..7fe4588593 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -19,20 +19,12 @@ class ESPEasy_time { static void breakTime(unsigned long timeInput, struct tm & tm); -// Restore the last known system time -// This may be useful to get some idea of what time it is. -// This way the unit can do things based on local time even when NTP servers may not respond. -// Do not use this when booting from deep sleep. -// Only call this once during boot. -void restoreLastKnownUnixTime(unsigned long lastSysTime, uint8_t deepSleepState); - // Restore the last known system time // This may be useful to get some idea of what time it is. // This way the unit can do things based on local time even when NTP servers may not respond. // Do not use this when booting from deep sleep. // Only call this once during boot. - void restoreLastKnownUnixTime(unsigned long lastSysTime, - byte deepSleepState); + void restoreLastKnownUnixTime(unsigned long lastSysTime, uint8_t deepSleepState); void setExternalTimeSource(double time, timeSource_t source); From 32e831f638c972399cb2908536f078903b3c9104 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 6 Jul 2021 14:08:15 +0200 Subject: [PATCH 188/404] [ESPEasy-NOW] Add route info to MQTT packet to forward --- src/src/ControllerQueue/C011_queue_element.h | 4 +- src/src/ControllerQueue/C015_queue_element.h | 4 +- src/src/ControllerQueue/C016_queue_element.h | 4 +- src/src/ControllerQueue/C018_queue_element.h | 4 +- src/src/ControllerQueue/C019_queue_element.h | 6 +- .../ControllerDelayHandlerStruct.h | 8 +-- src/src/ControllerQueue/MQTT_queue_element.h | 8 +-- .../SimpleQueueElement_string_only.h | 4 +- .../queue_element_formatted_uservar.h | 4 +- .../queue_element_single_value_base.h | 4 +- src/src/DataStructs/MessageRouteInfo.cpp | 61 +++++++++++++++++++ src/src/DataStructs/MessageRouteInfo.h | 44 +++++++++++++ src/src/DataStructs/UnitMessageCount.cpp | 19 ------ src/src/DataStructs/UnitMessageCount.h | 30 --------- src/src/ESPEasyCore/Controller.cpp | 12 ++-- src/src/ESPEasyCore/Controller.h | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 10 +-- src/src/Helpers/ESPEasy_now_handler.h | 4 +- src/src/Helpers/PeriodicalActions.cpp | 2 +- src/src/Helpers/PeriodicalActions.h | 4 +- 20 files changed, 148 insertions(+), 92 deletions(-) create mode 100644 src/src/DataStructs/MessageRouteInfo.cpp create mode 100644 src/src/DataStructs/MessageRouteInfo.h delete mode 100644 src/src/DataStructs/UnitMessageCount.cpp delete mode 100644 src/src/DataStructs/UnitMessageCount.h diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 5b909d44bf..f86187dd73 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -29,7 +29,7 @@ class C011_queue_element { bool isDuplicate(const C011_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } size_t getSize() const; diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index c30d353dcc..ef936f193c 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -33,7 +33,7 @@ class C015_queue_element { bool isDuplicate(const C015_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } String txt[VARS_PER_TASK]; int vPin[VARS_PER_TASK] = { 0 }; diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 72f2b66d34..b5fe77b644 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/Plugins.h" struct EventStruct; @@ -36,7 +36,7 @@ class C016_queue_element { bool isDuplicate(const C016_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } float values[VARS_PER_TASK] = { 0 }; unsigned long _timestamp = 0; // Unix timestamp diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index b07a483061..5a480107c8 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -32,7 +32,7 @@ class C018_queue_element { bool isDuplicate(const C018_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } String packed; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 187b0b62a9..32d01ca736 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/ESPEasy_EventStruct.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -30,7 +30,7 @@ class C019_queue_element { bool isDuplicate(const C019_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } String packed; unsigned long _timestamp = millis(); @@ -38,7 +38,7 @@ class C019_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; EventStruct event; - UnitMessageCount_t UnitMessageCount; + MessageRouteInfo_t MessageRouteInfo; }; // #endif //USES_C019 diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index b4f3b1171e..cab9555040 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -3,7 +3,7 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../DataStructs/TimingStats.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/CPlugins.h" #include "../Globals/ESPEasy_Scheduler.h" @@ -108,12 +108,12 @@ struct ControllerDelayHandlerStruct { bool isDuplicate(const T& element) const { // Some controllers may receive duplicate messages, due to lost acknowledgement // This is actually the same message, so this should not be processed. - if (!unitLastMessageCount.isNew(element.getUnitMessageCount())) { + if (!unitMessageRouteInfo_map.isNew(element.getUnitMessageCount())) { return true; } // The unit message count is still stored to make sure a new one with the same count // is considered a duplicate, even when the queue is empty. - unitLastMessageCount.add(element.getUnitMessageCount()); + unitMessageRouteInfo_map.add(element.getUnitMessageCount()); // the setting 'deduplicate' does look at the content of the message and only compares it to messages in the queue. if (deduplicate && !sendQueue.empty()) { @@ -240,7 +240,7 @@ struct ControllerDelayHandlerStruct { } std::list sendQueue; - mutable UnitLastMessageCount_map unitLastMessageCount; + mutable UnitMessageRouteInfo_map unitMessageRouteInfo_map; unsigned long lastSend; unsigned int minTimeBetweenMessages; unsigned long expire_timeout = 0; diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index c6ec8471e2..b7f67cd3f5 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -2,7 +2,7 @@ #define CONTROLLERQUEUE_MQTT_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -34,8 +34,8 @@ class MQTT_queue_element { bool isDuplicate(const MQTT_queue_element& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return &UnitMessageCount; } - UnitMessageCount_t* getUnitMessageCount() { return &UnitMessageCount; } + const MessageRouteInfo_t* getUnitMessageCount() const { return &MessageRouteInfo; } + MessageRouteInfo_t* getUnitMessageCount() { return &MessageRouteInfo; } void removeEmptyTopics(); @@ -45,7 +45,7 @@ class MQTT_queue_element { taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; bool _retained = false; - UnitMessageCount_t UnitMessageCount; + MessageRouteInfo_t MessageRouteInfo; }; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 235034a266..8aa98f1016 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -2,7 +2,7 @@ #define CONTROLLERQUEUE_SIMPLE_QUEUE_ELEMENT_STRING_ONLY_H #include "../../ESPEasy_common.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -26,7 +26,7 @@ class simple_queue_element_string_only { bool isDuplicate(const simple_queue_element_string_only& other) const; - const UnitMessageCount_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } String txt; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index fed79983bc..b6273d2875 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" #include "../DataStructs/DeviceStruct.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -28,7 +28,7 @@ class queue_element_formatted_uservar { bool isDuplicate(const queue_element_formatted_uservar& other) const; - const UnitMessageCount_t * getUnitMessageCount() const { + const MessageRouteInfo_t * getUnitMessageCount() const { return nullptr; } diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 67990184bc..313ae83fc1 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" #include "../Globals/Plugins.h" @@ -35,7 +35,7 @@ class queue_element_single_value_base { bool isDuplicate(const queue_element_single_value_base& other) const; - const UnitMessageCount_t * getUnitMessageCount() const { + const MessageRouteInfo_t * getUnitMessageCount() const { return nullptr; } diff --git a/src/src/DataStructs/MessageRouteInfo.cpp b/src/src/DataStructs/MessageRouteInfo.cpp new file mode 100644 index 0000000000..c686c9ec0d --- /dev/null +++ b/src/src/DataStructs/MessageRouteInfo.cpp @@ -0,0 +1,61 @@ +#include "../DataStructs/MessageRouteInfo.h" + + +MessageRouteInfo_t::MessageRouteInfo_t(const uint8_t* serializedData, size_t size) { + deserialize(serializedData, size); +} + +MessageRouteInfo_t::MessageRouteInfo_t(const uint8_t_vector& serializedData) { + deserialize(&(serializedData[0]), serializedData.size()); +} + +bool MessageRouteInfo_t::deserialize(const uint8_t* serializedData, size_t size) { + if (size >= 4 && serializedData != nullptr) { + size_t index = 0; + unit = serializedData[index++]; + count = serializedData[index++]; + dest_unit = serializedData[index++]; + const size_t traceSize = serializedData[index++]; + if (size >= (traceSize + 4)) { + trace.resize(traceSize); + for (size_t i = 0; i < traceSize; ++i) { + trace[i] = serializedData[index++]; + } + return true; + } + } + return false; +} + +MessageRouteInfo_t::uint8_t_vector MessageRouteInfo_t::serialize() const { + uint8_t_vector res; + res.resize(4 + trace.size()); + + size_t index = 0; + res[index++] = unit; + res[index++] = count; + res[index++] = dest_unit; + res[index++] = trace.size(); + for (size_t i = 0; i < trace.size(); ++i) { + res[index++] = trace[i]; + } + return res; +} + +bool UnitMessageRouteInfo_map::isNew(const MessageRouteInfo_t *info) const { + if (info == nullptr) { return true; } + auto it = _map.find(info->unit); + + if (it != _map.end()) { + return it->second.count != info->count; + } + return true; +} + +void UnitMessageRouteInfo_map::add(const MessageRouteInfo_t *info) { + if (info == nullptr) { return; } + + if ((info->unit != 0) && (info->unit != 255)) { + _map[info->unit] = *info; + } +} diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h new file mode 100644 index 0000000000..1993b3bd50 --- /dev/null +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -0,0 +1,44 @@ +#ifndef DATASTRUCTS_UNITMESSAGECOUNT_H +#define DATASTRUCTS_UNITMESSAGECOUNT_H + +#include "../../ESPEasy_common.h" + +#include + +// For deduplication, some controllers may add a unit ID and current counter. +// This count will wrap around, so it is just to detect if a message is received multiple times. +// The unit ID is the unit where the message originates from and thus should be kept along when forwarding. +struct MessageRouteInfo_t { + typedef std::vector uint8_t_vector; + + + MessageRouteInfo_t() {} + + MessageRouteInfo_t(uint8_t unitnr, uint8_t messageCount) : unit(unitnr), count(messageCount) {} + + MessageRouteInfo_t(const uint8_t* serializedData, size_t size); + + MessageRouteInfo_t(const uint8_t_vector& serializedData); + + bool deserialize(const uint8_t* serializedData, size_t size); + + uint8_t_vector serialize() const; + + uint8_t unit = 0; // Initialize to "not set" + uint8_t count = 0; + uint8_t dest_unit = 0; // Initialize to "not set" + + uint8_t_vector trace; +}; + +struct UnitMessageRouteInfo_map { + bool isNew(const MessageRouteInfo_t *count) const; + + void add(const MessageRouteInfo_t *count); + +private: + + std::map _map; +}; + +#endif // ifndef DATASTRUCTS_UNITMESSAGECOUNT_H diff --git a/src/src/DataStructs/UnitMessageCount.cpp b/src/src/DataStructs/UnitMessageCount.cpp deleted file mode 100644 index 7ceaf696be..0000000000 --- a/src/src/DataStructs/UnitMessageCount.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "../DataStructs/UnitMessageCount.h" - -bool UnitLastMessageCount_map::isNew(const UnitMessageCount_t *count) const { - if (count == nullptr) { return true; } - auto it = _map.find(count->unit); - - if (it != _map.end()) { - return it->second != count->count; - } - return true; -} - -void UnitLastMessageCount_map::add(const UnitMessageCount_t *count) { - if (count == nullptr) { return; } - - if ((count->unit != 0) && (count->unit != 255)) { - _map[count->unit] = count->count; - } -} diff --git a/src/src/DataStructs/UnitMessageCount.h b/src/src/DataStructs/UnitMessageCount.h deleted file mode 100644 index de25505105..0000000000 --- a/src/src/DataStructs/UnitMessageCount.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef DATASTRUCTS_UNITMESSAGECOUNT_H -#define DATASTRUCTS_UNITMESSAGECOUNT_H - -#include "../../ESPEasy_common.h" - -#include - -// For deduplication, some controllers may add a unit ID and current counter. -// This count will wrap around, so it is just to detect if a message is received multiple times. -// The unit ID is the unit where the message originates from and thus should be kept along when forwarding. -struct UnitMessageCount_t { - UnitMessageCount_t() {} - - UnitMessageCount_t(uint8_t unitnr, uint8_t messageCount) : unit(unitnr), count(messageCount) {} - - uint8_t unit = 0; // Initialize to "not set" - uint8_t count = 0; -}; - -struct UnitLastMessageCount_map { - bool isNew(const UnitMessageCount_t *count) const; - - void add(const UnitMessageCount_t *count); - -private: - - std::map_map; -}; - -#endif // ifndef DATASTRUCTS_UNITMESSAGECOUNT_H diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 828666b57d..fc58b6d089 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -519,7 +519,7 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const UnitMessageCount_t& unitMessageCount, bool retained) +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& unitMessageCount, bool retained) { bool success = false; if (!MQTT_queueFull(controller_idx)) @@ -529,18 +529,18 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes size_t pos = 0; element.controller_idx = controller_idx; element._retained = retained; - element.UnitMessageCount = unitMessageCount; + element.MessageRouteInfo = unitMessageCount; const size_t payloadSize = message.getPayloadSize(); if (message.getString(element._topic, pos) && message.getString(element._payload, pos)) { success = true; const size_t bytesLeft = payloadSize - pos; if (bytesLeft >= 2) { - // There is some UnitMessageCount left - if (!(message.getBinaryData(&element.UnitMessageCount.unit, 1, pos) == 1 && - message.getBinaryData(&element.UnitMessageCount.count, 1, pos) == 1)) + // There is some MessageRouteInfo left + if (!(message.getBinaryData(&element.MessageRouteInfo.unit, 1, pos) == 1 && + message.getBinaryData(&element.MessageRouteInfo.count, 1, pos) == 1)) { // Whatever may have been present, it could not be loaded, so clear just to be sure. - element.UnitMessageCount = unitMessageCount; + element.MessageRouteInfo = unitMessageCount; } } } diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 0d8ee4489f..05642997db 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -5,7 +5,7 @@ #include "../DataTypes/EventValueSource.h" #include "../DataStructs/ESPEasy_now_merger.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" // ******************************************************************************** @@ -72,7 +72,7 @@ void SendStatus(struct EventStruct *event, const String& status); bool MQTT_queueFull(controllerIndex_t controller_idx); #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const UnitMessageCount_t& unitMessageCount, bool retained); +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& unitMessageCount, bool retained); #endif bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index e32f1cb810..d0e8aa2202 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -969,7 +969,7 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // * MQTT controller forwarder // ************************************************************* -bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const UnitMessageCount_t* unitMessageCount) +bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const MessageRouteInfo_t* unitMessageCount) { if (!use_EspEasy_now) { return false; } @@ -1059,15 +1059,15 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge bool success = false; if (message.getMac(mac)) { - UnitMessageCount_t UnitMessageCount; + MessageRouteInfo_t MessageRouteInfo; const NodeStruct* node = Nodes.getNodeByMac(mac); if (node != nullptr) { - if (message.getMessageCount(UnitMessageCount.count)) { - UnitMessageCount.unit = node->unit; + if (message.getMessageCount(MessageRouteInfo.count)) { + MessageRouteInfo.unit = node->unit; } } - success = MQTTpublish(controllerIndex, message, UnitMessageCount, _mqtt_retainFlag); + success = MQTTpublish(controllerIndex, message, MessageRouteInfo, _mqtt_retainFlag); if (!success) { mustKeep = false; return success; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index cddc77ad03..0839f20ab2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -14,7 +14,7 @@ # include "../DataStructs/ESPEasy_Now_p2p_data.h" # include "../DataStructs/ESPEasy_now_traceroute.h" # include "../DataStructs/MAC_address.h" -# include "../DataStructs/UnitMessageCount.h" +# include "../DataStructs/MessageRouteInfo.h" # include "../DataStructs/WiFi_AP_Candidate.h" # include "../Globals/CPlugins.h" @@ -72,7 +72,7 @@ class ESPEasy_now_handler_t { bool sendToMQTT(controllerIndex_t controllerIndex, const String & topic, const String & payload, - const UnitMessageCount_t* unitMessageCount); + const MessageRouteInfo_t* unitMessageCount); bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); bool sendMQTTCheckControllerQueue(const MAC_address& mac, diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 9967f1b812..30c7cb1929 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -381,7 +381,7 @@ bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, bool retained, - const UnitMessageCount_t* unitMessageCount) + const MessageRouteInfo_t* unitMessageCount) { bool processed = false; diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 0ea4e7c5ac..3c26e2e18a 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -4,7 +4,7 @@ #include #include "../../ESPEasy_common.h" -#include "../DataStructs/UnitMessageCount.h" +#include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" #include "../Helpers/Scheduler.h" @@ -41,7 +41,7 @@ bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, bool retained, - const UnitMessageCount_t* unitMessageCount); + const MessageRouteInfo_t* unitMessageCount); void updateMQTTclient_connected(); From ad79b700c4602d55d8c5afa91eb698f6ef4716f9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 6 Jul 2021 16:22:46 +0200 Subject: [PATCH 189/404] [Cleanup] No longer use `byte` type --- src/_C019.ino | 2 +- src/_P098_ESPEasyNowReceiver.ino | 2 +- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 8 ++++---- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 6 +++--- src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 +- src/src/DataStructs/ESPEasy_now_Node_statistics.cpp | 6 +++--- src/src/DataStructs/ESPEasy_now_Node_statistics.h | 8 ++++---- src/src/DataStructs/ESPEasy_now_hdr.cpp | 2 +- src/src/DataStructs/ESPEasy_now_hdr.h | 2 +- src/src/DataStructs/ESPEasy_now_traceroute.cpp | 6 +++--- src/src/DataStructs/ESPEasy_now_traceroute.h | 8 ++++---- src/src/DataStructs/NodeStruct.cpp | 2 +- src/src/DataStructs/NodeStruct.h | 2 +- src/src/DataStructs/NodesHandler.cpp | 12 ++++++------ src/src/DataStructs/NodesHandler.h | 10 +++++----- src/src/DataStructs/SecurityStruct.cpp | 4 ++-- src/src/DataStructs/SecurityStruct.h | 4 ++-- src/src/Helpers/ESPEasy_Storage.cpp | 6 +++--- src/src/Helpers/ESPEasy_Storage.h | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 2 +- src/src/Helpers/ESPEasy_now_peermanager.cpp | 2 +- src/src/Helpers/Networking.cpp | 4 ++-- 22 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/_C019.ino b/src/_C019.ino index 4b124e4e59..75fdffafcb 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -116,7 +116,7 @@ bool do_process_c019_delay_queue(int controller_number, const C019_queue_element data.sensorType = element.event.sensorType; data.valueCount = getValueCountForTask(taskIndex); - for (byte i = 0; i < data.valueCount; ++i) + for (uint8_t i = 0; i < data.valueCount; ++i) { switch (data.sensorType) { case Sensor_VType::SENSOR_TYPE_LONG: diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino index 69f736c33b..86f7b8257d 100644 --- a/src/_P098_ESPEasyNowReceiver.ino +++ b/src/_P098_ESPEasyNowReceiver.ino @@ -21,7 +21,7 @@ struct P098_data_struct : public PluginTaskData_base { ~P098_data_struct() {} }; -boolean Plugin_098(byte function, struct EventStruct *event, String& string) +boolean Plugin_098(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 35c3eaf11c..fc20dcec00 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -149,11 +149,11 @@ void ESPEasy_Now_NTP_query::reset(bool success) _expectedWander_ms = (1 << 30); _timeSource = timeSource_t::No_time_source; - for (byte i = 0; i < 6; ++i) { + for (uint8_t i = 0; i < 6; ++i) { _mac_prev_fail[i] = success ? 0 : _mac[i]; } - for (byte i = 0; i < 6; ++i) { + for (uint8_t i = 0; i < 6; ++i) { _mac[i] = 0; } } @@ -180,7 +180,7 @@ bool ESPEasy_Now_NTP_query::hasLowerWander() const bool ESPEasy_Now_NTP_query::isBroadcast() const { - for (byte i = 0; i < 6; ++i) { + for (uint8_t i = 0; i < 6; ++i) { if (_mac[i] != 0xFF) { return false; } } return true; @@ -193,7 +193,7 @@ void ESPEasy_Now_NTP_query::markSendTime() void ESPEasy_Now_NTP_query::createBroadcastNTP() { - for (byte i = 0; i < 6; ++i) + for (uint8_t i = 0; i < 6; ++i) { _mac[i] = 0xFF; } diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index d7f42f51d7..39fa7477b1 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -26,20 +26,20 @@ bool ESPEasy_Now_p2p_data::validate() const { } bool ESPEasy_Now_p2p_data::addFloat(float value) { - return addBinaryData((byte *)(&value), sizeof(float)); + return addBinaryData((uint8_t *)(&value), sizeof(float)); } bool ESPEasy_Now_p2p_data::getFloat(float& value, size_t& offset) const { if ((offset + sizeof(float)) >= dataSize) { return false; } - memcpy((byte *)(&value), &data[offset], sizeof(float)); + memcpy((uint8_t *)(&value), &data[offset], sizeof(float)); offset += sizeof(float); return true; } bool ESPEasy_Now_p2p_data::addString(const String& value) { - return addBinaryData((byte *)(value.c_str()), value.length() + 1); // Include null termination + return addBinaryData((uint8_t *)(value.c_str()), value.length() + 1); // Include null termination } bool ESPEasy_Now_p2p_data::getString(String& value, size_t& offset) const { diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index a614df88af..f6692808bb 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -150,7 +150,7 @@ void ESPEasy_Now_packet::setMac(const MAC_address& mac) void ESPEasy_Now_packet::setBroadcast() { - for (byte i = 0; i < 6; ++i) + for (uint8_t i = 0; i < 6; ++i) { _mac[i] = 0xFF; } diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 5741594b73..98b7c2d8d1 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -10,7 +10,7 @@ unsigned long ESPEasy_now_Node_statistics_t::getAge() const return timePassedSince(last_update_route[last_route_index]); } -void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_traceroute_struct& route) +void ESPEasy_now_Node_statistics_t::addRoute(uint8_t unit, const ESPEasy_now_traceroute_struct& route) { if (route.getDistance() == 255) { return; @@ -42,14 +42,14 @@ void ESPEasy_now_Node_statistics_t::addRoute(byte unit, const ESPEasy_now_tracer } } -void ESPEasy_now_Node_statistics_t::setDiscoveryRoute(byte unit, const ESPEasy_now_traceroute_struct& route) +void ESPEasy_now_Node_statistics_t::setDiscoveryRoute(uint8_t unit, const ESPEasy_now_traceroute_struct& route) { discovery_route = route; discovery_route.addUnit(unit); discovery_route.setSuccessRate_last_node(unit, success_rate); } -void ESPEasy_now_Node_statistics_t::updateSuccessRate(byte unit, bool success) +void ESPEasy_now_Node_statistics_t::updateSuccessRate(uint8_t unit, bool success) { if (success) { if (timePassedSince(last_update) < 100) { diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index fe5ed50d07..4920cefc2f 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -15,12 +15,12 @@ struct ESPEasy_now_Node_statistics_t { unsigned long getAge() const; // Store route received via traceroute packet - void addRoute(byte unit, const ESPEasy_now_traceroute_struct& route); + void addRoute(uint8_t unit, const ESPEasy_now_traceroute_struct& route); // Store route received via Discovery packet - void setDiscoveryRoute(byte unit, const ESPEasy_now_traceroute_struct& route); + void setDiscoveryRoute(uint8_t unit, const ESPEasy_now_traceroute_struct& route); - void updateSuccessRate(byte unit, bool success); + void updateSuccessRate(uint8_t unit, bool success); uint8_t getNodeSuccessRate() const; @@ -53,7 +53,7 @@ struct ESPEasy_now_Node_statistics_t { ESPEasy_Now_MQTT_queue_check_packet::QueueState mqtt_queue_state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; }; -typedef std::map ESPEasy_now_Node_statisticsMap; +typedef std::map ESPEasy_now_Node_statisticsMap; #endif diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index 3b1c977041..8ff40ead6f 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -2,7 +2,7 @@ #ifdef USES_ESPEASY_NOW -String ESPEasy_now_hdr::toString(ESPEasy_now_hdr::message_t messageType) +const __FlashStringHelper * ESPEasy_now_hdr::toString(ESPEasy_now_hdr::message_t messageType) { switch (messageType) { case ESPEasy_now_hdr::message_t::NotSet: return F("-"); diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 6310c88582..468af4443f 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -30,7 +30,7 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { ChecksumError = 255 }; - static String toString(message_t messageType); + static const __FlashStringHelper * toString(message_t messageType); ESPEasy_now_hdr(); diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index fdfebb98cf..fffc9dfe67 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -21,7 +21,7 @@ uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, uint8_t& succes return unit_vector[distance * 2]; } -void ESPEasy_now_traceroute_struct::addUnit(byte unit) +void ESPEasy_now_traceroute_struct::addUnit(uint8_t unit) { // Only add the unit if it isn't already part of the traceroute. const uint8_t index = static_cast(unit_vector.size()); @@ -57,7 +57,7 @@ uint8_t * ESPEasy_now_traceroute_struct::get() return &(unit_vector[0]); } -void ESPEasy_now_traceroute_struct::setSuccessRate_last_node(byte unit, uint8_t successRate) +void ESPEasy_now_traceroute_struct::setSuccessRate_last_node(uint8_t unit, uint8_t successRate) { int index = unit_vector.size() - 2; int attempt = 0; @@ -137,7 +137,7 @@ int ESPEasy_now_traceroute_struct::computeSuccessRate() const return res; } -bool ESPEasy_now_traceroute_struct::unitInTraceRoute(byte unit) const +bool ESPEasy_now_traceroute_struct::unitInTraceRoute(uint8_t unit) const { const uint8_t max_distance = getDistance(); for (uint8_t distance = 0; distance <= max_distance; ++distance) { diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.h b/src/src/DataStructs/ESPEasy_now_traceroute.h index 82c28724f6..b1c575059e 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.h +++ b/src/src/DataStructs/ESPEasy_now_traceroute.h @@ -23,7 +23,7 @@ struct ESPEasy_now_traceroute_struct uint8_t& successRate) const; // Append unit at the end (thus furthest distance) - void addUnit(byte unit); + void addUnit(uint8_t unit); uint8_t getDistance() const; @@ -33,7 +33,7 @@ struct ESPEasy_now_traceroute_struct // Make sure the array is large enough to store the data. uint8_t* get(); - void setSuccessRate_last_node(byte unit, uint8_t successRate); + void setSuccessRate_last_node(uint8_t unit, uint8_t successRate); // Return true when this tracerouteis more favorable bool operator<(const ESPEasy_now_traceroute_struct& other) const; @@ -45,7 +45,7 @@ struct ESPEasy_now_traceroute_struct // Compute success rate int computeSuccessRate() const; - bool unitInTraceRoute(byte unit) const; + bool unitInTraceRoute(uint8_t unit) const; private: @@ -55,6 +55,6 @@ struct ESPEasy_now_traceroute_struct std::vectorunit_vector; }; -typedef std::map TraceRouteMap; +typedef std::map TraceRouteMap; #endif // ifndef DATASTRUCTS_ESPEASY_NOW_TRACEROUTE_H diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index aaed6c1349..c1b51cf4eb 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -101,7 +101,7 @@ const __FlashStringHelper * NodeStruct::getNodeTypeDisplayString(uint8_t nodeTyp return F(""); } -String NodeStruct::getNodeTypeDisplayString() const { +const __FlashStringHelper * NodeStruct::getNodeTypeDisplayString() const { return NodeStruct::getNodeTypeDisplayString(nodeType); } diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index f9328603e7..ef9bd381c4 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -36,7 +36,7 @@ struct __attribute__((__packed__)) NodeStruct bool operator<(const NodeStruct &other) const; static const __FlashStringHelper * getNodeTypeDisplayString(uint8_t nodeType); - String getNodeTypeDisplayString() const; + const __FlashStringHelper * getNodeTypeDisplayString() const; String getNodeName() const; diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 327de383e0..7b4f32f52c 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -334,7 +334,7 @@ void NodesHandler::updateThisNode() { if (addIP) { IPAddress localIP = NetworkLocalIP(); - for (byte i = 0; i < 4; ++i) { + for (uint8_t i = 0; i < 4; ++i) { thisNode.ip[i] = localIP[i]; } } @@ -581,7 +581,7 @@ bool NodesHandler::lastTimeValidDistanceExpired() const } #ifdef USES_ESPEASY_NOW -void NodesHandler::updateSuccessRate(byte unit, bool success) +void NodesHandler::updateSuccessRate(uint8_t unit, bool success) { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { @@ -598,7 +598,7 @@ void NodesHandler::updateSuccessRate(const MAC_address& mac, bool success) updateSuccessRate(node->unit, success); } -int NodesHandler::getRouteSuccessRate(byte unit, uint8_t& distance) const +int NodesHandler::getRouteSuccessRate(uint8_t unit, uint8_t& distance) const { distance = 255; auto it = _nodeStats.find(unit); @@ -612,7 +612,7 @@ int NodesHandler::getRouteSuccessRate(byte unit, uint8_t& distance) const return 0; } -uint8_t NodesHandler::getSuccessRate(byte unit) const +uint8_t NodesHandler::getSuccessRate(uint8_t unit) const { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { @@ -621,7 +621,7 @@ uint8_t NodesHandler::getSuccessRate(byte unit) const return 127; } -ESPEasy_Now_MQTT_queue_check_packet::QueueState NodesHandler::getMQTTQueueState(byte unit) const +ESPEasy_Now_MQTT_queue_check_packet::QueueState NodesHandler::getMQTTQueueState(uint8_t unit) const { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { @@ -631,7 +631,7 @@ ESPEasy_Now_MQTT_queue_check_packet::QueueState NodesHandler::getMQTTQueueState( } -void NodesHandler::setMQTTQueueState(byte unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +void NodesHandler::setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 8d7e262c77..807d4d13ee 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -85,16 +85,16 @@ class NodesHandler { void setRSSI(uint8_t unit, int rssi); #ifdef USES_ESPEASY_NOW - void updateSuccessRate(byte unit, bool success); + void updateSuccessRate(uint8_t unit, bool success); void updateSuccessRate(const MAC_address& mac, bool success); - int getRouteSuccessRate(byte unit, uint8_t& distance) const; + int getRouteSuccessRate(uint8_t unit, uint8_t& distance) const; - uint8_t getSuccessRate(byte unit) const; + uint8_t getSuccessRate(uint8_t unit) const; - ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState(byte unit) const; + ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState(uint8_t unit) const; - void setMQTTQueueState(byte unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + void setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); void setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); #endif diff --git a/src/src/DataStructs/SecurityStruct.cpp b/src/src/DataStructs/SecurityStruct.cpp index a391c30045..11f9be72cd 100644 --- a/src/src/DataStructs/SecurityStruct.cpp +++ b/src/src/DataStructs/SecurityStruct.cpp @@ -16,7 +16,7 @@ SecurityStruct::SecurityStruct() { ZERO_FILL(ControllerUser[i]); ZERO_FILL(ControllerPassword[i]); } - for (byte i = 0; i < ESPEASY_NOW_PEER_MAX; ++i) { + for (uint8_t i = 0; i < ESPEASY_NOW_PEER_MAX; ++i) { ZERO_FILL(EspEasyNowPeerMAC[i]); } ZERO_FILL(Password); @@ -36,7 +36,7 @@ void SecurityStruct::validate() { ZERO_TERMINATE(Password); } -bool SecurityStruct::peerMacSet(byte peer_index) const { +bool SecurityStruct::peerMacSet(uint8_t peer_index) const { if (peer_index >= ESPEASY_NOW_PEER_MAX) { return false; } diff --git a/src/src/DataStructs/SecurityStruct.h b/src/src/DataStructs/SecurityStruct.h index c1d151d669..b997e5b0c4 100644 --- a/src/src/DataStructs/SecurityStruct.h +++ b/src/src/DataStructs/SecurityStruct.h @@ -19,7 +19,7 @@ struct SecurityStruct void validate(); - bool peerMacSet(byte peer_index) const; + bool peerMacSet(uint8_t peer_index) const; void clearWiFiCredentials(); @@ -45,7 +45,7 @@ struct SecurityStruct uint8_t ProgmemMd5[16] = {0}; // crc of the binary that last saved the struct to file. uint8_t md5[16] = {0}; - byte EspEasyNowPeerMAC[ESPEASY_NOW_PEER_MAX][6]; + uint8_t EspEasyNowPeerMAC[ESPEASY_NOW_PEER_MAX][6]; }; diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index cb6e3fc97e..5e46f789f0 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -996,7 +996,7 @@ String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings) if (memcmp(tmp_md5, ProvisioningSettings.md5, 16) != 0) { // Settings have changed, save to file. memcpy(ProvisioningSettings.md5, tmp_md5, 16); - err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (byte *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); } return err; } @@ -1009,7 +1009,7 @@ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) uint8_t calculatedMd5[16] = { 0 }; MD5Builder md5; - String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (byte *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); md5.begin(); md5.add(((uint8_t *)&ProvisioningSettings) + 16, sizeof(ProvisioningSettings) - 16); md5.calculate(); @@ -1098,7 +1098,7 @@ String SaveToFile(const char *fname, int index, const uint8_t *memAddress, int d return doSaveToFile(fname, index, memAddress, datasize, "r+"); } -String SaveToFile_trunc(const char *fname, int index, const byte *memAddress, int datasize) +String SaveToFile_trunc(const char *fname, int index, const uint8_t *memAddress, int datasize) { return doSaveToFile(fname, index, memAddress, datasize, "w+"); } diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index 620a6bbd99..2d18661e1c 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -208,7 +208,7 @@ String SaveToFile(const char *fname, int index, const uint8_t *memAddress, int d // Open for reading and writing. // The file is created if it does not exist, otherwise it is truncated. // The stream is positioned at the beginning of the file. -String SaveToFile_trunc(const char *fname, int index, const byte *memAddress, int datasize); +String SaveToFile_trunc(const char *fname, int index, const uint8_t *memAddress, int datasize); // See for mode description: https://github.com/esp8266/Arduino/blob/master/doc/filesystem.rst String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int datasize, const char *mode); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d0e8aa2202..93c6f06607 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -49,7 +49,7 @@ static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr key = key << 8; key += static_cast(messageType); - for (byte i = 0; i < 6; ++i) { + for (uint8_t i = 0; i < 6; ++i) { key = key << 8; key += mac[i]; } diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index 69eda99847..3fa54689a7 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -112,7 +112,7 @@ void ESPEasy_now_peermanager_t::removeAllPeers() { void ESPEasy_now_peermanager_t::addKnownPeers() { - for (byte peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { + for (uint8_t peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { if (SecuritySettings.peerMacSet(peer)) { addPeer(SecuritySettings.EspEasyNowPeerMAC[peer], 0); } diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index f9a303551d..5a4d8e7eb9 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -458,12 +458,12 @@ void sendSysInfoUDP(uint8_t repeats) } // Prepare UDP packet to send - byte data[80]; + uint8_t data[80]; data[0] = 255; data[1] = 1; memcpy(&data[2], thisNode, sizeof(NodeStruct)); - for (byte counter = 0; counter < repeats; counter++) + for (uint8_t counter = 0; counter < repeats; counter++) { statusLED(true); From 9b0de9344fc189b7d33edcbd21d2c27314cd8511 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 6 Jul 2021 23:35:00 +0200 Subject: [PATCH 190/404] [ESPEasy-NOW] Extend message route info for MQTT packets --- src/src/ControllerQueue/C011_queue_element.h | 2 +- src/src/ControllerQueue/C015_queue_element.h | 2 +- src/src/ControllerQueue/C016_queue_element.h | 2 +- src/src/ControllerQueue/C018_queue_element.h | 2 +- src/src/ControllerQueue/C019_queue_element.h | 2 +- .../ControllerDelayHandlerStruct.h | 4 +-- src/src/ControllerQueue/MQTT_queue_element.h | 4 +-- .../SimpleQueueElement_string_only.h | 2 +- .../queue_element_formatted_uservar.h | 2 +- .../queue_element_single_value_base.h | 2 +- src/src/DataStructs/MessageRouteInfo.cpp | 35 +++++++++++++++++-- src/src/DataStructs/MessageRouteInfo.h | 7 ++++ src/src/ESPEasyCore/Controller.cpp | 23 ++++++++---- src/src/ESPEasyCore/Controller.h | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 17 +++++++-- src/src/Helpers/ESPEasy_now_handler.h | 2 +- src/src/Helpers/PeriodicalActions.cpp | 8 ++--- src/src/Helpers/PeriodicalActions.h | 2 +- 18 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index f86187dd73..b8e432d7b2 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -29,7 +29,7 @@ class C011_queue_element { bool isDuplicate(const C011_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } size_t getSize() const; diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index ef936f193c..c6f11b766c 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -33,7 +33,7 @@ class C015_queue_element { bool isDuplicate(const C015_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } String txt[VARS_PER_TASK]; int vPin[VARS_PER_TASK] = { 0 }; diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index b5fe77b644..0d42743159 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -36,7 +36,7 @@ class C016_queue_element { bool isDuplicate(const C016_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } float values[VARS_PER_TASK] = { 0 }; unsigned long _timestamp = 0; // Unix timestamp diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 5a480107c8..8a0a23b682 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -32,7 +32,7 @@ class C018_queue_element { bool isDuplicate(const C018_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } String packed; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 32d01ca736..7acdfe29cf 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -30,7 +30,7 @@ class C019_queue_element { bool isDuplicate(const C019_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } String packed; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index cab9555040..528831fb14 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -108,12 +108,12 @@ struct ControllerDelayHandlerStruct { bool isDuplicate(const T& element) const { // Some controllers may receive duplicate messages, due to lost acknowledgement // This is actually the same message, so this should not be processed. - if (!unitMessageRouteInfo_map.isNew(element.getUnitMessageCount())) { + if (!unitMessageRouteInfo_map.isNew(element.getMessageRouteInfo())) { return true; } // The unit message count is still stored to make sure a new one with the same count // is considered a duplicate, even when the queue is empty. - unitMessageRouteInfo_map.add(element.getUnitMessageCount()); + unitMessageRouteInfo_map.add(element.getMessageRouteInfo()); // the setting 'deduplicate' does look at the content of the message and only compares it to messages in the queue. if (deduplicate && !sendQueue.empty()) { diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index b7f67cd3f5..2b19fb43aa 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -34,8 +34,8 @@ class MQTT_queue_element { bool isDuplicate(const MQTT_queue_element& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return &MessageRouteInfo; } - MessageRouteInfo_t* getUnitMessageCount() { return &MessageRouteInfo; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return &MessageRouteInfo; } + MessageRouteInfo_t* getMessageRouteInfo() { return &MessageRouteInfo; } void removeEmptyTopics(); diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 8aa98f1016..aefb29b538 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -26,7 +26,7 @@ class simple_queue_element_string_only { bool isDuplicate(const simple_queue_element_string_only& other) const; - const MessageRouteInfo_t* getUnitMessageCount() const { return nullptr; } + const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } String txt; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/queue_element_formatted_uservar.h b/src/src/ControllerQueue/queue_element_formatted_uservar.h index b6273d2875..b9e9907dfd 100644 --- a/src/src/ControllerQueue/queue_element_formatted_uservar.h +++ b/src/src/ControllerQueue/queue_element_formatted_uservar.h @@ -28,7 +28,7 @@ class queue_element_formatted_uservar { bool isDuplicate(const queue_element_formatted_uservar& other) const; - const MessageRouteInfo_t * getUnitMessageCount() const { + const MessageRouteInfo_t * getMessageRouteInfo() const { return nullptr; } diff --git a/src/src/ControllerQueue/queue_element_single_value_base.h b/src/src/ControllerQueue/queue_element_single_value_base.h index 313ae83fc1..f8b39d586d 100644 --- a/src/src/ControllerQueue/queue_element_single_value_base.h +++ b/src/src/ControllerQueue/queue_element_single_value_base.h @@ -35,7 +35,7 @@ class queue_element_single_value_base { bool isDuplicate(const queue_element_single_value_base& other) const; - const MessageRouteInfo_t * getUnitMessageCount() const { + const MessageRouteInfo_t * getMessageRouteInfo() const { return nullptr; } diff --git a/src/src/DataStructs/MessageRouteInfo.cpp b/src/src/DataStructs/MessageRouteInfo.cpp index c686c9ec0d..2457a504a0 100644 --- a/src/src/DataStructs/MessageRouteInfo.cpp +++ b/src/src/DataStructs/MessageRouteInfo.cpp @@ -6,7 +6,16 @@ MessageRouteInfo_t::MessageRouteInfo_t(const uint8_t* serializedData, size_t siz } MessageRouteInfo_t::MessageRouteInfo_t(const uint8_t_vector& serializedData) { - deserialize(&(serializedData[0]), serializedData.size()); + if (serializedData.size() > 0) { + deserialize(&(serializedData[0]), serializedData.size()); + } +} + +bool MessageRouteInfo_t::deserialize(const uint8_t_vector& serializedData) { + if (serializedData.size() > 0) { + return deserialize(&(serializedData[0]), serializedData.size()); + } + return false; } bool MessageRouteInfo_t::deserialize(const uint8_t* serializedData, size_t size) { @@ -29,7 +38,7 @@ bool MessageRouteInfo_t::deserialize(const uint8_t* serializedData, size_t size) MessageRouteInfo_t::uint8_t_vector MessageRouteInfo_t::serialize() const { uint8_t_vector res; - res.resize(4 + trace.size()); + res.resize(getSerializedSize()); size_t index = 0; res[index++] = unit; @@ -42,6 +51,28 @@ MessageRouteInfo_t::uint8_t_vector MessageRouteInfo_t::serialize() const { return res; } +size_t MessageRouteInfo_t::getSerializedSize() const { + return 4 + trace.size(); +} + +bool MessageRouteInfo_t::appendUnit(uint8_t unitnr) { + if (unitnr == 0 || unitnr == 255 || traceHasUnit(unitnr)) { + return false; + } + trace.push_back(unitnr); +} + +bool MessageRouteInfo_t::traceHasUnit(uint8_t unitnr) const { + if (unitnr == 0 || unitnr == 255) { + return false; + } + for (auto it = trace.begin(); it != trace.end(); ++it) { + if (*it == unitnr) return true; + } + return false; +} + + bool UnitMessageRouteInfo_map::isNew(const MessageRouteInfo_t *info) const { if (info == nullptr) { return true; } auto it = _map.find(info->unit); diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h index 1993b3bd50..f5403b1f54 100644 --- a/src/src/DataStructs/MessageRouteInfo.h +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -20,10 +20,17 @@ struct MessageRouteInfo_t { MessageRouteInfo_t(const uint8_t_vector& serializedData); + bool deserialize(const uint8_t_vector& serializedData); bool deserialize(const uint8_t* serializedData, size_t size); uint8_t_vector serialize() const; + size_t getSerializedSize() const; + + bool appendUnit(uint8_t unitnr); + + bool traceHasUnit(uint8_t unitnr) const; + uint8_t unit = 0; // Initialize to "not set" uint8_t count = 0; uint8_t dest_unit = 0; // Initialize to "not set" diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index fc58b6d089..579edc4d43 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -519,7 +519,7 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& unitMessageCount, bool retained) +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& messageRouteInfo, bool retained) { bool success = false; if (!MQTT_queueFull(controller_idx)) @@ -529,18 +529,27 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes size_t pos = 0; element.controller_idx = controller_idx; element._retained = retained; - element.MessageRouteInfo = unitMessageCount; + element.MessageRouteInfo = messageRouteInfo; const size_t payloadSize = message.getPayloadSize(); if (message.getString(element._topic, pos) && message.getString(element._payload, pos)) { success = true; const size_t bytesLeft = payloadSize - pos; - if (bytesLeft >= 2) { + if (bytesLeft >= 4) { + bool validMessageRouteInfo = false; // There is some MessageRouteInfo left - if (!(message.getBinaryData(&element.MessageRouteInfo.unit, 1, pos) == 1 && - message.getBinaryData(&element.MessageRouteInfo.count, 1, pos) == 1)) - { + MessageRouteInfo_t::uint8_t_vector routeInfoData; + routeInfoData.resize(bytesLeft); + // Use temp position as we don't yet know the true size of the message route info + size_t tmp_pos = pos; + if (message.getBinaryData(&routeInfoData[0], bytesLeft, tmp_pos) == bytesLeft) { + validMessageRouteInfo = element.MessageRouteInfo.deserialize(routeInfoData); + if (validMessageRouteInfo) { + pos += element.MessageRouteInfo.getSerializedSize(); + } + } + if (!validMessageRouteInfo) { // Whatever may have been present, it could not be loaded, so clear just to be sure. - element.MessageRouteInfo = unitMessageCount; + element.MessageRouteInfo = messageRouteInfo; } } } diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 05642997db..908ccbd415 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -72,7 +72,7 @@ void SendStatus(struct EventStruct *event, const String& status); bool MQTT_queueFull(controllerIndex_t controller_idx); #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& unitMessageCount, bool retained); +bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& messageRouteInfo, bool retained); #endif bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 93c6f06607..0874aa3521 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -969,7 +969,7 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // * MQTT controller forwarder // ************************************************************* -bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const MessageRouteInfo_t* unitMessageCount) +bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const MessageRouteInfo_t* messageRouteInfo) { if (!use_EspEasy_now) { return false; } @@ -990,7 +990,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { // Must make sure we don't forward it to the unit we received the message from. - const uint8_t unit_nr = (unitMessageCount == nullptr) ? 0 : unitMessageCount->unit; + const uint8_t unit_nr = (messageRouteInfo == nullptr) ? 0 : messageRouteInfo->unit; const NodeStruct *preferred = Nodes.getPreferredNode_notMatching(unit_nr); if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { @@ -1008,9 +1008,17 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const // each string has null termination const size_t topic_length = topic.length() + 1; const size_t payload_length = payload.length() + 1; + size_t routeInfo_length = 0; + + MessageRouteInfo_t::uint8_t_vector routeInfo; + // FIXME TD-er: Must check if the intended recipient supports routeInfo + if (messageRouteInfo != nullptr) { + routeInfo = messageRouteInfo->serialize(); + routeInfo_length = routeInfo.size(); + } // Todo: Add cpluginID_t cpluginID; to the message - size_t len = topic_length + payload_length; + size_t len = topic_length + payload_length + routeInfo_length; ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTControllerMessage, len); @@ -1020,6 +1028,9 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (payload_length != msg.addString(payload)) { return false; } + if (routeInfo_length != 0 && routeInfo_length != msg.addBinaryData(&(routeInfo[0]), routeInfo_length)) { + return false; + } WifiEspNowSendStatus sendStatus = msg.send(mac, _ClientTimeout, preferred->channel); diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 0839f20ab2..c4fbdf95be 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -72,7 +72,7 @@ class ESPEasy_now_handler_t { bool sendToMQTT(controllerIndex_t controllerIndex, const String & topic, const String & payload, - const MessageRouteInfo_t* unitMessageCount); + const MessageRouteInfo_t* messageRouteInfo); bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); bool sendMQTTCheckControllerQueue(const MAC_address& mac, diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 30c7cb1929..d4747e07fe 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -350,11 +350,11 @@ void processMQTTdelayQueue() { message += ';'; message += element->_payload; - processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, element->getUnitMessageCount()); + processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, element->getMessageRouteInfo()); } else #endif { - processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, element->getUnitMessageCount()); + processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, element->getMessageRouteInfo()); } @@ -381,13 +381,13 @@ bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, bool retained, - const MessageRouteInfo_t* unitMessageCount) + const MessageRouteInfo_t* messageRouteInfo) { bool processed = false; #ifdef USES_ESPEASY_NOW if (!MQTTclient_connected) { - processed = ESPEasy_now_handler.sendToMQTT(controllerIndex, topic, payload, unitMessageCount); + processed = ESPEasy_now_handler.sendToMQTT(controllerIndex, topic, payload, messageRouteInfo); } #endif diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 3c26e2e18a..e63352b558 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -41,7 +41,7 @@ bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, bool retained, - const MessageRouteInfo_t* unitMessageCount); + const MessageRouteInfo_t* messageRouteInfo); void updateMQTTclient_connected(); From 7b57762f90cbbdb527bff36dc1ffc73ee848c448 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Jul 2021 14:41:38 +0200 Subject: [PATCH 191/404] [ESPEasy-NOW] Reduce node success rate when loop is detected --- src/src/DataStructs/ESPEasy_now_splitter.cpp | 2 +- .../DataStructs/ESPEasy_now_traceroute.cpp | 4 +- src/src/DataStructs/MessageRouteInfo.cpp | 52 +++++++++-- src/src/DataStructs/MessageRouteInfo.h | 19 ++++ src/src/DataTypes/SettingsType.cpp | 3 +- src/src/ESPEasyCore/Controller.cpp | 3 + src/src/Helpers/ESPEasy_now_handler.cpp | 10 ++- src/src/Helpers/PeriodicalActions.cpp | 8 ++ src/src/WebServer/ControllerPage.cpp | 86 ++++++++++--------- 9 files changed, 133 insertions(+), 54 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 7aca296c3b..830fe894c9 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -20,7 +20,7 @@ ESPEasy_now_splitter::ESPEasy_now_splitter(ESPEasy_now_hdr::message_t message_ty size_t ESPEasy_now_splitter::addBinaryData(const uint8_t *data, size_t length) { - if (data == nullptr) { + if (data == nullptr || length == 0) { return 0; } size_t data_left = length; diff --git a/src/src/DataStructs/ESPEasy_now_traceroute.cpp b/src/src/DataStructs/ESPEasy_now_traceroute.cpp index fffc9dfe67..8c803b3295 100644 --- a/src/src/DataStructs/ESPEasy_now_traceroute.cpp +++ b/src/src/DataStructs/ESPEasy_now_traceroute.cpp @@ -24,7 +24,7 @@ uint8_t ESPEasy_now_traceroute_struct::getUnit(uint8_t distance, uint8_t& succes void ESPEasy_now_traceroute_struct::addUnit(uint8_t unit) { // Only add the unit if it isn't already part of the traceroute. - const uint8_t index = static_cast(unit_vector.size()); + const size_t index = unit_vector.size(); for (size_t i = 0; i < index; i+=2) { if (unit_vector[i] == unit) { return; @@ -45,7 +45,7 @@ uint8_t ESPEasy_now_traceroute_struct::getDistance() const const uint8_t * ESPEasy_now_traceroute_struct::getData(uint8_t& size) const { - size = static_cast(unit_vector.size()); + size = static_cast(std::min(unit_vector.size(), 255u)); return &(unit_vector[0]); } diff --git a/src/src/DataStructs/MessageRouteInfo.cpp b/src/src/DataStructs/MessageRouteInfo.cpp index 2457a504a0..2941310bef 100644 --- a/src/src/DataStructs/MessageRouteInfo.cpp +++ b/src/src/DataStructs/MessageRouteInfo.cpp @@ -44,7 +44,7 @@ MessageRouteInfo_t::uint8_t_vector MessageRouteInfo_t::serialize() const { res[index++] = unit; res[index++] = count; res[index++] = dest_unit; - res[index++] = trace.size(); + res[index++] = static_cast(std::min(trace.size(), 255u)); for (size_t i = 0; i < trace.size(); ++i) { res[index++] = trace[i]; } @@ -56,20 +56,60 @@ size_t MessageRouteInfo_t::getSerializedSize() const { } bool MessageRouteInfo_t::appendUnit(uint8_t unitnr) { - if (unitnr == 0 || unitnr == 255 || traceHasUnit(unitnr)) { + if (unitnr == 0 || unitnr == 255) { return false; } - trace.push_back(unitnr); + if (unit == 0) { + unit = unitnr; + } else { + trace.push_back(unitnr); + } + return true; } bool MessageRouteInfo_t::traceHasUnit(uint8_t unitnr) const { + return countUnitInTrace(unitnr) != 0; +} + +size_t MessageRouteInfo_t::countUnitInTrace(uint8_t unitnr) const { + size_t res = 0; if (unitnr == 0 || unitnr == 255) { - return false; + return res; } for (auto it = trace.begin(); it != trace.end(); ++it) { - if (*it == unitnr) return true; + if (*it == unitnr) { + ++res; + } } - return false; + if (unitnr == unit) { + ++res; + } + return res; +} + +uint8_t MessageRouteInfo_t::getLastUnitNotMatching(uint8_t unitnr) const { + for (auto it = trace.rbegin(); it != trace.rend(); ++it) { + if (*it != unitnr) { + return *it; + } + } + // Try the source unit + if (unitnr != unit) return unit; + return 0; +} + +String MessageRouteInfo_t::toString() const { + String res; + res = F("src: "); + res += unit; + res += F(" dst: "); + res += dest_unit; + res += F(" path:"); + for (auto it = trace.begin(); it != trace.end(); ++it) { + res += ' '; + res += *it; + } + return res; } diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h index f5403b1f54..e440bb74bd 100644 --- a/src/src/DataStructs/MessageRouteInfo.h +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -20,6 +20,11 @@ struct MessageRouteInfo_t { MessageRouteInfo_t(const uint8_t_vector& serializedData); + MessageRouteInfo_t(const MessageRouteInfo_t& other) = default; + MessageRouteInfo_t(MessageRouteInfo_t&& other) = default; + MessageRouteInfo_t& operator=(const MessageRouteInfo_t& other) = default; + MessageRouteInfo_t& operator=(MessageRouteInfo_t&& other) = default; + bool deserialize(const uint8_t_vector& serializedData); bool deserialize(const uint8_t* serializedData, size_t size); @@ -31,10 +36,24 @@ struct MessageRouteInfo_t { bool traceHasUnit(uint8_t unitnr) const; + size_t countUnitInTrace(uint8_t unitnr) const; + + uint8_t getLastUnitNotMatching(uint8_t unitnr) const; + + String toString() const; + + // Source unit uint8_t unit = 0; // Initialize to "not set" + + // Message counter of the source unit, used to check for duplicates. uint8_t count = 0; + + // Destination unit (not yet used) + // Can be useful for sending messages to other units in the mesh uint8_t dest_unit = 0; // Initialize to "not set" + // List of all unit numbers that may have forwarded the message. + // Used to detect loops uint8_t_vector trace; }; diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index 4da7efd842..eba3da7d76 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -218,7 +218,8 @@ String SettingsType::getSettingsFileName(SettingsType::SettingsFileEnum file_typ size_t SettingsType::getInitFileSize(SettingsType::SettingsFileEnum file_type) { switch (file_type) { case SettingsFileEnum::FILE_CONFIG_type: return CONFIG_FILE_SIZE; - case SettingsFileEnum::FILE_NOTIFICATION_type: return 4096; + case SettingsFileEnum::FILE_NOTIFICATION_type: + // fall through case SettingsFileEnum::FILE_SECURITY_type: return 4096; case SettingsFileEnum::FILE_UNKNOWN_type: break; } diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 579edc4d43..97e6bad723 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -544,6 +544,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes if (message.getBinaryData(&routeInfoData[0], bytesLeft, tmp_pos) == bytesLeft) { validMessageRouteInfo = element.MessageRouteInfo.deserialize(routeInfoData); if (validMessageRouteInfo) { + // Move pos for the actual number of bytes we read. pos += element.MessageRouteInfo.getSerializedSize(); } } @@ -551,6 +552,8 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes // Whatever may have been present, it could not be loaded, so clear just to be sure. element.MessageRouteInfo = messageRouteInfo; } + // Append our own unit number + element.MessageRouteInfo.appendUnit(Settings.Unit); } } if (success) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 0874aa3521..c3d03490f1 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -990,10 +990,14 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const if (_enableESPEasyNowFallback /*&& !WiFiConnected(10) */) { // Must make sure we don't forward it to the unit we received the message from. - const uint8_t unit_nr = (messageRouteInfo == nullptr) ? 0 : messageRouteInfo->unit; + const uint8_t unit_nr = (messageRouteInfo == nullptr) ? 0 : messageRouteInfo->getLastUnitNotMatching(Settings.Unit); const NodeStruct *preferred = Nodes.getPreferredNode_notMatching(unit_nr); if (preferred != nullptr /* && Nodes.getDistance() > preferred->distance */) { + if ((messageRouteInfo != nullptr) && messageRouteInfo->countUnitInTrace(preferred->unit) > 2) { + // Preferred node appears in trace quite often, reduce success rate of this node. + Nodes.updateSuccessRate(preferred->unit, false); + } MAC_address mac = preferred->ESPEasy_Now_MAC(); switch (Nodes.getMQTTQueueState(preferred->unit)) { case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: @@ -1011,8 +1015,8 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const size_t routeInfo_length = 0; MessageRouteInfo_t::uint8_t_vector routeInfo; - // FIXME TD-er: Must check if the intended recipient supports routeInfo - if (messageRouteInfo != nullptr) { + // Check if the intended recipient supports routeInfo + if (messageRouteInfo != nullptr && preferred->build > 20113) { routeInfo = messageRouteInfo->serialize(); routeInfo_length = routeInfo.size(); } diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index d4747e07fe..72d8f42c9c 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -393,9 +393,17 @@ bool processMQTT_message(controllerIndex_t controllerIndex, if (!processed) { if (MQTTclient.publish(topic.c_str(), payload.c_str(), retained)) { + // FIXME TD-er: Must check if connected via WiFi or Ethernet if (WiFiEventData.connectionFailures > 0) { --WiFiEventData.connectionFailures; } +//#ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG) && messageRouteInfo != nullptr) { + String log = F("MQTT : published from mesh: "); + log += messageRouteInfo->toString(); + addLog(LOG_LEVEL_DEBUG, log); + } +//#endif // ifndef BUILD_NO_DEBUG processed = true; } } diff --git a/src/src/WebServer/ControllerPage.cpp b/src/src/WebServer/ControllerPage.cpp index f21170684b..20b21754a3 100644 --- a/src/src/WebServer/ControllerPage.cpp +++ b/src/src/WebServer/ControllerPage.cpp @@ -3,41 +3,40 @@ #ifdef WEBSERVER_CONTROLLERS -#include "../WebServer/WebServer.h" -#include "../WebServer/HTML_wrappers.h" -#include "../WebServer/Markup.h" -#include "../WebServer/Markup_Buttons.h" -#include "../WebServer/Markup_Forms.h" +# include "../WebServer/WebServer.h" +# include "../WebServer/HTML_wrappers.h" +# include "../WebServer/Markup.h" +# include "../WebServer/Markup_Buttons.h" +# include "../WebServer/Markup_Forms.h" -#include "../DataStructs/ESPEasy_EventStruct.h" +# include "../DataStructs/ESPEasy_EventStruct.h" -#include "../ESPEasyCore/Controller.h" +# include "../ESPEasyCore/Controller.h" -#include "../Globals/CPlugins.h" -#include "../Globals/Protocol.h" -#include "../Globals/Settings.h" - -#include "../Helpers/_CPlugin_Helper_webform.h" -#include "../Helpers/_Plugin_SensorTypeHelper.h" -#include "../Helpers/ESPEasy_Storage.h" -#include "../Helpers/StringConverter.h" +# include "../Globals/CPlugins.h" +# include "../Globals/Protocol.h" +# include "../Globals/Settings.h" +# include "../Helpers/_CPlugin_Helper_webform.h" +# include "../Helpers/_Plugin_SensorTypeHelper.h" +# include "../Helpers/ESPEasy_Storage.h" +# include "../Helpers/StringConverter.h" // ******************************************************************************** // Web Interface controller page // ******************************************************************************** void handle_controllers() { - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_controllers")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER if (!isLoggedIn()) { return; } navMenuIndex = MENU_INDEX_CONTROLLERS; TXBuffer.startStream(); sendHeadandTail_stdtemplate(_HEAD); - uint8_t controllerindex = getFormItemInt(F("index"), 0); + uint8_t controllerindex = getFormItemInt(F("index"), 0); boolean controllerNotSet = controllerindex == 0; --controllerindex; // Index in URL is starting from 1, but starting from 0 in the array. @@ -46,11 +45,12 @@ void handle_controllers() { // submitted data if ((protocol != -1) && !controllerNotSet) { - bool mustInit = false; + bool mustInit = false; bool mustCallCpluginSave = false; { // Place in a scope to free ControllerSettings memory ASAP MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addHtmlError(F("Not enough free memory to save settings")); } else { @@ -81,10 +81,11 @@ void handle_controllers() { addHtmlError(SaveControllerSettings(controllerindex, ControllerSettings)); } } + if (mustCallCpluginSave) { // Call CPLUGIN_WEBFORM_SAVE after destructing ControllerSettings object to reduce RAM usage. // Controller plugin almost only deals with custom controller settings. - // Even if they need to save things to the ControllerSettings, then the changes must + // Even if they need to save things to the ControllerSettings, then the changes must // already be saved first as the CPluginCall does not have the ControllerSettings as argument. handle_controllers_CopySubmittedSettings_CPluginCall(controllerindex); } @@ -98,7 +99,8 @@ void handle_controllers() { struct EventStruct TempEvent; TempEvent.ControllerIndex = controllerindex; String dummy; - CPlugin::Function cfunction = Settings.ControllerEnabled[controllerindex] ? CPlugin::Function::CPLUGIN_INIT : CPlugin::Function::CPLUGIN_EXIT; + CPlugin::Function cfunction = + Settings.ControllerEnabled[controllerindex] ? CPlugin::Function::CPLUGIN_INIT : CPlugin::Function::CPLUGIN_EXIT; CPluginCall(ProtocolIndex, cfunction, &TempEvent, dummy); } } @@ -199,6 +201,7 @@ void handle_controllers_ShowAllControllersTable() html_table_header(F("Port")); MakeControllerSettings(ControllerSettings); + if (AllocatedControllerSettings()) { for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { @@ -276,6 +279,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addFormHeader(F("Controller Settings")); addRowLabel(F("Protocol")); uint8_t choice = Settings.Protocol[controllerindex]; + addSelector_Head_reloadOnChange(F("protocol")); addSelector_Item(F("- Standalone -"), 0, false, false, EMPTY_STRING); @@ -294,9 +298,10 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex const protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); if (Settings.Protocol[controllerindex]) - { + { { MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addHtmlError(F("Out of memory, cannot load page")); } else { @@ -317,20 +322,14 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex } } addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PORT); - #ifdef USES_ESPEASY_NOW - if (Protocol[ProtocolIndex].usesMQTT) { - // FIXME TD-er: Currently only enabled for MQTT protocols, later for more - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK); - } - #endif - - if (Protocol[ProtocolIndex].usesQueue) { - addTableSeparator(F("Controller Queue"), 2, 3); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MIN_SEND_INTERVAL); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); - } + # ifdef USES_ESPEASY_NOW + + if (Protocol[ProtocolIndex].usesMQTT) { + // FIXME TD-er: Currently only enabled for MQTT protocols, later for more + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK); + } + # endif // ifdef USES_ESPEASY_NOW + if (Protocol[ProtocolIndex].usesQueue) { addTableSeparator(F("Controller Queue"), 2, 3); @@ -338,6 +337,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); + if (Protocol[ProtocolIndex].allowsExpire) { addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ALLOW_EXPIRE); } @@ -373,18 +373,19 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex { addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PASS); } - #ifdef USES_MQTT + # ifdef USES_MQTT + if (Protocol[ProtocolIndex].usesMQTT) { addTableSeparator(F("MQTT"), 2, 3); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLIENT_ID); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT); addRowLabel(F("Current Client ID")); addHtml(getMQTTclientID(ControllerSettings)); addFormNote(F("Updated on load of this page")); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_RETAINFLAG); } - #endif // USES_MQTT + # endif // USES_MQTT if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT) @@ -392,7 +393,8 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SUBSCRIBE); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PUBLISH); } - #ifdef USES_MQTT + # ifdef USES_MQTT + if (Protocol[ProtocolIndex].usesMQTT) { addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_TOPIC); @@ -402,9 +404,10 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_WILL_RETAIN); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLEAN_SESSION); } - #endif // USES_MQTT + # endif // USES_MQTT } } + // End of scope for ControllerSettings, destruct it to save memory. } { @@ -419,6 +422,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addHtmlError(F("Bug in CPlugin::Function::CPLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead")); } } + // Separate enabled checkbox as it doesn't need to use the ControllerSettings. // So ControllerSettings object can be destructed before controller specific settings are loaded. addControllerEnabledForm(controllerindex); From 5e6f2d3410e11f5e8c5b7dd1a2cf4c7ce4107922 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 10 Jul 2021 23:19:30 +0200 Subject: [PATCH 192/404] [ESP32 core 2.1.0] Later cores do NOT work with ESP-now --- platformio_esp32_envs.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 5388dd7c43..74d9d93bf0 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -9,7 +9,7 @@ lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266H [esp32_common] -extends = common, core_esp32_3_3_0 +extends = common, core_esp32_2_1_0 lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, WifiEspNow lib_ignore = ${esp32_always.lib_ignore}, ESP32_ping, IRremoteESP8266, HeatpumpIR board_build.f_flash = 80000000L From e8358b999ff3938ca3892127fca7ed87fdab8f83 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 10 Jul 2021 23:20:21 +0200 Subject: [PATCH 193/404] [ESPEasy-NOW] Find out why MQTT messages are not sent to broker Still debugging.... --- src/src/DataStructs/MessageRouteInfo.cpp | 8 ++++++++ src/src/ESPEasyCore/Controller.cpp | 7 +++++++ src/src/Helpers/PeriodicalActions.cpp | 11 ++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/src/DataStructs/MessageRouteInfo.cpp b/src/src/DataStructs/MessageRouteInfo.cpp index 2941310bef..b253fb2638 100644 --- a/src/src/DataStructs/MessageRouteInfo.cpp +++ b/src/src/DataStructs/MessageRouteInfo.cpp @@ -62,6 +62,14 @@ bool MessageRouteInfo_t::appendUnit(uint8_t unitnr) { if (unit == 0) { unit = unitnr; } else { + // First check we're not adding the same unitnr twice. + auto it = trace.rbegin(); + if (it != trace.rend()) { + if (*it == unitnr) { + return true; + } + } + trace.push_back(unitnr); } return true; diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 97e6bad723..1d4df52824 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -547,6 +547,13 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes // Move pos for the actual number of bytes we read. pos += element.MessageRouteInfo.getSerializedSize(); } + { + String log = F("MQTT : MQTTpublish MessageRouteInfo: "); + log += element.MessageRouteInfo.toString(); + log += F(" bytesLeft: "); + log += bytesLeft; + addLog(LOG_LEVEL_INFO, log); + } } if (!validMessageRouteInfo) { // Whatever may have been present, it could not be loaded, so clear just to be sure. diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 72d8f42c9c..7a954fd6ad 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -310,10 +310,10 @@ void processMQTTdelayQueue() { return; } + runPeriodicalMQTT(); // Update MQTT connected state. #ifndef USES_ESPEASY_NOW // When using ESPEasy_NOW we may still send MQTT messages even when we're not connected. // For all other situations no need to continue. - runPeriodicalMQTT(); // Update MQTT connected state. if (!MQTTclient_connected) { scheduleNextMQTTdelayQueue(); return; @@ -338,6 +338,11 @@ void processMQTTdelayQueue() { #endif bool processed = false; + MessageRouteInfo_t messageRouteInfo; + if (element->getMessageRouteInfo() != nullptr) { + messageRouteInfo = *(element->getMessageRouteInfo()); + } + messageRouteInfo.appendUnit(Settings.Unit); #ifdef USES_ESPEASY_NOW if (element->_topic.startsWith(F("traceroute/")) || element->_topic.indexOf(F("/traceroute/")) != -1) { @@ -350,11 +355,11 @@ void processMQTTdelayQueue() { message += ';'; message += element->_payload; - processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, element->getMessageRouteInfo()); + processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, &messageRouteInfo); } else #endif { - processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, element->getMessageRouteInfo()); + processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, &messageRouteInfo); } From a5589f170740359700eae85b78a3001f126f3528 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 11 Jul 2021 23:28:48 +0200 Subject: [PATCH 194/404] [WiFi] Fix scan issue, causing failed connections --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index c59efc0079..30c4009e24 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -908,6 +908,7 @@ void WifiScan(bool async, uint8_t channel) { } --nrScans; #ifdef ESP8266 + /* { static bool FIRST_SCAN = true; @@ -929,6 +930,7 @@ void WifiScan(bool async, uint8_t channel) { wifi_station_scan(&config, &onWiFiScanDone); } + */ WiFi.scanNetworks(async, show_hidden, channel); #endif #ifdef ESP32 From 284cd5bca904c757ca13b7c5d3350285da44d8da Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 08:03:19 +0200 Subject: [PATCH 195/404] [ESPEasy-NOW] disable loop detection for now (mqtt forward unreliable) --- src/src/Helpers/ESPEasy_now_handler.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index c3d03490f1..d3c3df5f55 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -969,7 +969,11 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // * MQTT controller forwarder // ************************************************************* -bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const String& topic, const String& payload, const MessageRouteInfo_t* messageRouteInfo) +bool ESPEasy_now_handler_t::sendToMQTT( + controllerIndex_t controllerIndex, + const String& topic, + const String& payload, + const MessageRouteInfo_t* messageRouteInfo) { if (!use_EspEasy_now) { return false; } @@ -1017,8 +1021,9 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const MessageRouteInfo_t::uint8_t_vector routeInfo; // Check if the intended recipient supports routeInfo if (messageRouteInfo != nullptr && preferred->build > 20113) { - routeInfo = messageRouteInfo->serialize(); - routeInfo_length = routeInfo.size(); + // FIXME TD-er: Disabled for now as forwarding messages does not work well right now +// routeInfo = messageRouteInfo->serialize(); +// routeInfo_length = routeInfo.size(); } // Todo: Add cpluginID_t cpluginID; to the message @@ -1033,7 +1038,7 @@ bool ESPEasy_now_handler_t::sendToMQTT(controllerIndex_t controllerIndex, const return false; } if (routeInfo_length != 0 && routeInfo_length != msg.addBinaryData(&(routeInfo[0]), routeInfo_length)) { - return false; +// return false; } WifiEspNowSendStatus sendStatus = msg.send(mac, _ClientTimeout, preferred->channel); From 56eb6da54e0951be4bd1ef22886cfa7e102e798f Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 11:41:07 +0200 Subject: [PATCH 196/404] [WiFi] Fix WiFi need to connect flag not always set --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 30c4009e24..0dc5e1e7fc 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -470,6 +470,7 @@ bool prepareWiFi() { #endif // if defined(ESP32) setConnectionSpeed(); setupStaticIPconfig(); + WiFiEventData.wifiConnectAttemptNeeded = true; return true; } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index ea68d2269a..66dc9e648e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -211,7 +211,7 @@ void handle_unprocessedNetworkEvents() // ******************************************************************************** void processDisconnect() { if (WiFiEventData.processingDisconnect.isSet()) { - if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000) { + if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000 || WiFiEventData.processedDisconnect) { WiFiEventData.processingDisconnect.clear(); } } From 4ffa1e7f3a5918b262664cfb3346e9ff68e5c59d Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 11:41:44 +0200 Subject: [PATCH 197/404] [NTP] Fix NTP not updating --- src/src/Helpers/ESPEasy_time.cpp | 12 ++++++++++-- src/src/Helpers/ESPEasy_time.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 8ddd03a0a2..487d4ec518 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -119,7 +119,7 @@ unsigned long ESPEasy_time::now() { // nextSyncTime & sysTime are in seconds double unixTime_d = -1.0; - if (externalUnixTime_d > 0.0f) { + if (externalUnixTime_d > 0.0) { unixTime_d = externalUnixTime_d; // Correct for the delay between the last received external time and applying it @@ -129,7 +129,7 @@ unsigned long ESPEasy_time::now() { // Try NTP if the time source is not external. bool updatedTime = (unixTime_d > 0.0); - if (!isExternalTimeSource(timeSource)) { + if (!isExternalTimeSource(timeSource) || timeSource_t::NTP_time_source == timeSource) { if (getNtpTime(unixTime_d)) { updatedTime = true; } @@ -233,6 +233,13 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) if (!Settings.UseNTP || !NetworkConnected(10)) { return false; } + if (lastNTPSyncTime != 0) { + if (timePassedSince(lastNTPSyncTime) < static_cast(1000 * syncInterval)) { + // Make sure not to flood the NTP servers with requests. + return false; + } + } + IPAddress timeServerIP; String log = F("NTP : NTP host "); @@ -392,6 +399,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) } udp.stop(); timeSource = timeSource_t::NTP_time_source; + lastNTPSyncTime = millis(); CheckRunningServices(); // FIXME TD-er: Sometimes services can only be started after NTP is successful return true; } diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 7fe4588593..83d5082559 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -181,6 +181,7 @@ String weekday_str() const; uint32_t prevMillis = 0; uint32_t nextSyncTime = 0; uint32_t lastSyncTime = 0; + uint32_t lastNTPSyncTime = 0; double externalUnixTime_d = -1.0; // Used to set time from a source other than NTP. struct tm tsRise, tsSet; struct tm sunRise; From 0d5262f1ca186dc087dd193f18d817e2a7f0f748 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 12:16:38 +0200 Subject: [PATCH 198/404] [WiFi] No need to disable interrupts when connecting WiFi As it is already done in the Arduino code calls --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 0dc5e1e7fc..c370eca53b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -406,17 +406,11 @@ void AttemptWiFiConnect() { SetWiFiTXpower(tx_pwr, candidate.rssi); // Start connect attempt now, so no longer needed to attempt new connection. WiFiEventData.wifiConnectAttemptNeeded = false; - #ifdef ESP8266 - ETS_UART_INTR_DISABLE(); - #endif if (candidate.allowQuickConnect()) { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str(), candidate.channel, candidate.bssid.mac); } else { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str()); } - #ifdef ESP8266 - ETS_UART_INTR_ENABLE(); - #endif } } else { if (!wifiAPmodeActivelyUsed() || WiFiEventData.wifiSetupConnect) { @@ -785,11 +779,11 @@ WiFiConnectionProtocol getConnectionProtocol() { // ******************************************************************************** void WifiDisconnect() { - #if defined(ESP32) + #ifdef ESP32 WiFi.disconnect(); WiFi.removeEvent(wm_event_id); - #else // if defined(ESP32) - + #endif + #ifdef ESP8266 // Only call disconnect when STA is active if (WifiIsSTA(WiFiMode())) { wifi_station_disconnect(); From fa2cdb8f2ca6675ff0ddd5eed321111bb2dd0b9b Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 14:35:33 +0200 Subject: [PATCH 199/404] [WiFi] Clear wifiConnectInProgress when prepare WiFi failed --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index c370eca53b..b493e74854 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -411,6 +411,8 @@ void AttemptWiFiConnect() { } else { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str()); } + } else { + WiFiEventData.wifiConnectInProgress = false; } } else { if (!wifiAPmodeActivelyUsed() || WiFiEventData.wifiSetupConnect) { From ac9d4a855287b005b384ea48507d7b1dcd435ca4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 21:59:11 +0200 Subject: [PATCH 200/404] [Security Settings] Add alignment checks at compile time. --- src/src/Helpers/ESPEasy_checks.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index bf35c32603..08b2e1ff26 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -119,8 +119,30 @@ void run_compiletime_checks() { #endif // Check for alignment issues at compile time - static_assert(256u == offsetof(SecurityStruct, ControllerUser), ""); - static_assert((256 + (CONTROLLER_MAX * 26)) == offsetof(SecurityStruct, ControllerPassword), ""); + { + const unsigned int ControllerUser_offset = 256u; + static_assert(ControllerUser_offset == offsetof(SecurityStruct, ControllerUser), ""); + + const unsigned int ControllerPassword_offset = 256u + (CONTROLLER_MAX * 26); + static_assert(ControllerPassword_offset == offsetof(SecurityStruct, ControllerPassword), ""); + + const unsigned int Password_offset = ControllerPassword_offset + (CONTROLLER_MAX * 64); + static_assert(Password_offset == offsetof(SecurityStruct, Password), ""); + + const unsigned int AllowedIPrangeLow_offset = Password_offset + 26; + static_assert(AllowedIPrangeLow_offset == offsetof(SecurityStruct, AllowedIPrangeLow), ""); + + const unsigned int IPblockLevel_offset = AllowedIPrangeLow_offset + 8; + static_assert(IPblockLevel_offset == offsetof(SecurityStruct, IPblockLevel), ""); + + const unsigned int ProgmemMd5_offset = IPblockLevel_offset + 1; + static_assert(ProgmemMd5_offset == offsetof(SecurityStruct, ProgmemMd5), ""); + + const unsigned int md5_offset = ProgmemMd5_offset + 16; + static_assert(md5_offset == offsetof(SecurityStruct, md5), ""); + } + + static_assert(192u == offsetof(SettingsStruct, Protocol), ""); static_assert(195u == offsetof(SettingsStruct, Notification), "CONTROLLER_MAX has changed?"); static_assert(198u == offsetof(SettingsStruct, TaskDeviceNumber), "NOTIFICATION_MAX has changed?"); From 73b10d84650a5fe7ad655f03a65911414815bef4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 12 Jul 2021 21:59:58 +0200 Subject: [PATCH 201/404] [WiFi] Try to connect right after WiFi scan found known APs --- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 66dc9e648e..a7392835c3 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -99,6 +99,14 @@ void handle_unprocessedNetworkEvents() if (active_network_medium == NetworkMedium_t::WIFI || active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents()) { if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { + if (WiFiEventData.wifiConnectInProgress) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() > 20000) { + WiFiEventData.last_wifi_connect_attempt_moment.clear(); + } + if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { + WiFiEventData.wifiConnectInProgress = false; + } + } delay(10); } @@ -561,6 +569,10 @@ void processScanDone() { } WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); + + if (WiFi_AP_Candidates.addedKnownCandidate()) { + NetworkConnectRelaxed(); + } #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { From e81f88b8b9c1fac5e1ebfa96ec6dc5ef76bb3e30 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 26 Jul 2021 14:56:17 +0200 Subject: [PATCH 202/404] [ESPEasy-NOW] Fix merge issues --- src/src/Helpers/ESPEasy_time.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 19408b0437..ecb3fb8d62 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -13,6 +13,12 @@ class ESPEasy_time { ESPEasy_time(); + struct tm addSeconds(const struct tm& ts, + int seconds, + bool toLocalTime) const; + static void breakTime(unsigned long timeInput, + struct tm & tm); + // Restore the last known system time // This may be useful to get some idea of what time it is. // This way the unit can do things based on local time even when NTP servers may not respond. From 27c1e3b05723e731e25708037fe78d356e18bb02 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 1 Aug 2021 14:50:15 +0200 Subject: [PATCH 203/404] [ESPEasy-now] Fix merge issues --- src/src/Commands/Tasks.cpp | 2 +- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 3 +++ src/src/Globals/Plugins.h | 3 --- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/src/Commands/Tasks.cpp b/src/src/Commands/Tasks.cpp index 85ee11c93a..39f8d460f4 100644 --- a/src/src/Commands/Tasks.cpp +++ b/src/src/Commands/Tasks.cpp @@ -74,7 +74,7 @@ bool taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& task String TmpStr1; unsigned int varNr; - if (!(validateAndParseTaskValueArguments(event, Line, taskIndex, varNr) && (getDevicePluginID_from_TaskIndex(taskIndex) == 33))) { return false; } // PluginID 33 = Dummy Device + if (!(validateAndParseTaskValueArguments(event, Line, taskIndex, varNr) && (getPluginID_from_TaskIndex(taskIndex) == 33))) { return false; } // PluginID 33 = Dummy Device unsigned int uservarIndex = (VARS_PER_TASK * taskIndex) + varNr; diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index fc20dcec00..ffca4b7361 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -48,9 +48,12 @@ unsigned long ESPEasy_Now_NTP_query::computeExpectedWander(timeSource_t timeSou } case timeSource_t::GPS_time_source: { + // Not sure about the wander here, as GPS does not have a drift. + // But the moment a message is received from a second's start may differ. expectedWander_ms += 10; break; } + case timeSource_t::External_RTC_time_source: case timeSource_t::NTP_time_source: { expectedWander_ms += 10; diff --git a/src/src/Globals/Plugins.h b/src/src/Globals/Plugins.h index bfb38c2dda..78163abc0d 100644 --- a/src/src/Globals/Plugins.h +++ b/src/src/Globals/Plugins.h @@ -77,9 +77,6 @@ deviceIndex_t getDeviceIndex_from_TaskIndex(taskIndex_t taskIndex); /********************************************************************************************* * get the taskPluginID with required checks, INVALID_PLUGIN_ID when invalid ********************************************************************************************/ -pluginID_t getDevicePluginID_from_TaskIndex(taskIndex_t taskIndex); - - pluginID_t getPluginID_from_TaskIndex(taskIndex_t taskIndex); From c92cffe2afb810e668ebf8e13b19d72cbf9105f5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 5 Aug 2021 00:51:17 +0200 Subject: [PATCH 204/404] [ESPEasy-NOW] Obey "Do Not Start AP" when using mesh --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index b493e74854..7ba4a2115f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1209,7 +1209,9 @@ void setWifiMode(WiFiMode_t wifimode) { if (WifiIsAP(cur_mode) != new_mode_AP_enabled) { // Mode has changed - setAPinternal(new_mode_AP_enabled); + if (!Settings.DoNotStartAP()) { + setAPinternal(new_mode_AP_enabled); + } } #ifdef FEATURE_MDNS #ifdef ESP8266 From bde8e097ff060c8066f0b290a0efa3bfcf1d70fe Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Aug 2021 08:35:35 +0200 Subject: [PATCH 205/404] [MAC Address] Add explicit copy constructor --- src/src/DataStructs/MAC_address.cpp | 8 ++++++++ src/src/DataStructs/MAC_address.h | 2 ++ src/src/Helpers/CRC_functions.cpp | 24 +++++++++++------------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/src/DataStructs/MAC_address.cpp b/src/src/DataStructs/MAC_address.cpp index 2588adcef0..f5f0bd019f 100644 --- a/src/src/DataStructs/MAC_address.cpp +++ b/src/src/DataStructs/MAC_address.cpp @@ -10,6 +10,14 @@ MAC_address::MAC_address(const uint8_t new_mac[6]) memcpy(mac, new_mac, 6); } +MAC_address& MAC_address::operator=(const MAC_address& other) +{ + for (int i = 0; i < 6; ++i) { + mac[i] = other.mac[i]; + } + return *this; +} + bool MAC_address::set(const char *string) { unsigned u[6]; diff --git a/src/src/DataStructs/MAC_address.h b/src/src/DataStructs/MAC_address.h index 0ac0d7bb33..47d5120aa5 100644 --- a/src/src/DataStructs/MAC_address.h +++ b/src/src/DataStructs/MAC_address.h @@ -11,6 +11,8 @@ class __attribute__((__packed__)) MAC_address { MAC_address(const uint8_t new_mac[6]); + MAC_address& operator=(const MAC_address& other); + bool operator==(const MAC_address& other) const { return mac_addr_cmp(other.mac); } diff --git a/src/src/Helpers/CRC_functions.cpp b/src/src/Helpers/CRC_functions.cpp index 47b38614a2..ee3b5b0fb2 100644 --- a/src/src/Helpers/CRC_functions.cpp +++ b/src/src/Helpers/CRC_functions.cpp @@ -11,6 +11,10 @@ int calc_CRC16(const char *ptr, int count) crc = 0; + if (ptr == nullptr) { + return crc; + } + while (--count >= 0) { crc = crc ^ static_cast(*ptr++) << 8; @@ -18,19 +22,13 @@ int calc_CRC16(const char *ptr, int count) do { - crc = crc ^ (int)*ptr++ << 8; - char i = 8; - - do - { - if (crc & 0x8000) { - crc = crc << 1 ^ 0x1021; - } - else { - crc = crc << 1; - } - } while(--i); - } + if (crc & 0x8000) { + crc = crc << 1 ^ 0x1021; + } + else { + crc = crc << 1; + } + } while(--i); } return crc; } From b164b81aa62bcc555efbb4cd978481536bd3a055 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Aug 2021 08:45:53 +0200 Subject: [PATCH 206/404] [WiFi] Don't allow WiFi key to be less than 8 characters --- src/src/DataStructs/WiFi_AP_Candidate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index 58879071d7..57b769a3a8 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -105,6 +105,7 @@ bool WiFi_AP_Candidate::usable() const { } } if (!isHidden && (ssid.isEmpty())) { return false; } + if (ssid.length() < 8) {return false; } return true; } From 4bef6a0ef0d53cf6a29e4369f0ab0bdf917a4c13 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Aug 2021 12:25:56 +0200 Subject: [PATCH 207/404] [WiFi] Try connect to hidden SSID without explicit BSSID + channel --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 7 +++-- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 33 ++++++++++++++++------ src/src/Helpers/WiFi_AP_CandidatesList.h | 2 ++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 7ba4a2115f..be861c55bd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -386,7 +386,7 @@ void AttemptWiFiConnect() { WiFiEventData.markWiFiTurnOn(); if (WiFi_AP_Candidates.getNext(WiFiScanAllowed())) { - const WiFi_AP_Candidate& candidate = WiFi_AP_Candidates.getCurrent(); + const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WIFI : Connecting "); @@ -406,7 +406,7 @@ void AttemptWiFiConnect() { SetWiFiTXpower(tx_pwr, candidate.rssi); // Start connect attempt now, so no longer needed to attempt new connection. WiFiEventData.wifiConnectAttemptNeeded = false; - if (candidate.allowQuickConnect()) { + if (candidate.allowQuickConnect() && !candidate.isHidden) { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str(), candidate.channel, candidate.bssid.mac); } else { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str()); @@ -477,7 +477,7 @@ bool checkAndResetWiFi() { switch(status) { case STATION_GOT_IP: - if (WiFi.RSSI() < 0 && NetworkLocalIP().isSet()) { + if (WiFi.RSSI() < 0 && WiFi.localIP().isSet()) { //if (WiFi.channel() == WiFiEventData.usedChannel || WiFiEventData.usedChannel == 0) { // This is a valid status, no need to reset if (!WiFiEventData.WiFiServicesInitialized()) { @@ -599,6 +599,7 @@ void SetWiFiTXpower(float dBm) { } void SetWiFiTXpower(float dBm, float rssi) { + return; const WiFiMode_t cur_mode = WiFi.getMode(); if (cur_mode == WIFI_OFF) { return; diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index f714deac14..9957087ac7 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -45,11 +45,12 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { while (!done) { if (get_SSID_key(index, ssid, key)) { known.emplace_back(index, ssid, key); - if (index == WIFI_CUSTOM_DEPLOYMENT_KEY_INDEX || - index == WIFI_CUSTOM_SUPPORT_KEY_INDEX) { - known.back().lowPriority = true; - } else if (index == WIFI_CREDENTIALS_FALLBACK_SSID_INDEX) { - known.back().isEmergencyFallback = true; + if (SettingsIndexMatchCustomCredentials(index)) { + if (SettingsIndexMatchEmergencyFallback(index)) { + known.back().isEmergencyFallback = true; + } else { + known.back().lowPriority = true; + } } ++index; } else { @@ -199,10 +200,18 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { } if (mustPop) { - known_it = known.begin(); - if (!candidates.empty()) { - candidates.pop_front(); + if (currentCandidate.isHidden) { + // We tried to connect to hidden SSIDs in 1 run, so pop all hidden candidates. + for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->isHidden; ) { + cand_it = candidates.erase(cand_it); + } + } else { + if (!candidates.empty()) { + candidates.pop_front(); + } } + + known_it = known.begin(); } return currentCandidate.usable(); } @@ -269,9 +278,15 @@ bool WiFi_AP_CandidatesList::SettingsIndexMatchCustomCredentials(uint8_t index) { return (WIFI_CUSTOM_DEPLOYMENT_KEY_INDEX == index || WIFI_CUSTOM_SUPPORT_KEY_INDEX == index || - WIFI_CREDENTIALS_FALLBACK_SSID_INDEX == index); + SettingsIndexMatchEmergencyFallback(index)); +} + +bool WiFi_AP_CandidatesList::SettingsIndexMatchEmergencyFallback(uint8_t index) +{ + return (WIFI_CREDENTIALS_FALLBACK_SSID_INDEX == index); } + void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { if (candidates.size() > 1) { // Do not mess with the current candidates order if > 1 present diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 0c40523f6b..c0b2ac7682 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -60,6 +60,8 @@ struct WiFi_AP_CandidatesList { static bool SettingsIndexMatchCustomCredentials(uint8_t index); + static bool SettingsIndexMatchEmergencyFallback(uint8_t index); + private: // Pick the possible From 7e5945225fbc6928dec8811ffc85c43cf5a6529f Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 2 Sep 2021 16:47:42 +0200 Subject: [PATCH 208/404] [ESP32 ETH] Fix not getting DNS from DHCP at boot The WiFi radio was started too soon, which probably let parts of the DHCP request be stored in the wrong network settings. --- src/src/ESPEasyCore/ESPEasyEth.cpp | 4 ++++ src/src/ESPEasyCore/ESPEasy_setup.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index fadaa408e0..f968c177f3 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -152,6 +152,10 @@ bool ETHConnected() { } return false; } else { + if (EthEventData.last_eth_connect_attempt_moment.isSet() && + EthEventData.last_eth_connect_attempt_moment.millisPassedSince() < 5000) { + return false; + } setNetworkMedium(NetworkMedium_t::WIFI); } } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 23bc437be5..36a87bc12a 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -235,7 +235,8 @@ void ESPEasy_setup() // This ensures, that changing WIFI OR ETHERNET MODE happens properly only after reboot. Changing without reboot would not be a good idea. // This only works after LoadSettings(); - setNetworkMedium(Settings.NetworkMedium); + // Do not call setNetworkMedium here as that may try to clean up settings. + active_network_medium = Settings.NetworkMedium; #endif // ifdef HAS_ETHERNET if (active_network_medium == NetworkMedium_t::WIFI) { From ffc9b42a978c85c0fcf606fcd2dd6e362e391e2a Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 2 Sep 2021 23:03:48 +0200 Subject: [PATCH 209/404] [ESP32] Switch to Arduino ESP32 v.2.0.0 --- lib/TinyGPSPlus-1.0.2/src/TinyGPS++.cpp | 2 ++ platformio_core_defs.ini | 7 ++++--- platformio_esp32_envs.ini | 5 ++--- src/src/DataStructs/ESPEasy_Now_packet.h | 1 + src/src/DataStructs/MessageRouteInfo.h | 1 + src/src/DataStructs/UserVarStruct.h | 2 ++ src/src/Helpers/ESPEasy_checks.cpp | 8 ++++++++ src/src/Helpers/ESPEasy_time.h | 1 + 8 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/TinyGPSPlus-1.0.2/src/TinyGPS++.cpp b/lib/TinyGPSPlus-1.0.2/src/TinyGPS++.cpp index 61d286f753..aae37b3009 100644 --- a/lib/TinyGPSPlus-1.0.2/src/TinyGPS++.cpp +++ b/lib/TinyGPSPlus-1.0.2/src/TinyGPS++.cpp @@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#include + TinyGPSPlus::TinyGPSPlus() : parity(0) , isChecksumTerm(false) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 89ddaccaba..f9e365b72f 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -147,9 +147,10 @@ platform = espressif32@1.12.4 platform = espressif32@2.1.0 build_flags = -[core_esp32_3_3_0] -platform = espressif32@3.3.0 -build_flags = +[core_esp32_3_3_2] +platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/424/framework-arduinoespressif32-master-cdcf92440.tar.gz +build_flags = -DESP32_STAGE [core_esp32_stage] diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index f1ae644d53..9966ff8d21 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -9,7 +9,7 @@ lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266H [esp32_common] -extends = common, core_esp32_2_1_0 +extends = common, core_esp32_3_3_2 lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.5, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, WifiEspNow lib_ignore = ${esp32_always.lib_ignore}, ESP32_ping, IRremoteESP8266, HeatpumpIR board_build.f_flash = 80000000L @@ -19,11 +19,10 @@ board_build.partitions = esp32_partition_app1810k_spiffs316k.csv extra_scripts = post:tools/pio/post_esp32.py ${extra_scripts_default.extra_scripts} build_unflags = -Wall -build_flags = ${core_esp32_stage.build_flags} +build_flags = ${core_esp32_3_3_2.build_flags} ${mqtt_flags.build_flags} -DCONFIG_FREERTOS_ASSERT_DISABLE -DCONFIG_LWIP_ESP_GRATUITOUS_ARP - -DCONFIG_LWIP_GARP_TMR_INTERVAL=30 -fno-strict-aliasing monitor_filters = esp32_exception_decoder diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index bb9d99f4f2..7b2b8daa5b 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -11,6 +11,7 @@ # include # include +# include class ESPEasy_Now_packet { public: diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h index e440bb74bd..5a19f6b083 100644 --- a/src/src/DataStructs/MessageRouteInfo.h +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -4,6 +4,7 @@ #include "../../ESPEasy_common.h" #include +#include // For deduplication, some controllers may add a unit ID and current counter. // This count will wrap around, so it is just to detect if a message is received multiple times. diff --git a/src/src/DataStructs/UserVarStruct.h b/src/src/DataStructs/UserVarStruct.h index e97cf5dc2d..2b3ee171bc 100644 --- a/src/src/DataStructs/UserVarStruct.h +++ b/src/src/DataStructs/UserVarStruct.h @@ -5,6 +5,8 @@ #include "../DataTypes/TaskIndex.h" +#include + struct UserVarStruct { UserVarStruct(); diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 08b2e1ff26..3650b86724 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -88,11 +88,19 @@ void run_compiletime_checks() { check_size(); #endif check_size(); + #ifdef ESP32_STAGE + check_size(); // Is not stored + #else check_size(); // Is not stored + #endif // LogStruct is mainly dependent on the number of lines. // Has to be round up to multiple of 4. + #ifdef ESP32_STAGE + const unsigned int LogStructSize = ((12u + 21 * LOG_STRUCT_MESSAGE_LINES) + 3) & ~3; + #else const unsigned int LogStructSize = ((12u + 17 * LOG_STRUCT_MESSAGE_LINES) + 3) & ~3; + #endif check_size(); // Is not stored check_size(); // Is not stored check_size(); diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 154eafbd89..5b0b4ab651 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -6,6 +6,7 @@ #include "../DataTypes/ESPEasyTimeSource.h" +#include class ESPEasy_time { From 13f94fd71e49441a82508855ac820706070dd6d4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 26 Sep 2021 02:30:31 +0200 Subject: [PATCH 210/404] [Build] Fix build error --- src/src/Helpers/ESPEasy_checks.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index c3fea7c5bd..9080cbcac7 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -110,13 +110,7 @@ void run_compiletime_checks() { check_size(); #endif - #if ESP_IDF_VERSION_MAJOR > 3 - // String class has increased with 4 bytes - check_size(); - #else check_size(); - #endif - check_size(); check_size(); From b6637241083f9351c4c14c7c5e2e7951542b8ae4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 28 Dec 2021 17:32:24 +0100 Subject: [PATCH 211/404] [ESP-NOW] zero esp_now_peer_info_t on IDF 4.4 builds --- lib/WifiEspNow/src/WifiEspNow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/WifiEspNow/src/WifiEspNow.cpp b/lib/WifiEspNow/src/WifiEspNow.cpp index 08628a5844..0e93474c93 100644 --- a/lib/WifiEspNow/src/WifiEspNow.cpp +++ b/lib/WifiEspNow/src/WifiEspNow.cpp @@ -52,7 +52,10 @@ WifiEspNowClass::listPeers(WifiEspNowPeerInfo* peers, int maxPeers) const mac = esp_now_fetch_peer(false)) { uint8_t channel = static_cast(esp_now_get_peer_channel(mac)); #elif defined(ESP32) + // For IDF 4.4 make sure to zero peer + // See: https://github.com/espressif/arduino-esp32/issues/6029 esp_now_peer_info_t peer; + memset(&peer, 0, sizeof(peer)); for (esp_err_t e = esp_now_fetch_peer(true, &peer); e == ESP_OK; e = esp_now_fetch_peer(false, &peer)) { @@ -97,7 +100,10 @@ bool WifiEspNowClass::addPeer(const uint8_t mac[6], int channel, const uint8_t key[WIFIESPNOW_KEYLEN], int netif) { if (!m_begin) return false; + // For IDF 4.4 make sure to zero peer + // See: https://github.com/espressif/arduino-esp32/issues/6029 esp_now_peer_info_t pi; + memset(&pi, 0, sizeof(pi)); if (esp_now_get_peer(mac, &pi) == ESP_OK) { if (pi.channel == static_cast(channel)) { return true; From a17ead770d2d62e4dc1575e5d2161dba24b87cc3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 22 Jan 2022 01:16:54 +0100 Subject: [PATCH 212/404] Fix include paths --- src/_C019.ino | 2 +- src/src/Globals/ESPEasy_now_state.cpp | 2 +- src/src/Globals/SendData_DuplicateChecker.cpp | 2 +- .../Helpers/{Controller => }/C019_ESPEasyNow_helper.cpp | 8 ++++---- src/src/Helpers/{Controller => }/C019_ESPEasyNow_helper.h | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename src/src/Helpers/{Controller => }/C019_ESPEasyNow_helper.cpp (85%) rename src/src/Helpers/{Controller => }/C019_ESPEasyNow_helper.h (86%) diff --git a/src/_C019.ino b/src/_C019.ino index 75fdffafcb..3a7b286431 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -8,7 +8,7 @@ #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" #include "src/Helpers/_CPlugin_Helper.h" -#include "src/Helpers/Controller/C019_ESPEasyNow_helper.h" +#include "src/Helpers/C019_ESPEasyNow_helper.h" #define CPLUGIN_019 diff --git a/src/src/Globals/ESPEasy_now_state.cpp b/src/src/Globals/ESPEasy_now_state.cpp index 74673eeb26..fbe7b9779c 100644 --- a/src/src/Globals/ESPEasy_now_state.cpp +++ b/src/src/Globals/ESPEasy_now_state.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_state.h" +#include "../Globals/ESPEasy_now_state.h" diff --git a/src/src/Globals/SendData_DuplicateChecker.cpp b/src/src/Globals/SendData_DuplicateChecker.cpp index 69ede6960c..acfc7298d9 100644 --- a/src/src/Globals/SendData_DuplicateChecker.cpp +++ b/src/src/Globals/SendData_DuplicateChecker.cpp @@ -1,3 +1,3 @@ -#include "SendData_DuplicateChecker.h" +#include "../Globals/SendData_DuplicateChecker.h" SendData_DuplicateChecker_struct SendData_DuplicateChecker; \ No newline at end of file diff --git a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp b/src/src/Helpers/C019_ESPEasyNow_helper.cpp similarity index 85% rename from src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp rename to src/src/Helpers/C019_ESPEasyNow_helper.cpp index c5e60b94a5..eb607cee49 100644 --- a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.cpp +++ b/src/src/Helpers/C019_ESPEasyNow_helper.cpp @@ -1,8 +1,8 @@ -#include "C019_ESPEasyNow_helper.h" +#include "../Helpers/C019_ESPEasyNow_helper.h" -#include "../../DataStructs/ESPEasy_EventStruct.h" -#include "../../ESPEasyCore/ESPEasy_Log.h" -#include "../../Globals/CPlugins.h" +#include "../DataStructs/ESPEasy_EventStruct.h" +#include "../ESPEasyCore/ESPEasy_Log.h" +#include "../Globals/CPlugins.h" bool C019_ESPEasyNow_helper::process_receive(struct EventStruct *event) { diff --git a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.h b/src/src/Helpers/C019_ESPEasyNow_helper.h similarity index 86% rename from src/src/Helpers/Controller/C019_ESPEasyNow_helper.h rename to src/src/Helpers/C019_ESPEasyNow_helper.h index 7a29b92ade..e4e468edd0 100644 --- a/src/src/Helpers/Controller/C019_ESPEasyNow_helper.h +++ b/src/src/Helpers/C019_ESPEasyNow_helper.h @@ -1,7 +1,7 @@ #ifndef HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H #define HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H -#include "../../DataStructs/ESPEasy_Now_p2p_data.h" +#include "../DataStructs/ESPEasy_Now_p2p_data.h" struct C019_ESPEasyNow_helper { static bool process_receive(struct EventStruct *event); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d3c3df5f55..e9418e6118 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_handler.h" +#include "../Helpers/ESPEasy_now_handler.h" #ifdef USES_ESPEASY_NOW From 68235538c6abef5b16a0111d39495343ec465a72 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 22 Jan 2022 02:11:31 +0100 Subject: [PATCH 213/404] [ESPEasy-NOW] Disable ESP32-S2 for now due to compile issues --- src/src/CustomBuild/define_plugin_sets.h | 8 ++++++++ src/src/Helpers/ESPEasy_time.cpp | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 9219f674eb..bec6d5b49a 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1589,6 +1589,14 @@ To create/register a plugin, you have to : #endif */ +#ifdef ESP32S2 // For now not yet support for ESPEasy-NOW on ESP32-S2 due to compile issues + #ifdef USES_C019 + #undef USES_C019 + #endif + #ifdef USES_P098 + #undef USES_P098 + #endif +#endif #if defined(USES_C018) || defined(USES_C019) #define USES_PACKED_RAW_DATA diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index ec1cf2ef2f..4dd4bcf0ea 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -1,5 +1,7 @@ #include "../Helpers/ESPEasy_time.h" +#include "../../ESPEasy_common.h" + #include "../DataTypes/TimeSource.h" #include "../ESPEasyCore/ESPEasy_Log.h" From ce779b9b59dbb8efeb4b0167e723001ff3bc3cf3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 22 Jan 2022 04:12:23 +0100 Subject: [PATCH 214/404] [ESPEasy-NOW] Fix incomplete include paths --- src/ESPEasy_common.h | 14 ++-- src/_C019.ino | 1 + src/src/Commands/Diagnostic.cpp | 8 -- src/src/Commands/ESPEasy_Now_cmd.cpp | 3 +- src/src/Commands/ESPEasy_Now_cmd.h | 1 + src/src/Commands/Networks.cpp | 2 +- src/src/CustomBuild/define_plugin_sets.h | 12 +-- .../ESPEasy_Now_DuplicateCheck.cpp | 2 +- .../ESPEasy_Now_MQTT_queue_check_packet.h | 1 + src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 3 +- src/src/DataStructs/ESPEasy_Now_NTP_query.h | 3 +- src/src/DataStructs/ESPEasy_Now_p2p_data.cpp | 2 +- src/src/DataStructs/ESPEasy_Now_packet.cpp | 2 +- src/src/DataStructs/ESPEasy_Now_packet.h | 5 +- .../ESPEasy_now_Node_statistics.cpp | 11 +-- .../DataStructs/ESPEasy_now_Node_statistics.h | 2 +- src/src/DataStructs/ESPEasy_now_hdr.cpp | 2 +- src/src/DataStructs/ESPEasy_now_hdr.h | 1 + src/src/DataStructs/ESPEasy_now_merger.cpp | 17 ++-- src/src/DataStructs/ESPEasy_now_merger.h | 5 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 2 +- src/src/DataStructs/ESPEasy_now_splitter.h | 5 +- .../DataStructs/EventStructCommandWrapper.h | 2 +- src/src/DataStructs/NodeStruct.h | 2 +- src/src/DataStructs/NodesHandler.cpp | 8 +- src/src/DataStructs/NodesHandler.h | 84 +++++++++++-------- .../DataStructs/RTC_cache_handler_struct.h | 2 +- .../SendData_DuplicateChecker_data.cpp | 2 +- .../SendData_DuplicateChecker_data.h | 2 +- .../SendData_DuplicateChecker_struct.cpp | 2 +- src/src/DataTypes/CPluginID.cpp | 2 +- src/src/DataTypes/ControllerIndex.cpp | 2 +- src/src/DataTypes/DeviceIndex.cpp | 2 +- src/src/DataTypes/ESPEasyTimeSource.cpp | 2 +- src/src/DataTypes/EthernetParameters.cpp | 2 +- src/src/DataTypes/NetworkMedium.cpp | 2 +- src/src/DataTypes/PluginID.cpp | 2 +- src/src/DataTypes/ProtocolIndex.cpp | 2 +- src/src/DataTypes/SettingsType.cpp | 2 +- src/src/DataTypes/TaskIndex.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 4 +- src/src/Globals/I2Cdev.cpp | 2 +- src/src/Helpers/DeepSleep.cpp | 2 +- src/src/Helpers/ESPEasy_time.cpp | 1 - src/src/Helpers/ESPEasy_time.h | 5 ++ src/src/Helpers/FS_Helper.h | 6 +- src/src/Helpers/Memory.cpp | 2 +- src/src/Helpers/Networking.cpp | 2 +- src/src/Helpers/StringProvider.cpp | 2 +- src/src/Helpers/_CPlugin_Helper.cpp | 2 +- src/src/WebServer/ConfigPage.cpp | 2 +- tools/pio/pre_custom_esp32.py | 5 +- 52 files changed, 142 insertions(+), 121 deletions(-) diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index 819f17a4aa..223d2e6262 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -64,7 +64,7 @@ namespace std #define FS_NO_GLOBALS #if defined(ESP8266) - #include "core_version.h" + #include #define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD #include #ifndef LWIP_VERSION_MAJOR @@ -80,13 +80,13 @@ namespace std #ifndef LWIP_OPEN_SRC #define LWIP_OPEN_SRC #endif - #include "lwip/opt.h" - #include "lwip/udp.h" - #include "lwip/igmp.h" - #include "include/UdpContext.h" - #include "limits.h" + #include + #include + #include + #include + #include extern "C" { - #include "user_interface.h" + #include } #define SMALLEST_OTA_IMAGE 276848 // smallest known 2-step OTA image diff --git a/src/_C019.ino b/src/_C019.ino index 3a7b286431..d5e6efe430 100644 --- a/src/_C019.ino +++ b/src/_C019.ino @@ -5,6 +5,7 @@ // ####################################################################################################### #include "ESPEasy_fdwdecl.h" +#include "ESPEasy_common.h" #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" #include "src/Helpers/_CPlugin_Helper.h" diff --git a/src/src/Commands/Diagnostic.cpp b/src/src/Commands/Diagnostic.cpp index f20afbee93..dff3c072c2 100644 --- a/src/src/Commands/Diagnostic.cpp +++ b/src/src/Commands/Diagnostic.cpp @@ -1,13 +1,5 @@ #include "../Commands/Diagnostic.h" -/* - #include "Common.h" - #include "../../ESPEasy_common.h" - - #include "../DataStructs/ESPEasy_EventStruct.h" - */ - - #include "../Commands/Common.h" diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index cf21841892..3b4ab64f36 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -3,10 +3,11 @@ #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" + #ifdef USES_ESPEASY_NOW #include "../Commands/Common.h" -#include "../../ESPEasy_common.h" #include "../Globals/ESPEasy_now_handler.h" String Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line) diff --git a/src/src/Commands/ESPEasy_Now_cmd.h b/src/src/Commands/ESPEasy_Now_cmd.h index 9f35f2a671..e3ce8d192b 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.h +++ b/src/src/Commands/ESPEasy_Now_cmd.h @@ -2,6 +2,7 @@ #define COMMANDS_ESPEASY_NOW_CMD_H #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW class String; diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index 04b0d96eb6..7aba7004aa 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -7,7 +7,7 @@ #ifdef HAS_ETHERNET -#include "ETH.h" +#include #endif String Command_AccessInfo_Ls(struct EventStruct *event, const char* Line) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index bec6d5b49a..601a05302e 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1140,7 +1140,7 @@ To create/register a plugin, you have to : //#define USES_P095 // TFT ILI9341 //#define USES_P096 // eInk (Needs lib_deps = Adafruit GFX Library, LOLIN_EPD ) #define USES_P097 // Touch (ESP32) - #define USES_P098 // ESPEasy-NOW Reader + //#define USES_P098 // ESPEasy-NOW Reader //#define USES_P099 // XPT2046 Touchscreen #define USES_P105 // AHT10/20/21 #endif @@ -1417,7 +1417,7 @@ To create/register a plugin, you have to : #define USES_P096 // eInk (Needs lib_deps = Adafruit GFX Library, LOLIN_EPD ) #endif #ifndef USES_P098 - #define USES_P098 // ESPEasy-NOW Receiver +// #define USES_P098 // ESPEasy-NOW Receiver #endif #ifndef USES_P099 #define USES_P099 // XPT2046 Touchscreen @@ -1589,14 +1589,6 @@ To create/register a plugin, you have to : #endif */ -#ifdef ESP32S2 // For now not yet support for ESPEasy-NOW on ESP32-S2 due to compile issues - #ifdef USES_C019 - #undef USES_C019 - #endif - #ifdef USES_P098 - #undef USES_P098 - #endif -#endif #if defined(USES_C018) || defined(USES_C019) #define USES_PACKED_RAW_DATA diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp index 9ddb61890d..b1eb5ae9be 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_DuplicateCheck.h" +#include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck() : _key(0), _type(ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck) {} diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h index 9677745814..b381e41abd 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h @@ -4,6 +4,7 @@ #include #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW class ESPEasy_Now_MQTT_queue_check_packet { diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index ffca4b7361..a4c9b47844 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_NTP_query.h" +#include "../DataStructs/ESPEasy_Now_NTP_query.h" #ifdef USES_ESPEASY_NOW @@ -251,6 +251,7 @@ bool ESPEasy_Now_NTP_query::processReply(const ESPEasy_Now_NTP_query& received, } double compensation_ms = air_time + timePassedSince(receiveTimestamp); double new_unixTime_d = received._unixTime_d + (compensation_ms / 1000); + node_time.setExternalTimeSource(new_unixTime_d, timeSource_t::ESP_now_peer); node_time.now(); diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index f44b6c46a4..e9a689d3d5 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -4,10 +4,11 @@ #include #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW # include "../Helpers/ESPEasy_time.h" -# include "MAC_address.h" +# include "../DataStructs/MAC_address.h" class ESPEasy_Now_NTP_query { diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp index 39fa7477b1..d412555618 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_p2p_data.h" +#include "../DataStructs/ESPEasy_Now_p2p_data.h" #include diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index f6692808bb..ab8bf9fa3f 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_Now_packet.h" +#include "../DataStructs/ESPEasy_Now_packet.h" #ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index 7b2b8daa5b..aa2532fcb8 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -4,10 +4,11 @@ #include #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW -# include "MAC_address.h" -# include "ESPEasy_now_hdr.h" +# include "../DataStructs/MAC_address.h" +# include "../DataStructs/ESPEasy_now_hdr.h" # include # include diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 98b7c2d8d1..6cdd44dc77 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -16,7 +16,7 @@ void ESPEasy_now_Node_statistics_t::addRoute(uint8_t unit, const ESPEasy_now_tra return; } - if (last_update_route[last_route_index] != 0 && timePassedSince(last_update_route[last_route_index]) < 1000) { + if ((last_update_route[last_route_index] != 0) && (timePassedSince(last_update_route[last_route_index]) < 1000)) { // Handling a burst of updates, only add those which have a higher success rate. if (routes[last_route_index] < route) { return; @@ -55,7 +55,8 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(uint8_t unit, bool success if (timePassedSince(last_update) < 100) { // Apply some rate limiter. return; - //if (success_rate > 100) { --success_rate; } + + // if (success_rate > 100) { --success_rate; } } else if (success_rate < 255) { ++success_rate; } last_update = millis(); } else { @@ -63,7 +64,7 @@ void ESPEasy_now_Node_statistics_t::updateSuccessRate(uint8_t unit, bool success } for (unsigned int i = 0; i < ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES; ++i) { - if (last_update_route[i] != 0 && timePassedSince(last_update_route[i]) > 125000) { + if ((last_update_route[i] != 0) && (timePassedSince(last_update_route[i]) > 125000)) { last_update_route[i] = 0; routes[i].clear(); } else { @@ -99,7 +100,7 @@ const ESPEasy_now_traceroute_struct * ESPEasy_now_Node_statistics_t::bestRoute() const int successRate = routes[i].computeSuccessRate(); if (distance == bestDistance) { - if (successRate > bestSuccessRate && distance < 255) { + if ((successRate > bestSuccessRate) && (distance < 255)) { bestSuccessRate = successRate; bestIndex = i; } @@ -132,4 +133,4 @@ void ESPEasy_now_Node_statistics_t::setMQTTQueueState(ESPEasy_Now_MQTT_queue_che mqtt_queue_state = state; } -#endif \ No newline at end of file +#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index 4920cefc2f..599a849cd0 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -55,6 +55,6 @@ struct ESPEasy_now_Node_statistics_t { typedef std::map ESPEasy_now_Node_statisticsMap; -#endif +#endif // ifdef USES_ESPEASY_NOW #endif // ifndef DATASTRUCTS_ESPEASY_NOW_NODE_STATISTICS_H diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index 8ff40ead6f..f27f32f769 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_hdr.h" +#include "../DataStructs/ESPEasy_now_hdr.h" #ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 468af4443f..bcba85e470 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -6,6 +6,7 @@ \*********************************************************************************************/ #include "../Globals/ESPEasy_now_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW # include diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index dcdb14827b..e14238ab25 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_merger.h" +#include "../DataStructs/ESPEasy_now_merger.h" #ifdef USES_ESPEASY_NOW @@ -18,7 +18,7 @@ void ESPEasy_now_merger::addPacket( const uint8_t *buf, size_t packetSize) { - #ifdef ESP8266 + # ifdef ESP8266 const uint16_t maxFreeBlock = ESP.getMaxFreeBlockSize(); if (2 * packetSize > maxFreeBlock) { @@ -27,14 +27,15 @@ void ESPEasy_now_merger::addPacket( _firstPacketTimestamp -= ESPEASY_NOW_MESSAGE_TIMEOUT; return; } - #endif + # endif // ifdef ESP8266 // FIXME TD-er: How to handle duplicates? // We might receive some packets several times if the sender does not receive our acknowledgement ESPEasy_Now_packet packet; packet.setReceivedPacket(mac, buf, packetSize); + if (packet.valid()) { - _queue[packet_nr] = std::move(packet); + _queue[packet_nr] = std::move(packet); _firstPacketTimestamp = millis(); } } @@ -122,6 +123,7 @@ String ESPEasy_now_merger::getLogString() const getMac(mac); String log; + log.reserve(64); log += mac.toString(); log += F(" payload: "); @@ -166,13 +168,14 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const if (stringLength == 0) { return false; } + if (!string.reserve(stringLength)) { return false; } } const size_t bufsize = 128; - uint8_t buf[bufsize] = {0}; + uint8_t buf[bufsize] = { 0 }; bool done = false; @@ -201,8 +204,8 @@ bool ESPEasy_now_merger::getString(String& string, size_t& payload_pos) const size_t ESPEasy_now_merger::str_len(size_t& payload_pos) const { const size_t bufsize = 128; - uint8_t buf[bufsize] = {0}; - bool done = false; + uint8_t buf[bufsize] = { 0 }; + bool done = false; // We do fetch more data from the message than the string size, so copy payload_pos first size_t tmp_payload_pos = payload_pos; diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index d0071e4cac..358ad3e316 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -1,11 +1,12 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_MERGER_H #define DATASTRUCTS_ESPEASY_NOW_MERGER_H -#include "ESPEasy_Now_packet.h" +#include "../DataStructs/ESPEasy_Now_packet.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW -# include "MAC_address.h" +# include "../DataStructs/MAC_address.h" // Class to process all incoming messages from a single sender. // One or more packets form a complete message. diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 830fe894c9..dbb866aa88 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -1,4 +1,4 @@ -#include "ESPEasy_now_splitter.h" +#include "../DataStructs/ESPEasy_now_splitter.h" #ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 918e6c7787..91d35d9dfb 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -1,10 +1,13 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_SPLITTER_H #define DATASTRUCTS_ESPEASY_NOW_SPLITTER_H -#include "ESPEasy_Now_packet.h" +#include "../DataStructs/ESPEasy_Now_packet.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW +# include "../Globals/ESPEasy_now_peermanager.h" + class ESPEasy_now_splitter { public: diff --git a/src/src/DataStructs/EventStructCommandWrapper.h b/src/src/DataStructs/EventStructCommandWrapper.h index ef3cd5c31e..86ae05fc6e 100644 --- a/src/src/DataStructs/EventStructCommandWrapper.h +++ b/src/src/DataStructs/EventStructCommandWrapper.h @@ -2,7 +2,7 @@ #define DATASTRUCTS_EVENTSTRUCTCOMMANDWRAPPER_H #include -#include "ESPEasy_EventStruct.h" +#include "../DataStructs/ESPEasy_EventStruct.h" struct EventStructCommandWrapper { EventStructCommandWrapper() : id(0) {} diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index b9b9f16cd9..f22b491d57 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" #include "../Helpers/ESPEasy_time.h" -#include "MAC_address.h" +#include "../DataStructs/MAC_address.h" #include #include diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 7b4f32f52c..51644f74f5 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -1,12 +1,16 @@ -#include "NodesHandler.h" +#include "../DataStructs/NodesHandler.h" #include "../../ESPEasy_common.h" #include "../../ESPEasy-Globals.h" + +#ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_peermanager.h" +#endif + #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Globals/ESPEasy_time.h" -#include "../Globals/ESPEasy_now_peermanager.h" #include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 807d4d13ee..008d9b8ad1 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -1,14 +1,16 @@ #ifndef DATASTRUCTS_NODESHANDLER_H #define DATASTRUCTS_NODESHANDLER_H -#include "../DataStructs/NodeStruct.h" +#include "../../ESPEasy_common.h" #include "../DataStructs/MAC_address.h" +#include "../DataStructs/NodeStruct.h" #ifdef USES_ESPEASY_NOW -#include "../DataStructs/ESPEasy_now_traceroute.h" -#include "../DataStructs/ESPEasy_now_Node_statistics.h" -#endif +# include "../DataStructs/ESPEasy_now_traceroute.h" +# include "../DataStructs/ESPEasy_now_Node_statistics.h" +# include "../Globals/ESPEasy_now_peermanager.h" +#endif // ifdef USES_ESPEASY_NOW #include "../Helpers/ESPEasyMutex.h" @@ -18,11 +20,12 @@ class NodesHandler { // Add node to the list of known nodes. // @retval true when the node was not yet present in the list. - bool addNode(const NodeStruct& node); + bool addNode(const NodeStruct& node); #ifdef USES_ESPEASY_NOW - bool addNode(const NodeStruct& node, const ESPEasy_now_traceroute_struct& traceRoute); -#endif + bool addNode(const NodeStruct & node, + const ESPEasy_now_traceroute_struct& traceRoute); +#endif // ifdef USES_ESPEASY_NOW bool hasNode(uint8_t unit_nr) const; @@ -44,68 +47,77 @@ class NodesHandler { // Remove nodes in list older than max_age_allowed (msec) // Returns oldest age, max_age (msec) not removed from the list. // Return true if a node has been removed. - bool refreshNodeList(unsigned long max_age_allowed, - unsigned long& max_age); + bool refreshNodeList(unsigned long max_age_allowed, + unsigned long& max_age); + - - const NodeStruct* getPreferredNode() const; - const NodeStruct* getPreferredNode_notMatching(uint8_t unit_nr) const; - const NodeStruct* getPreferredNode_notMatching(const MAC_address& not_matching) const; + const NodeStruct * getPreferredNode() const; + const NodeStruct * getPreferredNode_notMatching(uint8_t unit_nr) const; + const NodeStruct * getPreferredNode_notMatching(const MAC_address& not_matching) const; #ifdef USES_ESPEASY_NOW const ESPEasy_now_traceroute_struct* getTraceRoute(uint8_t unit) const; const ESPEasy_now_traceroute_struct* getDiscoveryRoute(uint8_t unit) const; - void setTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute); -#endif + void setTraceRoute(const MAC_address & mac, + const ESPEasy_now_traceroute_struct& traceRoute); +#endif // ifdef USES_ESPEASY_NOW // Update the node referring to this unit with the most recent info. - void updateThisNode(); + void updateThisNode(); - const NodeStruct * getThisNode(); + const NodeStruct* getThisNode(); - uint8_t getDistance() const; + uint8_t getDistance() const; - bool lastTimeValidDistanceExpired() const; + bool lastTimeValidDistanceExpired() const; - unsigned long get_lastTimeValidDistance() const { + unsigned long get_lastTimeValidDistance() const { return _lastTimeValidDistance; } - bool isEndpoint() const; + bool isEndpoint() const; #ifdef USES_ESPEASY_NOW uint8_t getESPEasyNOW_channel() const; -#endif +#endif // ifdef USES_ESPEASY_NOW - bool recentlyBecameDistanceZero(); + bool recentlyBecameDistanceZero(); - void setRSSI(const MAC_address& mac, int rssi); + void setRSSI(const MAC_address& mac, + int rssi); - void setRSSI(uint8_t unit, int rssi); + void setRSSI(uint8_t unit, + int rssi); #ifdef USES_ESPEASY_NOW - void updateSuccessRate(uint8_t unit, bool success); - void updateSuccessRate(const MAC_address& mac, bool success); + void updateSuccessRate(uint8_t unit, + bool success); + void updateSuccessRate(const MAC_address& mac, + bool success); - int getRouteSuccessRate(uint8_t unit, uint8_t& distance) const; + int getRouteSuccessRate(uint8_t unit, + uint8_t& distance) const; - uint8_t getSuccessRate(uint8_t unit) const; + uint8_t getSuccessRate(uint8_t unit) const; ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState(uint8_t unit) const; - void setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); - void setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + void setMQTTQueueState(uint8_t unit, + ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + void setMQTTQueueState(const MAC_address & mac, + ESPEasy_Now_MQTT_queue_check_packet::QueueState state); -#endif +#endif // ifdef USES_ESPEASY_NOW private: - void setRSSI(NodeStruct * node, int rssi); + void setRSSI(NodeStruct *node, + int rssi); unsigned long _lastTimeValidDistance = 0; - uint8_t _distance = 255; // Cached value + uint8_t _distance = 255; // Cached value NodesMap _nodes; ESPEasy_Mutex _nodes_mutex; @@ -113,10 +125,10 @@ class NodesHandler { #ifdef USES_ESPEASY_NOW ESPEasy_now_Node_statisticsMap _nodeStats; ESPEasy_Mutex _nodeStats_mutex; -#endif +#endif // ifdef USES_ESPEASY_NOW bool _recentlyBecameDistanceZero = false; }; -#endif // DATASTRUCTS_NODESHANDLER_H +#endif // ifndef DATASTRUCTS_NODESHANDLER_H diff --git a/src/src/DataStructs/RTC_cache_handler_struct.h b/src/src/DataStructs/RTC_cache_handler_struct.h index 9717e6522e..9984011c6a 100644 --- a/src/src/DataStructs/RTC_cache_handler_struct.h +++ b/src/src/DataStructs/RTC_cache_handler_struct.h @@ -2,7 +2,7 @@ #define DATASTRUCTS_RTC_CACHE_HANDLER_STRUCT_H -#include "RTCCacheStruct.h" +#include "../DataStructs/RTCCacheStruct.h" #include "../../ESPEasy_common.h" diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp index 201dcead32..1f588fdff1 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_data.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.cpp @@ -1,4 +1,4 @@ -#include "SendData_DuplicateChecker_data.h" +#include "../DataStructs/SendData_DuplicateChecker_data.h" #include "../ESPEasyCore/Controller.h" #include "../Helpers/ESPEasy_time_calc.h" diff --git a/src/src/DataStructs/SendData_DuplicateChecker_data.h b/src/src/DataStructs/SendData_DuplicateChecker_data.h index 4ed2d44445..a61e04fe8c 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_data.h +++ b/src/src/DataStructs/SendData_DuplicateChecker_data.h @@ -1,7 +1,7 @@ #ifndef DATASTRUCTS_SENDDATA_DUPLICATECHECKER_DATA_H #define DATASTRUCTS_SENDDATA_DUPLICATECHECKER_DATA_H -#include "ESPEasy_EventStruct.h" +#include "../DataStructs/ESPEasy_EventStruct.h" class SendData_DuplicateChecker_data { public: diff --git a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp index 544a84d3d8..0bf40e6dab 100644 --- a/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp +++ b/src/src/DataStructs/SendData_DuplicateChecker_struct.cpp @@ -1,4 +1,4 @@ -#include "SendData_DuplicateChecker_struct.h" +#include "../DataStructs/SendData_DuplicateChecker_struct.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/Plugins.h" diff --git a/src/src/DataTypes/CPluginID.cpp b/src/src/DataTypes/CPluginID.cpp index 9c55bc4887..bf5470fd2f 100644 --- a/src/src/DataTypes/CPluginID.cpp +++ b/src/src/DataTypes/CPluginID.cpp @@ -1,3 +1,3 @@ -#include "CPluginID.h" +#include "../DataTypes/CPluginID.h" cpluginID_t INVALID_C_PLUGIN_ID = 0; diff --git a/src/src/DataTypes/ControllerIndex.cpp b/src/src/DataTypes/ControllerIndex.cpp index ada9588cd6..ff5d61e1ed 100644 --- a/src/src/DataTypes/ControllerIndex.cpp +++ b/src/src/DataTypes/ControllerIndex.cpp @@ -1,4 +1,4 @@ -#include "ControllerIndex.h" +#include "../DataTypes/ControllerIndex.h" #include "../CustomBuild/ESPEasyLimits.h" diff --git a/src/src/DataTypes/DeviceIndex.cpp b/src/src/DataTypes/DeviceIndex.cpp index 3cefdd3892..1141c88e8f 100644 --- a/src/src/DataTypes/DeviceIndex.cpp +++ b/src/src/DataTypes/DeviceIndex.cpp @@ -1,4 +1,4 @@ -#include "DeviceIndex.h" +#include "../DataTypes/DeviceIndex.h" #include "../CustomBuild/ESPEasyLimits.h" diff --git a/src/src/DataTypes/ESPEasyTimeSource.cpp b/src/src/DataTypes/ESPEasyTimeSource.cpp index 3b39e2c1bc..61cea67252 100644 --- a/src/src/DataTypes/ESPEasyTimeSource.cpp +++ b/src/src/DataTypes/ESPEasyTimeSource.cpp @@ -1,4 +1,4 @@ -#include "ESPEasyTimeSource.h" +#include "../DataTypes/ESPEasyTimeSource.h" #include diff --git a/src/src/DataTypes/EthernetParameters.cpp b/src/src/DataTypes/EthernetParameters.cpp index b4cac0de46..cb25de9dda 100644 --- a/src/src/DataTypes/EthernetParameters.cpp +++ b/src/src/DataTypes/EthernetParameters.cpp @@ -1,4 +1,4 @@ -#include "EthernetParameters.h" +#include "../DataTypes/EthernetParameters.h" bool isValid(EthClockMode_t clockMode) { switch (clockMode) { diff --git a/src/src/DataTypes/NetworkMedium.cpp b/src/src/DataTypes/NetworkMedium.cpp index 1cc6a13ccd..0c94ffb3ad 100644 --- a/src/src/DataTypes/NetworkMedium.cpp +++ b/src/src/DataTypes/NetworkMedium.cpp @@ -1,4 +1,4 @@ -#include "NetworkMedium.h" +#include "../DataTypes/NetworkMedium.h" #include "../../ESPEasy_common.h" diff --git a/src/src/DataTypes/PluginID.cpp b/src/src/DataTypes/PluginID.cpp index 1ac2039797..72302df71f 100644 --- a/src/src/DataTypes/PluginID.cpp +++ b/src/src/DataTypes/PluginID.cpp @@ -1,3 +1,3 @@ -#include "PluginID.h" +#include "../DataTypes/PluginID.h" pluginID_t INVALID_PLUGIN_ID = 0; \ No newline at end of file diff --git a/src/src/DataTypes/ProtocolIndex.cpp b/src/src/DataTypes/ProtocolIndex.cpp index ceff2f5bf4..45ec8c3728 100644 --- a/src/src/DataTypes/ProtocolIndex.cpp +++ b/src/src/DataTypes/ProtocolIndex.cpp @@ -1,4 +1,4 @@ -#include "ProtocolIndex.h" +#include "../DataTypes/ProtocolIndex.h" #include "../CustomBuild/ESPEasyLimits.h" diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index eba3da7d76..516ce847f7 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -1,4 +1,4 @@ -#include "SettingsType.h" +#include "../DataTypes/SettingsType.h" #include "../CustomBuild/StorageLayout.h" #include "../DataStructs/NotificationSettingsStruct.h" diff --git a/src/src/DataTypes/TaskIndex.cpp b/src/src/DataTypes/TaskIndex.cpp index 989a32d2ee..7f68f61258 100644 --- a/src/src/DataTypes/TaskIndex.cpp +++ b/src/src/DataTypes/TaskIndex.cpp @@ -1,4 +1,4 @@ -#include "TaskIndex.h" +#include "../DataTypes/TaskIndex.h" diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 2bb059a9fe..58bea4ae8c 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -1,7 +1,7 @@ -#include "ESPEasyWiFiEvent.h" +#include "../ESPEasyCore/ESPEasyWiFiEvent.h" #ifdef HAS_ETHERNET -#include "ETH.h" +#include #endif #include "../DataStructs/RTCStruct.h" diff --git a/src/src/Globals/I2Cdev.cpp b/src/src/Globals/I2Cdev.cpp index 5c2f05c386..f4062267a7 100644 --- a/src/src/Globals/I2Cdev.cpp +++ b/src/src/Globals/I2Cdev.cpp @@ -1,4 +1,4 @@ -#include "I2Cdev.h" +#include "../Globals/I2Cdev.h" I2Cdev i2cdev; diff --git a/src/src/Helpers/DeepSleep.cpp b/src/src/Helpers/DeepSleep.cpp index 2a90f13931..8ac9284dec 100644 --- a/src/src/Helpers/DeepSleep.cpp +++ b/src/src/Helpers/DeepSleep.cpp @@ -141,7 +141,7 @@ void deepSleepStart(int dsdelay) if (Settings.UseAlternativeDeepSleep()) { // See: https://github.com/esp8266/Arduino/issues/6318#issuecomment-711389479 - #include "c_types.h" + #include // system_phy_set_powerup_option: // 1 = RF initialization only calibrate VDD33 and Tx power which will take about 18 ms // 2 = RF initialization only calibrate VDD33 which will take about 2 ms diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 4dd4bcf0ea..50c0be87c8 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -9,7 +9,6 @@ #include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" -#include "../Globals/ESPEasy_now_handler.h" #include "../Globals/RTC.h" #include "../Globals/Settings.h" #include "../Globals/TimeZone.h" diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 08884600f7..9c28f9307b 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -7,6 +7,11 @@ #include +#ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_handler.h" +#endif + + class ESPEasy_time { public: diff --git a/src/src/Helpers/FS_Helper.h b/src/src/Helpers/FS_Helper.h index 26d8755f79..e887619f49 100644 --- a/src/src/Helpers/FS_Helper.h +++ b/src/src/Helpers/FS_Helper.h @@ -11,7 +11,7 @@ #define FS_NO_GLOBALS #if defined(ESP8266) extern "C" { - #include "spi_flash.h" + #include } #ifdef CORE_POST_2_6_0 extern "C" uint32_t _FS_start; @@ -28,9 +28,9 @@ #if defined(ESP32) #ifdef USE_LITTLEFS - #include "LITTLEFS.h" + #include #else - #include "SPIFFS.h" + #include #endif #endif diff --git a/src/src/Helpers/Memory.cpp b/src/src/Helpers/Memory.cpp index 67822f49d4..7b865815ef 100644 --- a/src/src/Helpers/Memory.cpp +++ b/src/src/Helpers/Memory.cpp @@ -3,7 +3,7 @@ #ifdef ESP8266 extern "C" { -#include "user_interface.h" +#include } #endif diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 67c30ba1f9..def88772ec 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -62,7 +62,7 @@ void etharp_gratuitous_r(struct netif *netif) { # include # endif // ifdef ESP8266 # ifdef ESP32 -# include "HTTPClient.h" +# include # endif // ifdef ESP32 #endif diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 6f1fa49d5e..ad038dbfd5 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -1,7 +1,7 @@ #include "../Helpers/StringProvider.h" #ifdef HAS_ETHERNET -# include "ETH.h" +# include #endif // ifdef HAS_ETHERNET #include "../../ESPEasy-Globals.h" diff --git a/src/src/Helpers/_CPlugin_Helper.cpp b/src/src/Helpers/_CPlugin_Helper.cpp index f0f973ac6b..23f9861a7b 100644 --- a/src/src/Helpers/_CPlugin_Helper.cpp +++ b/src/src/Helpers/_CPlugin_Helper.cpp @@ -36,7 +36,7 @@ # include #endif // ifdef ESP8266 #ifdef ESP32 -# include "HTTPClient.h" +# include #endif // ifdef ESP32 bool safeReadStringUntil(Stream & input, diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index 8e12d7bc40..94299bb000 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -24,7 +24,7 @@ -#include "src/DataStructs/MAC_address.h" +#include "../DataStructs/MAC_address.h" // ******************************************************************************** // Web Interface config page diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 2860816e58..49a348928f 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -48,15 +48,16 @@ # "-DUSES_P094", # CUL Reader # "-DUSES_P095", # TFT ILI9341 "-DUSES_P097", # Touch (ESP32) - "-DUSES_P098", # ESPEasy-NOW Reader +# "-DUSES_P098", # ESPEasy-NOW Reader "-DUSES_P106", # BME680 "-DUSES_P107", # SI1145 UV index # "-DUSES_C015", # Blynk "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 - "-DUSES_C019", # ESPEasy-NOW +# "-DUSES_C019", # ESPEasy-NOW + "-DUSES_ESPEASY_NOW", "-DUSE_EXT_RTC", "-DFEATURE_SD", "-DFEATURE_I2CMULTIPLEXER", From 63d4d0c0a10d4f72665f2961dafd43af6397bd76 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 23 Jan 2022 20:39:57 +0100 Subject: [PATCH 215/404] [ESPEasy-NOW] Fix build errors Really strange build issue, no idea why it would not build. Helpers/ESPEasy_now_handler.h cannot have `ESPEasy_Now_NTP_query` as member in the .h file. Now forward declared and only included in the .cpp to make it work. Thus had to use it as a member pointer instead of a local member. --- src/_N001_Email.ino | 4 +- src/__NPlugin.ino | 2 +- src/src/Commands/Time.cpp | 2 + src/src/Commands/WiFi.cpp | 2 + src/src/ControllerQueue/C016_queue_element.h | 1 + src/src/CustomBuild/CompiletimeDefines.h | 6 +- src/src/CustomBuild/ESPEasyDefaults.h | 6 +- src/src/CustomBuild/ESPEasyLimits.h | 1 + src/src/CustomBuild/ESPEasy_buildinfo.h | 6 +- src/src/CustomBuild/StorageLayout.h | 6 +- src/src/CustomBuild/define_plugin_sets.h | 6 +- src/src/DataStructs/C013_p2p_dataStructs.cpp | 5 - src/src/DataStructs/C013_p2p_dataStructs.h | 5 +- src/src/DataStructs/ESPEasy_EventStruct.h | 11 +- .../ESPEasy_Now_MQTT_queue_check_packet.cpp | 10 +- .../ESPEasy_Now_MQTT_queue_check_packet.h | 13 +-- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 9 +- src/src/DataStructs/ESPEasy_Now_NTP_query.h | 9 +- src/src/DataStructs/ESPEasy_Now_p2p_data.h | 2 + src/src/DataStructs/ESPEasy_Now_packet.cpp | 10 +- src/src/DataStructs/ESPEasy_Now_packet.h | 21 ++-- .../ESPEasy_now_Node_statistics.cpp | 4 +- .../DataStructs/ESPEasy_now_Node_statistics.h | 9 +- src/src/DataStructs/ESPEasy_now_hdr.cpp | 5 + src/src/DataStructs/ESPEasy_now_hdr.h | 8 +- src/src/DataStructs/ESPEasy_now_merger.h | 8 +- src/src/DataStructs/ESPEasy_now_splitter.cpp | 1 + src/src/DataStructs/ESPEasy_now_splitter.h | 4 +- src/src/DataStructs/ESPEasy_packed_raw_data.h | 6 +- .../ExtendedControllerCredentialsStruct.h | 6 +- src/src/DataStructs/I2CTypes.h | 6 +- src/src/DataStructs/MAC_address.cpp | 7 ++ src/src/DataStructs/MAC_address.h | 2 + src/src/DataStructs/MessageRouteInfo.h | 6 +- src/src/DataStructs/NodesHandler.cpp | 8 +- src/src/DataStructs/NodesHandler.h | 9 +- src/src/DataStructs/SettingsStruct.cpp | 6 +- src/src/DataStructs/Web_StreamingBuffer.h | 6 +- src/src/DataTypes/CPluginID.h | 6 +- src/src/DataTypes/ControllerIndex.h | 4 +- src/src/DataTypes/DeviceIndex.cpp | 2 +- src/src/DataTypes/DeviceIndex.h | 12 +- src/src/DataTypes/DeviceModel.h | 6 +- .../ESPEasy_Now_MQTT_queue_check_state.cpp | 1 + .../ESPEasy_Now_MQTT_queue_check_state.h | 16 +++ src/src/DataTypes/ESPEasy_plugin_functions.h | 6 +- src/src/DataTypes/NPluginID.cpp | 3 + src/src/DataTypes/NPluginID.h | 12 ++ src/src/DataTypes/NetworkMedium.h | 6 +- src/src/DataTypes/NotifierIndex.cpp | 5 + src/src/DataTypes/NotifierIndex.h | 10 ++ src/src/DataTypes/PluginID.cpp | 2 +- src/src/DataTypes/PluginID.h | 6 +- src/src/DataTypes/ProtocolIndex.h | 4 +- src/src/DataTypes/SPI_options.h | 6 +- src/src/DataTypes/SettingsType.h | 6 +- src/src/DataTypes/TaskIndex.cpp | 2 +- src/src/DataTypes/TaskIndex.h | 10 +- src/src/Globals/ESPEasy_now_handler.h | 11 +- src/src/Globals/ESPEasy_now_peermanager.h | 6 +- src/src/Globals/NPlugins.cpp | 4 +- src/src/Globals/NPlugins.h | 14 +-- src/src/Globals/Plugins.h | 6 +- src/src/Helpers/ESPEasy_now_handler.cpp | 45 ++++++-- src/src/Helpers/ESPEasy_now_handler.h | 109 ++++++++++-------- src/src/Helpers/Scheduler.cpp | 1 + src/src/Helpers/Scheduler.h | 1 + src/src/WebServer/NotificationPage.cpp | 1 - 68 files changed, 325 insertions(+), 236 deletions(-) create mode 100644 src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.cpp create mode 100644 src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h create mode 100644 src/src/DataTypes/NPluginID.cpp create mode 100644 src/src/DataTypes/NPluginID.h create mode 100644 src/src/DataTypes/NotifierIndex.cpp create mode 100644 src/src/DataTypes/NotifierIndex.h diff --git a/src/_N001_Email.ino b/src/_N001_Email.ino index 5ad734bc9b..ce9e98f526 100644 --- a/src/_N001_Email.ino +++ b/src/_N001_Email.ino @@ -84,8 +84,7 @@ boolean NPlugin_001(NPlugin::Function function, struct EventStruct *event, Strin return success; } - -#ifdef USES_NOTIFIER +boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg); boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg) { @@ -186,7 +185,6 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, return myStatus; } -#endif boolean NPlugin_001_Auth(WiFiClient& client, const String& user, const String& pass) { diff --git a/src/__NPlugin.ino b/src/__NPlugin.ino index b90dde7ba9..da0f22b640 100644 --- a/src/__NPlugin.ino +++ b/src/__NPlugin.ino @@ -1,8 +1,8 @@ #include "ESPEasy_common.h" -#ifdef USES_NOTIFIER #include "src/Globals/NPlugins.h" #include "src/DataStructs/ESPEasy_EventStruct.h" +#ifdef USES_NOTIFIER // ******************************************************************************** diff --git a/src/src/Commands/Time.cpp b/src/src/Commands/Time.cpp index d841edfd07..edf192f0ed 100644 --- a/src/src/Commands/Time.cpp +++ b/src/src/Commands/Time.cpp @@ -6,6 +6,8 @@ #include "../Commands/Common.h" +#include "../DataStructs/ESPEasy_EventStruct.h" + #include "../ESPEasyCore/Serial.h" #include "../Globals/ESPEasy_time.h" diff --git a/src/src/Commands/WiFi.cpp b/src/src/Commands/WiFi.cpp index 9d27dbbb5d..ed13682238 100644 --- a/src/src/Commands/WiFi.cpp +++ b/src/src/Commands/WiFi.cpp @@ -4,6 +4,8 @@ #include "../Commands/Common.h" +#include "../DataStructs/ESPEasy_EventStruct.h" + #include "../ESPEasyCore/ESPEasyWifi.h" #include "../ESPEasyCore/Serial.h" diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 0d42743159..74a9db7008 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -5,6 +5,7 @@ #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../DataStructs/MessageRouteInfo.h" +#include "../DataTypes/ControllerIndex.h" #include "../Globals/Plugins.h" struct EventStruct; diff --git a/src/src/CustomBuild/CompiletimeDefines.h b/src/src/CustomBuild/CompiletimeDefines.h index 68021118e9..14a7ff057b 100644 --- a/src/src/CustomBuild/CompiletimeDefines.h +++ b/src/src/CustomBuild/CompiletimeDefines.h @@ -1,5 +1,5 @@ -#ifndef HELPERS_COMPILETIMEDEFINES_H -#define HELPERS_COMPILETIMEDEFINES_H +#ifndef CUSTOMBUILD_COMPILETIMEDEFINES_H +#define CUSTOMBUILD_COMPILETIMEDEFINES_H #include @@ -13,4 +13,4 @@ const __FlashStringHelper * get_build_platform(); const __FlashStringHelper * get_git_head(); -#endif // HELPERS_COMPILETIMEDEFINES_H +#endif // CUSTOMBUILD_COMPILETIMEDEFINES_H diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index e454272c6c..2e3e0d03bf 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -1,5 +1,5 @@ -#ifndef ESPEASY_DEFAULTS_H_ -#define ESPEASY_DEFAULTS_H_ +#ifndef CUSTOMBUILD_ESPEASY_DEFAULTS_H_ +#define CUSTOMBUILD_ESPEASY_DEFAULTS_H_ // Needed to make sure Custom.h is used. #include "../../ESPEasy_common.h" @@ -397,4 +397,4 @@ #define DEFAULT_I2C_CLOCK_LIMIT 0 // */ -#endif // ESPEASY_DEFAULTS_H_ +#endif // CUSTOMBUILD_ESPEASY_DEFAULTS_H_ diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index f76d18dd48..72a295d6f9 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -66,6 +66,7 @@ #define NAME_FORMULA_LENGTH_MAX 40 #endif +#define USERVAR_MAX_INDEX (VARS_PER_TASK * TASKS_MAX) // *********************************************************************** diff --git a/src/src/CustomBuild/ESPEasy_buildinfo.h b/src/src/CustomBuild/ESPEasy_buildinfo.h index 68297f013a..9fcc3c9224 100644 --- a/src/src/CustomBuild/ESPEasy_buildinfo.h +++ b/src/src/CustomBuild/ESPEasy_buildinfo.h @@ -1,5 +1,5 @@ -#ifndef ESPEASY_BUILD_INFO_H -#define ESPEASY_BUILD_INFO_H +#ifndef CUSTOMBUILD_ESPEASY_BUILD_INFO_H +#define CUSTOMBUILD_ESPEASY_BUILD_INFO_H // ******************************************************************************** @@ -46,4 +46,4 @@ # define ESPEASY_NOW_NAME "ESPEasy-NOW" #endif -#endif // ESPEASY_BUILD_INFO_H +#endif // CUSTOMBUILD_ESPEASY_BUILD_INFO_H diff --git a/src/src/CustomBuild/StorageLayout.h b/src/src/CustomBuild/StorageLayout.h index 37b891cfbb..3b3cebfd3f 100644 --- a/src/src/CustomBuild/StorageLayout.h +++ b/src/src/CustomBuild/StorageLayout.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_STORAGE_LAYOUT_H -#define DATASTRUCTS_STORAGE_LAYOUT_H +#ifndef CUSTOMBUILD_STORAGE_LAYOUT_H +#define CUSTOMBUILD_STORAGE_LAYOUT_H #include "../../ESPEasy_common.h" @@ -172,4 +172,4 @@ #endif // if defined(ESP32) -#endif // DATASTRUCTS_STORAGE_LAYOUT_H +#endif // CUSTOMBUILD_STORAGE_LAYOUT_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 601a05302e..cbb875b1c2 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1,5 +1,5 @@ -#ifndef DEFINE_PLUGIN_SETS_H -#define DEFINE_PLUGIN_SETS_H +#ifndef CUSTOMBUILD_DEFINE_PLUGIN_SETS_H +#define CUSTOMBUILD_DEFINE_PLUGIN_SETS_H #include "../../ESPEasy_common.h" @@ -1834,4 +1834,4 @@ To create/register a plugin, you have to : #endif #endif -#endif // DEFINE_PLUGIN_SETS_H \ No newline at end of file +#endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H \ No newline at end of file diff --git a/src/src/DataStructs/C013_p2p_dataStructs.cpp b/src/src/DataStructs/C013_p2p_dataStructs.cpp index cea255abe3..fc31041d2f 100644 --- a/src/src/DataStructs/C013_p2p_dataStructs.cpp +++ b/src/src/DataStructs/C013_p2p_dataStructs.cpp @@ -1,9 +1,6 @@ #include "../DataStructs/C013_p2p_dataStructs.h" #include "../Globals/Plugins.h" -#include "../../ESPEasy_common.h" - -#ifdef USES_C013 C013_SensorInfoStruct::C013_SensorInfoStruct() { @@ -45,5 +42,3 @@ bool C013_SensorDataStruct::isValid() const } return true; } - -#endif \ No newline at end of file diff --git a/src/src/DataStructs/C013_p2p_dataStructs.h b/src/src/DataStructs/C013_p2p_dataStructs.h index e8b11fe363..c465d7195d 100644 --- a/src/src/DataStructs/C013_p2p_dataStructs.h +++ b/src/src/DataStructs/C013_p2p_dataStructs.h @@ -4,11 +4,11 @@ #include #include "../CustomBuild/ESPEasyLimits.h" -#include "../Globals/Plugins.h" +#include "../DataTypes/TaskIndex.h" +#include "../DataTypes/PluginID.h" // These structs are sent to other nodes, so make sure not to change order or offset in struct. -#ifdef USES_C013 struct C013_SensorInfoStruct { C013_SensorInfoStruct(); @@ -41,6 +41,5 @@ struct C013_SensorDataStruct float Values[VARS_PER_TASK]; }; -#endif #endif // DATASTRUCTS_C013_P2P_DATASTRUCTS_H diff --git a/src/src/DataStructs/ESPEasy_EventStruct.h b/src/src/DataStructs/ESPEasy_EventStruct.h index 21fbbcdfe6..ab2ebd0f5e 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.h +++ b/src/src/DataStructs/ESPEasy_EventStruct.h @@ -1,17 +1,16 @@ -#ifndef ESPEASY_EVENTSTRUCT_H -#define ESPEASY_EVENTSTRUCT_H +#ifndef DATASTRUCTS_ESPEASY_EVENTSTRUCT_H +#define DATASTRUCTS_ESPEASY_EVENTSTRUCT_H #include #include "../DataTypes/ControllerIndex.h" #include "../DataTypes/EventValueSource.h" #include "../DataTypes/TaskIndex.h" -//#include "../Globals/CPlugins.h" -#include "../Globals/NPlugins.h" -//#include "../Globals/Plugins.h" +#include "../DataTypes/NotifierIndex.h" #include "../DataStructs/DeviceStruct.h" + /*********************************************************************************************\ * EventStruct * This should not be copied, only moved. @@ -68,4 +67,4 @@ struct EventStruct uint8_t OriginTaskIndex = 0; }; -#endif // ESPEASY_EVENTSTRUCT_H +#endif // DATASTRUCTS_ESPEASY_EVENTSTRUCT_H diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp index 94dae3ad6c..11237d25ef 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.cpp @@ -3,24 +3,26 @@ #ifdef USES_ESPEASY_NOW +ESPEasy_Now_MQTT_queue_check_packet::ESPEasy_Now_MQTT_queue_check_packet() {} + void ESPEasy_Now_MQTT_queue_check_packet::markSendTime() { _millis_out = millis(); - state = QueueState::Unset; + state = ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; } void ESPEasy_Now_MQTT_queue_check_packet::setState(bool isFull) { - state = isFull ? QueueState::Full : QueueState::Empty; + state = isFull ? ESPEasy_Now_MQTT_QueueCheckState::Enum::Full : ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty; } bool ESPEasy_Now_MQTT_queue_check_packet::isFull() const { - return state == QueueState::Full; + return state == ESPEasy_Now_MQTT_QueueCheckState::Enum::Full; } bool ESPEasy_Now_MQTT_queue_check_packet::isSet() const { - return state != QueueState::Unset; + return state != ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; } #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h index b381e41abd..9d267bfeba 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h @@ -4,19 +4,14 @@ #include #include "../Globals/ESPEasy_now_state.h" -#include "../../ESPEasy_common.h" +#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" + #ifdef USES_ESPEASY_NOW class ESPEasy_Now_MQTT_queue_check_packet { public: - enum class QueueState : uint8_t { - Unset, - Empty, - Full - }; - - ESPEasy_Now_MQTT_queue_check_packet() {} + ESPEasy_Now_MQTT_queue_check_packet(); void setState(bool isFull); @@ -27,7 +22,7 @@ class ESPEasy_Now_MQTT_queue_check_packet { void markSendTime(); unsigned long _millis_out = millis(); - QueueState state = QueueState::Unset; + ESPEasy_Now_MQTT_QueueCheckState::Enum state = ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; }; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index a4c9b47844..076b8d72e5 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -1,6 +1,5 @@ #include "../DataStructs/ESPEasy_Now_NTP_query.h" -#ifdef USES_ESPEASY_NOW // Typical time wander for ESP nodes is 0.04 ms/sec @@ -12,10 +11,10 @@ # define MINIMUM_TIME_BETWEEN_UPDATES (1800 * 1000) // Half an hour +# include "../DataStructs/MAC_address.h" # include "../ESPEasyCore/ESPEasy_Log.h" # include "../Globals/ESPEasy_time.h" # include "../Helpers/ESPEasy_time_calc.h" -# include "../../ESPEasy_fdwdecl.h" ESPEasy_Now_NTP_query::ESPEasy_Now_NTP_query() { @@ -99,8 +98,8 @@ void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, return; } } - bool updated = false; - unsigned long expectedWander_ms = + bool updated = false; + const unsigned long expectedWander_ms = computeExpectedWander(timeSource, timePassedSinceLastTimeSync); // First check if it matches the current best candidate. @@ -269,5 +268,3 @@ bool ESPEasy_Now_NTP_query::processReply(const ESPEasy_Now_NTP_query& received, reset(true); return true; } - -#endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index e9a689d3d5..3d928ddece 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -2,14 +2,13 @@ #define DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H #include +#include #include "../Globals/ESPEasy_now_state.h" -#include "../../ESPEasy_common.h" -#ifdef USES_ESPEASY_NOW -# include "../Helpers/ESPEasy_time.h" -# include "../DataStructs/MAC_address.h" +#include "../DataTypes/ESPEasyTimeSource.h" +class MAC_address; class ESPEasy_Now_NTP_query { public: @@ -55,6 +54,4 @@ class ESPEasy_Now_NTP_query { uint8_t _mac_prev_fail[6] = { 0 }; }; -#endif // ifdef USES_ESPEASY_NOW - #endif // DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H diff --git a/src/src/DataStructs/ESPEasy_Now_p2p_data.h b/src/src/DataStructs/ESPEasy_Now_p2p_data.h index e74b1eeb20..f351a64d97 100644 --- a/src/src/DataStructs/ESPEasy_Now_p2p_data.h +++ b/src/src/DataStructs/ESPEasy_Now_p2p_data.h @@ -5,6 +5,8 @@ #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" +#include "../DataTypes/PluginID.h" +#include "../DataTypes/TaskIndex.h" #include "../Globals/Plugins.h" #define ESPEASY_NOW_P2P_DATA_VERSION 1 diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index ab8bf9fa3f..2f672e2678 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -1,13 +1,12 @@ -#include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_Now_packet.h" -#ifdef USES_ESPEASY_NOW - -# include "../../ESPEasy_fdwdecl.h" +# include "../DataStructs/ESPEasy_now_hdr.h" # include "../Helpers/CRC_functions.h" # include "../Helpers/Memory.h" # define ESPEASY_NOW_MAX_PACKET_SIZE 200 +#ifdef USES_ESPEASY_NOW ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { @@ -245,5 +244,4 @@ const uint8_t * ESPEasy_Now_packet::begin() const return &_buf[sizeof(ESPEasy_now_hdr)]; } - -#endif // ifdef USES_ESPEASY_NOW +#endif // ifdef USES_ESPEASY_NOW \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index aa2532fcb8..fa4f72ed73 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -1,18 +1,21 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_INCOMING_H -#define DATASTRUCTS_ESPEASY_NOW_INCOMING_H +#ifndef DATASTRUCTS_ESPEASY_NOW_PACKET_H +#define DATASTRUCTS_ESPEASY_NOW_PACKET_H #include #include "../Globals/ESPEasy_now_state.h" #include "../../ESPEasy_common.h" +#include "../DataStructs/MAC_address.h" + + +#include +#include +#include + #ifdef USES_ESPEASY_NOW -# include "../DataStructs/MAC_address.h" -# include "../DataStructs/ESPEasy_now_hdr.h" +class ESPEasy_now_hdr; -# include -# include -# include class ESPEasy_Now_packet { public: @@ -107,7 +110,7 @@ typedef std::list ESPEasy_Now_packet_list; typedef std::map ESPEasy_Now_packet_map; - #endif // ifdef USES_ESPEASY_NOW -#endif // DATASTRUCTS_ESPEASY_NOW_INCOMING_H + +#endif // DATASTRUCTS_ESPEASY_NOW_PACKET_H diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 6cdd44dc77..5fe9d6e375 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -123,12 +123,12 @@ const ESPEasy_now_traceroute_struct& ESPEasy_now_Node_statistics_t::discoveryRou return discovery_route; } -ESPEasy_Now_MQTT_queue_check_packet::QueueState ESPEasy_now_Node_statistics_t::getMQTTQueueState() const +ESPEasy_Now_MQTT_QueueCheckState::Enum ESPEasy_now_Node_statistics_t::getMQTTQueueState() const { return mqtt_queue_state; } -void ESPEasy_now_Node_statistics_t::setMQTTQueueState(ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +void ESPEasy_now_Node_statistics_t::setMQTTQueueState(ESPEasy_Now_MQTT_QueueCheckState::Enum state) { mqtt_queue_state = state; } diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.h b/src/src/DataStructs/ESPEasy_now_Node_statistics.h index 599a849cd0..986c630b5a 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.h +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.h @@ -3,6 +3,8 @@ #include "../../ESPEasy_common.h" +#ifdef USES_ESPEASY_NOW + #include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" #include "../DataStructs/ESPEasy_now_traceroute.h" @@ -10,7 +12,6 @@ #define ESPEASY_NOW_NODE_STATISTICS_NR_ROUTES 3 -#ifdef USES_ESPEASY_NOW struct ESPEasy_now_Node_statistics_t { unsigned long getAge() const; @@ -32,9 +33,9 @@ struct ESPEasy_now_Node_statistics_t { const ESPEasy_now_traceroute_struct& discoveryRoute() const; - ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState() const; + ESPEasy_Now_MQTT_QueueCheckState::Enum getMQTTQueueState() const; - void setMQTTQueueState(ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + void setMQTTQueueState(ESPEasy_Now_MQTT_QueueCheckState::Enum state); private: @@ -50,7 +51,7 @@ struct ESPEasy_now_Node_statistics_t { // Increase on success, decrease on fail, with limits of 255 and 0. uint8_t success_rate = 127; - ESPEasy_Now_MQTT_queue_check_packet::QueueState mqtt_queue_state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; + ESPEasy_Now_MQTT_QueueCheckState::Enum mqtt_queue_state = ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; }; typedef std::map ESPEasy_now_Node_statisticsMap; diff --git a/src/src/DataStructs/ESPEasy_now_hdr.cpp b/src/src/DataStructs/ESPEasy_now_hdr.cpp index f27f32f769..f769ce1620 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.cpp +++ b/src/src/DataStructs/ESPEasy_now_hdr.cpp @@ -29,6 +29,11 @@ ESPEasy_now_hdr::ESPEasy_now_hdr(const uint8_t *buf) memcpy(this, buf, sizeof(ESPEasy_now_hdr)); } +ESPEasy_now_hdr::ESPEasy_now_hdr(const ESPEasy_now_hdr& other) +{ + *this = other; +} + ESPEasy_now_hdr& ESPEasy_now_hdr::operator=(const ESPEasy_now_hdr& other) { if (&other == this) { diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index bcba85e470..571eb8615e 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H -#define DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H +#ifndef DATASTRUCTS_ESPEASY_NOW_HDR_H +#define DATASTRUCTS_ESPEASY_NOW_HDR_H /*********************************************************************************************\ * ESPEasy_now_message_struct @@ -39,6 +39,8 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { ESPEasy_now_hdr(const uint8_t *buf); + ESPEasy_now_hdr(const ESPEasy_now_hdr& other); + ESPEasy_now_hdr& operator=(const ESPEasy_now_hdr& other); @@ -53,4 +55,4 @@ class __attribute__((__packed__)) ESPEasy_now_hdr { #endif // ifdef USES_ESPEASY_NOW -#endif // DATASTRUCTS_ESPEASY_NOW_MESSAGE_HEADER_STRUCT_H +#endif // DATASTRUCTS_ESPEASY_NOW_HDR_H diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 358ad3e316..6795defb66 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -1,12 +1,14 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_MERGER_H #define DATASTRUCTS_ESPEASY_NOW_MERGER_H -#include "../DataStructs/ESPEasy_Now_packet.h" #include "../../ESPEasy_common.h" +#include "../DataStructs/ESPEasy_now_hdr.h" +#include "../DataStructs/ESPEasy_Now_packet.h" +#include "../DataStructs/MAC_address.h" -#ifdef USES_ESPEASY_NOW +#include -# include "../DataStructs/MAC_address.h" +#ifdef USES_ESPEASY_NOW // Class to process all incoming messages from a single sender. // One or more packets form a complete message. diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index dbb866aa88..4a7cf95aa9 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -4,6 +4,7 @@ # include "../ESPEasyCore/ESPEasy_Log.h" # include "../ESPEasyCore/ESPEasyWifi.h" +# include "../DataStructs/ESPEasy_now_hdr.h" # include "../DataStructs/TimingStats.h" # include "../Globals/Nodes.h" # include "../Globals/Settings.h" diff --git a/src/src/DataStructs/ESPEasy_now_splitter.h b/src/src/DataStructs/ESPEasy_now_splitter.h index 91d35d9dfb..9f94cdb992 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.h +++ b/src/src/DataStructs/ESPEasy_now_splitter.h @@ -1,11 +1,13 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_SPLITTER_H #define DATASTRUCTS_ESPEASY_NOW_SPLITTER_H -#include "../DataStructs/ESPEasy_Now_packet.h" #include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW +# include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_now_hdr.h" + # include "../Globals/ESPEasy_now_peermanager.h" class ESPEasy_now_splitter { diff --git a/src/src/DataStructs/ESPEasy_packed_raw_data.h b/src/src/DataStructs/ESPEasy_packed_raw_data.h index 2512c11e84..9cf4c97929 100644 --- a/src/src/DataStructs/ESPEasy_packed_raw_data.h +++ b/src/src/DataStructs/ESPEasy_packed_raw_data.h @@ -1,5 +1,5 @@ -#ifndef ESPEASY_PACKED_RAW_DATA_H -#define ESPEASY_PACKED_RAW_DATA_H +#ifndef DATASTRUCT_ESPEASY_PACKED_RAW_DATA_H +#define DATASTRUCT_ESPEASY_PACKED_RAW_DATA_H #include "../../ESPEasy_common.h" @@ -80,4 +80,4 @@ String LoRa_addInt(uint64_t value, PackedData_enum datatype); String LoRa_addFloat(float value, PackedData_enum datatype); -#endif // ESPEASY_PACKED_RAW_DATA_H +#endif // DATASTRUCT_ESPEASY_PACKED_RAW_DATA_H diff --git a/src/src/DataStructs/ExtendedControllerCredentialsStruct.h b/src/src/DataStructs/ExtendedControllerCredentialsStruct.h index 4df65733a3..e83e5c0fa5 100644 --- a/src/src/DataStructs/ExtendedControllerCredentialsStruct.h +++ b/src/src/DataStructs/ExtendedControllerCredentialsStruct.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_EXTENDED_SECURITYSTRUCT_H -#define DATASTRUCTS_EXTENDED_SECURITYSTRUCT_H +#ifndef DATASTRUCTS_EXTENDED_CONTROLLERCREDENTIALSSTRUCT_H +#define DATASTRUCTS_EXTENDED_CONTROLLERCREDENTIALSSTRUCT_H #include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" @@ -32,4 +32,4 @@ struct ExtendedControllerCredentialsStruct -#endif // DATASTRUCTS_EXTENDED_SECURITYSTRUCT_H \ No newline at end of file +#endif // DATASTRUCTS_EXTENDED_CONTROLLERCREDENTIALSSTRUCT_H diff --git a/src/src/DataStructs/I2CTypes.h b/src/src/DataStructs/I2CTypes.h index 1fa8c24ffc..ee9760cd74 100644 --- a/src/src/DataStructs/I2CTypes.h +++ b/src/src/DataStructs/I2CTypes.h @@ -1,5 +1,5 @@ -#ifndef I2C_TYPES_H -#define I2C_TYPES_H I2C_TYPES_H +#ifndef DATASTRUCTS_I2C_TYPES_H +#define DATASTRUCTS_I2C_TYPES_H #include #include @@ -70,4 +70,4 @@ const __FlashStringHelper * toString(I2C_bus_state state); -#endif // I2C_TYPES_H +#endif // DATASTRUCTS_I2C_TYPES_H diff --git a/src/src/DataStructs/MAC_address.cpp b/src/src/DataStructs/MAC_address.cpp index f5f0bd019f..b3d9c15cf7 100644 --- a/src/src/DataStructs/MAC_address.cpp +++ b/src/src/DataStructs/MAC_address.cpp @@ -10,6 +10,13 @@ MAC_address::MAC_address(const uint8_t new_mac[6]) memcpy(mac, new_mac, 6); } +MAC_address::MAC_address(const MAC_address& other) +{ + for (int i = 0; i < 6; ++i) { + mac[i] = other.mac[i]; + } +} + MAC_address& MAC_address::operator=(const MAC_address& other) { for (int i = 0; i < 6; ++i) { diff --git a/src/src/DataStructs/MAC_address.h b/src/src/DataStructs/MAC_address.h index 47d5120aa5..3d2e2fed29 100644 --- a/src/src/DataStructs/MAC_address.h +++ b/src/src/DataStructs/MAC_address.h @@ -11,6 +11,8 @@ class __attribute__((__packed__)) MAC_address { MAC_address(const uint8_t new_mac[6]); + MAC_address(const MAC_address& other); + MAC_address& operator=(const MAC_address& other); bool operator==(const MAC_address& other) const { diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h index 5a19f6b083..90bcfd269e 100644 --- a/src/src/DataStructs/MessageRouteInfo.h +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_UNITMESSAGECOUNT_H -#define DATASTRUCTS_UNITMESSAGECOUNT_H +#ifndef DATASTRUCTS_MESSAGEROUTEINFO_H +#define DATASTRUCTS_MESSAGEROUTEINFO_H #include "../../ESPEasy_common.h" @@ -68,4 +68,4 @@ struct UnitMessageRouteInfo_map { std::map _map; }; -#endif // ifndef DATASTRUCTS_UNITMESSAGECOUNT_H +#endif // ifndef DATASTRUCTS_MESSAGEROUTEINFO_H diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 51644f74f5..2c6b7ad40b 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -625,17 +625,17 @@ uint8_t NodesHandler::getSuccessRate(uint8_t unit) const return 127; } -ESPEasy_Now_MQTT_queue_check_packet::QueueState NodesHandler::getMQTTQueueState(uint8_t unit) const +ESPEasy_Now_MQTT_QueueCheckState::Enum NodesHandler::getMQTTQueueState(uint8_t unit) const { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { return it->second.getMQTTQueueState(); } - return ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset; + return ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; } -void NodesHandler::setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +void NodesHandler::setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_QueueCheckState::Enum state) { auto it = _nodeStats.find(unit); if (it != _nodeStats.end()) { @@ -643,7 +643,7 @@ void NodesHandler::setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_queue_check_ } } -void NodesHandler::setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_queue_check_packet::QueueState state) +void NodesHandler::setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_QueueCheckState::Enum state) { const NodeStruct * node = getNodeByMac(mac); if (node != nullptr) { diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index 008d9b8ad1..73da3bdd7e 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -9,9 +9,12 @@ #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_now_traceroute.h" # include "../DataStructs/ESPEasy_now_Node_statistics.h" +# include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" # include "../Globals/ESPEasy_now_peermanager.h" #endif // ifdef USES_ESPEASY_NOW +#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" + #include "../Helpers/ESPEasyMutex.h" @@ -101,12 +104,12 @@ class NodesHandler { uint8_t getSuccessRate(uint8_t unit) const; - ESPEasy_Now_MQTT_queue_check_packet::QueueState getMQTTQueueState(uint8_t unit) const; + ESPEasy_Now_MQTT_QueueCheckState::Enum getMQTTQueueState(uint8_t unit) const; void setMQTTQueueState(uint8_t unit, - ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + ESPEasy_Now_MQTT_QueueCheckState::Enum state); void setMQTTQueueState(const MAC_address & mac, - ESPEasy_Now_MQTT_queue_check_packet::QueueState state); + ESPEasy_Now_MQTT_QueueCheckState::Enum state); #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index 960aa90791..93b8f53101 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -1,11 +1,11 @@ #include "../DataStructs/SettingsStruct.h" -#include "../Globals/Plugins.h" -#include "../Globals/CPlugins.h" +#include "../../ESPEasy_common.h" #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../DataTypes/SPI_options.h" -#include "../../ESPEasy_common.h" +#include "../Globals/Plugins.h" +#include "../Globals/CPlugins.h" #ifndef DATASTRUCTS_SETTINGSSTRUCT_CPP #define DATASTRUCTS_SETTINGSSTRUCT_CPP diff --git a/src/src/DataStructs/Web_StreamingBuffer.h b/src/src/DataStructs/Web_StreamingBuffer.h index 7757669a71..7ff47f96b8 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.h +++ b/src/src/DataStructs/Web_StreamingBuffer.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_TXBUFFER_STRUCT_H -#define DATASTRUCTS_TXBUFFER_STRUCT_H +#ifndef DATASTRUCTS_WEB_STREAMINGBUFFER_H +#define DATASTRUCTS_WEB_STREAMINGBUFFER_H #include #include "../../ESPEasy_common.h" @@ -86,4 +86,4 @@ class Web_StreamingBuffer { }; -#endif // DATASTRUCTS_TXBUFFER_STRUCT_H +#endif // DATASTRUCTS_WEB_STREAMINGBUFFER_H diff --git a/src/src/DataTypes/CPluginID.h b/src/src/DataTypes/CPluginID.h index 075a9a6d24..b9fc144df4 100644 --- a/src/src/DataTypes/CPluginID.h +++ b/src/src/DataTypes/CPluginID.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_CPLUGINID_H -#define DATASTRUCTS_CPLUGINID_H +#ifndef DATATYPES_CPLUGINID_H +#define DATATYPES_CPLUGINID_H #include @@ -9,4 +9,4 @@ typedef uint8_t cpluginID_t; extern cpluginID_t INVALID_C_PLUGIN_ID; -#endif // ifndef DATASTRUCTS_CPLUGINID_H +#endif // ifndef DATATYPES_CPLUGINID_H diff --git a/src/src/DataTypes/ControllerIndex.h b/src/src/DataTypes/ControllerIndex.h index 75f7db59b7..dc219a6fa3 100644 --- a/src/src/DataTypes/ControllerIndex.h +++ b/src/src/DataTypes/ControllerIndex.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_CONTROLLERINDEX_H -#define DATASTRUCTS_CONTROLLERINDEX_H +#ifndef DATATYPES_CONTROLLERINDEX_H +#define DATATYPES_CONTROLLERINDEX_H #include diff --git a/src/src/DataTypes/DeviceIndex.cpp b/src/src/DataTypes/DeviceIndex.cpp index 1141c88e8f..64869e5531 100644 --- a/src/src/DataTypes/DeviceIndex.cpp +++ b/src/src/DataTypes/DeviceIndex.cpp @@ -2,4 +2,4 @@ #include "../CustomBuild/ESPEasyLimits.h" -deviceIndex_t INVALID_DEVICE_INDEX = PLUGIN_MAX; \ No newline at end of file +deviceIndex_t INVALID_DEVICE_INDEX = PLUGIN_MAX; diff --git a/src/src/DataTypes/DeviceIndex.h b/src/src/DataTypes/DeviceIndex.h index a2bfa4d2e0..d3d693613b 100644 --- a/src/src/DataTypes/DeviceIndex.h +++ b/src/src/DataTypes/DeviceIndex.h @@ -1,12 +1,10 @@ -#ifndef DATASTRUCT_DEVICEINDEX_H -#define DATASTRUCT_DEVICEINDEX_H +#ifndef DATATYPES_DEVICEINDEX_H +#define DATATYPES_DEVICEINDEX_H #include -typedef uint8_t deviceIndex_t; +typedef uint8_t deviceIndex_t; +extern deviceIndex_t INVALID_DEVICE_INDEX; -extern deviceIndex_t INVALID_DEVICE_INDEX; - - -#endif \ No newline at end of file +#endif // ifndef DATATYPES_DEVICEINDEX_H diff --git a/src/src/DataTypes/DeviceModel.h b/src/src/DataTypes/DeviceModel.h index 4649359a45..a55fb8df57 100644 --- a/src/src/DataTypes/DeviceModel.h +++ b/src/src/DataTypes/DeviceModel.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_DEVICEMODEL_H -#define DATASTRUCTS_DEVICEMODEL_H +#ifndef DATATYPES_DEVICEMODEL_H +#define DATATYPES_DEVICEMODEL_H /********************************************************************************************\ Pre defined settings for off-the-shelf hardware @@ -32,4 +32,4 @@ enum class DeviceModel : uint8_t { }; -#endif // DATASTRUCTS_DEVICEMODEL_H \ No newline at end of file +#endif // DATATYPES_DEVICEMODEL_H \ No newline at end of file diff --git a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.cpp b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.cpp new file mode 100644 index 0000000000..3d9c985b77 --- /dev/null +++ b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.cpp @@ -0,0 +1 @@ +#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" diff --git a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h new file mode 100644 index 0000000000..d62d866859 --- /dev/null +++ b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h @@ -0,0 +1,16 @@ +#ifndef DATATYPES_ESPEASY_NOW_MQTT_QUEUE_CHECK_STATE_H +#define DATATYPES_ESPEASY_NOW_MQTT_QUEUE_CHECK_STATE_H + + +#include +#include + +struct ESPEasy_Now_MQTT_QueueCheckState { + enum Enum : uint8_t { + Unset = 0, + Empty = 1, + Full = 2 + }; +}; + +#endif diff --git a/src/src/DataTypes/ESPEasy_plugin_functions.h b/src/src/DataTypes/ESPEasy_plugin_functions.h index 911c49bb39..a6addb6bec 100644 --- a/src/src/DataTypes/ESPEasy_plugin_functions.h +++ b/src/src/DataTypes/ESPEasy_plugin_functions.h @@ -1,5 +1,5 @@ -#ifndef ESPEASY_PLUGIN_DEFS_H -#define ESPEASY_PLUGIN_DEFS_H +#ifndef DATATYPES_ESPEASY_PLUGIN_DEFS_H +#define DATATYPES_ESPEASY_PLUGIN_DEFS_H // ******************************************************************************** @@ -105,4 +105,4 @@ class NPlugin { }; -#endif // ESPEASY_PLUGIN_DEFS_H +#endif // DATATYPES_ESPEASY_PLUGIN_DEFS_H diff --git a/src/src/DataTypes/NPluginID.cpp b/src/src/DataTypes/NPluginID.cpp new file mode 100644 index 0000000000..f4ee3a195c --- /dev/null +++ b/src/src/DataTypes/NPluginID.cpp @@ -0,0 +1,3 @@ +#include "../DataTypes/NPluginID.h" + +npluginID_t INVALID_N_PLUGIN_ID = 0; diff --git a/src/src/DataTypes/NPluginID.h b/src/src/DataTypes/NPluginID.h new file mode 100644 index 0000000000..9dc6abd749 --- /dev/null +++ b/src/src/DataTypes/NPluginID.h @@ -0,0 +1,12 @@ +#ifndef DATATYPES_NPLUGINID_H +#define DATATYPES_NPLUGINID_H + +#include + + +typedef uint8_t npluginID_t; + +extern npluginID_t INVALID_N_PLUGIN_ID; + + +#endif // ifndef DATATYPES_NPLUGINID_H diff --git a/src/src/DataTypes/NetworkMedium.h b/src/src/DataTypes/NetworkMedium.h index 63e21ad6fc..603c47dc72 100644 --- a/src/src/DataTypes/NetworkMedium.h +++ b/src/src/DataTypes/NetworkMedium.h @@ -1,5 +1,5 @@ -#ifndef ESPEASY_WTH_WIFI_H_ -#define ESPEASY_WTH_WIFI_H_ +#ifndef DATATYPES_NETWORKMEDIUM_H +#define DATATYPES_NETWORKMEDIUM_H #include @@ -16,4 +16,4 @@ bool isValid(NetworkMedium_t medium); const __FlashStringHelper * toString(NetworkMedium_t medium); -#endif // ESPEASY_WTH_WIFI_H_ +#endif // DATATYPES_NETWORKMEDIUM_H diff --git a/src/src/DataTypes/NotifierIndex.cpp b/src/src/DataTypes/NotifierIndex.cpp new file mode 100644 index 0000000000..cb22d0f51c --- /dev/null +++ b/src/src/DataTypes/NotifierIndex.cpp @@ -0,0 +1,5 @@ +#include "../DataTypes/NotifierIndex.h" + +#include "../CustomBuild/ESPEasyLimits.h" + +notifierIndex_t INVALID_NOTIFIER_INDEX = NOTIFICATION_MAX; diff --git a/src/src/DataTypes/NotifierIndex.h b/src/src/DataTypes/NotifierIndex.h new file mode 100644 index 0000000000..c747ac453a --- /dev/null +++ b/src/src/DataTypes/NotifierIndex.h @@ -0,0 +1,10 @@ +#ifndef DATATYPES_NOTIFIERINDEX_H +#define DATATYPES_NOTIFIERINDEX_H + +#include + +typedef uint8_t notifierIndex_t; + +extern notifierIndex_t INVALID_NOTIFIER_INDEX; + +#endif // ifndef DATATYPES_NOTIFIERINDEX_H diff --git a/src/src/DataTypes/PluginID.cpp b/src/src/DataTypes/PluginID.cpp index 72302df71f..832943791f 100644 --- a/src/src/DataTypes/PluginID.cpp +++ b/src/src/DataTypes/PluginID.cpp @@ -1,3 +1,3 @@ #include "../DataTypes/PluginID.h" -pluginID_t INVALID_PLUGIN_ID = 0; \ No newline at end of file +pluginID_t INVALID_PLUGIN_ID = 0; diff --git a/src/src/DataTypes/PluginID.h b/src/src/DataTypes/PluginID.h index 48e4b6be42..a4e71c1002 100644 --- a/src/src/DataTypes/PluginID.h +++ b/src/src/DataTypes/PluginID.h @@ -3,8 +3,8 @@ #include -typedef uint8_t pluginID_t; +typedef uint8_t pluginID_t; -extern pluginID_t INVALID_PLUGIN_ID; +extern pluginID_t INVALID_PLUGIN_ID; -#endif \ No newline at end of file +#endif // ifndef DATASTRUCT_PLUGINID_H diff --git a/src/src/DataTypes/ProtocolIndex.h b/src/src/DataTypes/ProtocolIndex.h index 9167f3546f..accbd429b1 100644 --- a/src/src/DataTypes/ProtocolIndex.h +++ b/src/src/DataTypes/ProtocolIndex.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_PROTOCOLINDEX_H -#define DATASTRUCTS_PROTOCOLINDEX_H +#ifndef DATATYPES_PROTOCOLINDEX_H +#define DATATYPES_PROTOCOLINDEX_H #include diff --git a/src/src/DataTypes/SPI_options.h b/src/src/DataTypes/SPI_options.h index a7e014c038..71b767e291 100644 --- a/src/src/DataTypes/SPI_options.h +++ b/src/src/DataTypes/SPI_options.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_SPI_OPTIONS_H -#define DATASTRUCTS_SPI_OPTIONS_H +#ifndef DATATYPES_SPI_OPTIONS_H +#define DATATYPES_SPI_OPTIONS_H #include @@ -15,4 +15,4 @@ const __FlashStringHelper* getSPI_optionToString(SPI_Options_e option); const __FlashStringHelper* getSPI_optionToShortString(SPI_Options_e option); #endif // ifdef ESP32 -#endif // ifndef DATASTRUCTS_SPI_OPTIONS_H +#endif // ifndef DATATYPES_SPI_OPTIONS_H diff --git a/src/src/DataTypes/SettingsType.h b/src/src/DataTypes/SettingsType.h index 4e36589826..046f593a9e 100644 --- a/src/src/DataTypes/SettingsType.h +++ b/src/src/DataTypes/SettingsType.h @@ -1,5 +1,5 @@ -#ifndef DATASTRUCTS_SETTINGSTYPE_H -#define DATASTRUCTS_SETTINGSTYPE_H +#ifndef DATATYPES_SETTINGSTYPE_H +#define DATATYPES_SETTINGSTYPE_H #include "../../ESPEasy_common.h" @@ -53,4 +53,4 @@ class SettingsType { }; -#endif // DATASTRUCTS_SETTINGSTYPE_H +#endif // DATATYPES_SETTINGSTYPE_H diff --git a/src/src/DataTypes/TaskIndex.cpp b/src/src/DataTypes/TaskIndex.cpp index 7f68f61258..f2ebea9167 100644 --- a/src/src/DataTypes/TaskIndex.cpp +++ b/src/src/DataTypes/TaskIndex.cpp @@ -1,6 +1,6 @@ #include "../DataTypes/TaskIndex.h" - +#include "../../ESPEasy_common.h" taskIndex_t INVALID_TASK_INDEX = TASKS_MAX; userVarIndex_t INVALID_USERVAR_INDEX = USERVAR_MAX_INDEX; diff --git a/src/src/DataTypes/TaskIndex.h b/src/src/DataTypes/TaskIndex.h index 610e94c6b6..cefc8f73cf 100644 --- a/src/src/DataTypes/TaskIndex.h +++ b/src/src/DataTypes/TaskIndex.h @@ -1,12 +1,8 @@ -#ifndef DATASTRUCT_TASKINDEX_H -#define DATASTRUCT_TASKINDEX_H +#ifndef DATATYPES_TASKINDEX_H +#define DATATYPES_TASKINDEX_H #include -#include "../CustomBuild/ESPEasyLimits.h" - -#define USERVAR_MAX_INDEX (VARS_PER_TASK * TASKS_MAX) - typedef uint8_t taskIndex_t; typedef uint16_t userVarIndex_t; typedef uint16_t taskVarIndex_t; @@ -16,4 +12,4 @@ extern userVarIndex_t INVALID_USERVAR_INDEX; extern taskVarIndex_t INVALID_TASKVAR_INDEX; -#endif // ifndef DATASTRUCT_TASKINDEX_H +#endif // ifndef DATATYPES_TASKINDEX_H diff --git a/src/src/Globals/ESPEasy_now_handler.h b/src/src/Globals/ESPEasy_now_handler.h index e259904b65..af0733a00f 100644 --- a/src/src/Globals/ESPEasy_now_handler.h +++ b/src/src/Globals/ESPEasy_now_handler.h @@ -1,15 +1,14 @@ -#ifndef GLOBALS_ESPEASY_NOW_H -#define GLOBALS_ESPEASY_NOW_H +#ifndef GLOBALS_ESPEASY_NOW_HANDLER_H +#define GLOBALS_ESPEASY_NOW_HANDLER_H #include "../../ESPEasy_common.h" -#ifdef USES_ESPEASY_NOW +#include "../Helpers/ESPEasy_now_handler.h" -# include "../Helpers/ESPEasy_now_handler.h" +#ifdef USES_ESPEASY_NOW extern ESPEasy_now_handler_t ESPEasy_now_handler; - #endif // ifdef USES_ESPEASY_NOW -#endif // GLOBALS_ESPEASY_NOW_H +#endif // ifndef GLOBALS_ESPEASY_NOW_HANDLER_H diff --git a/src/src/Globals/ESPEasy_now_peermanager.h b/src/src/Globals/ESPEasy_now_peermanager.h index 10b64be740..6f0452f16b 100644 --- a/src/src/Globals/ESPEasy_now_peermanager.h +++ b/src/src/Globals/ESPEasy_now_peermanager.h @@ -1,5 +1,5 @@ -#ifndef GLOBALS_ESPEASY_NOW_H -#define GLOBALS_ESPEASY_NOW_H +#ifndef GLOBALS_ESPEASY_NOW_PEERMANAGER_H +#define GLOBALS_ESPEASY_NOW_PEERMANAGER_H #include "../../ESPEasy_common.h" @@ -12,4 +12,4 @@ extern ESPEasy_now_peermanager_t ESPEasy_now_peermanager; #endif // ifdef USES_ESPEASY_NOW -#endif // GLOBALS_ESPEASY_NOW_H +#endif // GLOBALS_ESPEASY_NOW_PEERMANAGER_H diff --git a/src/src/Globals/NPlugins.cpp b/src/src/Globals/NPlugins.cpp index 05ca1abea4..940a50d2c9 100644 --- a/src/src/Globals/NPlugins.cpp +++ b/src/src/Globals/NPlugins.cpp @@ -1,12 +1,11 @@ #include "../Globals/NPlugins.h" + #include "../DataStructs/NotificationStruct.h" #include "../Globals/Settings.h" nprotocolIndex_t INVALID_NPROTOCOL_INDEX = NPLUGIN_MAX; -notifierIndex_t INVALID_NOTIFIER_INDEX = NOTIFICATION_MAX; -npluginID_t INVALID_N_PLUGIN_ID = 0; boolean (*NPlugin_ptr[NPLUGIN_MAX])(NPlugin::Function, @@ -66,3 +65,4 @@ nprotocolIndex_t getNProtocolIndex_from_NotifierIndex(notifierIndex_t index) { } return INVALID_NPROTOCOL_INDEX; } + diff --git a/src/src/Globals/NPlugins.h b/src/src/Globals/NPlugins.h index 38f4e659e0..eb34a771f1 100644 --- a/src/src/Globals/NPlugins.h +++ b/src/src/Globals/NPlugins.h @@ -1,21 +1,22 @@ #ifndef GLOBALS_NPLUGIN_H #define GLOBALS_NPLUGIN_H -#include -#include +#include "../../ESPEasy_common.h" + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/NotificationStruct.h" #include "../DataStructs/NotificationSettingsStruct.h" #include "../DataTypes/ESPEasy_plugin_functions.h" +#include "../DataTypes/NotifierIndex.h" +#include "../DataTypes/NPluginID.h" +#include +#include +#include typedef uint8_t nprotocolIndex_t; -typedef uint8_t notifierIndex_t; -typedef uint8_t npluginID_t; extern nprotocolIndex_t INVALID_NPROTOCOL_INDEX; -extern notifierIndex_t INVALID_NOTIFIER_INDEX; -extern npluginID_t INVALID_N_PLUGIN_ID; extern boolean (*NPlugin_ptr[NPLUGIN_MAX])(NPlugin::Function, @@ -39,5 +40,4 @@ String getNPluginNameFromNotifierIndex(notifierIndex_t NotifierIndex); nprotocolIndex_t getNProtocolIndex(npluginID_t Number); nprotocolIndex_t getNProtocolIndex_from_NotifierIndex(notifierIndex_t index); - #endif // GLOBALS_NPLUGIN_H diff --git a/src/src/Globals/Plugins.h b/src/src/Globals/Plugins.h index 053c9560f4..a04919e13f 100644 --- a/src/src/Globals/Plugins.h +++ b/src/src/Globals/Plugins.h @@ -1,16 +1,16 @@ #ifndef GLOBALS_PLUGIN_H #define GLOBALS_PLUGIN_H +#include "../../ESPEasy_common.h" + #include #include #include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataTypes/PluginID.h" #include "../DataTypes/DeviceIndex.h" #include "../DataTypes/TaskIndex.h" -#include "../../ESPEasy_common.h" /********************************************************************************************\ @@ -41,7 +41,7 @@ - USERVAR_MAX_INDEX = (TASKS_MAX * VARS_PER_TASK) \*********************************************************************************************/ - +struct EventStruct; extern int deviceCount; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index e9418e6118..b5086c0fee 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1,14 +1,21 @@ #include "../Helpers/ESPEasy_now_handler.h" -#ifdef USES_ESPEASY_NOW -# include "../../ESPEasy_fdwdecl.h" # include "../ControllerQueue/MQTT_queue_element.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" +# include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" +# include "../DataStructs/ESPEasy_now_hdr.h" +# include "../DataStructs/ESPEasy_now_merger.h" # include "../DataStructs/ESPEasy_Now_packet.h" +# include "../DataStructs/ESPEasy_Now_p2p_data.h" # include "../DataStructs/ESPEasy_now_splitter.h" +# include "../DataStructs/ESPEasy_now_traceroute.h" +# include "../DataStructs/ESPEasy_Now_NTP_query.h" +# include "../DataStructs/MessageRouteInfo.h" +# include "../DataStructs/MAC_address.h" # include "../DataStructs/NodeStruct.h" # include "../DataStructs/TimingStats.h" +# include "../DataStructs/WiFi_AP_Candidate.h" # include "../ESPEasyCore/Controller.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../ESPEasyCore/ESPEasy_Log.h" @@ -32,6 +39,7 @@ # include +#ifdef USES_ESPEASY_NOW # define ESPEASY_NOW_ACTIVITY_TIMEOUT 125000 // 2 minutes + 5 sec # define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly @@ -94,6 +102,19 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t STOP_TIMER(RECEIVE_ESPEASY_NOW_LOOP); } +ESPEasy_now_handler_t::ESPEasy_now_handler_t() +{ + _best_NTP_candidate = new ESPEasy_Now_NTP_query(); +} + +ESPEasy_now_handler_t::~ESPEasy_now_handler_t() +{ + if (_best_NTP_candidate != nullptr) { + delete _best_NTP_candidate; + _best_NTP_candidate = nullptr; + } +} + bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } @@ -721,7 +742,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m } // Test to see if the discovery announce could be a good candidate for next NTP query. - _best_NTP_candidate.find_best_NTP( + _best_NTP_candidate->find_best_NTP( mac, static_cast(received.timeSource), received.lastUpdated); @@ -900,10 +921,10 @@ bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, void ESPEasy_now_handler_t::sendNTPquery() { - if (!_best_NTP_candidate.hasLowerWander()) { return; } + if (!_best_NTP_candidate->hasLowerWander()) { return; } MAC_address mac; - if (!_best_NTP_candidate.getMac(mac)) { return; } + if (!_best_NTP_candidate->getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F(ESPEASY_NOW_NAME ": Send NTP query to: "); @@ -911,7 +932,7 @@ void ESPEasy_now_handler_t::sendNTPquery() addLog(LOG_LEVEL_INFO, log); } - _best_NTP_candidate.markSendTime(); + _best_NTP_candidate->markSendTime(); ESPEasy_Now_NTP_query query; const size_t len = sizeof(ESPEasy_Now_NTP_query); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::NTP_Query, len); @@ -962,7 +983,7 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b } // Received a reply on our own query - return _best_NTP_candidate.processReply(query, message.getFirstPacketTimestamp()); + return _best_NTP_candidate->processReply(query, message.getFirstPacketTimestamp()); } // ************************************************************* @@ -1004,11 +1025,11 @@ bool ESPEasy_now_handler_t::sendToMQTT( } MAC_address mac = preferred->ESPEasy_Now_MAC(); switch (Nodes.getMQTTQueueState(preferred->unit)) { - case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset: - case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Full: + case ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset: + case ESPEasy_Now_MQTT_QueueCheckState::Enum::Full: ESPEasy_now_MQTT_check_queue.push_back(mac); return false; - case ESPEasy_Now_MQTT_queue_check_packet::QueueState::Empty: + case ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty: break; } @@ -1052,7 +1073,7 @@ bool ESPEasy_now_handler_t::sendToMQTT( case WifiEspNowSendStatus::NONE: case WifiEspNowSendStatus::FAIL: { - Nodes.setMQTTQueueState(preferred->unit, ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); + Nodes.setMQTTQueueState(preferred->unit, ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset); ESPEasy_now_MQTT_check_queue.push_back(mac); ++_send_failed_count; break; @@ -1137,7 +1158,7 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(controllerIndex_t contr bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address & mac, int channel, - ESPEasy_Now_MQTT_queue_check_packet::QueueState state) { + ESPEasy_Now_MQTT_QueueCheckState::Enum state) { ESPEasy_Now_MQTT_queue_check_packet query; query.state = state; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index c4fbdf95be..25f1db7c73 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -3,26 +3,25 @@ #include "../Globals/ESPEasy_now_state.h" -#ifdef USES_ESPEASY_NOW - -# include "../DataStructs/ESPEasy_now_hdr.h" -# include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" -# include "../DataStructs/ESPEasy_Now_packet.h" -# include "../DataStructs/ESPEasy_now_merger.h" -# include "../DataStructs/ESPEasy_Now_NTP_query.h" -# include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" -# include "../DataStructs/ESPEasy_Now_p2p_data.h" -# include "../DataStructs/ESPEasy_now_traceroute.h" -# include "../DataStructs/MAC_address.h" -# include "../DataStructs/MessageRouteInfo.h" -# include "../DataStructs/WiFi_AP_Candidate.h" -# include "../Globals/CPlugins.h" +#include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" +#include "../DataTypes/ControllerIndex.h" +#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" +#ifdef USES_ESPEASY_NOW +struct ESPEasy_Now_p2p_data; +class ESPEasy_now_merger; +struct ESPEasy_now_traceroute_struct; +struct MessageRouteInfo_t; +class MAC_address; +struct WiFi_AP_Candidate; +class ESPEasy_Now_NTP_query; class ESPEasy_now_handler_t { public: - ESPEasy_now_handler_t() {} + ESPEasy_now_handler_t(); + + ~ESPEasy_now_handler_t(); bool begin(); @@ -38,74 +37,87 @@ class ESPEasy_now_handler_t { void loop_process_ESPEasyNOW_send_queue(); - public: - bool active() const; + bool active() const; MAC_address getActiveESPEasyNOW_MAC() const; - void addPeerFromWiFiScan(); - void addPeerFromWiFiScan(const WiFi_AP_Candidate& peer); + void addPeerFromWiFiScan(); + void addPeerFromWiFiScan(const WiFi_AP_Candidate& peer); private: - bool processMessage(const ESPEasy_now_merger& message, bool& mustKeep); + bool processMessage(const ESPEasy_now_merger& message, + bool & mustKeep); public: // Send out the discovery announcement via broadcast. // This may be picked up by others void sendDiscoveryAnnounce(int channel = 0); - void sendDiscoveryAnnounce(const MAC_address& mac, int channel = 0); + void sendDiscoveryAnnounce(const MAC_address& mac, + int channel = 0); // Send trace route as 'connected' node void sendTraceRoute(); - - void sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); - void sendTraceRoute(const MAC_address& mac, const ESPEasy_now_traceroute_struct& traceRoute, int channel = 0); + + void sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, + int channel = 0); + void sendTraceRoute(const MAC_address & mac, + const ESPEasy_now_traceroute_struct& traceRoute, + int channel = 0); void sendNTPquery(); void sendNTPbroadcast(); - bool sendToMQTT(controllerIndex_t controllerIndex, - const String & topic, - const String & payload, - const MessageRouteInfo_t* messageRouteInfo); + bool sendToMQTT(controllerIndex_t controllerIndex, + const String & topic, + const String & payload, + const MessageRouteInfo_t *messageRouteInfo); bool sendMQTTCheckControllerQueue(controllerIndex_t controllerIndex); - bool sendMQTTCheckControllerQueue(const MAC_address& mac, - int channel, - ESPEasy_Now_MQTT_queue_check_packet::QueueState state = ESPEasy_Now_MQTT_queue_check_packet::QueueState::Unset); + bool sendMQTTCheckControllerQueue(const MAC_address & mac, + int channel, + ESPEasy_Now_MQTT_QueueCheckState::Enum state = ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset); void sendSendData_DuplicateCheck(uint32_t key, ESPEasy_Now_DuplicateCheck::message_t message_type, - const MAC_address& mac); + const MAC_address & mac); - bool sendESPEasyNow_p2p(controllerIndex_t controllerIndex, const MAC_address& mac, const ESPEasy_Now_p2p_data& data); + bool sendESPEasyNow_p2p(controllerIndex_t controllerIndex, + const MAC_address & mac, + const ESPEasy_Now_p2p_data& data); private: - bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_DiscoveryAnnounce(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_TraceRoute(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_TraceRoute(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_NTPquery(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_NTPquery(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_MQTTControllerMessage(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_SendData_DuplicateCheck(const ESPEasy_now_merger& message, + bool & mustKeep); - bool handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, bool& mustKeep); + bool handle_ESPEasyNow_p2p(const ESPEasy_now_merger& message, + bool & mustKeep); void load_ControllerSettingsCache(controllerIndex_t controllerIndex); - ESPEasy_Now_NTP_query _best_NTP_candidate; + ESPEasy_Now_NTP_query * _best_NTP_candidate = nullptr; - unsigned long _last_used = 0; + unsigned long _last_used = 0; unsigned long _last_started = 0; // Trace route is only sent by 'connected' nodes (distance = 0) @@ -116,14 +128,13 @@ class ESPEasy_now_handler_t { uint8_t _send_failed_count = 0; - unsigned int _ClientTimeout = 0; - uint8_t _usedWiFiChannel = 0; - uint8_t _lastScannedChannel = 0; + unsigned int _ClientTimeout = 0; + uint8_t _usedWiFiChannel = 0; + uint8_t _lastScannedChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; - bool _scanChannelsMode = true; - bool _enableESPEasyNowFallback = false; - bool _mqtt_retainFlag = false; - + bool _scanChannelsMode = true; + bool _enableESPEasyNowFallback = false; + bool _mqtt_retainFlag = false; }; diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index e9201c1635..0b1dd74419 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -12,6 +12,7 @@ #include "../ESPEasyCore/ESPEasyRules.h" #include "../Globals/GlobalMapPortStatus.h" #include "../Globals/RTC.h" +#include "../Globals/NPlugins.h" #include "../Helpers/DeepSleep.h" #include "../Helpers/ESPEasyRTC.h" #include "../Helpers/Networking.h" diff --git a/src/src/Helpers/Scheduler.h b/src/src/Helpers/Scheduler.h index 8b19a9dfcc..82ab1daa33 100644 --- a/src/src/Helpers/Scheduler.h +++ b/src/src/Helpers/Scheduler.h @@ -6,6 +6,7 @@ #include "../DataStructs/EventStructCommandWrapper.h" #include "../DataStructs/SystemTimerStruct.h" #include "../DataTypes/ProtocolIndex.h" +#include "../DataTypes/ESPEasy_plugin_functions.h" #include "../Helpers/msecTimerHandlerStruct.h" #include diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index 99763791d6..0426d1b76f 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -12,7 +12,6 @@ #include "../Helpers/ESPEasy_Storage.h" #include "../Globals/ESPEasy_Scheduler.h" -#include "../Globals/NPlugins.h" #include "../Globals/Settings.h" From d6f4f298c8c760686bb5c5aa27e1ac20c0ec9251 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 23 Jan 2022 21:16:38 +0100 Subject: [PATCH 216/404] Fix build error + upgrade I2Cdev.h library --- lib/I2Cdevlib/I2Cdev.cpp | 432 +++++++++++++++++++----------------- lib/I2Cdevlib/I2Cdev.h | 85 ++++--- lib/I2Cdevlib/library.json | 10 +- platformio_esp32_envs.ini | 2 +- platformio_esp82xx_base.ini | 2 +- src/_N001_Email.ino | 3 +- 6 files changed, 297 insertions(+), 237 deletions(-) diff --git a/lib/I2Cdevlib/I2Cdev.cpp b/lib/I2Cdevlib/I2Cdev.cpp index 21d4e18875..892274ba00 100644 --- a/lib/I2Cdevlib/I2Cdev.cpp +++ b/lib/I2Cdevlib/I2Cdev.cpp @@ -3,6 +3,9 @@ // 2013-06-05 by Jeff Rowberg // // Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument +// 2020-01-20 - hardija : complete support for Teensy 3.x +// 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications // 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan) // 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire @@ -44,11 +47,8 @@ THE SOFTWARE. */ #include "I2Cdev.h" -#if defined(ESP32) - #define BUFFER_LENGTH 32 -#endif -#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE #ifdef I2CDEV_IMPLEMENTATION_WARNINGS #if ARDUINO < 100 @@ -103,9 +103,9 @@ I2Cdev::I2Cdev() { * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout, void *wireObj) { uint8_t b; - uint8_t count = readByte(devAddr, regAddr, &b, timeout); + uint8_t count = readByte(devAddr, regAddr, &b, timeout, wireObj); *data = b & (1 << bitNum); return count; } @@ -118,9 +118,9 @@ int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout, void *wireObj) { uint16_t b; - uint8_t count = readWord(devAddr, regAddr, &b, timeout); + uint8_t count = readWord(devAddr, regAddr, &b, timeout, wireObj); *data = b & (1 << bitNum); return count; } @@ -134,14 +134,14 @@ int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout, void *wireObj) { // 01101001 read byte // 76543210 bit numbers // xxx args: bitStart=4, length=3 // 010 masked // -> 010 shifted uint8_t count, b; - if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) { + if ((count = readByte(devAddr, regAddr, &b, timeout, wireObj)) != 0) { uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); b &= mask; b >>= (bitStart - length + 1); @@ -159,7 +159,7 @@ int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (1 = success, 0 = failure, -1 = timeout) */ -int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout, void *wireObj) { // 1101011001101001 read byte // fedcba9876543210 bit numbers // xxx args: bitStart=12, length=3 @@ -167,7 +167,7 @@ int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uin // -> 010 shifted uint8_t count; uint16_t w; - if ((count = readWord(devAddr, regAddr, &w, timeout)) != 0) { + if ((count = readWord(devAddr, regAddr, &w, timeout, wireObj)) != 0) { uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1); w &= mask; w >>= (bitStart - length + 1); @@ -183,8 +183,8 @@ int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uin * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout) { - return readBytes(devAddr, regAddr, 1, data, timeout); +int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout, void *wireObj) { + return readBytes(devAddr, regAddr, 1, data, timeout, wireObj); } /** Read single word from a 16-bit device register. @@ -194,8 +194,8 @@ int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout) { - return readWords(devAddr, regAddr, 1, data, timeout); +int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout, void *wireObj) { + return readWords(devAddr, regAddr, 1, data, timeout, wireObj); } /** Read multiple bytes from an 8-bit device register. @@ -206,7 +206,7 @@ int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Number of bytes read (-1 indicates failure) */ -int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -220,71 +220,73 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8 int8_t count = 0; uint32_t t1 = millis(); - #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE) + #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; #if (ARDUINO < 100) // Arduino v00xx (before v1.0), Wire library // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += _min(length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.send(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)_min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.receive(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->receive(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); #endif } - Wire.endTransmission(); + useWire->endTransmission(); } #elif (ARDUINO == 100) // Arduino v1.0.0, Wire library // Adds standardized write() and read() stream methods instead of send() and receive() // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += _min(length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)_min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.read(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); #endif } - - Wire.endTransmission(); + + useWire->endTransmission(); } #elif (ARDUINO > 100) // Arduino v1.0.1+, Wire library // Adds official support for repeated start condition, yay! // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += _min(length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)_min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.read(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -326,7 +328,7 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Number of words read (-1 indicates failure) */ -int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -340,29 +342,31 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 int8_t count = 0; uint32_t t1 = millis(); - #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE) +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; #if (ARDUINO < 100) // Arduino v00xx (before v1.0), Wire library // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += _min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.send(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes - + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.receive() << 8; + data[count] = useWire->receive() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.receive(); + data[count] |= useWire->receive(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -372,30 +376,30 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 msb = !msb; } - Wire.endTransmission(); + useWire->endTransmission(); } #elif (ARDUINO == 100) // Arduino v1.0.0, Wire library // Adds standardized write() and read() stream methods instead of send() and receive() - + // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += _min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes - + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.read() << 8; + data[count] = useWire->read() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.read(); + data[count] |= useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -404,31 +408,31 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 } msb = !msb; } - - Wire.endTransmission(); + + useWire->endTransmission(); } #elif (ARDUINO > 100) // Arduino v1.0.1+, Wire library // Adds official support for repeated start condition, yay! // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += _min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes - + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->beginTransmission(devAddr); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.read() << 8; + data[count] = useWire->read() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.read(); + data[count] |= useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -437,8 +441,8 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 } msb = !msb; } - - Wire.endTransmission(); + + useWire->endTransmission(); } #endif @@ -446,8 +450,8 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 // Fastwire library // no loop required for fastwire - uint16_t intermediate[(uint8_t)length]; - uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, (uint8_t *)intermediate, (uint8_t)(length * 2)); + uint8_t intermediate[(uint8_t)length*2]; + uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, intermediate, (uint8_t)(length * 2)); if (status == 0) { count = length; // success for (uint8_t i = 0; i < length; i++) { @@ -466,7 +470,7 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 Serial.print(count, DEC); Serial.println(" read)."); #endif - + return count; } @@ -477,11 +481,11 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 * @param value New bit value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data) { +bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj) { uint8_t b; - readByte(devAddr, regAddr, &b); + readByte(devAddr, regAddr, &b, I2Cdev::readTimeout, wireObj); b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); - return writeByte(devAddr, regAddr, b); + return writeByte(devAddr, regAddr, b, wireObj); } /** write a single bit in a 16-bit device register. @@ -491,11 +495,11 @@ bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t * @param value New bit value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data) { +bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj) { uint16_t w; - readWord(devAddr, regAddr, &w); + readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj); w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum)); - return writeWord(devAddr, regAddr, w); + return writeWord(devAddr, regAddr, w, wireObj); } /** Write multiple bits in an 8-bit device register. @@ -506,7 +510,7 @@ bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_ * @param data Right-aligned value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) { +bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj) { // 010 value to write // 76543210 bit numbers // xxx args: bitStart=4, length=3 @@ -515,13 +519,13 @@ bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8 // 10100011 original & ~mask // 10101011 masked | value uint8_t b; - if (readByte(devAddr, regAddr, &b) != 0) { + if (readByte(devAddr, regAddr, &b, I2Cdev::readTimeout, wireObj) != 0) { uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); data <<= (bitStart - length + 1); // shift data into correct position data &= mask; // zero all non-important bits in data b &= ~(mask); // zero all important bits in existing byte b |= data; // combine data with existing byte - return writeByte(devAddr, regAddr, b); + return writeByte(devAddr, regAddr, b, wireObj); } else { return false; } @@ -535,7 +539,7 @@ bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8 * @param data Right-aligned value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data) { +bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj) { // 010 value to write // fedcba9876543210 bit numbers // xxx args: bitStart=12, length=3 @@ -544,13 +548,13 @@ bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint // 1010001110010110 original & ~mask // 1010101110010110 masked | value uint16_t w; - if (readWord(devAddr, regAddr, &w) != 0) { + if (readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj) != 0) { uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1); data <<= (bitStart - length + 1); // shift data into correct position data &= mask; // zero all non-important bits in data w &= ~(mask); // zero all important bits in existing word w |= data; // combine data with existing word - return writeWord(devAddr, regAddr, w); + return writeWord(devAddr, regAddr, w, wireObj); } else { return false; } @@ -562,8 +566,8 @@ bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint * @param data New byte value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { - return writeBytes(devAddr, regAddr, 1, &data); +bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj) { + return writeBytes(devAddr, regAddr, 1, &data, wireObj); } /** Write single word to a 16-bit device register. @@ -572,8 +576,8 @@ bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { * @param data New word value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) { - return writeWords(devAddr, regAddr, 1, &data); +bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj) { + return writeWords(devAddr, regAddr, 1, &data, wireObj); } /** Write multiple bytes to an 8-bit device register. @@ -583,7 +587,7 @@ bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) { * @param data Buffer to copy new data from * @return Status of operation (true = success) */ -bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data) { +bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -594,12 +598,20 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ Serial.print("..."); #endif uint8_t status = 0; + +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.beginTransmission(devAddr); - Wire.send((uint8_t) regAddr); // send address - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - Wire.beginTransmission(devAddr); - Wire.write((uint8_t) regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->send((uint8_t) regAddr); // send address + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->beginTransmission(devAddr); + useWire->write((uint8_t) regAddr); // send address #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::beginTransmission(devAddr); Fastwire::write(regAddr); @@ -610,17 +622,21 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ if (i + 1 < length) Serial.print(" "); #endif #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.send((uint8_t) data[i]); - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - Wire.write((uint8_t) data[i]); + useWire->send((uint8_t) data[i]); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->write((uint8_t) data[i]); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::write((uint8_t) data[i]); #endif } #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.endTransmission(); - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - status = Wire.endTransmission(); + useWire->endTransmission(); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + status = useWire->endTransmission(); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::stop(); //status = Fastwire::endTransmission(); @@ -638,7 +654,7 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ * @param data Buffer to copy new data from * @return Status of operation (true = success) */ -bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data) { +bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -649,37 +665,49 @@ bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16 Serial.print("..."); #endif uint8_t status = 0; + +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.beginTransmission(devAddr); - Wire.send(regAddr); // send address - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - Wire.beginTransmission(devAddr); - Wire.write(regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->send(regAddr); // send address + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->beginTransmission(devAddr); + useWire->write(regAddr); // send address #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::beginTransmission(devAddr); Fastwire::write(regAddr); #endif - for (uint8_t i = 0; i < length * 2; i++) { + for (uint8_t i = 0; i < length; i++) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[i], HEX); if (i + 1 < length) Serial.print(" "); #endif #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.send((uint8_t)(data[i] >> 8)); // send MSB - Wire.send((uint8_t)data[i++]); // send LSB - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - Wire.write((uint8_t)(data[i] >> 8)); // send MSB - Wire.write((uint8_t)data[i++]); // send LSB + useWire->send((uint8_t)(data[i] >> 8)); // send MSB + useWire->send((uint8_t)data[i]); // send LSB + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + useWire->write((uint8_t)(data[i] >> 8)); // send MSB + useWire->write((uint8_t)data[i]); // send LSB #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::write((uint8_t)(data[i] >> 8)); // send MSB - status = Fastwire::write((uint8_t)data[i++]); // send LSB + status = Fastwire::write((uint8_t)data[i]); // send LSB if (status != 0) break; #endif } #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.endTransmission(); - #elif (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) - status = Wire.endTransmission(); + useWire->endTransmission(); + #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ + || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ + || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + status = useWire->endTransmission(); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::stop(); //status = Fastwire::endTransmission(); @@ -739,15 +767,15 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; #endif TWSR = 0; // no prescaler => prescaler = 1 - TWBR = ((16000L / khz) - 16) / 2; // change the I2C clock rate + TWBR = F_CPU / 2000 / khz - 8; // change the I2C clock rate TWCR = 1 << TWEN; // enable twi module, no interrupt } // added by Jeff Rowberg 2013-05-07: // Arduino Wire-style "beginTransmission" function // (takes 7-bit device address like the Wire method, NOT 8-bit: 0x68, not 0xD0/0xD1) - uint8_t Fastwire::beginTransmission(uint8_t device) { - uint8_t twst, retry; + byte Fastwire::beginTransmission(byte device) { + byte twst, retry; retry = 2; do { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA); @@ -766,8 +794,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - uint8_t Fastwire::writeBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num) { - uint8_t twst, retry; + byte Fastwire::writeBuf(byte device, byte address, byte *data, byte num) { + byte twst, retry; retry = 2; do { @@ -793,7 +821,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twst = TWSR & 0xF8; if (twst != TW_MT_DATA_ACK) return 6; - for (uint8_t i = 0; i < num; i++) { + for (byte i = 0; i < num; i++) { //Serial.print(data[i], HEX); //Serial.print(" "); TWDR = data[i]; // send data to the previously addressed device @@ -807,8 +835,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - uint8_t Fastwire::write(uint8_t value) { - uint8_t twst; + byte Fastwire::write(byte value) { + byte twst; //Serial.println(value, HEX); TWDR = value; // send data TWCR = (1 << TWINT) | (1 << TWEN); @@ -818,8 +846,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - uint8_t Fastwire::readBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num) { - uint8_t twst, retry; + byte Fastwire::readBuf(byte device, byte address, byte *data, byte num) { + byte twst, retry; retry = 2; do { @@ -885,7 +913,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWCR = 0; } - uint8_t Fastwire::stop() { + byte Fastwire::stop() { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); if (!waitInt()) return 1; return 0; @@ -899,50 +927,50 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; /* call this version 1.0 - + Offhand, the only funky part that I can think of is in nbrequestFrom, where the buffer length and index are set *before* the data is actually read. The problem is that these are variables local to the TwoWire object, and by the time we actually have read the - data, and know what the length actually is, we have no simple access to the object's + data, and know what the length actually is, we have no simple access to the object's variables. The actual bytes read *is* given to the callback function, though. - + The ISR code for a slave receiver is commented out. I don't have that setup, and can't verify it at this time. Save it for 2.0! - - The handling of the read and write processes here is much like in the demo sketch code: + + The handling of the read and write processes here is much like in the demo sketch code: the process is broken down into sequential functions, where each registers the next as a callback, essentially. - - For example, for the Read process, twi_read00 just returns if TWI is not yet in a + + For example, for the Read process, twi_read00 just returns if TWI is not yet in a ready state. When there's another interrupt, and the interface *is* ready, then it sets up the read, starts it, and registers twi_read01 as the function to call after the *next* interrupt. twi_read01, then, just returns if the interface is still in a "reading" state. When the reading is done, it copies the information to the buffer, - cleans up, and calls the user-requested callback function with the actual number of + cleans up, and calls the user-requested callback function with the actual number of bytes read. - + The writing is similar. - + Questions, comments and problems can go to Gene@Telobot.com. - + Thumbs Up! Gene Knight - + */ - + uint8_t TwoWire::rxBuffer[NBWIRE_BUFFER_LENGTH]; uint8_t TwoWire::rxBufferIndex = 0; uint8_t TwoWire::rxBufferLength = 0; - + uint8_t TwoWire::txAddress = 0; uint8_t TwoWire::txBuffer[NBWIRE_BUFFER_LENGTH]; uint8_t TwoWire::txBufferIndex = 0; uint8_t TwoWire::txBufferLength = 0; - + //uint8_t TwoWire::transmitting = 0; void (*TwoWire::user_onRequest)(void); void (*TwoWire::user_onReceive)(int); - + static volatile uint8_t twi_transmitting; static volatile uint8_t twi_state; static uint8_t twi_slarw; @@ -957,7 +985,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; static volatile uint8_t twi_Done; void (*twi_cbendTransmissionDone)(int); void (*twi_cbreadFromDone)(int); - + void twi_init() { // initialize state twi_state = TWI_READY; @@ -979,7 +1007,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; // bitrate register // enable twi module, acks, and twi interrupt - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA); /* TWEN - TWI Enable Bit TWIE - TWI Interrupt Enable @@ -988,7 +1016,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWSTA - TWI Start Condition */ } - + typedef struct { uint8_t address; uint8_t* data; @@ -1000,7 +1028,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_Write_Vars *ptwv = 0; static void (*fNextInterruptFunction)(void) = 0; - void twi_Finish(uint8_t bRetVal) { + void twi_Finish(byte bRetVal) { if (ptwv) { free(ptwv); ptwv = 0; @@ -1009,13 +1037,13 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_Return_Value = bRetVal; fNextInterruptFunction = 0; } - + uint8_t twii_WaitForDone(uint16_t timeout) { uint32_t endMillis = millis() + timeout; while (!twi_Done && (timeout == 0 || millis() < endMillis)) continue; return twi_Return_Value; } - + void twii_SetState(uint8_t ucState) { twi_state = ucState; } @@ -1048,7 +1076,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; } void twii_SetStart() { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWSTA); } void twi_write01() { @@ -1065,8 +1093,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; if (twi_cbendTransmissionDone) return twi_cbendTransmissionDone(twi_Return_Value); return; } - - + + void twi_write00() { if (TWI_READY != twi_state) return; // blocking test if (TWI_BUFFER_LENGTH < ptwv -> length) { @@ -1083,7 +1111,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; fNextInterruptFunction = twi_write01; // next routine return twi_write01(); } - + void twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) { uint8_t i; ptwv = (twi_Write_Vars *)malloc(sizeof(twi_Write_Vars)); @@ -1103,7 +1131,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; if (twi_cbreadFromDone) return twi_cbreadFromDone(twi_Return_Value); return; } - + void twi_read00() { if (TWI_READY != twi_state) return; // blocking test if (TWI_BUFFER_LENGTH < ptwv -> length) twi_Finish(0); // error return @@ -1131,34 +1159,34 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; void twi_reply(uint8_t ack) { // transmit master read ready signal, with or without ack if (ack){ - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); } else { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT); } } - + void twi_stop(void) { // send stop condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); - + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWSTO); + // wait for stop condition to be exectued on bus // TWINT is not set after a stop condition! - while (TWCR & _BV(TWSTO)) { + while (TWCR & (1 << TWSTO)) { continue; } - + // update twi state twi_state = TWI_READY; } void twi_releaseBus(void) { // release bus - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); - + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT); + // update twi state twi_state = TWI_READY; } - + SIGNAL(TWI_vect) { switch (TW_STATUS) { // All Master @@ -1168,7 +1196,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWDR = twi_slarw; twi_reply(1); break; - + // Master Transmitter case TW_MT_SLA_ACK: // slave receiver acked address case TW_MT_DATA_ACK: // slave receiver acked data @@ -1196,7 +1224,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_error = TW_MT_ARB_LOST; twi_releaseBus(); break; - + // Master Receiver case TW_MR_DATA_ACK: // data received, ack sent // put byte into buffer @@ -1294,7 +1322,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_txBufferLength = 1; twi_txBuffer[0] = 0x00; } - + // transmit first byte from buffer, fall through case TW_ST_DATA_ACK: // byte sent, ack returned @@ -1332,26 +1360,26 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; } TwoWire::TwoWire() { } - + void TwoWire::begin(void) { rxBufferIndex = 0; rxBufferLength = 0; - + txBufferIndex = 0; txBufferLength = 0; twi_init(); } - + void TwoWire::beginTransmission(uint8_t address) { //beginTransmission((uint8_t)address); // indicate that we are transmitting twi_transmitting = 1; - + // set address of targeted slave txAddress = address; - + // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; @@ -1378,7 +1406,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_writeTo(txAddress, txBuffer, txBufferLength, 1); return; } - + void TwoWire::send(uint8_t data) { if (twi_transmitting) { // in master transmitter mode @@ -1399,21 +1427,21 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; //twi_transmit(&data, 1); } } - + uint8_t TwoWire::receive(void) { // default to returning null char // for people using with char strings uint8_t value = 0; - + // get each successive byte on each call if (rxBufferIndex < rxBufferLength) { value = rxBuffer[rxBufferIndex]; ++rxBufferIndex; } - + return value; } - + uint8_t TwoWire::requestFrom(uint8_t address, int quantity, uint16_t timeout) { // clamp to buffer length if (quantity > NBWIRE_BUFFER_LENGTH) { @@ -1428,10 +1456,10 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; // set rx buffer iterator vars rxBufferIndex = 0; rxBufferLength = read; - + return read; } - + void TwoWire::nbrequestFrom(uint8_t address, int quantity, void (*function)(int)) { // clamp to buffer length if (quantity > NBWIRE_BUFFER_LENGTH) { diff --git a/lib/I2Cdevlib/I2Cdev.h b/lib/I2Cdevlib/I2Cdev.h index 007281de68..5b59c56ff2 100644 --- a/lib/I2Cdevlib/I2Cdev.h +++ b/lib/I2Cdevlib/I2Cdev.h @@ -3,6 +3,8 @@ // 2013-06-05 by Jeff Rowberg // // Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument +// 2020-01-20 - hardija : complete support for Teensy 3.x // 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications // 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan) @@ -47,11 +49,18 @@ THE SOFTWARE. #ifndef _I2CDEV_H_ #define _I2CDEV_H_ +// ----------------------------------------------------------------------------- +// Enable deprecated pgmspace typedefs in avr-libc +// ----------------------------------------------------------------------------- +#define __PROG_TYPES_COMPAT__ + // ----------------------------------------------------------------------------- // I2C interface implementation setting // ----------------------------------------------------------------------------- #ifndef I2CDEV_IMPLEMENTATION #define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE +//#define I2CDEV_IMPLEMENTATION I2CDEV_TEENSY_3X_WIRE +//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE //#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE #endif // I2CDEV_IMPLEMENTATION @@ -67,6 +76,8 @@ THE SOFTWARE. // ^^^ NBWire implementation is still buggy w/some interrupts! #define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project #define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library +#define I2CDEV_BUILTIN_SBWIRE 5 // I2C object from Shuning (Steve) Bian's SBWire Library at https://github.com/freespace/SBWire +#define I2CDEV_TEENSY_3X_WIRE 6 // Teensy 3.x support using i2c_t3 library // ----------------------------------------------------------------------------- // Arduino-style "Serial.print" debug constant (uncomment to enable) @@ -82,16 +93,38 @@ THE SOFTWARE. #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + #include + #endif #if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY #include #endif + #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE + #include "SBWire.h" + #endif #endif #ifdef SPARK - #include + #include "application.h" #define ARDUINO 101 + #define BUFFER_LENGTH 32 #endif +#ifndef I2CDEVLIB_WIRE_BUFFER_LENGTH + #if defined(I2C_BUFFER_LENGTH) + // Arduino ESP32 core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH I2C_BUFFER_LENGTH + #elif defined(BUFFER_LENGTH) + // Arduino AVR core Wire and many others use this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH BUFFER_LENGTH + #elif defined(SERIAL_BUFFER_SIZE) + // Arduino SAMD core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH SERIAL_BUFFER_SIZE + #else + // should be a safe fallback, though possibly inefficient + #define I2CDEVLIB_WIRE_BUFFER_LENGTH 32 + #endif +#endif // 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];") #define I2CDEV_DEFAULT_READ_TIMEOUT 1000 @@ -100,23 +133,23 @@ class I2Cdev { public: I2Cdev(); - static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - - static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data); - static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data); - static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data); - static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data); - static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data); - static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data); - static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data); - static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data); + static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + + static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj=0); + static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj=0); + static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj=0); + static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj=0); + static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj=0); + static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj=0); + static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, void *wireObj=0); + static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, void *wireObj=0); static uint16_t readTimeout; }; @@ -156,12 +189,12 @@ class I2Cdev { public: static void setup(int khz, boolean pullup); - static uint8_t beginTransmission(uint8_t device); - static uint8_t write(uint8_t value); - static uint8_t writeBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num); - static uint8_t readBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num); + static byte beginTransmission(byte device); + static byte write(byte value); + static byte writeBuf(byte device, byte address, byte *data, byte num); + static byte readBuf(byte device, byte address, byte *data, byte num); static void reset(); - static uint8_t stop(); + static byte stop(); }; #endif @@ -229,7 +262,7 @@ class I2Cdev { /* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */ - #define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3)) + #define TW_STATUS_MASK ((1 << TWS7)|(1 << TWS6)|(1 << TWS5)|(1 << TWS4)|(1 << TWS3)) #define TW_STATUS (TWSR & TW_STATUS_MASK) #define TW_START 0x08 #define TW_REP_START 0x10 @@ -264,11 +297,11 @@ class I2Cdev { //#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr)) #ifndef sbi // set bit - #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) + #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit)) #endif // sbi #ifndef cbi // clear bit - #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) + #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit)) #endif // cbi extern TwoWire Wire; diff --git a/lib/I2Cdevlib/library.json b/lib/I2Cdevlib/library.json index e974a9ab31..5c5eab8fbb 100644 --- a/lib/I2Cdevlib/library.json +++ b/lib/I2Cdevlib/library.json @@ -9,10 +9,10 @@ "url": "https://github.com/jrowberg/i2cdevlib.git" }, "frameworks": "arduino", - "platforms": "atmelavr", - "dependencies": [ - { - "name": "Wire" - } + "platforms": "*", + "dependencies": [ + { + "name": "Wire" + } ] } diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 08dfaf20b6..3cab3389ac 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -10,7 +10,7 @@ lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266H [esp32_common] extends = common, core_esp32_3_3_0 -lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ArduinoOTA, ESP32HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, SparkFun ADXL345 Arduino Library, ITG3205, WifiEspNow +lib_deps = td-er/ESPeasySerial @ 2.0.8, I2Cdevlib-Core, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ArduinoOTA, ESP32HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, SparkFun ADXL345 Arduino Library, ITG3205, WifiEspNow lib_ignore = ${esp32_always.lib_ignore}, ESP32_ping, IRremoteESP8266, HeatpumpIR board_build.f_flash = 80000000L board_build.flash_mode = dout diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 956a4a17a3..b8a6309e37 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -52,7 +52,7 @@ extends = common board_build.f_cpu = 80000000L build_flags = ${debug_flags.build_flags} ${mqtt_flags.build_flags} -DHTTPCLIENT_1_1_COMPATIBLE=0 build_unflags = -DDEBUG_ESP_PORT -lib_deps = td-er/ESPeasySerial @ 2.0.8, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, bblanchon/ArduinoJson @ ^6.17.2, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/RABurton ESP8266 Mutex @ ^1.0.2, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ESP8266HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, SparkFun ADXL345 Arduino Library, ITG3205, WifiEspNow +lib_deps = td-er/ESPeasySerial @ 2.0.8, I2Cdevlib-Core, adafruit/Adafruit ILI9341 @ ^1.5.6, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO, bblanchon/ArduinoJson @ ^6.17.2, VL53L0X @ 1.3.0, SparkFun VL53L1X 4m Laser Distance Sensor @ 1.2.9, td-er/RABurton ESP8266 Mutex @ ^1.0.2, td-er/SparkFun MAX1704x Fuel Gauge Arduino Library @ ^1.0.1, ESP8266HTTPUpdateServer, FrogmoreScd30, Multi Channel Relay Arduino Library, SparkFun ADXL345 Arduino Library, ITG3205, WifiEspNow lib_ignore = ${esp82xx_defaults.lib_ignore}, IRremoteESP8266, HeatpumpIR, LittleFS(esp8266), ServoESP32, TinyWireM board = esp12e monitor_filters = esp8266_exception_decoder diff --git a/src/_N001_Email.ino b/src/_N001_Email.ino index ce9e98f526..5e9285aabd 100644 --- a/src/_N001_Email.ino +++ b/src/_N001_Email.ino @@ -22,6 +22,7 @@ #include "src/Helpers/StringParser.h" #include "src/Helpers/_CPlugin_Helper.h" // safeReadStringUntil +boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg); // The message body is included in event->String1 @@ -84,8 +85,6 @@ boolean NPlugin_001(NPlugin::Function function, struct EventStruct *event, Strin return success; } -boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg); - boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg) { // String& aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort) From d390dffe31530c38c9d18627d314fd6c653242f4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 27 Jan 2022 23:42:35 +0100 Subject: [PATCH 217/404] [ESPEasy-NOW] Remove no longer needed P098 ESPEasy-NOW receiver --- src/Custom-sample.h | 2 +- src/_P098_ESPEasyNowReceiver.ino | 120 ----------------------- src/src/CustomBuild/define_plugin_sets.h | 5 +- tools/pio/pre_custom_esp32.py | 5 +- tools/pio/pre_custom_esp82xx.py | 4 +- 5 files changed, 7 insertions(+), 129 deletions(-) delete mode 100644 src/_P098_ESPEasyNowReceiver.ino diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 0559ace501..64126153c2 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -394,7 +394,7 @@ static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = { // #define USES_P095 // ILI9341 // #define USES_P096 // eInk // #define USES_P097 // ESP32Touch -// #define USES_P098 // +// #define USES_P098 // PWM Motor // #define USES_P099 // XPT2046 touchscreen // #define USES_P100 // DS2423 counter diff --git a/src/_P098_ESPEasyNowReceiver.ino b/src/_P098_ESPEasyNowReceiver.ino deleted file mode 100644 index 86f7b8257d..0000000000 --- a/src/_P098_ESPEasyNowReceiver.ino +++ /dev/null @@ -1,120 +0,0 @@ -#include "_Plugin_Helper.h" -#ifdef USES_P098 - -// ####################################################################################################### -// #################################### Plugin 098: ESPEasy-NOW Receiver ################################# -// ####################################################################################################### - - -#include "src/Globals/ESPEasy_now_handler.h" - - -#define PLUGIN_098 -#define PLUGIN_ID_098 98 -#define PLUGIN_NAME_098 "Generic - " ESPEASY_NOW_NAME " Receiver" -#define PLUGIN_VALUENAME1_098 "Value" - - -struct P098_data_struct : public PluginTaskData_base { - P098_data_struct() {} - - ~P098_data_struct() {} -}; - -boolean Plugin_098(uint8_t function, struct EventStruct *event, String& string) -{ - boolean success = false; - - switch (function) - { - case PLUGIN_DEVICE_ADD: - { - Device[++deviceCount].Number = PLUGIN_ID_098; - Device[deviceCount].Type = DEVICE_TYPE_DUMMY; - Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_STRING; // FIXME TD-er: Must make this the same as the sender. - Device[deviceCount].Ports = 0; - Device[deviceCount].PullUpOption = false; - Device[deviceCount].InverseLogicOption = false; - Device[deviceCount].FormulaOption = false; - Device[deviceCount].DecimalsOnly = true; - Device[deviceCount].ValueCount = 1; - Device[deviceCount].SendDataOption = true; - Device[deviceCount].TimerOption = false; - Device[deviceCount].GlobalSyncOption = false; - break; - } - - case PLUGIN_GET_DEVICENAME: - { - string = F(PLUGIN_NAME_098); - break; - } - - case PLUGIN_GET_DEVICEVALUENAMES: - { - strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_098)); - break; - } - - case PLUGIN_WEBFORM_LOAD: - { - success = true; - break; - } - - case PLUGIN_WEBFORM_SAVE: - { - success = true; - break; - } - - case PLUGIN_INIT: - { - // Do not set the sensor type, or else it will be set for all instances of the Dummy plugin. - // sensorTypeHelper_setSensorType(event, 0); - - success = true; - break; - } - - case PLUGIN_EXIT: - { - success = true; - break; - } - - case PLUGIN_FIFTY_PER_SECOND: - { - /* - if (ESPEasy_now_handler.loop()) { - // Some packet was handled, check if it is something for this plugin - } - // Moved to run10TimesPerSecond() - */ - break; - } - - case PLUGIN_READ: - { - event->sensorType = static_cast(PCONFIG(0)); - success = true; - break; - } - - case PLUGIN_WRITE: - { - // FIXME TD-er: Create commands for ESPEasy_now receiver - String command = parseString(string, 1); - - if (command == F("espeasynow")) { - String subcommand = parseString(string, 2); - - if (subcommand == F("")) {} - } - break; - } - } - return success; -} - -#endif // USES_P098 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 140c53916e..a206f6e3c2 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1140,9 +1140,8 @@ To create/register a plugin, you have to : //#define USES_P095 // TFT ILI9341 //#define USES_P096 // eInk (Needs lib_deps = Adafruit GFX Library, LOLIN_EPD ) #define USES_P097 // Touch (ESP32) - //#define USES_P098 // ESPEasy-NOW Reader - //#define USES_P099 // XPT2046 Touchscreen #define USES_P098 // PWM motor (relies on iRAM, cannot be combined with all other plugins) + //#define USES_P099 // XPT2046 Touchscreen #define USES_P105 // AHT10/20/21 #endif @@ -1598,7 +1597,7 @@ To create/register a plugin, you have to : #define USES_PACKED_RAW_DATA #endif -#if defined(USES_C019) || defined(USES_P098) +#if defined(USES_C019) #ifndef USES_ESPEASY_NOW #define USES_ESPEASY_NOW #endif diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index b669ae282d..5a9854a283 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -43,14 +43,13 @@ "-DUSES_P081", # Cron "-DUSES_P082", # GPS "-DUSES_P085", # AcuDC24x - "-DUSES_P098", # PWM motor - "-DUSES_P100", # Pulse Counter - DS2423 # "-DUSES_P087", # Serial Proxy # "-DUSES_P094", # CUL Reader # "-DUSES_P095", # TFT ILI9341 "-DUSES_P097", # Touch (ESP32) -# "-DUSES_P098", # ESPEasy-NOW Reader + "-DUSES_P098", # PWM motor + "-DUSES_P100", # Pulse Counter - DS2423 "-DUSES_P106", # BME680 "-DUSES_P107", # SI1145 UV index diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 6158e56060..c682a16789 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -43,12 +43,12 @@ "-DUSES_P081", # Cron "-DUSES_P082", # GPS "-DUSES_P085", # AcuDC24x - "-DUSES_P098", # PWM motor - "-DUSES_P100", # Pulse Counter - DS2423 # "-DUSES_P087", # Serial Proxy "-DUSES_P094", # CUL Reader # "-DUSES_P095", # TFT ILI9341 + "-DUSES_P098", # PWM motor + "-DUSES_P100", # Pulse Counter - DS2423 # "-DUSES_P106", # BME680 # "-DUSES_P107", # SI1145 UV index From 941bf909ea15c9d335b263ccd972a3aa701708cf Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 8 Feb 2022 16:03:47 +0100 Subject: [PATCH 218/404] [ESPEasy-NOW] Fix merge issues --- lib/WifiEspNow/src/WifiEspNowBroadcast.cpp | 2 +- src/src/ControllerQueue/C016_queue_element.h | 1 - src/src/DataStructs/EventQueue.cpp | 2 -- src/src/DataTypes/ESPEasyFileType.cpp | 20 ++++--------- src/src/DataTypes/ESPEasyFileType.h | 3 +- src/src/Helpers/ESPEasy_FactoryDefault.cpp | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 8 ++--- src/src/Helpers/StringProvider.cpp | 31 -------------------- src/src/Helpers/StringProvider.h | 5 ---- src/src/WebServer/JSON.cpp | 4 +-- src/src/WebServer/RootPage.cpp | 9 ++++-- tools/pio/pre_custom_esp82xx.py | 1 + 12 files changed, 23 insertions(+), 65 deletions(-) diff --git a/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp index b013336b8f..5b97543a26 100644 --- a/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp +++ b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp @@ -48,7 +48,7 @@ WifiEspNowBroadcastClass::end() { WifiEspNow.end(); WiFi.softAPdisconnect(); - m_ssid = ""; + m_ssid.clear(); } bool diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 50cf0e5dba..3b352e8d07 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -6,7 +6,6 @@ #include "../DataStructs/DeviceStruct.h" #include "../DataTypes/ControllerIndex.h" #include "../DataStructs/MessageRouteInfo.h" -#include "../DataStructs/UnitMessageCount.h" #include "../Globals/Plugins.h" struct EventStruct; diff --git a/src/src/DataStructs/EventQueue.cpp b/src/src/DataStructs/EventQueue.cpp index 76cb117627..28bb892fa7 100644 --- a/src/src/DataStructs/EventQueue.cpp +++ b/src/src/DataStructs/EventQueue.cpp @@ -2,8 +2,6 @@ #include "../../ESPEasy_common.h" -EventQueueStruct::EventQueueStruct() {} - void EventQueueStruct::add(const String& event) { #ifdef USE_SECOND_HEAP diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index 38e066f62c..3e879f7256 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -18,22 +18,14 @@ bool isProtectedFileType(const String& filename) matchFileType(filename, FileType::PROVISIONING_DAT); } -String getFileName(FileType::Enum filetype) { - String result; +const __FlashStringHelper * getFileName(FileType::Enum filetype) { switch (filetype) { - case FileType::CONFIG_DAT: - result += F("config.dat"); - break; - case FileType::NOTIFICATION_DAT: - result += F("notification.dat"); - break; - case FileType::SECURITY_DAT: - result += F("security.dat"); - break; - case FileType::PROVISIONING_DAT: - result += F("provisioning.dat"); + case FileType::CONFIG_DAT: return F("config.dat"); + case FileType::NOTIFICATION_DAT: return F("notification.dat"); + case FileType::SECURITY_DAT: return F("security.dat"); + case FileType::PROVISIONING_DAT: return F("provisioning.dat"); case FileType::RULES_TXT: // Use getRulesFileName break; @@ -41,7 +33,7 @@ String getFileName(FileType::Enum filetype) { case FileType::MAX_FILETYPE: break; } - return result; + return F(""); } String getFileName(FileType::Enum filetype, unsigned int filenr) { diff --git a/src/src/DataTypes/ESPEasyFileType.h b/src/src/DataTypes/ESPEasyFileType.h index 52cde62a9f..7b257b0664 100644 --- a/src/src/DataTypes/ESPEasyFileType.h +++ b/src/src/DataTypes/ESPEasyFileType.h @@ -20,11 +20,10 @@ bool matchFileType(const String& filename, FileType::Enum filetype); bool isProtectedFileType(const String& filename); -String getFileName(FileType::Enum filetype); +const __FlashStringHelper * getFileName(FileType::Enum filetype); String getFileName(FileType::Enum filetype, unsigned int filenr); - // filenr = 0...3 for files rules1.txt ... rules4.txt String getRulesFileName(unsigned int filenr); diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 185c809359..e9ba6dbc2d 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -113,7 +113,7 @@ void ResetFactory() InitFile(SettingsType::SettingsFileEnum::FILE_NOTIFICATION_type); #endif - InitFile(F(FILE_RULES), 0); + InitFile(getRulesFileName(0), 0); Settings.clearMisc(); diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 589d24aed5..da08de2b20 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -457,7 +457,7 @@ String SaveSecuritySettings() { if (memcmp(tmp_md5, SecuritySettings.md5, 16) != 0) { // Settings have changed, save to file. memcpy(SecuritySettings.md5, tmp_md5, 16); - err = SaveToFile(getFileName(FileType::SECURITY_DAT).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecuritySettings)); + err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecuritySettings)); if (WifiIsAP(WiFi.getMode())) { // Security settings are saved, may be update of WiFi settings or hostname. @@ -541,7 +541,7 @@ String LoadSettings() } */ - err = LoadFromFile(getFileName(FileType::SECURITY_DAT).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecurityStruct)); + err = LoadFromFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecurityStruct)); md5.begin(); md5.add(reinterpret_cast< uint8_t *>(&SecuritySettings), sizeof(SecuritySettings) - 16); md5.calculate(); @@ -1033,7 +1033,7 @@ String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings) if (memcmp(tmp_md5, ProvisioningSettings.md5, 16) != 0) { // Settings have changed, save to file. memcpy(ProvisioningSettings.md5, tmp_md5, 16); - err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); } return err; } @@ -1046,7 +1046,7 @@ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) uint8_t calculatedMd5[16] = { 0 }; MD5Builder md5; - String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); md5.begin(); md5.add(((uint8_t *)&ProvisioningSettings) + 16, sizeof(ProvisioningSettings) - 16); md5.calculate(); diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 5cd935b43f..c9fe5cc8c7 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -484,35 +484,4 @@ String getExtendedValue(LabelType::Enum label) { return ""; } -const __FlashStringHelper * getFileName(FileType::Enum filetype) { - switch (filetype) - { - case FileType::CONFIG_DAT: return F("config.dat"); - case FileType::NOTIFICATION_DAT: return F("notification.dat"); - case FileType::SECURITY_DAT: return F("security.dat"); - case FileType::RULES_TXT: - // Use getRulesFileName - break; - } - return F(""); -} - -String getFileName(FileType::Enum filetype, unsigned int filenr) { - if (filetype == FileType::RULES_TXT) { - return getRulesFileName(filenr); - } - return getFileName(filetype); -} - -// filenr = 0...3 for files rules1.txt ... rules4.txt -String getRulesFileName(unsigned int filenr) { - String result; - - if (filenr < 4) { - result += F("rules"); - result += filenr + 1; - result += F(".txt"); - } - return result; -} diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 108f42c669..57b34c7573 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -203,10 +203,5 @@ String getExtendedValue(LabelType::Enum label); -const __FlashStringHelper * getFileName(FileType::Enum filetype); -String getFileName(FileType::Enum filetype, - unsigned int filenr); - - #endif // STRING_PROVIDER_TYPES_H diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index d66612abdc..842cfce968 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -310,8 +310,8 @@ void handle_json() if (rssi < 0) { stream_next_json_object_value(F("rssi"), rssi); } - stream_next_json_object_value(F("ip"), it->second.ip.toString()); - stream_last_json_object_value(F("age"), it->second.age); + stream_next_json_object_value(F("ip"), it->second.IP().toString()); + stream_last_json_object_value(F("age"), it->second.getAge()); } // if node info exists } // for loop diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 8e40c56c70..8fed231b99 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -174,6 +174,11 @@ void handle_root() { #endif addHtml(html); } + { + #ifdef USE_SECOND_HEAP + addRowLabelValue(LabelType::FREE_HEAP_IRAM); + #endif + } { addRowLabel(LabelType::FREE_STACK); String html; @@ -260,7 +265,7 @@ void handle_root() { addHtml(F("Command Output
")); - printWebString = ""; + printWebString.clear(); } } html_end_table(); @@ -380,7 +385,7 @@ void handle_root() { html_end_table(); html_end_form(); - printWebString = ""; + printWebString.clear(); printToWeb = false; sendHeadandTail_stdtemplate(_TAIL); } diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index c682a16789..1bcde07ae2 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -57,6 +57,7 @@ "-DUSES_C018", # TTN/RN2483 "-DUSES_C019", # ESPEasy-NOW + "-DUSES_ESPEASY_NOW", # "-DFEATURE_MDNS", # "-DFEATURE_SD", "-DUSE_EXT_RTC", From 07dc49c878847925586b4431bd417bdb6e71d930 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 8 Feb 2022 18:28:00 +0100 Subject: [PATCH 219/404] [ESPEasy-NOW] fix build issue on ESP8266 using second heap --- src/{_C019.ino => _C019.cpp} | 9 ++------- src/src/ControllerQueue/C019_queue_element.cpp | 13 +++++++++++++ src/src/ControllerQueue/C019_queue_element.h | 4 ++++ src/src/DataStructs/ESPEasy_now_merger.cpp | 1 - src/src/ESPEasyCore/ESPEasy_setup.cpp | 2 -- 5 files changed, 19 insertions(+), 10 deletions(-) rename src/{_C019.ino => _C019.cpp} (94%) diff --git a/src/_C019.ino b/src/_C019.cpp similarity index 94% rename from src/_C019.ino rename to src/_C019.cpp index d5e6efe430..76c384001e 100644 --- a/src/_C019.ino +++ b/src/_C019.cpp @@ -1,14 +1,14 @@ +#include "src/Helpers/_CPlugin_Helper.h" + #ifdef USES_C019 // ####################################################################################################### // ################### Controller Plugin 019: ESPEasy-NOW ################################################ // ####################################################################################################### -#include "ESPEasy_fdwdecl.h" #include "ESPEasy_common.h" #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" -#include "src/Helpers/_CPlugin_Helper.h" #include "src/Helpers/C019_ESPEasyNow_helper.h" @@ -99,11 +99,6 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& return success; } -// Uncrustify may change this into multi line, which will result in failed builds -// *INDENT-OFF* -bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings); -// *INDENT-ON* - bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings) { ESPEasy_Now_p2p_data data; diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 9785453b79..d4f39fcd39 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -9,6 +9,19 @@ String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount); #endif // USES_PACKED_RAW_DATA +#ifdef USE_SECOND_HEAP +C019_queue_element::C019_queue_element(const C019_queue_element& other) : + packed(other.packed), + _timestamp(other._timestamp), + TaskIndex(other.TaskIndex), + controller_idx(other.controller_idx), + plugin_id(other.plugin_id), + MessageRouteInfo(other.MessageRouteInfo) +{ + event.deep_copy(other.event); +} +#endif + C019_queue_element::C019_queue_element(struct EventStruct *event_p) : controller_idx(event_p->ControllerIndex) { diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 7acdfe29cf..d334214c25 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -20,7 +20,11 @@ class C019_queue_element { C019_queue_element() = default; + #ifdef USE_SECOND_HEAP + C019_queue_element(const C019_queue_element& other); + #else C019_queue_element(const C019_queue_element& other) = delete; + #endif C019_queue_element(C019_queue_element&& other) = default; diff --git a/src/src/DataStructs/ESPEasy_now_merger.cpp b/src/src/DataStructs/ESPEasy_now_merger.cpp index e14238ab25..3ba7288cc7 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.cpp +++ b/src/src/DataStructs/ESPEasy_now_merger.cpp @@ -3,7 +3,6 @@ #ifdef USES_ESPEASY_NOW # include "../Helpers/ESPEasy_time_calc.h" -# include "../../ESPEasy_fdwdecl.h" # define ESPEASY_NOW_MESSAGE_TIMEOUT 5000 diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index f165121aad..d5d4cdf194 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -1,7 +1,5 @@ #include "../ESPEasyCore/ESPEasy_setup.h" -#include "../../ESPEasy_fdwdecl.h" // Needed for PluginInit() and CPluginInit() - #include "../../ESPEasy-Globals.h" #include "../../_Plugin_Helper.h" #include "../ESPEasyCore/ESPEasyNetwork.h" From 156d354ce88c815d0132cb273b1ea1108fd659be Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 8 Apr 2022 11:43:00 +0200 Subject: [PATCH 220/404] [ETH] Turn off Ethernet power on reboot + add delays for init LAN chip Having a power pin for the Ethernet chip appears to be a bit timing critical on some boards. This mainly has to do with tolerances in capacitors. We have to make sure the Ethernet chip has enough time before calling the ETH.begin() function to get ready or else initialization may fail. Also on boards which do have an external crystal, we must make sure the device is turned off when rebooting or else this clock signal on GPIO-0 may put the node into flash mode at boot. (this is theoretical as a warm boot does not appear to be checking the state of GPIO-0) --- src/src/ESPEasyCore/ESPEasyEth.cpp | 22 ++++++++++++++++++++++ src/src/ESPEasyCore/ESPEasyEth.h | 1 + src/src/Helpers/Hardware.cpp | 3 +++ src/src/Helpers/PeriodicalActions.cpp | 3 +++ 4 files changed, 29 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index 65d14cffb9..411383a33a 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -3,6 +3,7 @@ #ifdef HAS_ETHERNET #include "../CustomBuild/ESPEasyLimits.h" +#include "../ESPEasyCore/ESPEasyGPIO.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/ESPEasyWiFiEvent.h" @@ -113,6 +114,7 @@ bool ETHConnectRelaxed() { EthEventData.ethInitSuccess = false; return false; } + ethPower(true); EthEventData.markEthBegin(); EthEventData.ethInitSuccess = ETH.begin( Settings.ETH_Phy_Addr, @@ -127,6 +129,26 @@ bool ETHConnectRelaxed() { return EthEventData.ethInitSuccess; } +void ethPower(bool enable) { + if (Settings.ETH_Pin_power != -1) { + if (GPIO_Internal_Read(Settings.ETH_Pin_power) == enable) { + // Already the desired state + return; + } + EthEventData.ethInitSuccess = false; + ETH = ETHClass(); + GPIO_Write(1, Settings.ETH_Pin_power, enable ? 1 : 0); + if (!enable) { + if (Settings.ETH_Clock_Mode == EthClockMode_t::Ext_crystal_osc) { + delay(600); // Give some time to discharge any capacitors + // Delay is needed to make sure no clock signal remains present which may cause the ESP to boot into flash mode. + } + } else { + delay(400); // LAN chip needs to initialize before calling Eth.begin() + } + } +} + bool ETHConnected() { if (EthEventData.EthServicesInitialized()) { if (EthLinkUp()) { diff --git a/src/src/ESPEasyCore/ESPEasyEth.h b/src/src/ESPEasyCore/ESPEasyEth.h index bb06c969d5..b38bf9e569 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.h +++ b/src/src/ESPEasyCore/ESPEasyEth.h @@ -14,6 +14,7 @@ bool ethPrepare(); void ethPrintSettings(); bool ETHConnectRelaxed(); bool ETHConnected(); +void ethPower(bool enable); MAC_address ETHMacAddress(); #endif // ifdef HAS_ETHERNET diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 01e5935a69..24971aa5f2 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -185,6 +185,9 @@ void hardwareInit() } } #endif // ifdef FEATURE_SD +#ifdef HAS_ETHERNET + ethPower(false); +#endif } void initI2C() { diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 657ebeaae0..b19ad592ae 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -562,6 +562,9 @@ void prepareShutdown(ESPEasy_Scheduler::IntendedRebootReason_e reason) flushAndDisconnectAllClients(); saveUserVarToRTC(); setWifiMode(WIFI_OFF); + #ifdef HAS_ETHERNET + ethPower(false); + #endif ESPEASY_FS.end(); delay(100); // give the node time to flush all before reboot or sleep node_time.now(); From edba1640595a39f5e9811604a46ee1592cbbea31 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 22 Apr 2022 09:54:29 +0200 Subject: [PATCH 221/404] [Build] Fix missing include --- src/src/Helpers/PeriodicalActions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index b19ad592ae..b964902558 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -9,6 +9,7 @@ #include "../DataStructs/TimingStats.h" #include "../DataTypes/ESPEasy_plugin_functions.h" #include "../ESPEasyCore/Controller.h" +#include "../ESPEasyCore/ESPEasyEth.h" #include "../ESPEasyCore/ESPEasyGPIO.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" From 46cb5e4b7e678782e1b3a6f05d3205c04cc99eb1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 26 Apr 2022 13:22:06 +0200 Subject: [PATCH 222/404] [Build] Fix merge issues. --- src/src/DataStructs/EventQueue.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/src/DataStructs/EventQueue.cpp b/src/src/DataStructs/EventQueue.cpp index eb8c152470..14b6c84d1a 100644 --- a/src/src/DataStructs/EventQueue.cpp +++ b/src/src/DataStructs/EventQueue.cpp @@ -2,8 +2,6 @@ #include "../../ESPEasy_common.h" -EventQueueStruct::EventQueueStruct() {} - void EventQueueStruct::add(const String& event, bool deduplicate) { #ifdef USE_SECOND_HEAP From 346f94d174b51e62ea129f3616df95bdc9e68519 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 27 Apr 2022 21:23:49 +0200 Subject: [PATCH 223/404] [Build] Fix merge issue --- src/src/DataStructs/ESPEasy_now_splitter.cpp | 3 +++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/src/DataStructs/ESPEasy_now_splitter.cpp b/src/src/DataStructs/ESPEasy_now_splitter.cpp index 4a7cf95aa9..432769e7d6 100644 --- a/src/src/DataStructs/ESPEasy_now_splitter.cpp +++ b/src/src/DataStructs/ESPEasy_now_splitter.cpp @@ -2,6 +2,7 @@ #ifdef USES_ESPEASY_NOW +# include "../ESPEasyCore/ESPEasyWifi.h" # include "../ESPEasyCore/ESPEasy_Log.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../DataStructs/ESPEasy_now_hdr.h" @@ -187,11 +188,13 @@ bool ESPEasy_now_splitter::send(const ESPEasy_Now_packet& packet, int channel) bool res = false; START_TIMER; if (ESPEasy_now_peermanager.addPeer(packet._mac, channel)) { + #ifdef ESP8266 // Set TX power based on RSSI of other ESPEasy-NOW node. // For broadcast messages power must be max. float tx_pwr = 30; // Will be set higher based on RSSI when needed. int8_t rssi = -99; // Assume worst RSSI for broadcast SetWiFiTXpower(tx_pwr, rssi); + #endif if (packet.valid()) { res = WifiEspNow.send(packet._mac, packet[0], packet.getSize()); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 3a8421f6f4..31649867fa 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1365,7 +1365,9 @@ void setConnectionSpeed() { } */ #endif // ifdef ESP32 + #ifdef ESP8266 SetWiFiTXpower(); + #endif } void setupStaticIPconfig() { From a64c1348615dc608b80e64b06da123b43dac80ee Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 28 Apr 2022 00:07:27 +0200 Subject: [PATCH 224/404] [Web flash] Let user choose to erase flash or not upon flashing --- tools/pio/copy_files.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/pio/copy_files.py b/tools/pio/copy_files.py index 44a9059034..23b74aeec6 100644 --- a/tools/pio/copy_files.py +++ b/tools/pio/copy_files.py @@ -93,6 +93,7 @@ def generate_webflash_json_manifest(variant, file_suffix): manifest = {} manifest['name'] = bin_file + manifest['new_install_prompt_erase'] = True parts = dict([('path', bin_file), ('offset', 0)]) if add_improve: builds = dict([('chipFamily', chipFamily), ('improv', False), ('parts', [parts])]) From fdcf8b7e810c1ad707f17fe08ce5585a62f4f0cd Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Apr 2022 13:29:55 +0200 Subject: [PATCH 225/404] [Ethernet] Fix IP related commands showing WiFi IP values --- src/src/Commands/Networks.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index 24775fd9d9..9b0632f5b0 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -2,6 +2,7 @@ #include "../../ESPEasy_common.h" #include "../Commands/Common.h" +#include "../ESPEasyCore/ESPEasyNetwork.h" #include "../Globals/Settings.h" #include "../WebServer/AccessControl.h" @@ -25,22 +26,22 @@ String Command_AccessInfo_Clear (struct EventStruct *event, const char* Line) String Command_DNS (struct EventStruct *event, const char* Line) { - return Command_GetORSetIP(event, F("DNS:"), Line, Settings.DNS,WiFi.dnsIP(0),1); + return Command_GetORSetIP(event, F("DNS:"), Line, Settings.DNS, NetworkDnsIP(0), 1); } String Command_Gateway (struct EventStruct *event, const char* Line) { - return Command_GetORSetIP(event, F("Gateway:"), Line, Settings.Gateway,WiFi.gatewayIP(),1); + return Command_GetORSetIP(event, F("Gateway:"), Line, Settings.Gateway, NetworkGatewayIP(),1); } String Command_IP (struct EventStruct *event, const char* Line) { - return Command_GetORSetIP(event, F("IP:"), Line, Settings.IP,WiFi.localIP(),1); + return Command_GetORSetIP(event, F("IP:"), Line, Settings.IP, NetworkLocalIP(),1); } String Command_Subnet (struct EventStruct *event, const char* Line) { - return Command_GetORSetIP(event, F("Subnet:"), Line, Settings.Subnet,WiFi.subnetMask(),1); + return Command_GetORSetIP(event, F("Subnet:"), Line, Settings.Subnet, NetworkSubnetMask(), 1); } #ifdef HAS_ETHERNET From 2dc9c7cf627832bef8475f16a875555c8621f138 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Apr 2022 14:52:28 +0200 Subject: [PATCH 226/404] [Eth] Fix Eth commands --- src/src/Commands/Common.cpp | 35 ++++++++++++++++++--------- src/src/Commands/Common.h | 13 +++++----- src/src/Commands/InternalCommands.cpp | 1 + src/src/Commands/Networks.cpp | 27 +++++++++++++++++++-- src/src/Commands/Networks.h | 1 + src/src/ESPEasyCore/ESPEasyEth.cpp | 1 + 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/src/Commands/Common.cpp b/src/src/Commands/Common.cpp index 8726071480..1386da7d57 100644 --- a/src/src/Commands/Common.cpp +++ b/src/src/Commands/Common.cpp @@ -60,7 +60,7 @@ const __FlashStringHelper * return_see_serial(struct EventStruct *event) } String Command_GetORSetIP(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, uint8_t *IP, const IPAddress & dhcpIP, @@ -98,7 +98,7 @@ String Command_GetORSetIP(struct EventStruct *event, } String Command_GetORSetString(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, char *target, size_t len, @@ -134,7 +134,7 @@ String Command_GetORSetString(struct EventStruct *event, } String Command_GetORSetBool(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, bool *value, int arg) @@ -167,8 +167,9 @@ String Command_GetORSetBool(struct EventStruct *event, return return_command_success(); } -String Command_GetORSetUint8_t(struct EventStruct *event, - const String & targetDescription, +String Command_GetORSetETH(struct EventStruct *event, + const __FlashStringHelper * targetDescription, + const __FlashStringHelper * valueToString, const char *Line, uint8_t *value, int arg) @@ -186,21 +187,33 @@ String Command_GetORSetUint8_t(struct EventStruct *event, if (validIntFromString(TmpStr1, tmp_int)) { *value = static_cast(tmp_int); } - else if (strcmp_P(PSTR("WIFI"), TmpStr1.c_str()) == 0) { *value = 0; } - else if (strcmp_P(PSTR("ETHERNET"), TmpStr1.c_str()) == 0) { *value = 1; } + + // FIXME TD-er: This should not be in a generic function, but rather pre-processed in the command itself + + + // WiFi/Eth mode + else if (TmpStr1.equals(F("wifi"))) { *value = 0; } + else if (TmpStr1.equals(F("ethernet"))) { *value = 1; } + + // ETH clockMode + else if (TmpStr1.startsWith(F("ext"))) { *value = 0; } + else if (TmpStr1.indexOf(F("gpio0")) != -1) { *value = 1; } + else if (TmpStr1.indexOf(F("gpio16")) != -1) { *value = 2; } + else if (TmpStr1.indexOf(F("gpio17")) != -1) { *value = 3; } } } + String result = targetDescription; if (hasArgument) { - String result = targetDescription; result += *value; - return return_result(event, result); + } else { + result += valueToString; } - return return_command_success(); + return return_result(event, result); } String Command_GetORSetInt8_t(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, int8_t *value, int arg) diff --git a/src/src/Commands/Common.h b/src/src/Commands/Common.h index 7cda15ee07..52f78906d4 100644 --- a/src/src/Commands/Common.h +++ b/src/src/Commands/Common.h @@ -18,14 +18,14 @@ String return_result(struct EventStruct *event, const __FlashStringHelper * return_see_serial(struct EventStruct *event); String Command_GetORSetIP(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, uint8_t *IP, const IPAddress& dhcpIP, int arg); String Command_GetORSetString(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, char *target, size_t len, @@ -33,19 +33,20 @@ String Command_GetORSetString(struct EventStruct *event, ); String Command_GetORSetBool(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, bool *value, int arg); -String Command_GetORSetUint8_t(struct EventStruct *event, - const String & targetDescription, +String Command_GetORSetETH(struct EventStruct *event, + const __FlashStringHelper * targetDescription, + const __FlashStringHelper * valueToString, const char *Line, uint8_t *value, int arg); String Command_GetORSetInt8_t(struct EventStruct *event, - const String & targetDescription, + const __FlashStringHelper * targetDescription, const char *Line, int8_t *value, int arg); diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index ea74328dd1..92bb8394a0 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -301,6 +301,7 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_R( "ethgateway", Command_ETH_Gateway, 1); // Network Command COMMAND_CASE_R( "ethsubnet", Command_ETH_Subnet, 1); // Network Command COMMAND_CASE_R( "ethdns", Command_ETH_DNS, 1); // Network Command + COMMAND_CASE_A("ethdisconnect", Command_ETH_Disconnect, 0); // Network Command COMMAND_CASE_R( "ethwifimode", Command_ETH_Wifi_Mode, 1); // Network Command #endif // HAS_ETHERNET #ifdef USES_ESPEASY_NOW diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index 9b0632f5b0..f3056dcc71 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../Commands/Common.h" #include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyEth.h" #include "../Globals/Settings.h" #include "../WebServer/AccessControl.h" @@ -72,7 +73,12 @@ String Command_ETH_Phy_Type (struct EventStruct *event, const char* Line) String Command_ETH_Clock_Mode (struct EventStruct *event, const char* Line) { - return Command_GetORSetUint8_t(event, F("ETH_Clock_Mode:"), Line, reinterpret_cast(&Settings.ETH_Clock_Mode),1); + return Command_GetORSetETH(event, + F("ETH_Clock_Mode:"), + toString(Settings.ETH_Clock_Mode), + Line, + reinterpret_cast(&Settings.ETH_Clock_Mode), + 1); } String Command_ETH_IP (struct EventStruct *event, const char* Line) @@ -97,7 +103,24 @@ String Command_ETH_DNS (struct EventStruct *event, const char* Line) String Command_ETH_Wifi_Mode (struct EventStruct *event, const char* Line) { - return Command_GetORSetUint8_t(event, F("NetworkMedium:"), Line, reinterpret_cast(&Settings.NetworkMedium),1); + + return Command_GetORSetETH(event, + F("NetworkMedium:"), + toString(Settings.NetworkMedium), + Line, + reinterpret_cast(&Settings.NetworkMedium), + 1); +} + +String Command_ETH_Disconnect (struct EventStruct *event, const char* Line) +{ + + ethPower(0); + ethPower(1); + setNetworkMedium(NetworkMedium_t::Ethernet); + ETHConnectRelaxed(); + + return return_command_success(); } #endif diff --git a/src/src/Commands/Networks.h b/src/src/Commands/Networks.h index 1b6745f520..f33f045669 100644 --- a/src/src/Commands/Networks.h +++ b/src/src/Commands/Networks.h @@ -21,5 +21,6 @@ String Command_ETH_Gateway (struct EventStruct *event, const char* Line); String Command_ETH_Subnet (struct EventStruct *event, const char* Line); String Command_ETH_DNS (struct EventStruct *event, const char* Line); String Command_ETH_Wifi_Mode (struct EventStruct *event, const char* Line); +String Command_ETH_Disconnect (struct EventStruct *event, const char* Line); #endif // COMMAND_NETWORKS_H diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index b564627008..9823a28aec 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -145,6 +145,7 @@ void ethPower(bool enable) { return; } EthEventData.ethInitSuccess = false; + EthEventData.clearAll(); ETH = ETHClass(); GPIO_Write(1, Settings.ETH_Pin_power, enable ? 1 : 0); if (!enable) { From 6376f16f61dab43463aac5d29b69106b1a0fb1b5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 30 Apr 2022 01:11:38 +0200 Subject: [PATCH 227/404] [Eth] Fix loosing DNS info when disabling WiFi after ETH got IP --- src/src/Commands/Networks.cpp | 19 +++++-- src/src/DataStructs/EthernetEventData.cpp | 1 + src/src/DataStructs/EthernetEventData.h | 3 + src/src/DataStructs/WiFiEventData.h | 1 + src/src/ESPEasyCore/ESPEasyEth.cpp | 56 ++++++++++++++++++- src/src/ESPEasyCore/ESPEasyEth.h | 1 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 15 +++++ src/src/ESPEasyCore/ESPEasyWifi.h | 6 ++ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 50 +++++++++++++++-- src/src/Helpers/StringProvider.cpp | 16 +++++- 10 files changed, 154 insertions(+), 14 deletions(-) diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index f3056dcc71..f17bbee9ba 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -4,6 +4,7 @@ #include "../Commands/Common.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyEth.h" +#include "../Globals/NetworkState.h" #include "../Globals/Settings.h" #include "../WebServer/AccessControl.h" @@ -103,20 +104,30 @@ String Command_ETH_DNS (struct EventStruct *event, const char* Line) String Command_ETH_Wifi_Mode (struct EventStruct *event, const char* Line) { - - return Command_GetORSetETH(event, + const NetworkMedium_t orig_medium = Settings.NetworkMedium; + const String result = Command_GetORSetETH(event, F("NetworkMedium:"), - toString(Settings.NetworkMedium), + toString(active_network_medium), Line, reinterpret_cast(&Settings.NetworkMedium), 1); + if (orig_medium != Settings.NetworkMedium) { + if (!isValid(Settings.NetworkMedium)) { + Settings.NetworkMedium = orig_medium; + return return_command_failed(); + } + setNetworkMedium(Settings.NetworkMedium); + } + + return result; } String Command_ETH_Disconnect (struct EventStruct *event, const char* Line) { ethPower(0); - ethPower(1); + delay(400); +// ethPower(1); setNetworkMedium(NetworkMedium_t::Ethernet); ETHConnectRelaxed(); diff --git a/src/src/DataStructs/EthernetEventData.cpp b/src/src/DataStructs/EthernetEventData.cpp index 70bdf51322..05bba6e1c1 100644 --- a/src/src/DataStructs/EthernetEventData.cpp +++ b/src/src/DataStructs/EthernetEventData.cpp @@ -50,6 +50,7 @@ void EthernetEventData_t::markEthBegin() { last_eth_connect_attempt_moment.setNow(); eth_considered_stable = false; ethConnectInProgress = true; + eth_dhcp_retries = 0; ++eth_connect_attempt; } diff --git a/src/src/DataStructs/EthernetEventData.h b/src/src/DataStructs/EthernetEventData.h index 1e3f6ebe77..6db6ffbb66 100644 --- a/src/src/DataStructs/EthernetEventData.h +++ b/src/src/DataStructs/EthernetEventData.h @@ -50,6 +50,7 @@ struct EthernetEventData_t { unsigned int eth_connect_attempt = 0; bool eth_considered_stable = false; int eth_reconnects = -1; // First connection attempt is not a reconnect. + unsigned int eth_dhcp_retries = 0; LongTermTimer lastConnectMoment; LongTermTimer lastDisconnectMoment; @@ -57,6 +58,8 @@ struct EthernetEventData_t { LongTermTimer lastGetIPmoment; LongTermTimer::Duration lastConnectedDuration_us = 0ll; + IPAddress dns0_cache; + IPAddress dns1_cache; // Semaphore like bools for processing data gathered from Eth events. bool processedConnect = true; diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 76eb433af7..97d6b62432 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -96,6 +96,7 @@ struct WiFiEventData_t { MAC_address lastMacConnectedAPmode; MAC_address lastMacDisconnectedAPmode; + // processDisconnect() may clear all WiFi settings, resulting in clearing processedDisconnect // This can cause recursion, so a semaphore is needed here. LongTermTimer processingDisconnect; diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index 9823a28aec..ef6f387783 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -5,6 +5,7 @@ #include "../CustomBuild/ESPEasyLimits.h" #include "../ESPEasyCore/ESPEasyGPIO.h" #include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyWifi.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyGPIO.h" #include "../Globals/ESPEasyWiFiEvent.h" @@ -13,6 +14,7 @@ #include "../Helpers/StringConverter.h" #include +#include #if ESP_IDF_VERSION_MAJOR > 3 #include #else @@ -50,6 +52,32 @@ void ethSetupStaticIPconfig() { ETH.config(ip, gw, subnet, dns); } +void ethSetDNS(const IPAddress dns0, const IPAddress dns1) +{ + ip_addr_t d; + d.type = IPADDR_TYPE_V4; + + if(dns0 != (uint32_t)0x00000000 && dns0 != INADDR_NONE) { + // Set DNS0-Server + d.u_addr.ip4.addr = static_cast(dns0); + dns_setserver(0, &d); + } + + if(dns1 != (uint32_t)0x00000000 && dns1 != INADDR_NONE) { + // Set DNS1-Server + d.u_addr.ip4.addr = static_cast(dns1); + dns_setserver(1, &d); + } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("ETH IP : Set DNS: "); + log += formatIP(dns0); + log += '/'; + log += formatIP(dns1); + addLogMove(LOG_LEVEL_INFO, log); + } +} + bool ethCheckSettings() { return isValid(Settings.ETH_Phy_Type) && isValid(Settings.ETH_Clock_Mode) @@ -117,8 +145,19 @@ bool ETHConnectRelaxed() { EthEventData.ethInitSuccess = false; return false; } + // Re-register event listener + #if defined(ESP32) + removeWiFiEventHandler(); + #endif + ethPower(true); EthEventData.markEthBegin(); + + // Re-register event listener + #if defined(ESP32) + registerWiFiEventHandler(); + #endif + if (!EthEventData.ethInitSuccess) { EthEventData.ethInitSuccess = ETH.begin( Settings.ETH_Phy_Addr, @@ -129,7 +168,9 @@ bool ETHConnectRelaxed() { (eth_clock_mode_t)Settings.ETH_Clock_Mode); } if (EthEventData.ethInitSuccess) { - EthEventData.ethConnectAttemptNeeded = false; + // FIXME TD-er: Not sure if this is correctly set to false + //EthEventData.ethConnectAttemptNeeded = false; + if (EthLinkUp()) { // We might miss the connected event, since we are already connected. EthEventData.markConnected(); @@ -146,7 +187,18 @@ void ethPower(bool enable) { } EthEventData.ethInitSuccess = false; EthEventData.clearAll(); - ETH = ETHClass(); + if (!enable) { + #ifdef ESP_IDF_VERSION_MAJOR + // FIXME TD-er: See: https://github.com/espressif/arduino-esp32/issues/6105 + // Need to store the last link state, as it will be cleared after destructing the object. + EthEventData.setEthDisconnected(); + if (ETH.linkUp()) { + EthEventData.setEthConnected(); + } + #endif + ETH = ETHClass(); + } + GPIO_Write(1, Settings.ETH_Pin_power, enable ? 1 : 0); if (!enable) { if (Settings.ETH_Clock_Mode == EthClockMode_t::Ext_crystal_osc) { diff --git a/src/src/ESPEasyCore/ESPEasyEth.h b/src/src/ESPEasyCore/ESPEasyEth.h index b38bf9e569..f3d4afc2f7 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.h +++ b/src/src/ESPEasyCore/ESPEasyEth.h @@ -9,6 +9,7 @@ bool ethUseStaticIP(); void ethSetupStaticIPconfig(); +void ethSetDNS(const IPAddress dns0, const IPAddress dns1); bool ethCheckSettings(); bool ethPrepare(); void ethPrintSettings(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 31649867fa..d75043a3c4 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -560,6 +560,21 @@ void resetWiFi() { initWiFi(); } +#ifdef ESP32 +void removeWiFiEventHandler() +{ + WiFi.removeEvent(wm_event_id); +} + +void registerWiFiEventHandler() +{ +#if defined(ESP32) + wm_event_id = WiFi.onEvent(WiFiEvent); +#endif +} +#endif + + void initWiFi() { #ifdef USES_ESPEASY_NOW diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index a2fbdddbe2..7bc1840fee 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -107,6 +107,12 @@ bool prepareWiFi(); bool checkAndResetWiFi(); void resetWiFi(); void initWiFi(); + +#ifdef ESP32 +void removeWiFiEventHandler(); +void registerWiFiEventHandler(); +#endif + #ifdef ESP8266 void SetWiFiTXpower(); void SetWiFiTXpower(float dBm); // 0-20.5 diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 63f7a39812..1fb04c866a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -6,6 +6,7 @@ #include "../DataStructs/NodesHandler.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" +#include "../ESPEasyCore/ESPEasyEth.h" #include "../ESPEasyCore/ESPEasyWifi.h" #include "../ESPEasyCore/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasyWiFiEvent.h" @@ -34,6 +35,8 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringGenerator_WiFi.h" + + // ******************************************************************************** // Called from the loop() to make sure events are processed as soon as possible. // These functions are called from Setup() or Loop() and thus may call delay() or yield() @@ -84,7 +87,6 @@ void handle_unprocessedNetworkEvents() } EthEventData.setEthServicesInitialized(); } - #endif if (WiFiEventData.unprocessedWifiEvents()) { // Process disconnect events before connect events. @@ -208,6 +210,21 @@ void handle_unprocessedNetworkEvents() } } } +#ifdef HAS_ETHERNET + // Check if DNS is still valid, as this may have been reset by the WiFi module turned off. + if (EthEventData.EthServicesInitialized() && + active_network_medium == NetworkMedium_t::Ethernet && + EthEventData.ethInitSuccess) { + const IPAddress dns0 = NetworkDnsIP(0); + const IPAddress dns1 = NetworkDnsIP(1); + + if (!dns0 && !dns1) { + addLog(LOG_LEVEL_ERROR, F("ETH : DNS server was cleared, use cached DNS IP")); + ethSetDNS(EthEventData.dns0_cache, EthEventData.dns1_cache); + } + } +#endif + updateUDPport(); } @@ -629,14 +646,30 @@ void processEthernetDisconnected() { } void processEthernetGotIP() { - if (EthEventData.processedGotIP) { + if (EthEventData.processedGotIP || !EthEventData.ethInitSuccess) { return; } - IPAddress ip = NetworkLocalIP(); + const IPAddress ip = NetworkLocalIP(); + + if (!ip) { + return; + } + const IPAddress gw = NetworkGatewayIP(); const IPAddress subnet = NetworkSubnetMask(); + + IPAddress dns0 = NetworkDnsIP(0); + IPAddress dns1 = NetworkDnsIP(1); const LongTermTimer::Duration dhcp_duration = EthEventData.lastConnectMoment.timeDiff(EthEventData.lastGetIPmoment); + if (!dns0 && !dns1) { + addLog(LOG_LEVEL_ERROR, F("ETH : No DNS server received via DHCP, use cached DNS IP")); + ethSetDNS(EthEventData.dns0_cache, EthEventData.dns1_cache); + } else { + EthEventData.dns0_cache = dns0; + EthEventData.dns1_cache = dns1; + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; @@ -650,13 +683,18 @@ void processEthernetGotIP() { log += F("DHCP"); } log += F(" IP: "); - log += NetworkLocalIP().toString(); + log += ip.toString(); log += ' '; log += wrap_braces(NetworkGetHostname()); log += F(" GW: "); - log += NetworkGatewayIP().toString(); + log += gw.toString(); log += F(" SN: "); - log += NetworkSubnetMask().toString(); + log += subnet.toString(); + log += F(" DNS: "); + log += dns0.toString(); + log += '/'; + log += dns1.toString(); + if (EthLinkUp()) { if (EthFullDuplex()) { log += F(" FULL_DUPLEX"); diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 602ac6f4f8..82a3fff920 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -339,10 +339,22 @@ String getValue(LabelType::Enum label) { case LabelType::CHANNEL: return String(WiFi.channel()); case LabelType::ENCRYPTION_TYPE_STA: return // WiFi_AP_Candidates.getCurrent().encryption_type(); WiFi_encryptionType(WiFiEventData.auth_mode); - case LabelType::CONNECTED: return format_msec_duration(WiFiEventData.lastConnectMoment.millisPassedSince()); + case LabelType::CONNECTED: + #ifdef HAS_ETHERNET + if(active_network_medium == NetworkMedium_t::Ethernet) { + return format_msec_duration(EthEventData.lastConnectMoment.millisPassedSince()); + } + #endif + return format_msec_duration(WiFiEventData.lastConnectMoment.millisPassedSince()); // Use only the nr of seconds to fit it in an int32, plus append '000' to have msec format again. - case LabelType::CONNECTED_MSEC: return String(static_cast(WiFiEventData.lastConnectMoment.millisPassedSince() / 1000ll)) + F("000"); + case LabelType::CONNECTED_MSEC: + #ifdef HAS_ETHERNET + if(active_network_medium == NetworkMedium_t::Ethernet) { + return String(static_cast(EthEventData.lastConnectMoment.millisPassedSince() / 1000ll)) + F("000"); + } + #endif + return String(static_cast(WiFiEventData.lastConnectMoment.millisPassedSince() / 1000ll)) + F("000"); case LabelType::LAST_DISCONNECT_REASON: return String(WiFiEventData.lastDisconnectReason); case LabelType::LAST_DISC_REASON_STR: return getLastDisconnectReason(); case LabelType::NUMBER_RECONNECTS: return String(WiFiEventData.wifi_reconnects); From f1298988ac93acc9549ef90e628fdec66a6834c4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 30 Apr 2022 22:30:44 +0200 Subject: [PATCH 228/404] [ETH] Cleanup unused variable --- src/src/DataStructs/EthernetEventData.cpp | 1 - src/src/DataStructs/EthernetEventData.h | 1 - src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/src/DataStructs/EthernetEventData.cpp b/src/src/DataStructs/EthernetEventData.cpp index 05bba6e1c1..70bdf51322 100644 --- a/src/src/DataStructs/EthernetEventData.cpp +++ b/src/src/DataStructs/EthernetEventData.cpp @@ -50,7 +50,6 @@ void EthernetEventData_t::markEthBegin() { last_eth_connect_attempt_moment.setNow(); eth_considered_stable = false; ethConnectInProgress = true; - eth_dhcp_retries = 0; ++eth_connect_attempt; } diff --git a/src/src/DataStructs/EthernetEventData.h b/src/src/DataStructs/EthernetEventData.h index 6db6ffbb66..7e06e1c163 100644 --- a/src/src/DataStructs/EthernetEventData.h +++ b/src/src/DataStructs/EthernetEventData.h @@ -50,7 +50,6 @@ struct EthernetEventData_t { unsigned int eth_connect_attempt = 0; bool eth_considered_stable = false; int eth_reconnects = -1; // First connection attempt is not a reconnect. - unsigned int eth_dhcp_retries = 0; LongTermTimer lastConnectMoment; LongTermTimer lastDisconnectMoment; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index d75043a3c4..d1e1114e40 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -568,9 +568,7 @@ void removeWiFiEventHandler() void registerWiFiEventHandler() { -#if defined(ESP32) wm_event_id = WiFi.onEvent(WiFiEvent); -#endif } #endif From 1e0500d886ec53e6d6d5d4a9ff503d71b07d907b Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 3 May 2022 12:32:13 +0200 Subject: [PATCH 229/404] [Cleanup] Use uint8_t instead of byte in I2Cdevlib --- lib/I2Cdevlib/I2Cdev.cpp | 22 +++++++++++----------- lib/I2Cdevlib/I2Cdev.h | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/I2Cdevlib/I2Cdev.cpp b/lib/I2Cdevlib/I2Cdev.cpp index 892274ba00..cf9f0ea004 100644 --- a/lib/I2Cdevlib/I2Cdev.cpp +++ b/lib/I2Cdevlib/I2Cdev.cpp @@ -774,8 +774,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; // added by Jeff Rowberg 2013-05-07: // Arduino Wire-style "beginTransmission" function // (takes 7-bit device address like the Wire method, NOT 8-bit: 0x68, not 0xD0/0xD1) - byte Fastwire::beginTransmission(byte device) { - byte twst, retry; + uint8_t Fastwire::beginTransmission(uint8_t device) { + uint8_t twst, retry; retry = 2; do { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA); @@ -794,8 +794,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - byte Fastwire::writeBuf(byte device, byte address, byte *data, byte num) { - byte twst, retry; + uint8_t Fastwire::writeBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num) { + uint8_t twst, retry; retry = 2; do { @@ -821,7 +821,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twst = TWSR & 0xF8; if (twst != TW_MT_DATA_ACK) return 6; - for (byte i = 0; i < num; i++) { + for (uint8_t i = 0; i < num; i++) { //Serial.print(data[i], HEX); //Serial.print(" "); TWDR = data[i]; // send data to the previously addressed device @@ -835,8 +835,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - byte Fastwire::write(byte value) { - byte twst; + uint8_t Fastwire::write(uint8_t value) { + uint8_t twst; //Serial.println(value, HEX); TWDR = value; // send data TWCR = (1 << TWINT) | (1 << TWEN); @@ -846,8 +846,8 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; return 0; } - byte Fastwire::readBuf(byte device, byte address, byte *data, byte num) { - byte twst, retry; + uint8_t Fastwire::readBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num) { + uint8_t twst, retry; retry = 2; do { @@ -913,7 +913,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWCR = 0; } - byte Fastwire::stop() { + uint8_t Fastwire::stop() { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); if (!waitInt()) return 1; return 0; @@ -1028,7 +1028,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; twi_Write_Vars *ptwv = 0; static void (*fNextInterruptFunction)(void) = 0; - void twi_Finish(byte bRetVal) { + void twi_Finish(uint8_t bRetVal) { if (ptwv) { free(ptwv); ptwv = 0; diff --git a/lib/I2Cdevlib/I2Cdev.h b/lib/I2Cdevlib/I2Cdev.h index ed2cf19132..500d49b5a6 100644 --- a/lib/I2Cdevlib/I2Cdev.h +++ b/lib/I2Cdevlib/I2Cdev.h @@ -189,12 +189,12 @@ class I2Cdev { public: static void setup(int khz, boolean pullup); - static byte beginTransmission(byte device); - static byte write(byte value); - static byte writeBuf(byte device, byte address, byte *data, byte num); - static byte readBuf(byte device, byte address, byte *data, byte num); + static uint8_t beginTransmission(uint8_t device); + static uint8_t write(uint8_t value); + static uint8_t writeBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num); + static uint8_t readBuf(uint8_t device, uint8_t address, uint8_t *data, uint8_t num); static void reset(); - static byte stop(); + static uint8_t stop(); }; #endif From ad07a386a8d26984b8d4729b02185abf473a59cd Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 9 May 2022 13:11:49 +0200 Subject: [PATCH 230/404] [Provisioning] Add command to download firmware OTA --- platformio_core_defs.ini | 2 +- src/src/Commands/InternalCommands.cpp | 1 + src/src/Commands/Provisioning.cpp | 11 +++ src/src/Commands/Provisioning.h | 2 + src/src/DataTypes/ESPEasyFileType.cpp | 3 + src/src/DataTypes/ESPEasyFileType.h | 2 +- src/src/Helpers/Networking.cpp | 123 +++++++++++++++++++++++--- src/src/Helpers/Networking.h | 2 + 8 files changed, 132 insertions(+), 14 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 948010d823..c7bf7da0a5 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -167,7 +167,7 @@ build_flags = -DESP32_STAGE ; IDF 4.4 = platform-espressif32 3.4.x = espressif/arduino-esp32 tag 2.0.3 ; Just for those who lost track of the extremely confusing numbering schema. [core_esp32_IDF4_4__2_0_3] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.3rc1/platform-espressif32-2.0.3new.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.3/platform-espressif32-v.2.0.3.zip platform_packages = build_flags = -DESP32_STAGE diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 92bb8394a0..6e9bd2b3c3 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -396,6 +396,7 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_A( "provisionnotification", Command_Provisioning_Notification, 0); // Provisioning.h COMMAND_CASE_A( "provisionprovision", Command_Provisioning_Provision, 0); // Provisioning.h COMMAND_CASE_A( "provisionrules", Command_Provisioning_Rules, 1); // Provisioning.h + COMMAND_CASE_A( "provisionfirmware", Command_Provisioning_Firmware, 1); // Provisioning.h #endif COMMAND_CASE_A( "pulse", Command_GPIO_Pulse, 3); // GPIO.h #ifdef USES_MQTT diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp index 5c4ac77916..018e16e008 100644 --- a/src/src/Commands/Provisioning.cpp +++ b/src/src/Commands/Provisioning.cpp @@ -39,4 +39,15 @@ String Command_Provisioning_Rules(struct EventStruct *event, const char *Line) return downloadFileType(FileType::RULES_TXT, event->Par1 - 1); } +String Command_Provisioning_Firmware(struct EventStruct *event, const char *Line) +{ + const String url = parseStringToEndKeepCase(Line, 2); + String error; + if (downloadFirmware(url, error)) { + // TODO TD-er: send events + } + return error; +} + + #endif // ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/Commands/Provisioning.h b/src/src/Commands/Provisioning.h index 16b448acb0..2911ed0dd8 100644 --- a/src/src/Commands/Provisioning.h +++ b/src/src/Commands/Provisioning.h @@ -18,6 +18,8 @@ String Command_Provisioning_Provision(struct EventStruct *event, String Command_Provisioning_Rules(struct EventStruct *event, const char *Line); +String Command_Provisioning_Firmware(struct EventStruct *event, + const char *Line); #endif // ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index 5bccbb0e9f..b5df5b9661 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -31,6 +31,9 @@ const __FlashStringHelper * getFileName(FileType::Enum filetype) { case FileType::RULES_TXT: // Use getRulesFileName break; + case FileType::FIRMWARE: + // File name may differ each time. + break; case FileType::MAX_FILETYPE: break; diff --git a/src/src/DataTypes/ESPEasyFileType.h b/src/src/DataTypes/ESPEasyFileType.h index 7b257b0664..3de4811912 100644 --- a/src/src/DataTypes/ESPEasyFileType.h +++ b/src/src/DataTypes/ESPEasyFileType.h @@ -10,7 +10,7 @@ struct FileType { RULES_TXT, NOTIFICATION_DAT, PROVISIONING_DAT, - + FIRMWARE, MAX_FILETYPE }; diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index d26dfa1a1b..d5fab462c0 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -63,6 +63,7 @@ void etharp_gratuitous_r(struct netif *netif) { # endif // ifdef ESP8266 # ifdef ESP32 # include +# include # endif // ifdef ESP32 #endif @@ -1133,7 +1134,7 @@ bool downloadFile(const String& url, String file_save) { return downloadFile(url, file_save, EMPTY_STRING, EMPTY_STRING, error); } -bool downloadFile(const String& url, String file_save, const String& user, const String& pass, String& error) { +bool start_downloadFile(WiFiClient& client, HTTPClient& http, const String& url, String& file_save, const String& user, const String& pass, String& error) { String host, file; uint16_t port; String uri = splitURL(url, host, port, file); @@ -1162,16 +1163,6 @@ bool downloadFile(const String& url, String file_save, const String& user, const return false; } - if (fileExists(file_save)) { - error = F("File exists: "); - error += file_save; - addLog(LOG_LEVEL_ERROR, error); - return false; - } - unsigned long timeout = millis() + 2000; - WiFiClient client; - HTTPClient http; - http.begin(client, host, port, uri); { if ((user.length() > 0) && (pass.length() > 0)) { @@ -1198,6 +1189,24 @@ bool downloadFile(const String& url, String file_save, const String& user, const http.end(); return false; } + return true; +} + +bool downloadFile(const String& url, String file_save, const String& user, const String& pass, String& error) { + WiFiClient client; + HTTPClient http; + + if (!start_downloadFile(client, http, url, file_save, user, pass, error)) { + return false; + } + + if (fileExists(file_save)) { + http.end(); + error = F("File exists: "); + error += file_save; + addLog(LOG_LEVEL_ERROR, error); + return false; + } long len = http.getSize(); fs::File f = tryOpenFile(file_save, "w"); @@ -1206,6 +1215,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const const size_t downloadBuffSize = 256; uint8_t buff[downloadBuffSize]; size_t bytesWritten = 0; + unsigned long timeout = millis() + 2000; // get tcp stream WiFiClient *stream = &client; @@ -1249,14 +1259,103 @@ bool downloadFile(const String& url, String file_save, const String& user, const String log = F("downloadFile: "); log += file_save; log += F(" Success"); - addLog(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, log); } return true; } + http.end(); error = F("Failed to open file for writing: "); error += file_save; addLog(LOG_LEVEL_ERROR, error); return false; } +bool downloadFirmware(const String& url, String& error) +{ + String file_save; + String user; + String pass; + WiFiClient client; + HTTPClient http; + client.setTimeout(2000); + + if (!start_downloadFile(client, http, url, file_save, user, pass, error)) { + return false; + } + + size_t len = http.getSize(); + + if (Update.begin(len, U_FLASH, Settings.Pin_status_led, Settings.Pin_status_led_Inversed ? LOW : HIGH)) { + const size_t downloadBuffSize = 256; + uint8_t buff[downloadBuffSize]; + size_t bytesWritten = 0; + unsigned long timeout = millis() + 2000; + + // get tcp stream + WiFiClient *stream = &client; + while (http.connected() && (len > 0 || len == -1)) { + // read up to downloadBuffSize at a time. + const size_t c = stream->readBytes(buff, std::min(static_cast(len), downloadBuffSize)); + + if (c > 0) { + timeout = millis() + 2000; + if (Update.write(buff, c) != c) { + error = F("Error saving firmware update: "); + error += file_save; + error += ' '; + error += bytesWritten; + error += F(" Bytes written"); + addLog(LOG_LEVEL_ERROR, error); + Update.end(); + http.end(); + return false; + } + bytesWritten += c; + if (len > 0) { len -= c; } + } + + if (timeOutReached(timeout)) { + error = F("Timeout: "); + error += file_save; + addLog(LOG_LEVEL_ERROR, error); + delay(0); + Update.end(); + http.end(); + return false; + } + if (!UseRTOSMultitasking) { + // On ESP32 the schedule is executed on the 2nd core. + Scheduler.handle_schedule(); + } + backgroundtasks(); + } + http.end(); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("downloadFile: "); + log += file_save; + log += F(" Success"); + addLogMove(LOG_LEVEL_INFO, log); + } + if (Update.end()) { + if (Settings.UseRules) { + String event = F("ProvisionFirmware#success="); + event += file_save; + eventQueue.addMove(std::move(event)); + } + } + return true; + } + http.end(); + Update.end(); + error = F("Failed update firmware: "); + error += file_save; + addLog(LOG_LEVEL_ERROR, error); + if (Settings.UseRules) { + String event = F("ProvisionFirmware#failed="); + event += file_save; + eventQueue.addMove(std::move(event)); + } + return false; +} + #endif diff --git a/src/src/Helpers/Networking.h b/src/src/Helpers/Networking.h index 5e4a677a50..dd5c53cbee 100644 --- a/src/src/Helpers/Networking.h +++ b/src/src/Helpers/Networking.h @@ -163,6 +163,8 @@ bool downloadFile(const String& url, String file_save); bool downloadFile(const String& url, String file_save, const String& user, const String& pass, String& error); +bool downloadFirmware(const String& url, String& error); + #endif From e0967f0c443604ef2492263b8f678f4aff227363 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 17 May 2022 16:50:45 +0200 Subject: [PATCH 231/404] [Build] Fix missing line in .ini file due to merge issues --- platformio_esp32_envs.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 10bb371544..2598945631 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -18,6 +18,7 @@ lib_ignore = ESP8266Ping [esp32_base] extends = common, core_esp32_IDF4_4__2_0_3 +lib_deps = Adafruit_ST77xx ArduinoOTA ESP32HTTPUpdateServer From 2673ec59e3babe19ac3fd430678658520ced7afa Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 17 May 2022 17:59:04 +0200 Subject: [PATCH 232/404] [Provisioning] Fix missing include --- src/src/Commands/Provisioning.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp index 018e16e008..35281047a2 100644 --- a/src/src/Commands/Provisioning.cpp +++ b/src/src/Commands/Provisioning.cpp @@ -9,6 +9,7 @@ # include "../DataTypes/ESPEasyFileType.h" # include "../DataStructs/ESPEasy_EventStruct.h" # include "../Helpers/ESPEasy_Storage.h" +# include "../Helpers/StringConverter.h" String Command_Provisioning_Config(struct EventStruct *event, const char *Line) From 2b15aee3fbc8bccea85532ad51c0c252efff39e7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 17 May 2022 18:10:30 +0200 Subject: [PATCH 233/404] [Provisioning] Fix another missing include. --- src/src/Commands/Provisioning.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp index 35281047a2..795bb322c6 100644 --- a/src/src/Commands/Provisioning.cpp +++ b/src/src/Commands/Provisioning.cpp @@ -9,6 +9,7 @@ # include "../DataTypes/ESPEasyFileType.h" # include "../DataStructs/ESPEasy_EventStruct.h" # include "../Helpers/ESPEasy_Storage.h" +# include "../Helpers/Networking.h" # include "../Helpers/StringConverter.h" From 35c9653c041bb1363cf70fea888a3c96923a8f0d Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 17 May 2022 18:13:30 +0200 Subject: [PATCH 234/404] [Provisioning] And another missing include.... --- src/src/Helpers/Networking.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index d5fab462c0..d77b22b982 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -5,11 +5,13 @@ #include "../DataStructs/TimingStats.h" #include "../DataTypes/EventValueSource.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasy_backgroundtasks.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" #include "../Globals/ESPEasy_now_handler.h" +#include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" #include "../Globals/Nodes.h" #include "../Globals/Settings.h" From db8cbe612f343d8269977737803925fc6d0350ac Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 15:43:36 +0200 Subject: [PATCH 235/404] [ESPEasy_NOW] Fix typo in #ifdef fixing WiFi stability --- src/src/CustomBuild/define_plugin_sets.h | 4 ++++ src/src/ESPEasyCore/ESPEasyNetwork.cpp | 6 +++--- src/src/Helpers/ESPEasy_now_handler.cpp | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index db2caa4af7..a7222ded64 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1878,4 +1878,8 @@ To create/register a plugin, you have to : #endif #endif +#if defined(LIMIT_BUILD_SIZE) && defined(USES_ESPEASY_NOW) + #undef USES_ESPEASY_NOW +#endif + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index dcea737459..a0ce3da168 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -35,7 +35,7 @@ void setNetworkMedium(NetworkMedium_t new_medium) { // Only allow to set to ESPEasyNOW_only from WiFi return; } - #ifdef USES_EASPEASY_NOW + #ifdef USES_ESPEASY_NOW if (use_EspEasy_now) { ESPEasy_now_handler.end(); active_network_medium = new_medium; @@ -64,7 +64,7 @@ void setNetworkMedium(NetworkMedium_t new_medium) { } break; case NetworkMedium_t::ESPEasyNOW_only: - #ifdef USES_EASPEASY_NOW + #ifdef USES_ESPEASY_NOW if (use_EspEasy_now) { ESPEasy_now_handler.end(); } @@ -83,7 +83,7 @@ void setNetworkMedium(NetworkMedium_t new_medium) { } bool isESPEasy_now_only() { - #ifdef USES_EASPEASY_NOW + #ifdef USES_ESPEASY_NOW if (active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { return true; } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index b5086c0fee..a34dffd5c3 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -156,7 +156,7 @@ bool ESPEasy_now_handler_t::begin() _last_traceroute_sent = 0; _last_traceroute_received = 0; _last_used = millis(); - _last_started = millis(); + _last_started = _last_used; _controllerIndex = INVALID_CONTROLLER_INDEX; if (isESPEasy_now_only()) { @@ -561,7 +561,7 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo WiFi.softAPmacAddress(tmp.mac); if (tmp == receivedMAC) return handled; WiFi.macAddress(tmp.mac); - if (tmp == receivedMAC) return handled; + if (tmp == receivedMAC) return handled; //-V649 } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; From 5c1c9789dc3019b8e35300253de411eada9d76aa Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 15:55:38 +0200 Subject: [PATCH 236/404] [Firmware Download] Fix downloading with no content length set --- src/src/Helpers/Networking.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index d77b22b982..aa943fa494 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -1225,7 +1225,11 @@ bool downloadFile(const String& url, String file_save, const String& user, const // read all data from server while (http.connected() && (len > 0 || len == -1)) { // read up to downloadBuffSize at a time. - const size_t c = stream->readBytes(buff, std::min(static_cast(len), downloadBuffSize)); + size_t bytes_to_read = downloadBuffSize; + if (len > 0 && len < bytes_to_read) { + bytes_to_read = len; + } + const size_t c = stream->readBytes(buff, bytes_to_read); if (c > 0) { timeout = millis() + 2000; @@ -1285,7 +1289,7 @@ bool downloadFirmware(const String& url, String& error) return false; } - size_t len = http.getSize(); + int len = http.getSize(); if (Update.begin(len, U_FLASH, Settings.Pin_status_led, Settings.Pin_status_led_Inversed ? LOW : HIGH)) { const size_t downloadBuffSize = 256; @@ -1297,7 +1301,11 @@ bool downloadFirmware(const String& url, String& error) WiFiClient *stream = &client; while (http.connected() && (len > 0 || len == -1)) { // read up to downloadBuffSize at a time. - const size_t c = stream->readBytes(buff, std::min(static_cast(len), downloadBuffSize)); + size_t bytes_to_read = downloadBuffSize; + if (len > 0 && len < bytes_to_read) { + bytes_to_read = len; + } + const size_t c = stream->readBytes(buff, bytes_to_read); if (c > 0) { timeout = millis() + 2000; From 54ebac8d1b8db5c432d57f104f7347396e1710fd Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 15:57:02 +0200 Subject: [PATCH 237/404] [Cleanup] Various PVS-Studio hints --- src/_P003_Pulse.ino | 23 ++++++++++++-------- src/src/DataTypes/ESPEasyFileType.cpp | 2 ++ src/src/Globals/Plugins.cpp | 2 ++ src/src/Helpers/ESPEasy_time.cpp | 3 ++- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 2 +- src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp | 2 +- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/_P003_Pulse.ino b/src/_P003_Pulse.ino index a81f2f5fe5..d02f767692 100644 --- a/src/_P003_Pulse.ino +++ b/src/_P003_Pulse.ino @@ -247,10 +247,13 @@ boolean Plugin_003(uint8_t function, struct EventStruct *event, String& string) static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P003_data) { - String command = parseString(string, 1); + const String command = parseString(string, 1); bool mustCallPluginRead = false; - if ((command == F("resetpulsecounter")) || (command == F("setpulsecountertotal"))) + const bool cmd_resetpulsecounter = command == F("resetpulsecounter"); + const bool cmd_setpulsecountertotal = command == F("setpulsecountertotal"); + + if (cmd_resetpulsecounter || cmd_setpulsecountertotal) { // Legacy commands ({...} indicate optional parameters): // - {[].}resetpulsecounter @@ -263,7 +266,7 @@ boolean Plugin_003(uint8_t function, struct EventStruct *event, String& string) // Legacy: Allow for an optional taskIndex parameter. uint8_t tidx = 1; - if (command == F("setpulsecountertotal")) { tidx = 2; } + if (cmd_setpulsecountertotal) { tidx = 2; } if (!pluginOptionalTaskIndexArgumentMatch(event->TaskIndex, string, tidx)) { break; @@ -271,12 +274,12 @@ boolean Plugin_003(uint8_t function, struct EventStruct *event, String& string) int par1 = 0; - if (command == F("setpulsecountertotal")) { + if (cmd_setpulsecountertotal) { if (!validIntFromString(parseString(string, 2), par1)) { break; } } P003_data->pulseHelper.setPulseCountTotal(par1); - if (command == F("resetpulsecounter")) { + if (cmd_resetpulsecounter) { P003_data->pulseHelper.resetPulseCounter(); } mustCallPluginRead = true; @@ -301,15 +304,17 @@ boolean Plugin_003(uint8_t function, struct EventStruct *event, String& string) // r = reset error and overdue counters after logging // i = increase the log level for regular statstic logs to "info" - String subcommand = parseString(string, 2); + const String subcommand = parseString(string, 2); + const bool sub_i = subcommand == F("i"); + const bool sub_r = subcommand == F("r"); - if ((subcommand == F("i")) || (subcommand == F("r")) || (subcommand == "")) { + if ((sub_i) || (sub_r) || (subcommand.isEmpty())) { P003_data->pulseHelper.doStatisticLogging(P003_PULSE_STATS_ADHOC_LOG_LEVEL); P003_data->pulseHelper.doTimingLogging(P003_PULSE_STATS_ADHOC_LOG_LEVEL); - if (subcommand == F("i")) { P003_data->pulseHelper.setStatsLogLevel(LOG_LEVEL_INFO); } + if (sub_i) { P003_data->pulseHelper.setStatsLogLevel(LOG_LEVEL_INFO); } - if (subcommand == F("r")) { P003_data->pulseHelper.resetStatsErrorVars(); } + if (sub_r) { P003_data->pulseHelper.resetStatsErrorVars(); } success = true; } # else // ifdef PULSE_STATISTIC diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index b5df5b9661..2cfd3ee850 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -69,6 +69,8 @@ bool getDownloadFiletypeChecked(FileType::Enum filetype, unsigned int filenr) { case FileType::NOTIFICATION_DAT: isChecked = ResetFactoryDefaultPreference.fetchNotificationDat(); break; case FileType::RULES_TXT: isChecked = ResetFactoryDefaultPreference.fetchRulesTXT(filenr); break; case FileType::PROVISIONING_DAT: isChecked = ResetFactoryDefaultPreference.fetchProvisioningDat(); break; + case FileType::FIRMWARE: + break; case FileType::MAX_FILETYPE: break; diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 7b6feb7b58..ae5a435d44 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -458,6 +458,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) } } +/* if (Function == PLUGIN_REQUEST) { // @FIXME TD-er: work-around as long as gpio command is still performed in P001_switch. for (deviceIndex_t deviceIndex = 0; deviceIndex < PLUGIN_MAX; deviceIndex++) { @@ -470,6 +471,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) } } } +*/ break; } diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index d2b79138cb..2342324561 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -165,9 +165,10 @@ unsigned long ESPEasy_time::now() { // Clock instability in msec/second timeWander = ((time_offset * 1000000.0) / timePassedSince(lastTimeWanderCalculation)); } - lastTimeWanderCalculation = millis(); prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) + lastTimeWanderCalculation = prevMillis; + timeSynced = true; sysTime = unixTime_d; diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index ebd201c3ea..7183e1abaa 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -361,7 +361,7 @@ void WiFi_AP_CandidatesList::addFromRTC() { // See if we may have a better candidate for the current network, with a significant better RSSI. auto bestMatch = candidates.end(); - auto lastUsed = candidates.end(); + auto lastUsed = bestMatch; for (auto it = candidates.begin(); lastUsed == candidates.end() && it != candidates.end(); ++it) { if (it->usable() && it->ssid.equals(fromRTC.ssid)) { const bool foundLastUsed = fromRTC.bssid_match(it->bssid); diff --git a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp index 8b46fafb29..d76348a081 100644 --- a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp +++ b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp @@ -99,7 +99,7 @@ float getLoRaAirTime(uint8_t pl, uint8_t sf, uint16_t bw, uint8_t cr, uint8_t n_ } // t_symbol and t_air in msec - float t_symbol = (1 << sf) / bw; + float t_symbol = static_cast(1 << sf) / bw; float t_air = ((n_preamble + 4.25f) + payload_length) * t_symbol; return t_air; } From 8b25a9322214d61fb28e0506fde93efcec7cec9a Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 16:07:01 +0200 Subject: [PATCH 238/404] [ESPEasy_NOW] Do not allow C019 to be included when ESPEasy_NOW is not --- src/src/CustomBuild/define_plugin_sets.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index a7222ded64..119cb5c283 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1882,4 +1882,9 @@ To create/register a plugin, you have to : #undef USES_ESPEASY_NOW #endif +#if defined(USES_C019) && !defined(USES_ESPEASY_NOW) + #undef USES_C019 +#endif + + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H \ No newline at end of file From 64387174ddffedde8f7be6e51ebb38b3606f4ae9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 16:47:36 +0200 Subject: [PATCH 239/404] [ESPEasy_NOW] Do not include in ESP8266 Custom IR builds due to size --- src/src/CustomBuild/define_plugin_sets.h | 8 ++++++-- src/src/WebServer/SettingsArchive.cpp | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 119cb5c283..cd521bdf92 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1878,11 +1878,15 @@ To create/register a plugin, you have to : #endif #endif -#if defined(LIMIT_BUILD_SIZE) && defined(USES_ESPEASY_NOW) - #undef USES_ESPEASY_NOW +#ifdef USES_ESPEASY_NOW + #if defined(LIMIT_BUILD_SIZE) || (defined(ESP8266) && defined(PLUGIN_BUILD_IR)) + // Will not fit on ESP8266 along with IR plugins included + #undef USES_ESPEASY_NOW + #endif #endif #if defined(USES_C019) && !defined(USES_ESPEASY_NOW) + // C019 depends on ESPEASY_NOW, so don't use it if ESPEasy_NOW is excluded #undef USES_C019 #endif diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index a0f325d714..95ef126010 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -222,6 +222,8 @@ void storeDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr) case FileType::NOTIFICATION_DAT: ResetFactoryDefaultPreference.fetchNotificationDat(isChecked); break; case FileType::RULES_TXT: { ResetFactoryDefaultPreference.fetchRulesTXT(filenr, isChecked); break; } case FileType::PROVISIONING_DAT: { ResetFactoryDefaultPreference.fetchProvisioningDat(isChecked); break; } + case FileType::FIRMWARE: + break; case FileType::MAX_FILETYPE: break; From 21ca8832320967bd48dfdea613716a3e03acbb1b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 16:48:02 +0200 Subject: [PATCH 240/404] [Download] Fix warning signed/unsigned --- src/src/Helpers/Networking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index aa943fa494..e723499146 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -1226,7 +1226,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const while (http.connected() && (len > 0 || len == -1)) { // read up to downloadBuffSize at a time. size_t bytes_to_read = downloadBuffSize; - if (len > 0 && len < bytes_to_read) { + if (len > 0 && len < static_cast(bytes_to_read)) { bytes_to_read = len; } const size_t c = stream->readBytes(buff, bytes_to_read); @@ -1302,7 +1302,7 @@ bool downloadFirmware(const String& url, String& error) while (http.connected() && (len > 0 || len == -1)) { // read up to downloadBuffSize at a time. size_t bytes_to_read = downloadBuffSize; - if (len > 0 && len < bytes_to_read) { + if (len > 0 && len < static_cast(bytes_to_read)) { bytes_to_read = len; } const size_t c = stream->readBytes(buff, bytes_to_read); From 5b9fc477367e4f717794a9d2fe1fa33636f99198 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 20:41:57 +0200 Subject: [PATCH 241/404] [ESPEasy-NOW] limit logging when being probed + ESPEasy-NOW when enabled --- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index c0dd9b6a85..d59e69ff6b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -493,19 +493,25 @@ void processProbeRequestAPmode() { Nodes.setRSSI(mac, rssi); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("AP Mode: Probe Request: "); - log += mac.toString(); - log += F(" ("); - log += rssi; - log += F(" dBm)"); - addLog(LOG_LEVEL_INFO, log); - } + static MAC_address last_probed_mac; + if (last_probed_mac != mac) { + last_probed_mac = mac; + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("AP Mode: Probe Request: "); + log += mac.toString(); + log += F(" ("); + log += rssi; + log += F(" dBm)"); + addLog(LOG_LEVEL_INFO, log); + } - // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery - #ifdef USES_ESPEASY_NOW - ESPEasy_now_handler.sendDiscoveryAnnounce(mac, WiFiEventData.usedChannel); - #endif + // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery + #ifdef USES_ESPEASY_NOW + if (Settings.UseESPEasyNow()) { + ESPEasy_now_handler.sendDiscoveryAnnounce(mac, WiFiEventData.usedChannel); + } + #endif + } APModeProbeRequestReceived_list.pop_front(); WiFiEventData.processedProbeRequestAPmode = APModeProbeRequestReceived_list.size() == 0; From 7df0ce4ce3411dc34b4be62ebb68aa67fde3e02b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 20:42:48 +0200 Subject: [PATCH 242/404] [PIO] Add build_flags to every intermediate PIO env. --- platformio_esp82xx_base.ini | 12 ++++++++---- src/src/CustomBuild/define_plugin_sets.h | 8 +++----- src/src/PluginStructs/P053_data_struct.h | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index e86b2e630f..e6c21e9ff7 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -203,8 +203,7 @@ build_flags = ${ir.build_flags} ; ********************************************************************* [esp82xx_1M] extends = esp82xx_common -build_flags = -DSIZE_1M - -DBUILD_NO_DEBUG +build_flags = -DBUILD_NO_DEBUG -Os -s ${esp82xx_common.build_flags} @@ -212,11 +211,12 @@ build_flags = -DSIZE_1M [esp8266_1M] extends = esp82xx_1M board = esp8266_1M128k +build_flags = ${esp82xx_1M.build_flags} [esp8285_1M] extends = esp82xx_1M board = esp8285_1M128k -build_flags = ${esp8266_1M.build_flags} +build_flags = ${esp82xx_1M.build_flags} -DESP8285 @@ -233,6 +233,7 @@ build_flags = ${esp82xx_1M.build_flags} [esp8266_1M_OTA] extends = esp82xx_1M_OTA board = esp8266_1M128k_OTA +build_flags = ${esp82xx_1M_OTA.build_flags} [esp8285_1M_OTA] extends = esp82xx_1M_OTA @@ -248,6 +249,7 @@ build_flags = ${esp82xx_1M_OTA.build_flags} [esp8266_2M256] extends = esp82xx_common board = esp8266_2M256 +build_flags = ${esp82xx_common.build_flags} [espWroom2M256] extends = esp82xx_common @@ -255,7 +257,7 @@ board_build.flash_mode = dout board_upload.maximum_size = 1044464 board = esp_wroom_02 board_build.ldscript = eagle.flash.2m256.ld - +build_flags = ${esp82xx_common.build_flags} ;;; 4MB flash nodes ************************************************** ; Layout for 4M flash nodes ; @@ -264,10 +266,12 @@ board_build.ldscript = eagle.flash.2m256.ld [esp8266_4M1M] extends = esp82xx_common board = esp8266_4M1M_board +build_flags = ${esp82xx_common.build_flags} [esp8266_4M2M] extends = esp82xx_common board = esp8266_4M2M_board +build_flags = ${esp82xx_common.build_flags} diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index cd521bdf92..ff77d4a3f9 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -137,8 +137,6 @@ To create/register a plugin, you have to : #endif #endif - - #ifdef MEMORY_ANALYSIS #ifdef MQTT_ONLY #define USES_C002 // Domoticz MQTT @@ -480,7 +478,7 @@ To create/register a plugin, you have to : // The following define is needed for extended decoding of A/C Messages and or using standardised common arguments for controlling all deeply supported A/C units #define P016_P035_Extended_AC #define P016_P035_USE_RAW_RAW2 //Use the RAW and RAW2 encodings, disabling it saves 3.7Kb - #ifndef SIZE_1M // Leaving out Heatpump IR for 1M builds because it won't fit after upgrading IRremoteESP8266 library to v2.8.1 + #ifndef ESP8266_1M // Leaving out Heatpump IR for 1M builds because it won't fit after upgrading IRremoteESP8266 library to v2.8.1 #define USES_P088 // ToniA IR plugin #endif #define PLUGIN_SET_ONLY_SWITCH @@ -1679,7 +1677,7 @@ To create/register a plugin, you have to : // Due to size restrictions, disable a few plugins/controllers for 1M builds -#ifdef SIZE_1M +#ifdef ESP8266_1M #ifdef USES_C003 #undef USES_C003 #endif @@ -1879,7 +1877,7 @@ To create/register a plugin, you have to : #endif #ifdef USES_ESPEASY_NOW - #if defined(LIMIT_BUILD_SIZE) || (defined(ESP8266) && defined(PLUGIN_BUILD_IR)) + #if defined(LIMIT_BUILD_SIZE) || defined(ESP8266_1M) || (defined(ESP8266) && defined(PLUGIN_BUILD_IR)) // Will not fit on ESP8266 along with IR plugins included #undef USES_ESPEASY_NOW #endif diff --git a/src/src/PluginStructs/P053_data_struct.h b/src/src/PluginStructs/P053_data_struct.h index eeece62c6f..81cb73c15e 100644 --- a/src/src/PluginStructs/P053_data_struct.h +++ b/src/src/PluginStructs/P053_data_struct.h @@ -15,9 +15,9 @@ // Difference in build size is roughly 4k # define PLUGIN_053_ENABLE_EXTRA_SENSORS -# if !defined(PLUGIN_BUILD_CUSTOM) && defined(SIZE_1M) && defined(PLUGIN_053_ENABLE_EXTRA_SENSORS) // Turn off for 1M OTA builds +# if !defined(PLUGIN_BUILD_CUSTOM) && defined(ESP8266_1M) && defined(PLUGIN_053_ENABLE_EXTRA_SENSORS) // Turn off for 1M OTA builds # undef PLUGIN_053_ENABLE_EXTRA_SENSORS -# endif // if defined(SIZE_1M) && defined(PLUGIN_BUILD_MINIMAL_OTA) && defined(PLUGIN_053_ENABLE_EXTRA_SENSORS) +# endif // if defined(ESP8266_1M) && defined(PLUGIN_BUILD_MINIMAL_OTA) && defined(PLUGIN_053_ENABLE_EXTRA_SENSORS) // Do not change values, as they are being stored From e3c149730ac4359cad667b8f5986aaf9d03dda92 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 21:08:00 +0200 Subject: [PATCH 243/404] [PIO] Add lib_ignore to all 1M non-Custom builds --- platformio_esp82xx_envs.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 8820b365ec..46d18132da 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -208,6 +208,12 @@ platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8266_1M.build_flags} +lib_ignore = ${regular_platform.lib_ignore} + SD(esp8266) + SD + SDFS + LittleFS(esp8266) + [env:normal_alt_wifi_ESP8266_1M] extends = esp8266_1M @@ -237,6 +243,11 @@ platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8266_1M.build_flags} -D FEATURE_ADC_VCC=true +lib_ignore = ${regular_platform.lib_ignore} + SD(esp8266) + SD + SDFS + LittleFS(esp8266) [env:normal_alt_wifi_ESP8266_1M_VCC] extends = esp8266_1M @@ -260,6 +271,12 @@ platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8285_1M.build_flags} +lib_ignore = ${regular_platform.lib_ignore} + SD(esp8266) + SD + SDFS + LittleFS(esp8266) + ; NORMAL: 2048k WROOM02 version 256k SPIFFS -------------------------- From a3ec3a9869538416bf4957346b41c8ace5c36da8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 11 Jun 2022 22:52:14 +0200 Subject: [PATCH 244/404] [Build] Set lib_ignore for all ESP8266 Testing builds --- platformio_esp82xx_base.ini | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index e6c21e9ff7..e9fc5dab30 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -130,21 +130,36 @@ platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} -DPLUGIN_BUILD_TESTING + -DLIMIT_BUILD_SIZE lib_ignore = ${regular_platform.lib_ignore} + SD(esp8266) + SD + SDFS + LittleFS(esp8266) + [testing_alt_wifi] platform = ${regular_platform_alt_wifi.platform} platform_packages = ${regular_platform_alt_wifi.platform_packages} build_flags = ${regular_platform_alt_wifi.build_flags} -DPLUGIN_BUILD_TESTING + -DLIMIT_BUILD_SIZE lib_ignore = ${regular_platform_alt_wifi.lib_ignore} + SD(esp8266) + SD + SDFS + LittleFS(esp8266) [testing_beta] platform = ${beta_platform.platform} platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} -DPLUGIN_BUILD_TESTING + -DLIMIT_BUILD_SIZE lib_ignore = ${beta_platform.lib_ignore} + SD + SDFS + LittleFS(esp8266) ;;; IR *********************************************************** From d1b9b1ed42e295b8792547d45cc0188c4fa7e77c Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 12 Jun 2022 01:25:44 +0200 Subject: [PATCH 245/404] [ESPEasy-NOW] Exclude ESPEasy-NOW code when not defined --- src/src/ControllerQueue/C011_queue_element.h | 2 ++ src/src/ControllerQueue/C015_queue_element.h | 2 ++ src/src/ControllerQueue/C016_queue_element.h | 2 ++ src/src/ControllerQueue/C018_queue_element.h | 2 ++ .../ControllerQueue/C019_queue_element.cpp | 6 ++++-- src/src/ControllerQueue/C019_queue_element.h | 4 ++++ .../ControllerDelayHandlerStruct.h | 6 ++++++ src/src/ControllerQueue/MQTT_queue_element.h | 4 ++++ .../SimpleQueueElement_formatted_Strings.h | 2 ++ .../SimpleQueueElement_string_only.h | 2 ++ src/src/CustomBuild/define_plugin_sets.h | 7 ++++++- .../DataStructs/ControllerSettingsStruct.h | 2 ++ .../ESPEasy_Now_DuplicateCheck.cpp | 4 ++++ .../DataStructs/ESPEasy_Now_DuplicateCheck.h | 5 +++++ src/src/DataStructs/MessageRouteInfo.cpp | 3 ++- src/src/DataStructs/MessageRouteInfo.h | 2 ++ src/src/DataStructs/TimingStats.cpp | 2 ++ src/src/DataStructs/TimingStats.h | 2 ++ src/src/DataStructs/WiFiEventData.cpp | 2 ++ src/src/DataStructs/WiFiEventData.h | 2 ++ src/src/DataStructs_templ/SettingsStruct.cpp | 6 ++++++ .../ESPEasy_Now_MQTT_queue_check_state.h | 5 +++++ src/src/ESPEasyCore/Controller.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 2 ++ src/src/ESPEasyCore/ESPEasyWiFiEvent.h | 2 ++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 ++ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 7 ++++++- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.h | 2 ++ src/src/Globals/ESPEasyWiFiEvent.cpp | 4 ++++ src/src/Globals/ESPEasyWiFiEvent.h | 4 ++++ src/src/Globals/ESPEasy_now_handler.h | 4 ++-- src/src/Helpers/C019_ESPEasyNow_helper.cpp | 2 ++ src/src/Helpers/C019_ESPEasyNow_helper.h | 5 +++++ src/src/Helpers/ESPEasy_now_handler.cpp | 6 ++++-- src/src/Helpers/ESPEasy_now_handler.h | 3 ++- src/src/Helpers/Networking.cpp | 2 ++ src/src/Helpers/PeriodicalActions.cpp | 20 ++++++++++++++----- src/src/Helpers/PeriodicalActions.h | 7 +++++-- src/src/Helpers/_CPlugin_Helper_webform.cpp | 6 ++++++ src/src/WebServer/WiFiScanner.cpp | 2 ++ 40 files changed, 139 insertions(+), 17 deletions(-) diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 46abc81f98..12c209f95b 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -33,7 +33,9 @@ class C011_queue_element { bool isDuplicate(const C011_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif size_t getSize() const; diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index b3d26556c1..61d346230b 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -39,7 +39,9 @@ class C015_queue_element { bool isDuplicate(const C015_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif String txt[VARS_PER_TASK]; int vPin[VARS_PER_TASK] = { 0 }; diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 3b352e8d07..51919ad204 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -37,7 +37,9 @@ class C016_queue_element { bool isDuplicate(const C016_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif float values[VARS_PER_TASK] = { 0 }; unsigned long _timestamp = 0; // Unix timestamp diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 06522ff57d..7a8e52e0fd 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -36,7 +36,9 @@ class C018_queue_element { bool isDuplicate(const C018_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif String packed; unsigned long _timestamp = millis(); diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index d4f39fcd39..edc17a00a7 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -15,8 +15,10 @@ C019_queue_element::C019_queue_element(const C019_queue_element& other) : _timestamp(other._timestamp), TaskIndex(other.TaskIndex), controller_idx(other.controller_idx), - plugin_id(other.plugin_id), - MessageRouteInfo(other.MessageRouteInfo) + plugin_id(other.plugin_id) +#ifdef USES_ESPEASY_NOW + , MessageRouteInfo(other.MessageRouteInfo) +#endif { event.deep_copy(other.event); } diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index d334214c25..aa3b7a41df 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -34,7 +34,9 @@ class C019_queue_element { bool isDuplicate(const C019_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif String packed; unsigned long _timestamp = millis(); @@ -42,7 +44,9 @@ class C019_queue_element { controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; EventStruct event; +#ifdef USES_ESPEASY_NOW MessageRouteInfo_t MessageRouteInfo; +#endif }; // #endif //USES_C019 diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 35b5a7bbff..e2d64eb7a5 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -40,7 +40,9 @@ struct ControllerDelayHandlerStruct { must_check_reply = settings.MustCheckReply; deduplicate = settings.deduplicate(); useLocalSystemTime = settings.useLocalSystemTime(); +#ifdef USES_ESPEASY_NOW enableESPEasyNowFallback = settings.enableESPEasyNowFallback(); +#endif if (settings.allowExpire()) { expire_timeout = max_queue_depth * max_retries * (minTimeBetweenMessages + settings.ClientTimeout); if (expire_timeout < CONTROLLER_QUEUE_MINIMAL_EXPIRE_TIME) { @@ -109,6 +111,7 @@ struct ControllerDelayHandlerStruct { // Return true if message is already present in the queue bool isDuplicate(const T& element) const { +#ifdef USES_ESPEASY_NOW // Some controllers may receive duplicate messages, due to lost acknowledgement // This is actually the same message, so this should not be processed. if (!unitMessageRouteInfo_map.isNew(element.getMessageRouteInfo())) { @@ -117,6 +120,7 @@ struct ControllerDelayHandlerStruct { // The unit message count is still stored to make sure a new one with the same count // is considered a duplicate, even when the queue is empty. unitMessageRouteInfo_map.add(element.getMessageRouteInfo()); +#endif // the setting 'deduplicate' does look at the content of the message and only compares it to messages in the queue. if (deduplicate && !sendQueue.empty()) { @@ -249,7 +253,9 @@ struct ControllerDelayHandlerStruct { } std::list sendQueue; +#ifdef USES_ESPEASY_NOW mutable UnitMessageRouteInfo_map unitMessageRouteInfo_map; +#endif unsigned long lastSend = 0u; unsigned int minTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT; unsigned long expire_timeout = 0; diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index 256d14e66f..7573650395 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -39,8 +39,10 @@ class MQTT_queue_element { bool isDuplicate(const MQTT_queue_element& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return &MessageRouteInfo; } MessageRouteInfo_t* getMessageRouteInfo() { return &MessageRouteInfo; } +#endif void removeEmptyTopics(); @@ -50,7 +52,9 @@ class MQTT_queue_element { taskIndex_t TaskIndex = INVALID_TASK_INDEX; controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; bool _retained = false; +#ifdef USES_ESPEASY_NOW MessageRouteInfo_t MessageRouteInfo; +#endif }; #endif // USES_MQTT diff --git a/src/src/ControllerQueue/SimpleQueueElement_formatted_Strings.h b/src/src/ControllerQueue/SimpleQueueElement_formatted_Strings.h index 9ae7fd54ce..6ebe0a6f12 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_formatted_Strings.h +++ b/src/src/ControllerQueue/SimpleQueueElement_formatted_Strings.h @@ -46,9 +46,11 @@ class SimpleQueueElement_formatted_Strings { bool isDuplicate(const SimpleQueueElement_formatted_Strings& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t * getMessageRouteInfo() const { return nullptr; } +#endif String txt[VARS_PER_TASK]; int idx = 0; diff --git a/src/src/ControllerQueue/SimpleQueueElement_string_only.h b/src/src/ControllerQueue/SimpleQueueElement_string_only.h index 657746c315..4f55a92568 100644 --- a/src/src/ControllerQueue/SimpleQueueElement_string_only.h +++ b/src/src/ControllerQueue/SimpleQueueElement_string_only.h @@ -30,7 +30,9 @@ class simple_queue_element_string_only { bool isDuplicate(const simple_queue_element_string_only& other) const; +#ifdef USES_ESPEASY_NOW const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } +#endif String txt; unsigned long _timestamp = millis(); diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index ff77d4a3f9..9a90967b88 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1625,7 +1625,7 @@ To create/register a plugin, you have to : */ -#if defined(USES_C018) || defined(USES_C019) +#if defined(USES_C018) #define USES_PACKED_RAW_DATA #endif @@ -1888,5 +1888,10 @@ To create/register a plugin, you have to : #undef USES_C019 #endif +#if defined(USES_C019) && !defined(USES_PACKED_RAW_DATA) + #define USES_PACKED_RAW_DATA +#endif + + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H \ No newline at end of file diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 1c77353fb5..4348a26de3 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -87,7 +87,9 @@ struct ControllerSettingsStruct CONTROLLER_TIMEOUT, CONTROLLER_SAMPLE_SET_INITIATOR, CONTROLLER_SEND_BINARY, +#ifdef USES_ESPEASY_NOW CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK, +#endif // Keep this as last, is used to loop over all parameters CONTROLLER_ENABLED diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp index b1eb5ae9be..9dac6b1086 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.cpp @@ -1,8 +1,12 @@ #include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" +#ifdef USES_ESPEASY_NOW + ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck() : _key(0), _type(ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck) {} ESPEasy_Now_DuplicateCheck::ESPEasy_Now_DuplicateCheck(uint32_t key, message_t message_type) : _key(key), _type(message_type) {} + +#endif \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h index 52b4302d96..acd3ea77e9 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h @@ -3,6 +3,9 @@ #include +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW class ESPEasy_Now_DuplicateCheck { public: @@ -20,5 +23,7 @@ class ESPEasy_Now_DuplicateCheck { const message_t _type; }; +#endif + #endif // DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H diff --git a/src/src/DataStructs/MessageRouteInfo.cpp b/src/src/DataStructs/MessageRouteInfo.cpp index b253fb2638..5296c5545f 100644 --- a/src/src/DataStructs/MessageRouteInfo.cpp +++ b/src/src/DataStructs/MessageRouteInfo.cpp @@ -1,6 +1,6 @@ #include "../DataStructs/MessageRouteInfo.h" - +#ifdef USES_ESPEASY_NOW MessageRouteInfo_t::MessageRouteInfo_t(const uint8_t* serializedData, size_t size) { deserialize(serializedData, size); } @@ -138,3 +138,4 @@ void UnitMessageRouteInfo_map::add(const MessageRouteInfo_t *info) { _map[info->unit] = *info; } } +#endif \ No newline at end of file diff --git a/src/src/DataStructs/MessageRouteInfo.h b/src/src/DataStructs/MessageRouteInfo.h index 90bcfd269e..f0e1c8e617 100644 --- a/src/src/DataStructs/MessageRouteInfo.h +++ b/src/src/DataStructs/MessageRouteInfo.h @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" +#ifdef USES_ESPEASY_NOW #include #include @@ -67,5 +68,6 @@ struct UnitMessageRouteInfo_map { std::map _map; }; +#endif #endif // ifndef DATASTRUCTS_MESSAGEROUTEINFO_H diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 90e5373c38..a16c2126e1 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -238,6 +238,7 @@ const __FlashStringHelper * getMiscStatsName_F(int stat) { case PARSE_SYSVAR: return F("parseSystemVariables()"); case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); +#ifdef USES_ESPEASY_NOW case HANDLE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " handle received message"); case EXPIRED_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete expired"); case INVALID_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete invalid"); @@ -246,6 +247,7 @@ const __FlashStringHelper * getMiscStatsName_F(int stat) { case ESPEASY_NOW_SEND_MSG_FAIL: return F(ESPEASY_NOW_NAME " send Message Fail"); case ESPEASY_NOW_SEND_PCKT: return F(ESPEASY_NOW_NAME " send Packet"); case ESPEASY_NOW_DEDUP_LOOP: return F(ESPEASY_NOW_NAME " DuplicateCheck loop"); +#endif case WIFI_SCAN_ASYNC: return F("WiFi Scan Async"); case WIFI_SCAN_SYNC: return F("WiFi Scan Sync (blocking)"); case C018_AIR_TIME: return F("C018 LoRa TTN - Air Time"); diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 923e67cbd0..3ffd14906b 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -87,6 +87,7 @@ # define HANDLE_SCHEDULER_IDLE 64 # define HANDLE_SCHEDULER_TASK 65 # define HANDLE_SERVING_WEBPAGE 66 +#ifdef USES_ESPEASY_NOW # define HANDLE_ESPEASY_NOW_LOOP 67 # define EXPIRED_ESPEASY_NOW_LOOP 68 # define INVALID_ESPEASY_NOW_LOOP 69 @@ -95,6 +96,7 @@ # define ESPEASY_NOW_SEND_MSG_FAIL 72 # define ESPEASY_NOW_SEND_PCKT 73 # define ESPEASY_NOW_DEDUP_LOOP 74 +#endif # define WIFI_SCAN_ASYNC 75 # define WIFI_SCAN_SYNC 76 diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index bf791a64fb..6459189c23 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -81,7 +81,9 @@ void WiFiEventData_t::markWiFiTurnOn() { processedConnectAPmode = true; processedDisconnectAPmode = true; processedScanDone = true; + #ifdef USES_ESPEASY_NOW processedProbeRequestAPmode = true; + #endif wifiConnectAttemptNeeded = true; wifiConnectInProgress = false; processingDisconnect.clear(); diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 97d6b62432..ba1f69b389 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -110,7 +110,9 @@ struct WiFiEventData_t { bool processedConnectAPmode = true; bool processedDisconnectAPmode = true; bool processedScanDone = true; + #ifdef USES_ESPEASY_NOW bool processedProbeRequestAPmode = true; + #endif bool wifiConnectAttemptNeeded = true; bool wifiConnectInProgress = false; bool warnedNoValidWiFiSettings = false; diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index fe957f33a9..71a49da75d 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -128,12 +128,18 @@ void SettingsStruct_tmpl::SendToHttp_ack(bool value) { template bool SettingsStruct_tmpl::UseESPEasyNow() const { +#ifdef USES_ESPEASY_NOW return bitRead(VariousBits1, 11); +#else + return false; +#endif } template void SettingsStruct_tmpl::UseESPEasyNow(bool value) { +#ifdef USES_ESPEASY_NOW bitWrite(VariousBits1, 11, value); +#endif } template diff --git a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h index d62d866859..132d4b957f 100644 --- a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h +++ b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h @@ -5,6 +5,9 @@ #include #include +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW struct ESPEasy_Now_MQTT_QueueCheckState { enum Enum : uint8_t { Unset = 0, @@ -14,3 +17,5 @@ struct ESPEasy_Now_MQTT_QueueCheckState { }; #endif + +#endif diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 875db78334..d5ecbcc510 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -20,8 +20,10 @@ #include "../Globals/Device.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" +#ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_handler.h" #include "../Globals/SendData_DuplicateChecker.h" +#endif #include "../Globals/MQTT.h" #include "../Globals/Plugins.h" #include "../Globals/Protocol.h" diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 67d31554cd..950b249343 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -351,10 +351,12 @@ void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) { WiFiEventData.markDisconnectedAPmode(event.mac); } +#ifdef USES_ESPEASY_NOW void onProbeRequestAPmode(const WiFiEventSoftAPModeProbeRequestReceived& event) { APModeProbeRequestReceived_list.push_back(event); WiFiEventData.processedProbeRequestAPmode = false; } +#endif void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event) { WiFiEventData.setAuthMode(event.newMode); diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h index 1bd783aa7e..7f35d7c686 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h @@ -60,7 +60,9 @@ void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event); void onDisconnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event); +#ifdef USES_ESPEASY_NOW void onProbeRequestAPmode(const WiFiEventSoftAPModeProbeRequestReceived& event); +#endif void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index d1e1114e40..5560d51c97 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -604,7 +604,9 @@ void initWiFi() stationModeAuthModeChangeHandler = WiFi.onStationModeAuthModeChanged(onStationModeAuthModeChanged); APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode); APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisconnectedAPmode); +#ifdef USES_ESPEASY_NOW APModeProbeRequestReceivedHandler = WiFi.onSoftAPModeProbeRequestReceived(onProbeRequestAPmode); +#endif #endif } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index d59e69ff6b..38fc50d8af 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -11,9 +11,10 @@ #include "../ESPEasyCore/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" +#ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_handler.h" #include "../Globals/ESPEasy_now_state.h" -#include "../Globals/ESPEasy_now_state.h" +#endif #include "../Globals/ESPEasy_time.h" #include "../Globals/EventQueue.h" #include "../Globals/MQTT.h" @@ -184,7 +185,9 @@ void handle_unprocessedNetworkEvents() if (!WiFiEventData.processedConnectAPmode) { processConnectAPmode(); } +#ifdef USES_ESPEASY_NOW if (!WiFiEventData.processedProbeRequestAPmode) { processProbeRequestAPmode(); } +#endif if (WiFiEventData.timerAPoff.isSet()) { processDisableAPmode(); } @@ -485,6 +488,7 @@ void processDisconnectAPmode() { } } +#ifdef USES_ESPEASY_NOW void processProbeRequestAPmode() { if (WiFiEventData.processedProbeRequestAPmode) { return; } @@ -516,6 +520,7 @@ void processProbeRequestAPmode() { APModeProbeRequestReceived_list.pop_front(); WiFiEventData.processedProbeRequestAPmode = APModeProbeRequestReceived_list.size() == 0; } +#endif // Client connects to AP on this node void processConnectAPmode() { diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h index 20c7de62a0..cc9397472f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h @@ -8,7 +8,9 @@ void processDisconnect(); void processConnect(); void processGotIP(); void processDisconnectAPmode(); +#ifdef USES_ESPEASY_NOW void processProbeRequestAPmode(); +#endif void processConnectAPmode(); void processDisableAPmode(); void processScanDone(); diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index e5ad1eee73..bd1c5927cd 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -13,14 +13,18 @@ WiFiEventHandler stationModeDHCPTimeoutHandler; WiFiEventHandler stationModeAuthModeChangeHandler; WiFiEventHandler APModeStationConnectedHandler; WiFiEventHandler APModeStationDisconnectedHandler; +#ifdef USES_ESPEASY_NOW WiFiEventHandler APModeProbeRequestReceivedHandler; std::list APModeProbeRequestReceived_list; +#endif #endif // ifdef ESP8266 #ifdef ESP32 +#ifdef USES_ESPEASY_NOW std::list APModeProbeRequestReceived_list; #endif +#endif WiFiEventData_t WiFiEventData; diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index afae88d365..6e9a5ea37e 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -33,13 +33,17 @@ extern WiFiEventHandler stationModeDHCPTimeoutHandler; extern WiFiEventHandler stationModeAuthModeChangeHandler; extern WiFiEventHandler APModeStationConnectedHandler; extern WiFiEventHandler APModeStationDisconnectedHandler; +#ifdef USES_ESPEASY_NOW extern WiFiEventHandler APModeProbeRequestReceivedHandler; extern std::list APModeProbeRequestReceived_list; +#endif #endif // ifdef ESP8266 #ifdef ESP32 +#ifdef USES_ESPEASY_NOW extern std::list APModeProbeRequestReceived_list; #endif +#endif extern WiFiEventData_t WiFiEventData; diff --git a/src/src/Globals/ESPEasy_now_handler.h b/src/src/Globals/ESPEasy_now_handler.h index af0733a00f..f6cb06a73d 100644 --- a/src/src/Globals/ESPEasy_now_handler.h +++ b/src/src/Globals/ESPEasy_now_handler.h @@ -3,10 +3,10 @@ #include "../../ESPEasy_common.h" -#include "../Helpers/ESPEasy_now_handler.h" - #ifdef USES_ESPEASY_NOW +#include "../Helpers/ESPEasy_now_handler.h" + extern ESPEasy_now_handler_t ESPEasy_now_handler; #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/C019_ESPEasyNow_helper.cpp b/src/src/Helpers/C019_ESPEasyNow_helper.cpp index eb607cee49..563eaf4771 100644 --- a/src/src/Helpers/C019_ESPEasyNow_helper.cpp +++ b/src/src/Helpers/C019_ESPEasyNow_helper.cpp @@ -1,5 +1,6 @@ #include "../Helpers/C019_ESPEasyNow_helper.h" +#ifdef USES_ESPEASY_NOW #include "../DataStructs/ESPEasy_EventStruct.h" #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Globals/CPlugins.h" @@ -45,3 +46,4 @@ bool C019_ESPEasyNow_helper::process_receive(struct EventStruct *event) { void C019_ESPEasyNow_helper::process_received_PluginData(const ESPEasy_Now_p2p_data& data) { } +#endif \ No newline at end of file diff --git a/src/src/Helpers/C019_ESPEasyNow_helper.h b/src/src/Helpers/C019_ESPEasyNow_helper.h index e4e468edd0..8cfc0463b1 100644 --- a/src/src/Helpers/C019_ESPEasyNow_helper.h +++ b/src/src/Helpers/C019_ESPEasyNow_helper.h @@ -1,6 +1,10 @@ #ifndef HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H #define HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + #include "../DataStructs/ESPEasy_Now_p2p_data.h" struct C019_ESPEasyNow_helper { @@ -9,5 +13,6 @@ struct C019_ESPEasyNow_helper { static void process_received_PluginData(const ESPEasy_Now_p2p_data& data); }; +#endif #endif // HELPERS_CONTROLLER_C019_ESPEASYNOW_HELPER_H diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index a34dffd5c3..986d61f3eb 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1,5 +1,9 @@ #include "../Helpers/ESPEasy_now_handler.h" +# include "../Helpers/_CPlugin_Helper.h" + +#ifdef USES_ESPEASY_NOW + # include "../ControllerQueue/MQTT_queue_element.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" @@ -34,12 +38,10 @@ # include "../Helpers/ESPEasy_time_calc.h" # include "../Helpers/ESPEasyMutex.h" # include "../Helpers/PeriodicalActions.h" -# include "../Helpers/_CPlugin_Helper.h" # include -#ifdef USES_ESPEASY_NOW # define ESPEASY_NOW_ACTIVITY_TIMEOUT 125000 // 2 minutes + 5 sec # define ESPEASY_NOW_SINCE_LAST_BROADCAST 65000 // 1 minute + 5 sec to start sending a node directly diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 25f1db7c73..cbbff3c8b9 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -3,11 +3,12 @@ #include "../Globals/ESPEasy_now_state.h" +#ifdef USES_ESPEASY_NOW + #include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" #include "../DataTypes/ControllerIndex.h" #include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" -#ifdef USES_ESPEASY_NOW struct ESPEasy_Now_p2p_data; class ESPEasy_now_merger; diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index e723499146..c774f88992 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -10,7 +10,9 @@ #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" +#ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_handler.h" +#endif #include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" #include "../Globals/Nodes.h" diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 5e86abb3d0..8a5dc8e834 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -28,8 +28,10 @@ #include "../Globals/Services.h" #include "../Globals/Settings.h" #include "../Globals/Statistics.h" +#ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_handler.h" #include "../Globals/SendData_DuplicateChecker.h" +#endif #include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/ESPEasyRTC.h" #include "../Helpers/Hardware.h" @@ -326,11 +328,13 @@ void processMQTTdelayQueue() { #endif bool processed = false; +#ifdef USES_ESPEASY_NOW MessageRouteInfo_t messageRouteInfo; if (element->getMessageRouteInfo() != nullptr) { messageRouteInfo = *(element->getMessageRouteInfo()); } messageRouteInfo.appendUnit(Settings.Unit); +#endif #ifdef USES_ESPEASY_NOW if (element->_topic.startsWith(F("traceroute/")) || element->_topic.indexOf(F("/traceroute/")) != -1) { @@ -344,11 +348,12 @@ void processMQTTdelayQueue() { message += element->_payload; processed = processMQTT_message(element->controller_idx, element->_topic, message, element->_retained, &messageRouteInfo); - } else - #endif - { + } else { processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained, &messageRouteInfo); } + #else + processed = processMQTT_message(element->controller_idx, element->_topic, element->_payload, element->_retained); + #endif MQTTDelayHandler->markProcessed(processed); @@ -373,8 +378,11 @@ void processMQTTdelayQueue() { bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, - bool retained, - const MessageRouteInfo_t* messageRouteInfo) + bool retained +#ifdef USES_ESPEASY_NOW + , const MessageRouteInfo_t* messageRouteInfo +#endif + ) { bool processed = false; @@ -391,11 +399,13 @@ bool processMQTT_message(controllerIndex_t controllerIndex, --WiFiEventData.connectionFailures; } //#ifndef BUILD_NO_DEBUG +#ifdef USES_ESPEASY_NOW if (loglevelActiveFor(LOG_LEVEL_DEBUG) && messageRouteInfo != nullptr) { String log = F("MQTT : published from mesh: "); log += messageRouteInfo->toString(); addLog(LOG_LEVEL_DEBUG, log); } +#endif //#endif // ifndef BUILD_NO_DEBUG processed = true; } diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index a330126cf3..4e0935e6b2 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -40,8 +40,11 @@ void processMQTTdelayQueue(); bool processMQTT_message(controllerIndex_t controllerIndex, const String & topic, const String & payload, - bool retained, - const MessageRouteInfo_t* messageRouteInfo); + bool retained +#ifdef USES_ESPEASY_NOW + , const MessageRouteInfo_t* messageRouteInfo +#endif + ); void updateMQTTclient_connected(); diff --git a/src/src/Helpers/_CPlugin_Helper_webform.cpp b/src/src/Helpers/_CPlugin_Helper_webform.cpp index e458f0eaa2..da3db414ed 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.cpp +++ b/src/src/Helpers/_CPlugin_Helper_webform.cpp @@ -49,7 +49,9 @@ const __FlashStringHelper * toString(ControllerSettingsStruct::VarType parameter case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: return F("Send Binary"); case ControllerSettingsStruct::CONTROLLER_TIMEOUT: return F("Client Timeout"); case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: return F("Sample Set Initiator"); +#ifdef USES_ESPEASY_NOW case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: return F("Enable " ESPEASY_NOW_NAME " Fallback"); +#endif case ControllerSettingsStruct::CONTROLLER_ENABLED: @@ -268,9 +270,11 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: addTaskSelectBox(displayName, internalName, ControllerSettings.SampleSetInitiator); break; +#ifdef USES_ESPEASY_NOW case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: addFormCheckBox(displayName, internalName, ControllerSettings.enableESPEasyNowFallback()); break; +#endif case ControllerSettingsStruct::CONTROLLER_ENABLED: addFormCheckBox(displayName, internalName, Settings.ControllerEnabled[controllerindex]); break; @@ -395,9 +399,11 @@ void saveControllerParameterForm(ControllerSettingsStruct & ControllerSet case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: ControllerSettings.SampleSetInitiator = getFormItemInt(internalName, ControllerSettings.SampleSetInitiator); break; +#ifdef USES_ESPEASY_NOW case ControllerSettingsStruct::CONTROLLER_ENABLE_ESPEASY_NOW_FALLBACK: ControllerSettings.enableESPEasyNowFallback(isFormItemChecked(internalName)); break; +#endif case ControllerSettingsStruct::CONTROLLER_ENABLED: Settings.ControllerEnabled[controllerindex] = isFormItemChecked(internalName); break; diff --git a/src/src/WebServer/WiFiScanner.cpp b/src/src/WebServer/WiFiScanner.cpp index a7b188b23c..f35d52974a 100644 --- a/src/src/WebServer/WiFiScanner.cpp +++ b/src/src/WebServer/WiFiScanner.cpp @@ -8,7 +8,9 @@ #include "../Globals/WiFi_AP_Candidates.h" #include "../Helpers/StringGenerator_WiFi.h" +#ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_handler.h" +#endif #ifdef WEBSERVER_NEW_UI From 82466581d89379e3322c0c10f59ffd8d088f90f9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 12 Jun 2022 01:26:28 +0200 Subject: [PATCH 246/404] [Build] Remove test_X_alt_wifi_ESP8266_4M1M_VCC envs --- platformio_esp82xx_envs.ini | 65 ++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 46d18132da..a598d7f1ec 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -560,11 +560,8 @@ build_flags = ${testing_ESP8266_4M1M.build_flags} -DTESTING_USE_RTTTL [env:test_E_ESP8266_4M1M] -extends = esp8266_4M1M -platform = ${testing.platform} -platform_packages = ${testing.platform_packages} -build_flags = ${testing.build_flags} - ${esp8266_4M1M.build_flags} +extends = testing_ESP8266_4M1M +build_flags = ${testing_ESP8266_4M1M.build_flags} -DPLUGIN_BUILD_TESTING_E -DTESTING_USE_RTTTL @@ -597,46 +594,40 @@ build_flags = ${testing_ESP8266_4M1M.build_flags} -DTESTING_USE_RTTTL [env:test_E_ESP8266_4M1M_VCC] -extends = esp8266_4M1M -platform = ${testing.platform} -platform_packages = ${testing.platform_packages} -build_flags = ${testing.build_flags} - ${esp8266_4M1M.build_flags} +extends = testing_ESP8266_4M1M +build_flags = ${testing_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true -DPLUGIN_BUILD_TESTING_E -DTESTING_USE_RTTTL -[env:test_A_alt_wifi_ESP8266_4M1M_VCC] -extends = testing_alt_wifi_ESP8266_4M1M -build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true +;[env:test_A_alt_wifi_ESP8266_4M1M_VCC] +;extends = testing_alt_wifi_ESP8266_4M1M +;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +; -DFEATURE_ADC_VCC=true -[env:test_B_alt_wifi_ESP8266_4M1M_VCC] -extends = testing_alt_wifi_ESP8266_4M1M -build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_B +;[env:test_B_alt_wifi_ESP8266_4M1M_VCC] +;extends = testing_alt_wifi_ESP8266_4M1M +;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +; -DFEATURE_ADC_VCC=true +; -DPLUGIN_BUILD_TESTING_B -[env:test_C_alt_wifi_ESP8266_4M1M_VCC] -extends = testing_alt_wifi_ESP8266_4M1M -build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_C +;[env:test_C_alt_wifi_ESP8266_4M1M_VCC] +;extends = testing_alt_wifi_ESP8266_4M1M +;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +; -DFEATURE_ADC_VCC=true +; -DPLUGIN_BUILD_TESTING_C -[env:test_D_alt_wifi_ESP8266_4M1M_VCC] -extends = testing_alt_wifi_ESP8266_4M1M -build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_D +;[env:test_D_alt_wifi_ESP8266_4M1M_VCC] +;extends = testing_alt_wifi_ESP8266_4M1M +;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +; -DFEATURE_ADC_VCC=true +; -DPLUGIN_BUILD_TESTING_D -[env:test_E_alt_wifi_ESP8266_4M1M_VCC] -extends = esp8266_4M1M -platform = ${testing_alt_wifi.platform} -platform_packages = ${testing_alt_wifi.platform_packages} -build_flags = ${testing_alt_wifi.build_flags} - ${esp8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_E +;[env:test_E_alt_wifi_ESP8266_4M1M_VCC] +;extends = testing_alt_wifi_ESP8266_4M1M +;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +; -DFEATURE_ADC_VCC=true +; -DPLUGIN_BUILD_TESTING_E ; TEST: 4096k version + FEATURE_ADC_VCC + FEATURE_MDNS + FEATURE_SD ---------- From f190c8528127d733a81cdb8b97f02951f0689aa4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 14 Jun 2022 14:16:34 +0200 Subject: [PATCH 247/404] [ESPEasy-NOW] Fix slow wifi connect at boot when using mesh --- src/src/DataStructs/NodesHandler.cpp | 12 ++++---- src/src/DataStructs/WiFiEventData.cpp | 17 +++++++---- src/src/DataStructs/WiFiEventData.h | 2 +- src/src/ESPEasyCore/ESPEasyWifi.cpp | 29 +++++++++++++++++-- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 5 ++-- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 2c6b7ad40b..3a3dfcab82 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -534,15 +534,17 @@ bool NodesHandler::isEndpoint() const #ifdef USES_ESPEASY_NOW uint8_t NodesHandler::getESPEasyNOW_channel() const { - if (isEndpoint()) { - if (active_network_medium == NetworkMedium_t::WIFI || - Settings.ForceESPEasyNOWchannel == 0) { - return WiFi.channel(); - } + if (active_network_medium == NetworkMedium_t::WIFI && NetworkConnected()) { + return WiFi.channel(); } if (Settings.ForceESPEasyNOWchannel > 0) { return Settings.ForceESPEasyNOWchannel; } + if (isEndpoint()) { + if (active_network_medium == NetworkMedium_t::WIFI) { + return WiFi.channel(); + } + } const NodeStruct *preferred = getPreferredNode(); if (preferred != nullptr) { if (preferred->distance < 255) { diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 6459189c23..cbb29dbe6b 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -29,29 +29,31 @@ bool WiFiEventData_t::WiFiConnectAllowed() const { return true; } -bool WiFiEventData_t::unprocessedWifiEvents() const { +bool WiFiEventData_t::unprocessedWifiEvents() { if (processedConnect && processedDisconnect && processedGotIP && processedDHCPTimeout) { return false; } if (!processedConnect) { if (lastConnectMoment.isSet() && lastConnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { - return false; + processedConnect = true; } } if (!processedGotIP) { if (lastGetIPmoment.isSet() && lastGetIPmoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { - return false; + processedGotIP = true;; } } if (!processedDisconnect) { if (lastDisconnectMoment.isSet() && lastDisconnectMoment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { - return false; + processedDisconnect = true; } } - if (!processedDHCPTimeout) { + if (processedConnect && processedDisconnect && processedGotIP && processedDHCPTimeout) + { return false; } + return true; } @@ -98,6 +100,9 @@ void WiFiEventData_t::markWiFiBegin() { if (!timerAPstart.isSet()) { timerAPstart.setMillisFromNow(WIFI_RECONNECT_WAIT); } + #ifdef USES_ESPEASY_NOW + temp_disable_EspEasy_now_timer = millis() + WIFI_RECONNECT_WAIT; + #endif } bool WiFiEventData_t::WiFiDisconnected() const { @@ -136,7 +141,7 @@ void WiFiEventData_t::setWiFiServicesInitialized() { wifiConnectInProgress = false; #ifdef USES_ESPEASY_NOW - temp_disable_EspEasy_now_timer = 0; + temp_disable_EspEasy_now_timer = millis() + WIFI_RECONNECT_WAIT; #endif } } diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index ba1f69b389..4245a7307e 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -29,7 +29,7 @@ struct WiFiEventData_t { bool WiFiConnectAllowed() const; - bool unprocessedWifiEvents() const; + bool unprocessedWifiEvents(); void clearAll(); void markWiFiTurnOn(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 5560d51c97..f1c8bb3234 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1098,13 +1098,27 @@ void setAPinternal(bool enable) addLog(LOG_LEVEL_ERROR, F("WIFI : [AP] softAPConfig failed!")); } - if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str())) { + int channel = 1; + if (WifiIsSTA(WiFi.getMode())) { + channel = WiFi.channel(); + } else { + #ifdef USES_ESPEASY_NOW + if (Settings.UseESPEasyNow() && Settings.ForceESPEasyNOWchannel != 0) { + channel = Settings.ForceESPEasyNOWchannel; + } + #endif + } + + + if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str(), channel)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { eventQueue.add(F("WiFi#APmodeEnabled")); String log(F("WIFI : AP Mode ssid will be ")); log += softAPSSID; log += F(" with address "); log += WiFi.softAPIP().toString(); + log += F(" on channel: "); + log += WiFi.channel(); addLogMove(LOG_LEVEL_INFO, log); } } else { @@ -1255,7 +1269,18 @@ void setWifiMode(WiFiMode_t wifimode) { if (WifiIsAP(cur_mode) != new_mode_AP_enabled) { // Mode has changed - if (!Settings.DoNotStartAP()) { + if (new_mode_AP_enabled) { + // Check if we should start internal AP + if (!WifiIsSTA(wifimode)) { + bool mustStartInternalAP = !Settings.DoNotStartAP(); + if (mustStartInternalAP && (WiFiEventData.wifiConnectInProgress || WiFiConnected())) { + mustStartInternalAP = false; + } + if (mustStartInternalAP) { + setAPinternal(new_mode_AP_enabled); + } + } + } else { setAPinternal(new_mode_AP_enabled); } } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 38fc50d8af..80d1062e53 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -283,7 +283,6 @@ void processDisconnect() { mustRestartWiFi = true; } #endif - WifiDisconnect(); // Needed or else node may not reconnect reliably. if (mustRestartWiFi) { WifiScan(false); @@ -609,7 +608,7 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { ESPEasy_now_handler.addPeerFromWiFiScan(); - if (!NetworkConnected()) { + if (!NetworkConnected() && (temp_disable_EspEasy_now_timer == 0 || timeOutReached(temp_disable_EspEasy_now_timer))) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); // if (isESPEasy_now_only() || !ESPEasy_now_handler.active()) { @@ -623,7 +622,7 @@ void processScanDone() { setSTA(false); setNetworkMedium(Settings.NetworkMedium); NetworkConnectRelaxed(); - // } +// } } else { setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); } From 38352521a4b52b5cccc4d1912571fd5d8e0112f9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 24 Jun 2022 00:41:32 +0200 Subject: [PATCH 248/404] [ESPEasy-NOW] Fix includes order to build on Linux --- src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h | 7 ++++--- src/src/Helpers/ESPEasy_now_handler.h | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h index 132d4b957f..463ee98ae9 100644 --- a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h +++ b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h @@ -6,16 +6,17 @@ #include #include "../../ESPEasy_common.h" +#include "../Globals/ESPEasy_now_state.h" #ifdef USES_ESPEASY_NOW struct ESPEasy_Now_MQTT_QueueCheckState { enum Enum : uint8_t { Unset = 0, Empty = 1, - Full = 2 + Full = 2 }; }; -#endif +#endif // ifdef USES_ESPEASY_NOW -#endif +#endif // ifndef DATATYPES_ESPEASY_NOW_MQTT_QUEUE_CHECK_STATE_H diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index cbbff3c8b9..dbcb31aae2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -5,9 +5,9 @@ #ifdef USES_ESPEASY_NOW -#include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" -#include "../DataTypes/ControllerIndex.h" -#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" +# include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" +# include "../DataTypes/ControllerIndex.h" +# include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" struct ESPEasy_Now_p2p_data; @@ -116,7 +116,7 @@ class ESPEasy_now_handler_t { void load_ControllerSettingsCache(controllerIndex_t controllerIndex); - ESPEasy_Now_NTP_query * _best_NTP_candidate = nullptr; + ESPEasy_Now_NTP_query *_best_NTP_candidate = nullptr; unsigned long _last_used = 0; unsigned long _last_started = 0; From 0e6d9f35ee50c063e035c782e88e2d0cbc3df62d Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 24 Jun 2022 00:48:05 +0200 Subject: [PATCH 249/404] [ESPEasy-NOW] Remove restrictive #ifdef check to help building on Linux --- src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h index 463ee98ae9..f45906dd2d 100644 --- a/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h +++ b/src/src/DataTypes/ESPEasy_Now_MQTT_queue_check_state.h @@ -6,9 +6,7 @@ #include #include "../../ESPEasy_common.h" -#include "../Globals/ESPEasy_now_state.h" -#ifdef USES_ESPEASY_NOW struct ESPEasy_Now_MQTT_QueueCheckState { enum Enum : uint8_t { Unset = 0, @@ -17,6 +15,4 @@ struct ESPEasy_Now_MQTT_QueueCheckState { }; }; -#endif // ifdef USES_ESPEASY_NOW - #endif // ifndef DATATYPES_ESPEASY_NOW_MQTT_QUEUE_CHECK_STATE_H From 547b4450248bf82def1fc95bc3db6533aafe007a Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 24 Jun 2022 09:47:38 +0200 Subject: [PATCH 250/404] [ESPEasy-NOW] Move include to fix build on Linux --- src/src/Helpers/ESPEasy_now_handler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index dbcb31aae2..087e5559b4 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -3,11 +3,12 @@ #include "../Globals/ESPEasy_now_state.h" +#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" + #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataTypes/ControllerIndex.h" -# include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" struct ESPEasy_Now_p2p_data; From d4aed17bd6f9836ca28760440077d7a7f1ad9fe8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 19 Jul 2022 16:37:21 +0200 Subject: [PATCH 251/404] [ESPEasy-NOW] Fix merge issue --- src/src/Helpers/Networking.cpp | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index b603eb6d6e..44295f3694 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -152,7 +152,7 @@ void SendUDPCommand(uint8_t destUnit, const char *data, uint8_t dataLength) sendUDP(destUnit, (const uint8_t *)data, dataLength); delay(10); } else { - for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) { + for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->first != Settings.Unit) { sendUDP(it->first, (const uint8_t *)data, dataLength); delay(10); @@ -358,30 +358,6 @@ void checkUDP() runningUPDCheck = false; } -/*********************************************************************************************\ - Send event using UDP message -\*********************************************************************************************/ -void SendUDPCommand(uint8_t destUnit, const char *data, uint8_t dataLength) -{ - if (!NetworkConnected(10)) { - return; - } - - if (destUnit != 0) - { - sendUDP(destUnit, (const uint8_t *)data, dataLength); - delay(10); - } else { - for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->first != Settings.Unit) { - sendUDP(it->first, (const uint8_t *)data, dataLength); - delay(10); - } - } - } - delay(50); -} - /*********************************************************************************************\ Get formatted IP address for unit formatcodes: 0 = default toString(), 1 = empty string when invalid, 2 = 0 when invalid From 75e86f8e66eb0038bc480d3e8377eb4693b45e12 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 19 Jul 2022 17:06:17 +0200 Subject: [PATCH 252/404] [ESPEasy_NOW] Fix missing includes (GHActions build failed) --- src/src/ESPEasyCore/ESPEasyNetwork.h | 2 ++ src/src/Globals/ESPEasy_now_state.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 0b27408482..7ea969bd4d 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -8,6 +8,8 @@ #include "../DataStructs/MAC_address.h" +#include "../Globals/ESPEasy_now_state.h" + void setNetworkMedium(NetworkMedium_t medium); bool isESPEasy_now_only(); diff --git a/src/src/Globals/ESPEasy_now_state.h b/src/src/Globals/ESPEasy_now_state.h index b1c8f31e98..13d6070a80 100644 --- a/src/src/Globals/ESPEasy_now_state.h +++ b/src/src/Globals/ESPEasy_now_state.h @@ -5,6 +5,8 @@ #ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_handler.h" + # include extern bool use_EspEasy_now; From e5c294b5016dadde94a90c8b37746b134d8bc2b3 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 25 Jul 2022 21:44:10 +0200 Subject: [PATCH 253/404] [ESPEasy-NOW] Fix merge issue --- src/src/DataTypes/ESPEasyFileType.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index 2e8161ec78..362d7ef34d 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -69,8 +69,6 @@ bool getDownloadFiletypeChecked(FileType::Enum filetype, unsigned int filenr) { case FileType::NOTIFICATION_DAT: isChecked = ResetFactoryDefaultPreference.fetchNotificationDat(); break; case FileType::RULES_TXT: isChecked = ResetFactoryDefaultPreference.fetchRulesTXT(filenr); break; case FileType::PROVISIONING_DAT: isChecked = ResetFactoryDefaultPreference.fetchProvisioningDat(); break; - case FileType::FIRMWARE: - break; case FileType::FIRMWARE: // FIXME TD-er: Must decide what to do with firmware description/protection on provisioning settings case FileType::MAX_FILETYPE: From 8db8379d2e02d93916db1ee46590c33e6a559cf2 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 22 Jul 2022 21:48:13 +0200 Subject: [PATCH 254/404] [Build] Rename TEST builds to COLLECTION to reduce confusion about build-names --- platformio_esp32_envs.ini | 95 ++-- platformio_esp32s2_envs.ini | 30 +- platformio_esp82xx_base.ini | 20 +- platformio_esp82xx_envs.ini | 284 +++++----- src/ESPEasy-Globals.h | 3 - src/_C012.cpp | 2 - src/_C015.cpp | 2 - src/src/CustomBuild/ESPEasyLimits.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 578 ++++++++++++--------- src/src/DataStructs/LogStruct.h | 2 +- src/src/Helpers/StringGenerator_System.cpp | 6 +- src/src/PluginStructs/P073_data_struct.h | 6 +- 12 files changed, 543 insertions(+), 487 deletions(-) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 526bc672ae..473d65c218 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -91,13 +91,12 @@ board_build.filesystem = littlefs [esp32_IRExt] extends = esp32_base -lib_ignore = AS_BH1750 - ${esp32_always.lib_ignore} +lib_ignore = ${esp32_always.lib_ignore} ESP32_ping build_flags = ${esp32_base.build_flags} -DFEATURE_ARDUINO_OTA -DPLUGIN_BUILD_NORMAL_IRext - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL lib_deps = ${esp32_base.lib_deps} LittleFS @@ -159,74 +158,76 @@ lib_deps = ${esp32_common_LittleFS.lib_deps} -[env:test_A_ESP32_4M316k] +[env:collection_A_ESP32_4M316k] extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} -DFEATURE_ARDUINO_OTA - -DPLUGIN_SET_TEST_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_B_ESP32_4M316k] +[env:collection_B_ESP32_4M316k] extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} -DFEATURE_ARDUINO_OTA - -DPLUGIN_SET_TEST_B_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_B_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_C_ESP32_4M316k] +[env:collection_C_ESP32_4M316k] extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} -DFEATURE_ARDUINO_OTA - -DPLUGIN_SET_TEST_C_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_C_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_D_ESP32_4M316k] +[env:collection_D_ESP32_4M316k] extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} -DFEATURE_ARDUINO_OTA - -DPLUGIN_SET_TEST_D_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_D_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_E_ESP32_4M316k] +[env:collection_E_ESP32_4M316k] extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} -DFEATURE_ARDUINO_OTA - -DPLUGIN_SET_TEST_E_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_E_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_A_ESP32_IRExt_4M316k] +[env:collection_A_ESP32_IRExt_4M316k] extends = esp32_IRExt board = esp32_4M +build_flags = ${esp32_IRExt.build_flags} + -DPLUGIN_SET_COLLECTION_ESP32 -[env:test_B_ESP32_IRExt_4M316k] +[env:collection_B_ESP32_IRExt_4M316k] extends = esp32_IRExt board = esp32_4M build_flags = ${esp32_IRExt.build_flags} - -DPLUGIN_SET_TEST_B_ESP32 + -DPLUGIN_SET_COLLECTION_B_ESP32 -[env:test_C_ESP32_IRExt_4M316k] +[env:collection_C_ESP32_IRExt_4M316k] extends = esp32_IRExt board = esp32_4M build_flags = ${esp32_IRExt.build_flags} - -DPLUGIN_SET_TEST_C_ESP32 + -DPLUGIN_SET_COLLECTION_C_ESP32 -[env:test_D_ESP32_IRExt_4M316k] +[env:collection_D_ESP32_IRExt_4M316k] extends = esp32_IRExt board = esp32_4M build_flags = ${esp32_IRExt.build_flags} - -DPLUGIN_SET_TEST_D_ESP32 + -DPLUGIN_SET_COLLECTION_D_ESP32 -[env:test_E_ESP32_IRExt_4M316k] +[env:collection_E_ESP32_IRExt_4M316k] extends = esp32_IRExt board = esp32_4M build_flags = ${esp32_IRExt.build_flags} - -DPLUGIN_SET_TEST_E_ESP32 + -DPLUGIN_SET_COLLECTION_E_ESP32 [env:energy_ESP32_4M316k] extends = esp32_common @@ -266,35 +267,35 @@ extends = env:normal_ESP32_4M316k build_flags = ${env:normal_ESP32_4M316k.build_flags} -DHAS_ETHERNET -[env:test_A_ESP32_4M316k_ETH] -extends = env:test_A_ESP32_4M316k -build_flags = ${env:test_A_ESP32_4M316k.build_flags} +[env:collection_A_ESP32_4M316k_ETH] +extends = env:collection_A_ESP32_4M316k +build_flags = ${env:collection_A_ESP32_4M316k.build_flags} -DHAS_ETHERNET - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL -[env:test_B_ESP32_4M316k_ETH] -extends = env:test_B_ESP32_4M316k -build_flags = ${env:test_B_ESP32_4M316k.build_flags} +[env:collection_B_ESP32_4M316k_ETH] +extends = env:collection_B_ESP32_4M316k +build_flags = ${env:collection_B_ESP32_4M316k.build_flags} -DHAS_ETHERNET - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL -[env:test_C_ESP32_4M316k_ETH] -extends = env:test_C_ESP32_4M316k -build_flags = ${env:test_C_ESP32_4M316k.build_flags} +[env:collection_C_ESP32_4M316k_ETH] +extends = env:collection_C_ESP32_4M316k +build_flags = ${env:collection_C_ESP32_4M316k.build_flags} -DHAS_ETHERNET - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL -[env:test_D_ESP32_4M316k_ETH] -extends = env:test_D_ESP32_4M316k -build_flags = ${env:test_D_ESP32_4M316k.build_flags} +[env:collection_D_ESP32_4M316k_ETH] +extends = env:collection_D_ESP32_4M316k +build_flags = ${env:collection_D_ESP32_4M316k.build_flags} -DHAS_ETHERNET - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL -[env:test_E_ESP32_4M316k_ETH] -extends = env:test_E_ESP32_4M316k -build_flags = ${env:test_E_ESP32_4M316k.build_flags} +[env:collection_E_ESP32_4M316k_ETH] +extends = env:collection_E_ESP32_4M316k +build_flags = ${env:collection_E_ESP32_4M316k.build_flags} -DHAS_ETHERNET - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL diff --git a/platformio_esp32s2_envs.ini b/platformio_esp32s2_envs.ini index 2605becb76..24c94bea8c 100644 --- a/platformio_esp32s2_envs.ini +++ b/platformio_esp32s2_envs.ini @@ -63,40 +63,40 @@ board = esp32s2 lib_deps = ${esp32s2_common.lib_deps} ServoESP32 -[env:test_A_ESP32s2_4M316k] +[env:collection_A_ESP32s2_4M316k] extends = esp32s2_common board = esp32s2 build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_SET_TEST_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_B_ESP32s2_4M316k] +[env:collection_B_ESP32s2_4M316k] extends = esp32s2_common board = esp32s2 build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_SET_TEST_B_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_B_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_C_ESP32s2_4M316k] +[env:collection_C_ESP32s2_4M316k] extends = esp32s2_common board = esp32s2 build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_SET_TEST_C_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_C_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_D_ESP32s2_4M316k] +[env:collection_D_ESP32s2_4M316k] extends = esp32s2_common board = esp32s2 build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_SET_TEST_D_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_D_ESP32 + -DCOLLECTION_USE_RTTTL -[env:test_E_ESP32s2_4M316k] +[env:collection_E_ESP32s2_4M316k] extends = esp32s2_common board = esp32s2 build_flags = ${esp32s2_common.build_flags} - -DPLUGIN_SET_TEST_E_ESP32 - -DTESTING_USE_RTTTL + -DPLUGIN_SET_COLLECTION_E_ESP32 + -DCOLLECTION_USE_RTTTL [env:energy_ESP32s2_4M316k] diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 0dacb6df91..1fee4715b3 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -132,16 +132,16 @@ lib_ignore = ${beta_platform.lib_ignore} LittleFS(esp8266) -;;; TEST ************************************************************* -; additional plugins (and dependend code) that is marked as TESTING ; -; Includes "normal" + "testing" plugins ; -; ********************************************************************* +;;; COLLECTION ******************************************************** +; additional plugins (and dependend code) that is marked as COLLECTION ; +; Includes "normal" + "collection" plugins ; +; ********************************************************************** -[testing] +[collection] platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} - -DPLUGIN_BUILD_TESTING + -DPLUGIN_BUILD_COLLECTION -DLIMIT_BUILD_SIZE -DDISABLE_SC16IS752_Serial lib_ignore = ${regular_platform.lib_ignore} @@ -151,11 +151,11 @@ lib_ignore = ${regular_platform.lib_ignore} LittleFS(esp8266) -[testing_alt_wifi] +[collection_alt_wifi] platform = ${regular_platform_alt_wifi.platform} platform_packages = ${regular_platform_alt_wifi.platform_packages} build_flags = ${regular_platform_alt_wifi.build_flags} - -DPLUGIN_BUILD_TESTING + -DPLUGIN_BUILD_COLLECTION -DLIMIT_BUILD_SIZE -DDISABLE_SC16IS752_Serial lib_ignore = ${regular_platform_alt_wifi.lib_ignore} @@ -164,11 +164,11 @@ lib_ignore = ${regular_platform_alt_wifi.lib_ignore} SDFS LittleFS(esp8266) -[testing_beta] +[collection_beta] platform = ${beta_platform.platform} platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} - -DPLUGIN_BUILD_TESTING + -DPLUGIN_BUILD_COLLECTION -DLIMIT_BUILD_SIZE -DDISABLE_SC16IS752_Serial lib_ignore = ${beta_platform.lib_ignore} diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 8d348af649..53973d0ed1 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -469,37 +469,37 @@ build_flags = ${normal_ir_extended_no_rx.build_flags} -;;; TEST ************************************************************* -; additional plugins (and dependend code) that is marked as TESTING ; -; Includes "normal" + "testing" plugins ; -; ********************************************************************* +;;; COLLECTION ********************************************************* +; additional plugins (and dependend code) that is grouped as COLLECTION ; +; Includes "normal" + "collection" plugins ; +; *********************************************************************** -[testing_ESP8266_4M1M] +[collection_ESP8266_4M1M] extends = esp8266_4M1M -platform = ${testing.platform} -platform_packages = ${testing.platform_packages} -build_flags = ${testing.build_flags} +platform = ${collection.platform} +platform_packages = ${collection.platform_packages} +build_flags = ${collection.build_flags} ${esp8266_4M1M.build_flags} -[testing_alt_wifi_ESP8266_4M1M] +[collection_alt_wifi_ESP8266_4M1M] extends = esp8266_4M1M -platform = ${testing_alt_wifi.platform} -platform_packages = ${testing_alt_wifi.platform_packages} -build_flags = ${testing_alt_wifi.build_flags} +platform = ${collection_alt_wifi.platform} +platform_packages = ${collection_alt_wifi.platform_packages} +build_flags = ${collection_alt_wifi.build_flags} ${esp8266_4M1M.build_flags} -[testing_beta_ESP8266_4M1M] +[collection_beta_ESP8266_4M1M] extends = esp8266_4M1M -platform = ${testing_beta.platform} -platform_packages = ${testing_beta.platform_packages} -build_flags = ${testing_beta.build_flags} +platform = ${collection_beta.platform} +platform_packages = ${collection_beta.platform_packages} +build_flags = ${collection_beta.build_flags} ${esp8266_4M1M.build_flags} -[testing_beta_ESP8266_16M_LittleFS] +[collection_beta_ESP8266_16M_LittleFS] extends = esp8266_16M -platform = ${testing_beta.platform} -platform_packages = ${testing_beta.platform_packages} -build_flags = ${testing_beta.build_flags} +platform = ${collection_beta.platform} +platform_packages = ${collection_beta.platform_packages} +build_flags = ${collection_beta.build_flags} ${esp8266_16M.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22y board_build.filesystem = littlefs @@ -511,106 +511,106 @@ lib_ignore = ESP32_ping HeatpumpIR -[env:test_A_ESP8266_4M1M] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} - -DTESTING_USE_RTTTL +[env:collection_A_ESP8266_4M1M] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} + -DCOLLECTION_USE_RTTTL -[env:test_B_ESP8266_4M1M] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} - -DPLUGIN_BUILD_TESTING_B +[env:collection_B_ESP8266_4M1M] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} + -DPLUGIN_BUILD_COLLECTION_B -[env:test_C_ESP8266_4M1M] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} - -DPLUGIN_BUILD_TESTING_C - -DTESTING_USE_RTTTL +[env:collection_C_ESP8266_4M1M] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} + -DPLUGIN_BUILD_COLLECTION_C + -DCOLLECTION_USE_RTTTL -[env:test_D_ESP8266_4M1M] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} - -DPLUGIN_BUILD_TESTING_D - -DTESTING_USE_RTTTL +[env:collection_D_ESP8266_4M1M] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} + -DPLUGIN_BUILD_COLLECTION_D + -DCOLLECTION_USE_RTTTL -[env:test_E_ESP8266_4M1M] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} - -DPLUGIN_BUILD_TESTING_E - -DTESTING_USE_RTTTL +[env:collection_E_ESP8266_4M1M] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} + -DPLUGIN_BUILD_COLLECTION_E + -DCOLLECTION_USE_RTTTL -; TEST: 4096k version + FEATURE_ADC_VCC ---------- -[env:test_A_ESP8266_4M1M_VCC] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} +; COLL: 4096k version + FEATURE_ADC_VCC ---------- +[env:collection_A_ESP8266_4M1M_VCC] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true - -DTESTING_USE_RTTTL + -DCOLLECTION_USE_RTTTL -[env:test_B_ESP8266_4M1M_VCC] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} +[env:collection_B_ESP8266_4M1M_VCC] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_B + -DPLUGIN_BUILD_COLLECTION_B -[env:test_C_ESP8266_4M1M_VCC] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} +[env:collection_C_ESP8266_4M1M_VCC] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_C - -DTESTING_USE_RTTTL + -DPLUGIN_BUILD_COLLECTION_C + -DCOLLECTION_USE_RTTTL -[env:test_D_ESP8266_4M1M_VCC] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} +[env:collection_D_ESP8266_4M1M_VCC] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_D - -DTESTING_USE_RTTTL + -DPLUGIN_BUILD_COLLECTION_D + -DCOLLECTION_USE_RTTTL -[env:test_E_ESP8266_4M1M_VCC] -extends = testing_ESP8266_4M1M -build_flags = ${testing_ESP8266_4M1M.build_flags} +[env:collection_E_ESP8266_4M1M_VCC] +extends = collection_ESP8266_4M1M +build_flags = ${collection_ESP8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true - -DPLUGIN_BUILD_TESTING_E - -DTESTING_USE_RTTTL + -DPLUGIN_BUILD_COLLECTION_E + -DCOLLECTION_USE_RTTTL -;[env:test_A_alt_wifi_ESP8266_4M1M_VCC] -;extends = testing_alt_wifi_ESP8266_4M1M -;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +;[env:collection_A_alt_wifi_ESP8266_4M1M_VCC] +;extends = collection_alt_wifi_ESP8266_4M1M +;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -;[env:test_B_alt_wifi_ESP8266_4M1M_VCC] -;extends = testing_alt_wifi_ESP8266_4M1M -;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +;[env:collection_B_alt_wifi_ESP8266_4M1M_VCC] +;extends = collection_alt_wifi_ESP8266_4M1M +;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -; -DPLUGIN_BUILD_TESTING_B +; -DPLUGIN_BUILD_COLLECTION_B -;[env:test_C_alt_wifi_ESP8266_4M1M_VCC] -;extends = testing_alt_wifi_ESP8266_4M1M -;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +;[env:collection_C_alt_wifi_ESP8266_4M1M_VCC] +;extends = collection_alt_wifi_ESP8266_4M1M +;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -; -DPLUGIN_BUILD_TESTING_C +; -DPLUGIN_BUILD_COLLECTION_C -;[env:test_D_alt_wifi_ESP8266_4M1M_VCC] -;extends = testing_alt_wifi_ESP8266_4M1M -;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +;[env:collection_D_alt_wifi_ESP8266_4M1M_VCC] +;extends = collection_alt_wifi_ESP8266_4M1M +;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -; -DPLUGIN_BUILD_TESTING_D +; -DPLUGIN_BUILD_COLLECTION_D -;[env:test_E_alt_wifi_ESP8266_4M1M_VCC] -;extends = testing_alt_wifi_ESP8266_4M1M -;build_flags = ${testing_alt_wifi_ESP8266_4M1M.build_flags} +;[env:collection_E_alt_wifi_ESP8266_4M1M_VCC] +;extends = collection_alt_wifi_ESP8266_4M1M +;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -; -DPLUGIN_BUILD_TESTING_E +; -DPLUGIN_BUILD_COLLECTION_E -; TEST: 4096k version + FEATURE_ADC_VCC + FEATURE_MDNS + FEATURE_SD ---------- +; COLL: 4096k version + FEATURE_ADC_VCC + FEATURE_MDNS + FEATURE_SD ---------- ; Disabled for now as it does not fit in IRAM and with VCC_SD it does not fit in max. build size -;[env:test_ESP8266_4M1M_VCC_MDNS_SD] +;[env:collection_ESP8266_4M1M_VCC_MDNS_SD] ;extends = esp8266_4M1M -;platform = ${testing.platform} -;platform_packages = ${testing.platform_packages} -;build_flags = ${testing.build_flags} +;platform = ${collection.platform} +;platform_packages = ${collection.platform_packages} +;build_flags = ${collection.build_flags} ; ${esp8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true ; -DFEATURE_MDNS @@ -624,68 +624,68 @@ build_flags = ${testing_ESP8266_4M1M.build_flags} ; HeatpumpIRLittleFS(esp8266) -;[env:test_A_beta_ESP8266_4M1M] -;extends = testing_beta_ESP8266_4M1M -;build_flags = ${testing_beta_ESP8266_4M1M.build_flags} +;[env:collection_A_beta_ESP8266_4M1M] +;extends = collection_beta_ESP8266_4M1M +;build_flags = ${collection_beta_ESP8266_4M1M.build_flags} ; -DLIMIT_BUILD_SIZE -; -DTESTING_USE_RTTTL +; -DCOLLECTION_USE_RTTTL -;[env:test_B_beta_ESP8266_4M1M] -;extends = testing_beta_ESP8266_4M1M -;build_flags = ${testing_beta_ESP8266_4M1M.build_flags} +;[env:collection_B_beta_ESP8266_4M1M] +;extends = collection_beta_ESP8266_4M1M +;build_flags = ${collection_beta_ESP8266_4M1M.build_flags} ; -DLIMIT_BUILD_SIZE -; -DPLUGIN_BUILD_TESTING_B +; -DPLUGIN_BUILD_COLLECTION_B -;[env:test_C_beta_ESP8266_4M1M] -;extends = testing_beta_ESP8266_4M1M -;build_flags = ${testing_beta_ESP8266_4M1M.build_flags} +;[env:collection_C_beta_ESP8266_4M1M] +;extends = collection_beta_ESP8266_4M1M +;build_flags = ${collection_beta_ESP8266_4M1M.build_flags} ; -DLIMIT_BUILD_SIZE -; -DPLUGIN_BUILD_TESTING_C -; -DTESTING_USE_RTTTL +; -DPLUGIN_BUILD_COLLECTION_C +; -DCOLLECTION_USE_RTTTL -;[env:test_D_beta_ESP8266_4M1M] -;extends = testing_beta_ESP8266_4M1M -;build_flags = ${testing_beta_ESP8266_4M1M.build_flags} +;[env:collection_D_beta_ESP8266_4M1M] +;extends = collection_beta_ESP8266_4M1M +;build_flags = ${collection_beta_ESP8266_4M1M.build_flags} ; -DLIMIT_BUILD_SIZE -; -DPLUGIN_BUILD_TESTING_D -; -DTESTING_USE_RTTTL +; -DPLUGIN_BUILD_COLLECTION_D +; -DCOLLECTION_USE_RTTTL -;[env:test_E_beta_ESP8266_4M1M] -;extends = testing_beta_ESP8266_4M1M -;build_flags = ${testing_beta_ESP8266_4M1M.build_flags} +;[env:collection_E_beta_ESP8266_4M1M] +;extends = collection_beta_ESP8266_4M1M +;build_flags = ${collection_beta_ESP8266_4M1M.build_flags} ; -DLIMIT_BUILD_SIZE -; -DPLUGIN_BUILD_TESTING_E -; -DTESTING_USE_RTTTL -; -DTESTING_USE_RTTTL +; -DPLUGIN_BUILD_COLLECTION_E +; -DCOLLECTION_USE_RTTTL +; -DCOLLECTION_USE_RTTTL -; Test: 16M version -- LittleFS -------------- +; COLL: 16M version -- LittleFS -------------- ; LittleFS is determined by using "LittleFS" in the pio env name -;[env:test_A_beta_ESP8266_16M_LittleFS] -;extends = testing_beta_ESP8266_16M_LittleFS -;build_flags = ${testing_beta_ESP8266_16M_LittleFS.build_flags} - -;[env:test_B_beta_ESP8266_16M_LittleFS] -;extends = testing_beta_ESP8266_16M_LittleFS -;build_flags = ${testing_beta_ESP8266_16M_LittleFS.build_flags} -; -DPLUGIN_BUILD_TESTING_B - -;[env:test_C_beta_ESP8266_16M_LittleFS] -;extends = testing_beta_ESP8266_16M_LittleFS -;build_flags = ${testing_beta_ESP8266_16M_LittleFS.build_flags} -; -DPLUGIN_BUILD_TESTING_C -; -DTESTING_USE_RTTTL - -;[env:test_D_beta_ESP8266_16M_LittleFS] -;extends = testing_beta_ESP8266_16M_LittleFS -;build_flags = ${testing_beta_ESP8266_16M_LittleFS.build_flags} -; -DPLUGIN_BUILD_TESTING_D -; -DTESTING_USE_RTTTL - -;[env:test_E_beta_ESP8266_16M_LittleFS] -;extends = testing_beta_ESP8266_16M_LittleFS -;build_flags = ${testing_beta_ESP8266_16M_LittleFS.build_flags} -; -DPLUGIN_BUILD_TESTING_E -; -DTESTING_USE_RTTTL +;[env:collection_A_beta_ESP8266_16M_LittleFS] +;extends = collection_beta_ESP8266_16M_LittleFS +;build_flags = ${collection_beta_ESP8266_16M_LittleFS.build_flags} + +;[env:collection_B_beta_ESP8266_16M_LittleFS] +;extends = collection_beta_ESP8266_16M_LittleFS +;build_flags = ${collection_beta_ESP8266_16M_LittleFS.build_flags} +; -DPLUGIN_BUILD_COLLECTION_B + +;[env:collection_C_beta_ESP8266_16M_LittleFS] +;extends = collection_beta_ESP8266_16M_LittleFS +;build_flags = ${collection_beta_ESP8266_16M_LittleFS.build_flags} +; -DPLUGIN_BUILD_COLLECTION_C +; -DCOLLECTION_USE_RTTTL + +;[env:collection_D_beta_ESP8266_16M_LittleFS] +;extends = collection_beta_ESP8266_16M_LittleFS +;build_flags = ${collection_beta_ESP8266_16M_LittleFS.build_flags} +; -DPLUGIN_BUILD_COLLECTION_D +; -DCOLLECTION_USE_RTTTL + +;[env:collection_E_beta_ESP8266_16M_LittleFS] +;extends = collection_beta_ESP8266_16M_LittleFS +;build_flags = ${collection_beta_ESP8266_16M_LittleFS.build_flags} +; -DPLUGIN_BUILD_COLLECTION_E +; -DCOLLECTION_USE_RTTTL diff --git a/src/ESPEasy-Globals.h b/src/ESPEasy-Globals.h index 354a9bcbef..6af813f095 100644 --- a/src/ESPEasy-Globals.h +++ b/src/ESPEasy-Globals.h @@ -22,9 +22,6 @@ //(512k is NOT finsihed or tested yet as of v2.0.0-dev6) -//build all plugins that are in test stadium -//#define PLUGIN_BUILD_TESTING - //build all plugins that still are being developed and are broken or incomplete //#define PLUGIN_BUILD_DEV diff --git a/src/_C012.cpp b/src/_C012.cpp index 196a813e8d..cae94a17e7 100644 --- a/src/_C012.cpp +++ b/src/_C012.cpp @@ -5,8 +5,6 @@ // ########################### Controller Plugin 012: Blynk ############################################# // ####################################################################################################### -// #ifdef PLUGIN_BUILD_TESTING - # include "src/Commands/Blynk.h" # define CPLUGIN_012 diff --git a/src/_C015.cpp b/src/_C015.cpp index 1b126df4a6..f52f0b2af3 100644 --- a/src/_C015.cpp +++ b/src/_C015.cpp @@ -18,8 +18,6 @@ // // https://www.youtube.com/watch?v=5_V_DibOypE -// #ifdef PLUGIN_BUILD_TESTING - // Uncomment this to use ssl connection. This requires more device resources than unencrypted one. // Also it requires valid server thumbprint string to be entered in plugin settings. // #define CPLUGIN_015_SSL diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index c141ac8ce3..e89271f760 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -96,7 +96,7 @@ # ifdef ESP32 # define DEVICES_MAX 130 #else - #if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV) + #if defined(PLUGIN_BUILD_COLLECTION) || defined(PLUGIN_BUILD_DEV) # define DEVICES_MAX 95 # else # define DEVICES_MAX 60 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 9544bbdb16..3f611df8a1 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -19,7 +19,7 @@ To create/register a plugin, you have to : either by adding "-DPLUGIN_BUILD_DEV" when compiling, or by momentarly adding "#define PLUGIN_BUILD_DEV" at the top of the ESPEasy.ino file - You will then have to push a PR including your plugin + the corret line (#define USES_P777) added to this file - When found stable enough, the maintainer (and only him) will choose to move it to TESTING or STABLE + When found stable enough, the maintainer (and only him) will choose to move it to COLLECTION or NORMAL */ //#define FEATURE_SD @@ -176,8 +176,8 @@ To create/register a plugin, you have to : #define PLUGIN_BUILD_IR #endif -#ifdef PLUGIN_BUILD_TESTING_IR - #define PLUGIN_BUILD_TESTING // add testing +#ifdef PLUGIN_BUILD_COLLECTION_IR + #define PLUGIN_BUILD_COLLECTION // add collection #define PLUGIN_BUILD_IR #endif @@ -220,69 +220,81 @@ To create/register a plugin, you have to : #endif #ifdef PLUGIN_BUILD_NORMAL_IRext - #define PLUGIN_BUILD_NORMAL // add stable + #define PLUGIN_BUILD_NORMAL // add stable + #if defined(PLUGIN_SET_COLLECTION_ESP32) + #define PLUGIN_DESCR "Collection_A, IR with AC" + #elif defined(PLUGIN_SET_COLLECTION_B_ESP32) + #define PLUGIN_DESCR "Collection_B, IR with AC" + #elif defined(PLUGIN_SET_COLLECTION_C_ESP32) + #define PLUGIN_DESCR "Collection_C, IR with AC" + #elif defined(PLUGIN_SET_COLLECTION_D_ESP32) + #define PLUGIN_DESCR "Collection_D, IR with AC" + #elif defined(PLUGIN_SET_COLLECTION_E_ESP32) + #define PLUGIN_DESCR "Collection_E, IR with AC" + #else #define PLUGIN_DESCR "Normal, IR with AC" - #define PLUGIN_BUILD_IR_EXTENDED + #endif + #define PLUGIN_BUILD_IR_EXTENDED #endif #ifdef PLUGIN_BUILD_DEV - #define PLUGIN_SET_EXPERIMENTAL - #define CONTROLLER_SET_EXPERIMENTAL - #define NOTIFIER_SET_EXPERIMENTAL - #define PLUGIN_BUILD_TESTING // add testing + #define PLUGIN_SET_EXPERIMENTAL + #define CONTROLLER_SET_EXPERIMENTAL + #define NOTIFIER_SET_EXPERIMENTAL + #define PLUGIN_BUILD_COLLECTION // add collection #endif -#ifdef PLUGIN_BUILD_TESTING - #if !defined(PLUGIN_BUILD_TESTING_B) && !defined(PLUGIN_BUILD_TESTING_C) && !defined(PLUGIN_BUILD_TESTING_D) && !defined(PLUGIN_BUILD_TESTING_E) - #define PLUGIN_DESCR "TEST_A" - #define PLUGIN_SET_TESTING_A - #endif - #define PLUGIN_SET_TESTING - #define CONTROLLER_SET_TESTING - #define NOTIFIER_SET_TESTING - #define PLUGIN_BUILD_NORMAL // add stable +#ifdef PLUGIN_BUILD_COLLECTION + #if !defined(PLUGIN_BUILD_COLLECTION_B) && !defined(PLUGIN_BUILD_COLLECTION_C) && !defined(PLUGIN_BUILD_COLLECTION_D) && !defined(PLUGIN_BUILD_COLLECTION_E) + #define PLUGIN_DESCR "Collection_A" + #define PLUGIN_SET_COLLECTION_A + #endif + #define PLUGIN_SET_COLLECTION + #define CONTROLLER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #define PLUGIN_BUILD_NORMAL // add stable #endif -#ifdef PLUGIN_BUILD_TESTING_B - #define PLUGIN_DESCR "TEST_B" - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_B - #define CONTROLLER_SET_TESTING - #define NOTIFIER_SET_TESTING - #define PLUGIN_BUILD_NORMAL // add stable +#ifdef PLUGIN_BUILD_COLLECTION_B + #define PLUGIN_DESCR "Collection_B" + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_B + #define CONTROLLER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #define PLUGIN_BUILD_NORMAL // add stable #endif -#ifdef PLUGIN_BUILD_TESTING_C - #define PLUGIN_DESCR "TEST_C" - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_C - #define CONTROLLER_SET_TESTING - #define NOTIFIER_SET_TESTING - #define PLUGIN_BUILD_NORMAL // add stable +#ifdef PLUGIN_BUILD_COLLECTION_C + #define PLUGIN_DESCR "Collection_C" + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_C + #define CONTROLLER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #define PLUGIN_BUILD_NORMAL // add stable #endif -#ifdef PLUGIN_BUILD_TESTING_D - #define PLUGIN_DESCR "TEST_D" - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_D - #define CONTROLLER_SET_TESTING - #define NOTIFIER_SET_TESTING - #define PLUGIN_BUILD_NORMAL // add stable +#ifdef PLUGIN_BUILD_COLLECTION_D + #define PLUGIN_DESCR "Collection_D" + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_D + #define CONTROLLER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #define PLUGIN_BUILD_NORMAL // add stable #endif -#ifdef PLUGIN_BUILD_TESTING_E - #define PLUGIN_DESCR "TEST_E" - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_E - #define CONTROLLER_SET_TESTING - #define NOTIFIER_SET_TESTING - #define PLUGIN_BUILD_NORMAL // add stable +#ifdef PLUGIN_BUILD_COLLECTION_E + #define PLUGIN_DESCR "Collection_E" + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_E + #define CONTROLLER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #define PLUGIN_BUILD_NORMAL // add stable #endif #ifndef PLUGIN_BUILD_CUSTOM - #ifndef PLUGIN_BUILD_NORMAL - #define PLUGIN_BUILD_NORMAL // defaults to stable, if not custom - #endif + #ifndef PLUGIN_BUILD_NORMAL + #define PLUGIN_BUILD_NORMAL // defaults to stable, if not custom + #endif #endif #ifdef PLUGIN_BUILD_NORMAL @@ -656,106 +668,156 @@ To create/register a plugin, you have to : #define USES_P028 // BME280 #endif -#ifdef PLUGIN_SET_TEST_ESP32 - #if !defined(PLUGIN_SET_TEST_B_ESP32) && !defined(PLUGIN_SET_TEST_C_ESP32) && !defined(PLUGIN_SET_TEST_D_ESP32) && !defined(PLUGIN_SET_TEST_E_ESP32) - #define PLUGIN_DESCR "TEST_A ESP32" - #define PLUGIN_SET_TESTING_A - #endif - #ifndef ESP32 - #define ESP32 - #endif - #ifdef ESP8266 - #undef ESP8266 +#ifdef PLUGIN_SET_COLLECTION_ESP32 + #if !defined(PLUGIN_SET_COLLECTION_B_ESP32) && !defined(PLUGIN_SET_COLLECTION_C_ESP32) && !defined(PLUGIN_SET_COLLECTION_D_ESP32) && !defined(PLUGIN_SET_COLLECTION_E_ESP32) + #ifndef PLUGIN_DESCR // COLLECTION_A_ESP32_IRExt also passes here + #define PLUGIN_DESCR "Collection_A ESP32" #endif -// #define PLUGIN_SET_ONLY_SWITCH - - #define PLUGIN_SET_TESTING - #define CONTROLLER_SET_STABLE - #define NOTIFIER_SET_STABLE - #define PLUGIN_SET_STABLE // add stable - // See also PLUGIN_SET_TEST_ESP32 section at end, - // where incompatible plugins will be disabled. - // TODO : Check compatibility of plugins for ESP32 board. + #define PLUGIN_SET_COLLECTION_A + #endif + #ifndef ESP32 + #define ESP32 + #endif + #ifdef ESP8266 + #undef ESP8266 + #endif + // Undefine contradictionary defines + #ifdef PLUGIN_SET_NONE + #undef PLUGIN_SET_NONE + #endif + #ifdef PLUGIN_SET_ONLY_SWITCH + #undef PLUGIN_SET_ONLY_SWITCH + #endif + #ifdef PLUGIN_SET_ONLY_TEMP_HUM + #undef PLUGIN_SET_ONLY_TEMP_HUM + #endif + #define PLUGIN_SET_COLLECTION + #define CONTROLLER_SET_STABLE + #define NOTIFIER_SET_STABLE + #define PLUGIN_SET_STABLE // add stable + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, + // where incompatible plugins will be disabled. + // TODO : Check compatibility of plugins for ESP32 board. #endif -#ifdef PLUGIN_SET_TEST_B_ESP32 - #define PLUGIN_DESCR "TEST_B ESP32" - #ifndef ESP32 - #define ESP32 - #endif - #ifdef ESP8266 - #undef ESP8266 - #endif -// #define PLUGIN_SET_ONLY_SWITCH - - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_B - #define CONTROLLER_SET_STABLE - #define NOTIFIER_SET_STABLE - #define PLUGIN_SET_STABLE // add stable - // See also PLUGIN_SET_TEST_ESP32 section at end, - // where incompatible plugins will be disabled. - // TODO : Check compatibility of plugins for ESP32 board. +#ifdef PLUGIN_SET_COLLECTION_B_ESP32 + #ifndef PLUGIN_DESCR // COLLECTION_B_ESP32_IRExt also passes here + #define PLUGIN_DESCR "Collection_B ESP32" + #endif + #ifndef ESP32 + #define ESP32 + #endif + #ifdef ESP8266 + #undef ESP8266 + #endif + // Undefine contradictionary defines + #ifdef PLUGIN_SET_NONE + #undef PLUGIN_SET_NONE + #endif + #ifdef PLUGIN_SET_ONLY_SWITCH + #undef PLUGIN_SET_ONLY_SWITCH + #endif + #ifdef PLUGIN_SET_ONLY_TEMP_HUM + #undef PLUGIN_SET_ONLY_TEMP_HUM + #endif + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_B + #define CONTROLLER_SET_STABLE + #define NOTIFIER_SET_STABLE + #define PLUGIN_SET_STABLE // add stable + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, + // where incompatible plugins will be disabled. + // TODO : Check compatibility of plugins for ESP32 board. #endif -#ifdef PLUGIN_SET_TEST_C_ESP32 - #define PLUGIN_DESCR "TEST_C ESP32" - #ifndef ESP32 - #define ESP32 - #endif - #ifdef ESP8266 - #undef ESP8266 - #endif -// #define PLUGIN_SET_ONLY_SWITCH - - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_C - #define CONTROLLER_SET_STABLE - #define NOTIFIER_SET_STABLE - #define PLUGIN_SET_STABLE // add stable - // See also PLUGIN_SET_TEST_ESP32 section at end, - // where incompatible plugins will be disabled. - // TODO : Check compatibility of plugins for ESP32 board. +#ifdef PLUGIN_SET_COLLECTION_C_ESP32 + #ifndef PLUGIN_DESCR // COLLECTION_C_ESP32_IRExt also passes here + #define PLUGIN_DESCR "Collection_C ESP32" + #endif + #ifndef ESP32 + #define ESP32 + #endif + #ifdef ESP8266 + #undef ESP8266 + #endif + // Undefine contradictionary defines + #ifdef PLUGIN_SET_NONE + #undef PLUGIN_SET_NONE + #endif + #ifdef PLUGIN_SET_ONLY_SWITCH + #undef PLUGIN_SET_ONLY_SWITCH + #endif + #ifdef PLUGIN_SET_ONLY_TEMP_HUM + #undef PLUGIN_SET_ONLY_TEMP_HUM + #endif + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_C + #define CONTROLLER_SET_STABLE + #define NOTIFIER_SET_STABLE + #define PLUGIN_SET_STABLE // add stable + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, + // where incompatible plugins will be disabled. + // TODO : Check compatibility of plugins for ESP32 board. #endif -#ifdef PLUGIN_SET_TEST_D_ESP32 - #define PLUGIN_DESCR "TEST_D ESP32" - #ifndef ESP32 - #define ESP32 - #endif - #ifdef ESP8266 - #undef ESP8266 - #endif -// #define PLUGIN_SET_ONLY_SWITCH - - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_D - #define CONTROLLER_SET_STABLE - #define NOTIFIER_SET_STABLE - #define PLUGIN_SET_STABLE // add stable - // See also PLUGIN_SET_TEST_ESP32 section at end, - // where incompatible plugins will be disabled. - // TODO : Check compatibility of plugins for ESP32 board. +#ifdef PLUGIN_SET_COLLECTION_D_ESP32 + #ifndef PLUGIN_DESCR // COLLECTION_D_ESP32_IRExt also passes here + #define PLUGIN_DESCR "Collection_D ESP32" + #endif + #ifndef ESP32 + #define ESP32 + #endif + #ifdef ESP8266 + #undef ESP8266 + #endif + // Undefine contradictionary defines + #ifdef PLUGIN_SET_NONE + #undef PLUGIN_SET_NONE + #endif + #ifdef PLUGIN_SET_ONLY_SWITCH + #undef PLUGIN_SET_ONLY_SWITCH + #endif + #ifdef PLUGIN_SET_ONLY_TEMP_HUM + #undef PLUGIN_SET_ONLY_TEMP_HUM + #endif + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_D + #define CONTROLLER_SET_STABLE + #define NOTIFIER_SET_STABLE + #define PLUGIN_SET_STABLE // add stable + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, + // where incompatible plugins will be disabled. + // TODO : Check compatibility of plugins for ESP32 board. #endif -#ifdef PLUGIN_SET_TEST_E_ESP32 - #define PLUGIN_DESCR "TEST_E ESP32" - #ifndef ESP32 - #define ESP32 - #endif - #ifdef ESP8266 - #undef ESP8266 - #endif -// #define PLUGIN_SET_ONLY_SWITCH - - #define PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING_E - #define CONTROLLER_SET_STABLE - #define NOTIFIER_SET_STABLE - #define PLUGIN_SET_STABLE // add stable - // See also PLUGIN_SET_TEST_ESP32 section at end, - // where incompatible plugins will be disabled. - // TODO : Check compatibility of plugins for ESP32 board. +#ifdef PLUGIN_SET_COLLECTION_E_ESP32 + #ifndef PLUGIN_DESCR // COLLECTION_E_ESP32_IRExt also passes here + #define PLUGIN_DESCR "Collection_E ESP32" + #endif + #ifndef ESP32 + #define ESP32 + #endif + #ifdef ESP8266 + #undef ESP8266 + #endif + // Undefine contradictionary defines + #ifdef PLUGIN_SET_NONE + #undef PLUGIN_SET_NONE + #endif + #ifdef PLUGIN_SET_ONLY_SWITCH + #undef PLUGIN_SET_ONLY_SWITCH + #endif + #ifdef PLUGIN_SET_ONLY_TEMP_HUM + #undef PLUGIN_SET_ONLY_TEMP_HUM + #endif + #define PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION_E + #define CONTROLLER_SET_STABLE + #define NOTIFIER_SET_STABLE + #define PLUGIN_SET_STABLE // add stable + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, + // where incompatible plugins will be disabled. + // TODO : Check compatibility of plugins for ESP32 board. #endif #ifdef PLUGIN_BUILD_MAX_ESP32 @@ -789,7 +851,7 @@ To create/register a plugin, you have to : #endif // See also PLUGIN_SET_MAX section at end, to include any disabled plugins from other definitions - // See also PLUGIN_SET_TEST_ESP32 section at end, + // See also PLUGIN_SET_COLLECTION_ESP32 section at end, // where incompatible plugins will be disabled. // TODO : Check compatibility of plugins for ESP32 board. #endif @@ -805,7 +867,7 @@ To create/register a plugin, you have to : #ifdef PLUGIN_SET_VENTUS_W266 #define PLUGIN_SET_ONLY_SWITCH #define PLUGIN_BUILD_DISABLED - #define USES_P046 // TESTING Hardware P046_VentusW266.ino + #define USES_P046 // Hardware P046_VentusW266.ino #endif @@ -881,136 +943,126 @@ To create/register a plugin, you have to : #endif - - - - /******************************************************************************\ * Main Families ************************************************************** \******************************************************************************/ // NONE ##################################### #ifdef PLUGIN_SET_NONE - #ifdef PLUGIN_SET_STABLE - #undef PLUGIN_SET_STABLE - #endif - #ifdef PLUGIN_SET_TESTING - #undef PLUGIN_SET_TESTING - #endif - #ifdef PLUGIN_SET_TESTING_A - #undef PLUGIN_SET_TESTING_A - #endif - #ifdef PLUGIN_SET_TESTING_B - #undef PLUGIN_SET_TESTING_B - #endif - #ifdef PLUGIN_SET_TESTING_C - #undef PLUGIN_SET_TESTING_C - #endif - #ifdef PLUGIN_SET_TESTING_D - #undef PLUGIN_SET_TESTING_D - #endif - #ifdef PLUGIN_SET_TESTING_E - #undef PLUGIN_SET_TESTING_E - #endif - #ifdef PLUGIN_SET_EXPERIMENTAL - #undef PLUGIN_SET_EXPERIMENTAL - #endif + #ifdef PLUGIN_SET_STABLE + #undef PLUGIN_SET_STABLE + #endif + #ifdef PLUGIN_SET_COLLECTION + #undef PLUGIN_SET_COLLECTION + #endif + #ifdef PLUGIN_SET_COLLECTION_A + #undef PLUGIN_SET_COLLECTION_A + #endif + #ifdef PLUGIN_SET_COLLECTION_B + #undef PLUGIN_SET_COLLECTION_B + #endif + #ifdef PLUGIN_SET_COLLECTION_C + #undef PLUGIN_SET_COLLECTION_C + #endif + #ifdef PLUGIN_SET_COLLECTION_D + #undef PLUGIN_SET_COLLECTION_D + #endif + #ifdef PLUGIN_SET_COLLECTION_E + #undef PLUGIN_SET_COLLECTION_E + #endif + #ifdef PLUGIN_SET_EXPERIMENTAL + #undef PLUGIN_SET_EXPERIMENTAL + #endif #endif #ifdef CONTROLLER_SET_NONE - #ifdef CONTROLLER_SET_STABLE - #undef CONTROLLER_SET_STABLE - #endif - #ifdef CONTROLLER_SET_TESTING - #undef CONTROLLER_SET_TESTING - #endif - #ifdef CONTROLLER_SET_EXPERIMENTAL - #undef CONTROLLER_SET_EXPERIMENTAL - #endif + #ifdef CONTROLLER_SET_STABLE + #undef CONTROLLER_SET_STABLE + #endif + #ifdef CONTROLLER_SET_COLLECTION + #undef CONTROLLER_SET_COLLECTION + #endif + #ifdef CONTROLLER_SET_EXPERIMENTAL + #undef CONTROLLER_SET_EXPERIMENTAL + #endif #endif #ifdef NOTIFIER_SET_NONE - #ifdef NOTIFIER_SET_STABLE - #undef NOTIFIER_SET_STABLE - #endif - #ifdef NOTIFIER_SET_TESTING - #undef NOTIFIER_SET_TESTING - #endif - #ifdef NOTIFIER_SET_EXPERIMENTAL - #undef NOTIFIER_SET_EXPERIMENTAL - #endif + #ifdef NOTIFIER_SET_STABLE + #undef NOTIFIER_SET_STABLE + #endif + #ifdef NOTIFIER_SET_COLLECTION + #undef NOTIFIER_SET_COLLECTION + #endif + #ifdef NOTIFIER_SET_EXPERIMENTAL + #undef NOTIFIER_SET_EXPERIMENTAL + #endif #endif // ALL ########################################### #ifdef PLUGIN_SET_ALL - #ifndef PLUGIN_SET_STABLE - #define PLUGIN_SET_STABLE - #endif - #ifndef PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING - #endif - // #ifndef PLUGIN_SET_TESTING_A - // #define PLUGIN_SET_TESTING_A - // #endif - #ifndef PLUGIN_SET_EXPERIMENTAL - #define PLUGIN_SET_EXPERIMENTAL - #endif + #ifndef PLUGIN_SET_STABLE + #define PLUGIN_SET_STABLE + #endif + #ifndef PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION + #endif + #ifndef PLUGIN_SET_EXPERIMENTAL + #define PLUGIN_SET_EXPERIMENTAL + #endif #endif #ifdef CONTROLLER_SET_ALL - #ifndef CONTROLLER_SET_STABLE - #define CONTROLLER_SET_STABLE - #endif - #ifndef CONTROLLER_SET_TESTING - #define CONTROLLER_SET_TESTING - #endif - #ifndef CONTROLLER_SET_EXPERIMENTAL - #define CONTROLLER_SET_EXPERIMENTAL - #endif + #ifndef CONTROLLER_SET_STABLE + #define CONTROLLER_SET_STABLE + #endif + #ifndef CONTROLLER_SET_COLLECTION + #define CONTROLLER_SET_COLLECTION + #endif + #ifndef CONTROLLER_SET_EXPERIMENTAL + #define CONTROLLER_SET_EXPERIMENTAL + #endif #endif #ifdef NOTIFIER_SET_ALL - #ifndef NOTIFIER_SET_STABLE - #define NOTIFIER_SET_STABLE - #endif - #ifndef NOTIFIER_SET_TESTING - #define NOTIFIER_SET_TESTING - #endif - #ifndef NOTIFIER_SET_EXPERIMENTAL - #define NOTIFIER_SET_EXPERIMENTAL - #endif + #ifndef NOTIFIER_SET_STABLE + #define NOTIFIER_SET_STABLE + #endif + #ifndef NOTIFIER_SET_COLLECTION + #define NOTIFIER_SET_COLLECTION + #endif + #ifndef NOTIFIER_SET_EXPERIMENTAL + #define NOTIFIER_SET_EXPERIMENTAL + #endif #endif // MAX ########################################### #ifdef PLUGIN_SET_MAX - #ifndef PLUGIN_SET_STABLE - #define PLUGIN_SET_STABLE - #endif - #ifndef PLUGIN_SET_TESTING - #define PLUGIN_SET_TESTING - #endif - #ifndef PLUGIN_SET_TESTING_A - #define PLUGIN_SET_TESTING_A - #endif - #ifndef PLUGIN_SET_TESTING_B - #define PLUGIN_SET_TESTING_B - #endif - #ifndef PLUGIN_SET_TESTING_C - #define PLUGIN_SET_TESTING_C - #endif - #ifndef PLUGIN_SET_TESTING_D - #define PLUGIN_SET_TESTING_D - #endif - #ifndef PLUGIN_SET_TESTING_E - #define PLUGIN_SET_TESTING_E - #endif - // #ifndef PLUGIN_SET_EXPERIMENTAL - // #define PLUGIN_SET_EXPERIMENTAL - // #endif + #ifndef PLUGIN_SET_STABLE + #define PLUGIN_SET_STABLE + #endif + #ifndef PLUGIN_SET_COLLECTION + #define PLUGIN_SET_COLLECTION + #endif + #ifndef PLUGIN_SET_COLLECTION_A + #define PLUGIN_SET_COLLECTION_A + #endif + #ifndef PLUGIN_SET_COLLECTION_B + #define PLUGIN_SET_COLLECTION_B + #endif + #ifndef PLUGIN_SET_COLLECTION_C + #define PLUGIN_SET_COLLECTION_C + #endif + #ifndef PLUGIN_SET_COLLECTION_D + #define PLUGIN_SET_COLLECTION_D + #endif + #ifndef PLUGIN_SET_COLLECTION_E + #define PLUGIN_SET_COLLECTION_E + #endif #endif @@ -1082,7 +1134,7 @@ To create/register a plugin, you have to : #define USES_P059 // Encoder #define USES_P063 // TTP229_KeyPad - #define USES_P073 // 7DG + #define USES_P073 // 7DGT #define USES_P079 // Wemos Motoshield #endif @@ -1111,7 +1163,7 @@ To create/register a plugin, you have to : #endif #endif -#if defined(PLUGIN_SET_TESTING) || defined(PLUGIN_SET_TESTING_A) || defined(PLUGIN_SET_TESTING_B) || defined(PLUGIN_SET_TESTING_C) || defined(PLUGIN_SET_TESTING_D) || defined(PLUGIN_SET_TESTING_E) +#if defined(PLUGIN_SET_COLLECTION) || defined(PLUGIN_SET_COLLECTION_A) || defined(PLUGIN_SET_COLLECTION_B) || defined(PLUGIN_SET_COLLECTION_C) || defined(PLUGIN_SET_COLLECTION_D) || defined(PLUGIN_SET_COLLECTION_E) #if !defined(PLUGIN_SET_MAX) && !defined(ESP32) #ifndef LIMIT_BUILD_SIZE #define LIMIT_BUILD_SIZE @@ -1122,8 +1174,8 @@ To create/register a plugin, you have to : #endif #endif -// TESTING ##################################### -#ifdef PLUGIN_SET_TESTING +// COLLECTIONS ##################################### +#ifdef PLUGIN_SET_COLLECTION #define USES_P045 // MPU6050 #define USES_P047 // I2C_soil_misture #define USES_P048 // Motoshield_v2 @@ -1153,7 +1205,7 @@ To create/register a plugin, you have to : #define USES_P089 // Ping #endif -#ifdef PLUGIN_SET_TESTING_A +#ifdef PLUGIN_SET_COLLECTION_A #define USES_P067 // HX711_Load_Cell #define USES_P068 // SHT3x @@ -1178,7 +1230,7 @@ To create/register a plugin, you have to : #define USES_P105 // AHT10/20/21 #endif -#ifdef PLUGIN_SET_TESTING_B +#ifdef PLUGIN_SET_COLLECTION_B #define USES_P069 // LM75A #define USES_P100 // Pulse Counter - DS2423 @@ -1193,7 +1245,7 @@ To create/register a plugin, you have to : #define USES_P113 // VL53L1X ToF #endif -#ifdef PLUGIN_SET_TESTING_C +#ifdef PLUGIN_SET_COLLECTION_C #define USES_P085 // AcuDC24x #define USES_P087 // Serial Proxy @@ -1203,7 +1255,7 @@ To create/register a plugin, you have to : #define USES_P111 // RC522 RFID reader #endif -#ifdef PLUGIN_SET_TESTING_D +#ifdef PLUGIN_SET_COLLECTION_D #define USES_P093 // Mitsubishi Heat Pump #define USES_P094 // CUL Reader #ifndef USES_P098 @@ -1221,7 +1273,7 @@ To create/register a plugin, you have to : #define USES_P127 // CDM7160 #endif -#ifdef PLUGIN_SET_TESTING_E +#ifdef PLUGIN_SET_COLLECTION_E #define USES_P119 // ITG3205 Gyro #define USES_P120 // ADXL345 I2C #define USES_P121 // HMC5883L @@ -1233,6 +1285,9 @@ To create/register a plugin, you have to : // Collection of all energy related plugins. #ifdef PLUGIN_ENERGY_COLLECTION + #ifndef PLUGIN_DESCR + #define PLUGIN_DESCR "Energy" + #endif #ifndef USES_P025 #define USES_P025 // ADS1115 #endif @@ -1271,6 +1326,9 @@ To create/register a plugin, you have to : // Collection of all display plugins. (also NeoPixel) #ifdef PLUGIN_DISPLAY_COLLECTION + #ifndef PLUGIN_DESCR + #define PLUGIN_DESCR "Display" + #endif #if !defined(LIMIT_BUILD_SIZE) && (defined(ESP8266) || !(ESP_IDF_VERSION_MAJOR > 3)) #define LIMIT_BUILD_SIZE // Reduce buildsize (on ESP8266 / pre-IDF4.x) to fit in all Display plugins #endif @@ -1326,6 +1384,9 @@ To create/register a plugin, you have to : // Collection of all NeoPixel plugins #ifdef PLUGIN_NEOPIXEL_COLLECTION + #ifndef PLUGIN_DESCR + #define PLUGIN_DESCR "NeoPixel" + #endif #ifndef USES_P038 #define USES_P038 // NeoPixel #endif @@ -1351,7 +1412,7 @@ To create/register a plugin, you have to : #endif #endif -#ifdef CONTROLLER_SET_TESTING +#ifdef CONTROLLER_SET_COLLECTION #define USES_C011 // Generic HTTP Advanced #define USES_C012 // Blynk HTTP #define USES_C014 // homie 3 & 4dev MQTT @@ -1362,7 +1423,8 @@ To create/register a plugin, you have to : #endif -#ifdef NOTIFIER_SET_TESTING +#ifdef NOTIFIER_SET_COLLECTION + // To be defined #endif @@ -1453,7 +1515,7 @@ To create/register a plugin, you have to : // Maximized build definition for an ESP(32) with 16MB Flash and 4MB sketch partition -// Add all plugins, controllers and features that don't fit in the TESTING set +// Add all plugins, controllers and features that don't fit in the COLLECTION set #ifdef PLUGIN_SET_MAX // Features #ifndef USE_SERVO @@ -1782,7 +1844,7 @@ To create/register a plugin, you have to : #ifdef USES_BLYNK #undef USES_BLYNK #endif - #if !defined(PLUGIN_SET_TESTING) && !defined(PLUGIN_SET_SONOFF_POW) + #if !defined(PLUGIN_SET_COLLECTION) && !defined(PLUGIN_SET_SONOFF_POW) #ifdef USES_P076 #undef USES_P076 // HWL8012 in POW r1 #endif @@ -1925,8 +1987,8 @@ To create/register a plugin, you have to : #endif #endif -// Here we can re-enable specific features in the TESTING sets as we have created some space there by splitting them up -#if defined(TESTING_USE_RTTTL) && (defined(PLUGIN_SET_TESTING_A) || defined(PLUGIN_SET_TESTING_B) || defined(PLUGIN_SET_TESTING_C) || defined(PLUGIN_SET_TESTING_D) || defined(PLUGIN_SET_TESTING_E)) +// Here we can re-enable specific features in the COLLECTION sets as we have created some space there by splitting them up +#if defined(COLLECTION_USE_RTTTL) && (defined(PLUGIN_SET_COLLECTION_A) || defined(PLUGIN_SET_COLLECTION_B) || defined(PLUGIN_SET_COLLECTION_C) || defined(PLUGIN_SET_COLLECTION_D) || defined(PLUGIN_SET_COLLECTION_E)) #ifndef USE_RTTTL #define USE_RTTTL #endif @@ -1952,7 +2014,7 @@ To create/register a plugin, you have to : // By default we enable the SHOW_SYSINFO_JSON when we enable the WEBSERVER_NEW_UI #ifdef WEBSERVER_NEW_UI - #define SHOW_SYSINFO_JSON + #define SHOW_SYSINFO_JSON #endif diff --git a/src/src/DataStructs/LogStruct.h b/src/src/DataStructs/LogStruct.h index 887256c107..df1d2c44b3 100644 --- a/src/src/DataStructs/LogStruct.h +++ b/src/src/DataStructs/LogStruct.h @@ -16,7 +16,7 @@ #ifdef USE_SECOND_HEAP #define LOG_STRUCT_MESSAGE_LINES 60 #else - #if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV) + #if defined(PLUGIN_BUILD_COLLECTION) || defined(PLUGIN_BUILD_DEV) #define LOG_STRUCT_MESSAGE_LINES 10 #else #define LOG_STRUCT_MESSAGE_LINES 15 diff --git a/src/src/Helpers/StringGenerator_System.cpp b/src/src/Helpers/StringGenerator_System.cpp index 80dc95e06c..d3d4a9f562 100644 --- a/src/src/Helpers/StringGenerator_System.cpp +++ b/src/src/Helpers/StringGenerator_System.cpp @@ -175,9 +175,9 @@ String getPluginDescriptionString() { #ifdef PLUGIN_BUILD_NORMAL result += F(" [Normal]"); #endif // ifdef PLUGIN_BUILD_NORMAL - #ifdef PLUGIN_BUILD_TESTING - result += F(" [Testing]"); - #endif // ifdef PLUGIN_BUILD_TESTING + #ifdef PLUGIN_BUILD_COLLECTION + result += F(" [Collection]"); + #endif // ifdef PLUGIN_BUILD_COLLECTION #ifdef PLUGIN_BUILD_DEV result += F(" [Development]"); #endif // ifdef PLUGIN_BUILD_DEV diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index ad741b6a43..c9ff600646 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -27,15 +27,15 @@ # define P073_SCROLL_TEXT // Enable scrolling of 7dtext by default # define P073_7DBIN_COMMAND // Enable input of binary data via 7dbin,uint8_t,... command -# ifndef PLUGIN_SET_TESTING +# ifndef PLUGIN_SET_COLLECTION // # define P073_DEBUG // Leave out some debugging on demand, activates extra log info in the debug -# else // ifndef PLUGIN_SET_TESTING +# else // ifndef PLUGIN_SET_COLLECTION # undef P073_7DDT_COMMAND // Optionally activate if .bin file space is really problematic, to remove the 7ddt command # undef P073_EXTRA_FONTS // Optionally activate if .bin file space is really problematic, to remove the font selection and 7dfont command # undef P073_SCROLL_TEXT // Optionally activate if .bin file space is really problematic, to remove the scrolling text feature # undef P073_7DBIN_COMMAND // Optionally activate if .bin file space is really problematic, to remove the 7dbin command -# endif // ifndef PLUGIN_SET_TESTING +# endif // ifndef PLUGIN_SET_COLLECTION # define TM1637_POWER_ON B10001000 # define TM1637_POWER_OFF B10000000 From 5a358dc488abbd3a67dfd54d85c4f8148bb304e4 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 22 Jul 2022 21:51:00 +0200 Subject: [PATCH 255/404] [Build] Remove TESTING tag from Stable plugins --- docs/source/Plugin/P075.rst | 2 +- docs/source/Plugin/P115.rst | 2 +- src/_C011.cpp | 2 +- src/_C012.cpp | 2 +- src/_C015.cpp | 4 ++-- src/_C018.cpp | 2 +- src/_P045_MPU6050.ino | 4 ++-- src/_P046_VentusW266.ino | 4 ++-- src/_P047_i2c-soil-moisture-sensor.ino | 2 +- src/_P048_Motorshield_v2.ino | 2 +- src/_P050_TCS34725.ino | 2 +- src/_P051_AM2320.ino | 2 +- src/_P054_DMX512.ino | 2 +- src/_P055_Chiming.ino | 2 +- src/_P057_HT16K33_LED.ino | 2 +- src/_P058_HT16K33_KeyPad.ino | 2 +- src/_P060_MCP3221.ino | 2 +- src/_P061_KeyPad.ino | 2 +- src/_P062_MPR121_KeyPad.ino | 2 +- src/_P065_DRF0299_MP3.ino | 2 +- src/_P066_VEML6040.ino | 2 +- src/_P067_HX711_Load_Cell.ino | 2 +- src/_P068_SHT3x.ino | 2 +- src/_P070_NeoPixel_Clock.ino | 2 +- src/_P071_Kamstrup401.ino | 2 +- src/_P072_HDC1080.ino | 2 +- src/_P074_TSL2591.ino | 2 +- src/_P075_Nextion.ino | 2 +- src/_P076_HLW8012.ino | 2 +- src/_P077_CSE7766.ino | 4 ++-- src/_P078_Eastron.ino | 2 +- src/_P080_DallasIButton.ino | 2 +- src/_P081_Cron.ino | 2 +- src/_P082_GPS.ino | 2 +- src/_P083_SGP30.ino | 2 +- src/_P084_VEML6070.ino | 2 +- src/_P085_AcuDC243.ino | 2 +- src/_P086_Homie.ino | 2 +- src/_P087_SerialProxy.ino | 2 +- src/_P088_HeatpumpIR.ino | 2 +- src/_P090_CCS811.ino | 2 +- src/_P092_DLbus.ino | 2 +- src/_P093_MitsubishiHP.ino | 2 +- src/_P095_ILI9341.ino | 2 +- src/_P096_eInk.ino | 2 +- src/_P099_XPT2046Touch.ino | 2 +- src/_P100_DS2423_counter.ino | 2 +- src/_P101_WakeOnLan.ino | 4 ++-- src/_P102_PZEM004Tv3.ino | 2 +- src/_P103_Atlas_EZO_pH_ORP_EC_DO.ino | 2 +- src/_P105_AHT.ino | 2 +- src/_P108_DDS238.ino | 2 +- src/_P110_VL53L0X.ino | 2 +- src/_P111_RC522_RFID.ino | 2 +- src/_P113_VL53L1X.ino | 2 +- src/_P114_VEML6075.ino | 2 +- src/_P115_MAX1704x_v2.ino | 2 +- src/_P116_ST77xx.ino | 2 +- src/_P117_SCD30.ino | 2 +- src/_P119_ITG3205_Gyro.ino | 2 +- src/_P120_ADXL345_Accelerometer.ino | 2 +- src/_P124_MultiRelay.ino | 2 +- src/_P125_ADXL345_SPI.ino | 2 +- src/_P126_74HC595.ino | 2 +- src/_P127_CDM7160.ino | 2 +- src/_P128_NeoPixelBusFX.ino | 2 +- src/_P132_INA3221.ino | 2 +- src/_P133_LTR390.ino | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- 69 files changed, 75 insertions(+), 75 deletions(-) diff --git a/docs/source/Plugin/P075.rst b/docs/source/Plugin/P075.rst index 6ae7c2cd35..d737205aae 100644 --- a/docs/source/Plugin/P075.rst +++ b/docs/source/Plugin/P075.rst @@ -156,7 +156,7 @@ Follow these steps to configure ESPEasy's Nextion plugin. 1. Use your favorite web browser and connect to your ESPEasy device. 2. Go to the *Devices* Tab and pick an empty task. -3. Choose the task *Add* button and select the *Display - Nextion [TESTING]* entry. +3. Choose the task *Add* button and select the *Display - Nextion* entry. 4. Configure the Nextion display as needed by your application. See the *Configuration Settings Summary* below. 5. Click the submit button. diff --git a/docs/source/Plugin/P115.rst b/docs/source/Plugin/P115.rst index d6f6c2f957..82d30f62f0 100644 --- a/docs/source/Plugin/P115.rst +++ b/docs/source/Plugin/P115.rst @@ -81,4 +81,4 @@ Change log .. versionchanged:: 2.0 - |added| 2021-05-08 Added to main repository as Plugin 115 Energy - Fuel Gauge MAX1704x [TESTING] + |added| 2021-05-08 Added to main repository as Plugin 115 Energy - Fuel Gauge MAX1704x diff --git a/src/_C011.cpp b/src/_C011.cpp index 1b596ed3b7..2481e9c68f 100644 --- a/src/_C011.cpp +++ b/src/_C011.cpp @@ -7,7 +7,7 @@ # define CPLUGIN_011 # define CPLUGIN_ID_011 11 -# define CPLUGIN_NAME_011 "Generic HTTP Advanced [TESTING]" +# define CPLUGIN_NAME_011 "Generic HTTP Advanced" # define C011_HTTP_METHOD_MAX_LEN 16 # define C011_HTTP_URI_MAX_LEN 240 diff --git a/src/_C012.cpp b/src/_C012.cpp index cae94a17e7..fc36c95854 100644 --- a/src/_C012.cpp +++ b/src/_C012.cpp @@ -9,7 +9,7 @@ # define CPLUGIN_012 # define CPLUGIN_ID_012 12 -# define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]" +# define CPLUGIN_NAME_012 "Blynk HTTP" bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& string) { diff --git a/src/_C015.cpp b/src/_C015.cpp index f52f0b2af3..5cd8c506e8 100644 --- a/src/_C015.cpp +++ b/src/_C015.cpp @@ -36,7 +36,7 @@ #ifdef ESP32 # include #endif - # define CPLUGIN_NAME_015 "Blynk SSL [TESTING]" + # define CPLUGIN_NAME_015 "Blynk SSL" // Current official blynk server thumbprint # define CPLUGIN_015_DEFAULT_THUMBPRINT "FD C0 7D 8D 47 97 F7 E3 07 05 D3 4E E3 BB 8E 3D C0 EA BE 1C" @@ -48,7 +48,7 @@ #ifdef ESP32 # include #endif - # define CPLUGIN_NAME_015 "Blynk [TESTING]" + # define CPLUGIN_NAME_015 "Blynk" # define C015_LOG_PREFIX "BL: " # endif // ifdef CPLUGIN_015_SSL diff --git a/src/_C018.cpp b/src/_C018.cpp index 38a72fb643..1da12b744a 100644 --- a/src/_C018.cpp +++ b/src/_C018.cpp @@ -8,7 +8,7 @@ # define CPLUGIN_018 # define CPLUGIN_ID_018 18 -# define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903 [TESTING]" +# define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903" # define C018_BAUDRATE_LABEL "baudrate" diff --git a/src/_P045_MPU6050.ino b/src/_P045_MPU6050.ino index caa521c9ec..7eb8f8d3e1 100644 --- a/src/_P045_MPU6050.ino +++ b/src/_P045_MPU6050.ino @@ -2,7 +2,7 @@ #ifdef USES_P045 // ####################################################################################################### -// #################################### Plugin 045: MPU6050 [Testing] #################################### +// #################################### Plugin 045: MPU6050 #################################### // ####################################################################################################### // Based on the works of Nolan Gilley @ https://home-assistant.io/blog/2016/08/03/laundry-automation-update/ @@ -68,7 +68,7 @@ #define PLUGIN_045 #define PLUGIN_ID_045 45 -#define PLUGIN_NAME_045 "Gyro - MPU 6050 [TESTING]" +#define PLUGIN_NAME_045 "Gyro - MPU 6050" #define PLUGIN_VALUENAME1_045 "" diff --git a/src/_P046_VentusW266.ino b/src/_P046_VentusW266.ino index 02534daac3..c6f0674b5b 100644 --- a/src/_P046_VentusW266.ino +++ b/src/_P046_VentusW266.ino @@ -1,7 +1,7 @@ #include "_Plugin_Helper.h" #ifdef USES_P046 //####################################################################################################### -//#################################### Plugin 046: Ventus W266 [Testing] ################################ +//#################################### Plugin 046: Ventus W266 ################################ //####################################################################################################### // Purpose: Sniff the data received by the Ventus W266 display unit and send it to Domoticz @@ -86,7 +86,7 @@ #define PLUGIN_046 // Mandatory framework constants #define PLUGIN_ID_046 46 -#define PLUGIN_NAME_046 "Hardware - Ventus W266 [TESTING]" +#define PLUGIN_NAME_046 "Hardware - Ventus W266" #define PLUGIN_VALUENAME1_046 "" #define PLUGIN_VALUENAME2_046 "" #define PLUGIN_VALUENAME3_046 "" diff --git a/src/_P047_i2c-soil-moisture-sensor.ino b/src/_P047_i2c-soil-moisture-sensor.ino index fc03ba2a8d..a373dc1757 100644 --- a/src/_P047_i2c-soil-moisture-sensor.ino +++ b/src/_P047_i2c-soil-moisture-sensor.ino @@ -13,7 +13,7 @@ #define PLUGIN_047 #define PLUGIN_ID_047 47 -#define PLUGIN_NAME_047 "Environment - Soil moisture sensor [TESTING]" +#define PLUGIN_NAME_047 "Environment - Soil moisture sensor" #define PLUGIN_VALUENAME1_047 "Temperature" #define PLUGIN_VALUENAME2_047 "Moisture" #define PLUGIN_VALUENAME3_047 "Light" diff --git a/src/_P048_Motorshield_v2.ino b/src/_P048_Motorshield_v2.ino index b3e2bd19bd..f5cd30af54 100644 --- a/src/_P048_Motorshield_v2.ino +++ b/src/_P048_Motorshield_v2.ino @@ -17,7 +17,7 @@ #define PLUGIN_048 #define PLUGIN_ID_048 48 -#define PLUGIN_NAME_048 "Motor - Adafruit Motorshield v2 [TESTING]" +#define PLUGIN_NAME_048 "Motor - Adafruit Motorshield v2" #define PLUGIN_VALUENAME1_048 "MotorShield v2" #define Plugin_048_MotorShield_address PCONFIG(0) diff --git a/src/_P050_TCS34725.ino b/src/_P050_TCS34725.ino index 20af5e55ac..cd75f4e15f 100644 --- a/src/_P050_TCS34725.ino +++ b/src/_P050_TCS34725.ino @@ -24,7 +24,7 @@ #define PLUGIN_050 #define PLUGIN_ID_050 50 -#define PLUGIN_NAME_050 "Color - TCS34725 [TESTING]" +#define PLUGIN_NAME_050 "Color - TCS34725 " #define PLUGIN_VALUENAME1_050 "Red" #define PLUGIN_VALUENAME2_050 "Green" #define PLUGIN_VALUENAME3_050 "Blue" diff --git a/src/_P051_AM2320.ino b/src/_P051_AM2320.ino index 8bf8df5707..ace56154f8 100644 --- a/src/_P051_AM2320.ino +++ b/src/_P051_AM2320.ino @@ -17,7 +17,7 @@ #define PLUGIN_051 #define PLUGIN_ID_051 51 -#define PLUGIN_NAME_051 "Environment - AM2320 [TESTING]" +#define PLUGIN_NAME_051 "Environment - AM2320" #define PLUGIN_VALUENAME1_051 "Temperature" #define PLUGIN_VALUENAME2_051 "Humidity" diff --git a/src/_P054_DMX512.ino b/src/_P054_DMX512.ino index 155e953823..d898e6d54f 100644 --- a/src/_P054_DMX512.ino +++ b/src/_P054_DMX512.ino @@ -54,7 +54,7 @@ #define PLUGIN_054 #define PLUGIN_ID_054 54 -#define PLUGIN_NAME_054 "Communication - DMX512 TX [TESTING]" +#define PLUGIN_NAME_054 "Communication - DMX512 TX" uint8_t* Plugin_054_DMXBuffer = 0; int16_t Plugin_054_DMXSize = 32; diff --git a/src/_P055_Chiming.ino b/src/_P055_Chiming.ino index c763b1c395..13f9c7f6dd 100644 --- a/src/_P055_Chiming.ino +++ b/src/_P055_Chiming.ino @@ -54,7 +54,7 @@ #define PLUGIN_055 #define PLUGIN_ID_055 55 -#define PLUGIN_NAME_055 "Notify - Chiming [TESTING]" +#define PLUGIN_NAME_055 "Notify - Chiming" #define PLUGIN_055_FIFO_SIZE 64 // must be power of 2 #define PLUGIN_055_FIFO_MASK (PLUGIN_055_FIFO_SIZE-1) diff --git a/src/_P057_HT16K33_LED.ino b/src/_P057_HT16K33_LED.ino index e7de658254..e48377f320 100644 --- a/src/_P057_HT16K33_LED.ino +++ b/src/_P057_HT16K33_LED.ino @@ -67,7 +67,7 @@ #define PLUGIN_057 #define PLUGIN_ID_057 57 -#define PLUGIN_NAME_057 "Display - HT16K33 [TESTING]" +#define PLUGIN_NAME_057 "Display - HT16K33" #include "src/PluginStructs/P057_data_struct.h" diff --git a/src/_P058_HT16K33_KeyPad.ino b/src/_P058_HT16K33_KeyPad.ino index 8686051338..39c08d713f 100644 --- a/src/_P058_HT16K33_KeyPad.ino +++ b/src/_P058_HT16K33_KeyPad.ino @@ -31,7 +31,7 @@ #define PLUGIN_058 #define PLUGIN_ID_058 58 -#define PLUGIN_NAME_058 "Keypad - HT16K33 [TESTING]" +#define PLUGIN_NAME_058 "Keypad - HT16K33" #define PLUGIN_VALUENAME1_058 "ScanCode" diff --git a/src/_P060_MCP3221.ino b/src/_P060_MCP3221.ino index ae1eed5133..a4f21caf36 100644 --- a/src/_P060_MCP3221.ino +++ b/src/_P060_MCP3221.ino @@ -13,7 +13,7 @@ #define PLUGIN_060 #define PLUGIN_ID_060 60 -#define PLUGIN_NAME_060 "Analog input - MCP3221 [TESTING]" +#define PLUGIN_NAME_060 "Analog input - MCP3221" #define PLUGIN_VALUENAME1_060 "Analog" diff --git a/src/_P061_KeyPad.ino b/src/_P061_KeyPad.ino index daaac4e420..976455f9dc 100644 --- a/src/_P061_KeyPad.ino +++ b/src/_P061_KeyPad.ino @@ -77,7 +77,7 @@ # define PLUGIN_061 # define PLUGIN_ID_061 61 -# define PLUGIN_NAME_061 "Keypad - PCF8574 / MCP23017 / PCF8575 [TESTING]" +# define PLUGIN_NAME_061 "Keypad - PCF8574 / MCP23017 / PCF8575" # define PLUGIN_VALUENAME1_061 "ScanCode" diff --git a/src/_P062_MPR121_KeyPad.ino b/src/_P062_MPR121_KeyPad.ino index 15204a6a32..b96a67ea12 100644 --- a/src/_P062_MPR121_KeyPad.ino +++ b/src/_P062_MPR121_KeyPad.ino @@ -23,7 +23,7 @@ # define PLUGIN_062 # define PLUGIN_ID_062 62 -# define PLUGIN_NAME_062 "Keypad - MPR121 Touch [TESTING]" +# define PLUGIN_NAME_062 "Keypad - MPR121 Touch" # define PLUGIN_VALUENAME1_062 "ScanCode" diff --git a/src/_P065_DRF0299_MP3.ino b/src/_P065_DRF0299_MP3.ino index 0a629c8af8..21796f1191 100644 --- a/src/_P065_DRF0299_MP3.ino +++ b/src/_P065_DRF0299_MP3.ino @@ -38,7 +38,7 @@ # define PLUGIN_065 # define PLUGIN_ID_065 65 -# define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3 [TESTING]" +# define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3" # define PLUGIN_VALUENAME1_065 "" # include diff --git a/src/_P066_VEML6040.ino b/src/_P066_VEML6040.ino index a6bd9abe15..585776f6e1 100644 --- a/src/_P066_VEML6040.ino +++ b/src/_P066_VEML6040.ino @@ -14,7 +14,7 @@ #define PLUGIN_066 #define PLUGIN_ID_066 66 -#define PLUGIN_NAME_066 "Color - VEML6040 [TESTING]" +#define PLUGIN_NAME_066 "Color - VEML6040" #define PLUGIN_VALUENAME1_066 "R" #define PLUGIN_VALUENAME2_066 "G" #define PLUGIN_VALUENAME3_066 "B" diff --git a/src/_P067_HX711_Load_Cell.ino b/src/_P067_HX711_Load_Cell.ino index 4920b2db34..67f966536d 100644 --- a/src/_P067_HX711_Load_Cell.ino +++ b/src/_P067_HX711_Load_Cell.ino @@ -19,7 +19,7 @@ #define PLUGIN_067 #define PLUGIN_ID_067 67 -#define PLUGIN_NAME_067 "Weight - HX711 Load Cell [TESTING]" +#define PLUGIN_NAME_067 "Weight - HX711 Load Cell" #define PLUGIN_VALUENAME1_067 "WeightChanA" #define PLUGIN_VALUENAME2_067 "WeightChanB" diff --git a/src/_P068_SHT3x.ino b/src/_P068_SHT3x.ino index 95220043fd..3d382631dd 100644 --- a/src/_P068_SHT3x.ino +++ b/src/_P068_SHT3x.ino @@ -24,7 +24,7 @@ # define PLUGIN_068 # define PLUGIN_ID_068 68 -# define PLUGIN_NAME_068 "Environment - SHT30/31/35 [TESTING]" +# define PLUGIN_NAME_068 "Environment - SHT30/31/35" # define PLUGIN_VALUENAME1_068 "Temperature" # define PLUGIN_VALUENAME2_068 "Humidity" diff --git a/src/_P070_NeoPixel_Clock.ino b/src/_P070_NeoPixel_Clock.ino index d189367cb1..a44f9278e7 100644 --- a/src/_P070_NeoPixel_Clock.ino +++ b/src/_P070_NeoPixel_Clock.ino @@ -17,7 +17,7 @@ # define PLUGIN_070 # define PLUGIN_ID_070 70 -# define PLUGIN_NAME_070 "Output - NeoPixel Ring Clock [TESTING]" +# define PLUGIN_NAME_070 "Output - NeoPixel Ring Clock" # define PLUGIN_VALUENAME1_070 "Enabled" # define PLUGIN_VALUENAME2_070 "Brightness" # define PLUGIN_VALUENAME3_070 "Marks" diff --git a/src/_P071_Kamstrup401.ino b/src/_P071_Kamstrup401.ino index 0eb53faa4c..9415df7a80 100644 --- a/src/_P071_Kamstrup401.ino +++ b/src/_P071_Kamstrup401.ino @@ -18,7 +18,7 @@ #define PLUGIN_071 #define PLUGIN_ID_071 71 -#define PLUGIN_NAME_071 "Communication - Kamstrup Multical 401 [TESTING]" +#define PLUGIN_NAME_071 "Communication - Kamstrup Multical 401" #define PLUGIN_VALUENAME1_071 "Heat" #define PLUGIN_VALUENAME2_071 "Volume" diff --git a/src/_P072_HDC1080.ino b/src/_P072_HDC1080.ino index 34c5936fe3..96f76f0ee8 100644 --- a/src/_P072_HDC1080.ino +++ b/src/_P072_HDC1080.ino @@ -8,7 +8,7 @@ #define PLUGIN_072 #define PLUGIN_ID_072 72 -#define PLUGIN_NAME_072 "Environment - HDC1080 (I2C) [TESTING]" +#define PLUGIN_NAME_072 "Environment - HDC1080 (I2C)" #define PLUGIN_VALUENAME1_072 "Temperature" #define PLUGIN_VALUENAME2_072 "Humidity" diff --git a/src/_P074_TSL2591.ino b/src/_P074_TSL2591.ino index 25c87bd1d4..70ea653505 100644 --- a/src/_P074_TSL2591.ino +++ b/src/_P074_TSL2591.ino @@ -20,7 +20,7 @@ # define PLUGIN_074 # define PLUGIN_ID_074 74 -# define PLUGIN_NAME_074 "Light/Lux - TSL2591 [TESTING]" +# define PLUGIN_NAME_074 "Light/Lux - TSL2591" # define PLUGIN_VALUENAME1_074 "Lux" # define PLUGIN_VALUENAME2_074 "Full" # define PLUGIN_VALUENAME3_074 "Visible" diff --git a/src/_P075_Nextion.ino b/src/_P075_Nextion.ino index 849ba15f94..2a658e9e52 100644 --- a/src/_P075_Nextion.ino +++ b/src/_P075_Nextion.ino @@ -27,7 +27,7 @@ // Plug-In defines # define PLUGIN_075 # define PLUGIN_ID_075 75 -# define PLUGIN_NAME_075 "Display - Nextion [TESTING]" +# define PLUGIN_NAME_075 "Display - Nextion" # define PLUGIN_DEFAULT_NAME "NEXTION" # define PLUGIN_VALUENAME1_075 "idx" # define PLUGIN_VALUENAME2_075 "value" diff --git a/src/_P076_HLW8012.ino b/src/_P076_HLW8012.ino index 94a6d4f807..b4df6ddaba 100644 --- a/src/_P076_HLW8012.ino +++ b/src/_P076_HLW8012.ino @@ -24,7 +24,7 @@ HLW8012 *Plugin_076_hlw = nullptr; #define PLUGIN_076 #define PLUGIN_ID_076 76 #define PLUGIN_076_DEBUG true // activate extra log info in the debug -#define PLUGIN_NAME_076 "Energy (AC) - HLW8012/BL0937 [TESTING]" +#define PLUGIN_NAME_076 "Energy (AC) - HLW8012/BL0937 " #define PLUGIN_VALUENAME1_076 "Voltage" #define PLUGIN_VALUENAME2_076 "Current" #define PLUGIN_VALUENAME3_076 "Power" diff --git a/src/_P077_CSE7766.ino b/src/_P077_CSE7766.ino index 0186372e35..a61dc26d57 100644 --- a/src/_P077_CSE7766.ino +++ b/src/_P077_CSE7766.ino @@ -12,9 +12,9 @@ # define PLUGIN_077 # define PLUGIN_ID_077 77 # ifdef PLUGIN_SET_SONOFF_POW - # define PLUGIN_NAME_077 "Energy (AC) - CSE7766 (POW r2) [TESTING]" + # define PLUGIN_NAME_077 "Energy (AC) - CSE7766 (POW r2)" # else // ifdef PLUGIN_SET_SONOFF_POW - # define PLUGIN_NAME_077 "Energy (AC) - CSE7766 [TESTING]" + # define PLUGIN_NAME_077 "Energy (AC) - CSE7766" # endif // ifdef PLUGIN_SET_SONOFF_POW # define PLUGIN_VALUENAME1_077 "Voltage" # define PLUGIN_VALUENAME2_077 "Power" diff --git a/src/_P078_Eastron.ino b/src/_P078_Eastron.ino index 6758129cee..6ee222bdd3 100644 --- a/src/_P078_Eastron.ino +++ b/src/_P078_Eastron.ino @@ -14,7 +14,7 @@ #define PLUGIN_078 #define PLUGIN_ID_078 78 -#define PLUGIN_NAME_078 "Energy (AC) - Eastron SDM120C/220T/230/630 [TESTING]" +#define PLUGIN_NAME_078 "Energy (AC) - Eastron SDM120C/220T/230/630" #define P078_DEV_ID PCONFIG(0) #define P078_DEV_ID_LABEL PCONFIG_LABEL(0) diff --git a/src/_P080_DallasIButton.ino b/src/_P080_DallasIButton.ino index e12e170f28..8f64c42039 100644 --- a/src/_P080_DallasIButton.ino +++ b/src/_P080_DallasIButton.ino @@ -11,7 +11,7 @@ # define PLUGIN_080 # define PLUGIN_ID_080 80 -# define PLUGIN_NAME_080 "Input - iButton [TESTING]" +# define PLUGIN_NAME_080 "Input - iButton" # define PLUGIN_VALUENAME1_080 "iButton" diff --git a/src/_P081_Cron.ino b/src/_P081_Cron.ino index 6b3b901bd9..44cb2ec7f6 100644 --- a/src/_P081_Cron.ino +++ b/src/_P081_Cron.ino @@ -13,7 +13,7 @@ # define PLUGIN_081 # define PLUGIN_ID_081 81 // plugin id -# define PLUGIN_NAME_081 "Generic - CRON [TESTING]" // "Plugin Name" is what will be displayed in the selection list +# define PLUGIN_NAME_081 "Generic - CRON" // "Plugin Name" is what will be displayed in the selection list # define PLUGIN_VALUENAME1_081 "LastExecution" # define PLUGIN_VALUENAME2_081 "NextExecution" diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index cb06fae2d2..f589492304 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -23,7 +23,7 @@ # define PLUGIN_082 # define PLUGIN_ID_082 82 -# define PLUGIN_NAME_082 "Position - GPS [TESTING]" +# define PLUGIN_NAME_082 "Position - GPS" # define PLUGIN_VALUENAME1_082 "Longitude" # define PLUGIN_VALUENAME2_082 "Latitude" # define PLUGIN_VALUENAME3_082 "Altitude" diff --git a/src/_P083_SGP30.ino b/src/_P083_SGP30.ino index 5d60c5be7c..f32e9240a8 100644 --- a/src/_P083_SGP30.ino +++ b/src/_P083_SGP30.ino @@ -13,7 +13,7 @@ #define PLUGIN_083 #define PLUGIN_ID_083 83 -#define PLUGIN_NAME_083 "Gasses - SGP30 [TESTING]" +#define PLUGIN_NAME_083 "Gasses - SGP30" #define PLUGIN_VALUENAME1_083 "TVOC" #define PLUGIN_VALUENAME2_083 "eCO2" diff --git a/src/_P084_VEML6070.ino b/src/_P084_VEML6070.ino index 239e7b7bf4..aa09abbd71 100644 --- a/src/_P084_VEML6070.ino +++ b/src/_P084_VEML6070.ino @@ -13,7 +13,7 @@ #define PLUGIN_084 #define PLUGIN_ID_084 84 -#define PLUGIN_NAME_084 "UV - VEML6070 [TESTING]" +#define PLUGIN_NAME_084 "UV - VEML6070" #define PLUGIN_VALUENAME1_084 "Raw" #define PLUGIN_VALUENAME2_084 "Risk" #define PLUGIN_VALUENAME3_084 "Power" diff --git a/src/_P085_AcuDC243.ino b/src/_P085_AcuDC243.ino index 9578448187..ccebfbe3ff 100644 --- a/src/_P085_AcuDC243.ino +++ b/src/_P085_AcuDC243.ino @@ -18,7 +18,7 @@ # define PLUGIN_085 # define PLUGIN_ID_085 85 -# define PLUGIN_NAME_085 "Energy - AccuEnergy AcuDC24x [TESTING]" +# define PLUGIN_NAME_085 "Energy - AccuEnergy AcuDC24x" # define PLUGIN_VALUENAME1_085 "" diff --git a/src/_P086_Homie.ino b/src/_P086_Homie.ino index 2161b25d04..05db16b133 100644 --- a/src/_P086_Homie.ino +++ b/src/_P086_Homie.ino @@ -7,7 +7,7 @@ #define PLUGIN_086 #define PLUGIN_ID_086 86 -#define PLUGIN_NAME_086 "Generic - Homie receiver [TESTING]" +#define PLUGIN_NAME_086 "Generic - Homie receiver" // empty default names because settings will be ignored / not used if value name is empty #define PLUGIN_VALUENAME1_086 "" diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index a2b9c58764..535114bb6a 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -23,7 +23,7 @@ #define PLUGIN_087 #define PLUGIN_ID_087 87 -#define PLUGIN_NAME_087 "Communication - Serial Proxy [TESTING]" +#define PLUGIN_NAME_087 "Communication - Serial Proxy" #define P087_BAUDRATE PCONFIG_LONG(0) diff --git a/src/_P088_HeatpumpIR.ino b/src/_P088_HeatpumpIR.ino index f3c1cf5a35..ed0b5a1e79 100644 --- a/src/_P088_HeatpumpIR.ino +++ b/src/_P088_HeatpumpIR.ino @@ -6,7 +6,7 @@ #define PLUGIN_088 #define PLUGIN_ID_088 88 -#define PLUGIN_NAME_088 "Energy (Heat) - Heatpump IR transmitter [TESTING]" +#define PLUGIN_NAME_088 "Energy (Heat) - Heatpump IR transmitter" /* diff --git a/src/_P090_CCS811.ino b/src/_P090_CCS811.ino index b29c80b44d..1e0f52278a 100644 --- a/src/_P090_CCS811.ino +++ b/src/_P090_CCS811.ino @@ -21,7 +21,7 @@ #define PLUGIN_090 #define PLUGIN_ID_090 90 -#define PLUGIN_NAME_090 "Gases - CCS811 TVOC/eCO2 [TESTING]" +#define PLUGIN_NAME_090 "Gases - CCS811 TVOC/eCO2" #define PLUGIN_VALUENAME1_090 "TVOC" #define PLUGIN_VALUENAME2_090 "eCO2" diff --git a/src/_P092_DLbus.ino b/src/_P092_DLbus.ino index e280219d70..dfd1ec4b27 100644 --- a/src/_P092_DLbus.ino +++ b/src/_P092_DLbus.ino @@ -67,7 +67,7 @@ # define PLUGIN_ID_092 92 // #define PLUGIN_092_DEBUG // additional debug messages in the log -# define PLUGIN_NAME_092 "Heating - DL-Bus (Technische Alternative) [TESTING]" +# define PLUGIN_NAME_092 "Heating - DL-Bus (Technische Alternative) " # define PLUGIN_VALUENAME1_092 "Value" // global values needed for all tasks diff --git a/src/_P093_MitsubishiHP.ino b/src/_P093_MitsubishiHP.ino index f2b3badbea..4221bbf5a8 100644 --- a/src/_P093_MitsubishiHP.ino +++ b/src/_P093_MitsubishiHP.ino @@ -9,7 +9,7 @@ # define PLUGIN_093 # define PLUGIN_ID_093 93 -# define PLUGIN_NAME_093 "Energy (Heat) - Mitsubishi Heat Pump [TESTING]" +# define PLUGIN_NAME_093 "Energy (Heat) - Mitsubishi Heat Pump" # define PLUGIN_VALUENAME1_093 "settings" # define P093_REQUEST_STATUS PCONFIG(0) diff --git a/src/_P095_ILI9341.ino b/src/_P095_ILI9341.ino index 32893c2867..28927742fb 100644 --- a/src/_P095_ILI9341.ino +++ b/src/_P095_ILI9341.ino @@ -7,7 +7,7 @@ # define PLUGIN_095 # define PLUGIN_ID_095 95 -# define PLUGIN_NAME_095 "Display - TFT 2.4 inches ILI9341 [TESTING]" +# define PLUGIN_NAME_095 "Display - TFT 2.4 inches ILI9341" # define PLUGIN_VALUENAME1_095 "CursorX" # define PLUGIN_VALUENAME2_095 "CursorY" # define PLUGIN_095_MAX_DISPLAY 1 diff --git a/src/_P096_eInk.ino b/src/_P096_eInk.ino index 575e14bf8c..97d9144870 100644 --- a/src/_P096_eInk.ino +++ b/src/_P096_eInk.ino @@ -7,7 +7,7 @@ # define PLUGIN_096 # define PLUGIN_ID_096 96 -# define PLUGIN_NAME_096 "Display - eInk with Lolin ePaper screen [TESTING]" +# define PLUGIN_NAME_096 "Display - eInk with Lolin ePaper screen" # define PLUGIN_VALUENAME1_096 "CursorX" # define PLUGIN_VALUENAME2_096 "CursorY" diff --git a/src/_P099_XPT2046Touch.ino b/src/_P099_XPT2046Touch.ino index 7ea207f0ea..82c646ffe5 100644 --- a/src/_P099_XPT2046Touch.ino +++ b/src/_P099_XPT2046Touch.ino @@ -31,7 +31,7 @@ #define PLUGIN_099 #define PLUGIN_ID_099 99 -#define PLUGIN_NAME_099 "Touch - XPT2046 on a TFT display [TESTING]" +#define PLUGIN_NAME_099 "Touch - XPT2046 on a TFT display" #define PLUGIN_VALUENAME1_099 "X" #define PLUGIN_VALUENAME2_099 "Y" #define PLUGIN_VALUENAME3_099 "Z" diff --git a/src/_P100_DS2423_counter.ino b/src/_P100_DS2423_counter.ino index 26c1569c2f..9b8f4acd82 100644 --- a/src/_P100_DS2423_counter.ino +++ b/src/_P100_DS2423_counter.ino @@ -11,7 +11,7 @@ # define PLUGIN_100 # define PLUGIN_ID_100 100 -# define PLUGIN_NAME_100 "Pulse Counter - DS2423 [TESTING]" +# define PLUGIN_NAME_100 "Pulse Counter - DS2423" # define PLUGIN_VALUENAME1_100 "CountDelta" boolean Plugin_100(uint8_t function, struct EventStruct *event, String& string) diff --git a/src/_P101_WakeOnLan.ino b/src/_P101_WakeOnLan.ino index b0f6ea262b..6f14e2e732 100644 --- a/src/_P101_WakeOnLan.ino +++ b/src/_P101_WakeOnLan.ino @@ -11,7 +11,7 @@ // Oct-12-2020: Creation // Oct-16-2020: Beta Test Release to ESPEasy Forum. // Oct-18-2020: Re-assigned as plugin number P101 (was P248). -// Oct-20-2020: Github PR #3328, Submitted as [Testing] plugin. +// Oct-20-2020: Github PR #3328, Submitted as plugin. // // This ESPEasy plugin requires the WakeOnLan library found here: // https://github.com/a7md0/WakeOnLan @@ -55,7 +55,7 @@ // Plugin defines #define PLUGIN_101 #define PLUGIN_ID_101 101 -#define PLUGIN_NAME_101 "Communication - Wake On LAN [Testing]" +#define PLUGIN_NAME_101 "Communication - Wake On LAN" // Config Setting defines #define CUSTOMTASK_STR_SIZE_P101 20 diff --git a/src/_P102_PZEM004Tv3.ino b/src/_P102_PZEM004Tv3.ino index 6bf595565a..9a0358adef 100644 --- a/src/_P102_PZEM004Tv3.ino +++ b/src/_P102_PZEM004Tv3.ino @@ -17,7 +17,7 @@ # define PLUGIN_102 # define PLUGIN_ID_102 102 # define PLUGIN_102_DEBUG true // activate extra log info in the debug -# define PLUGIN_NAME_102 "PZEM-004Tv30-Multiple [TESTING]" +# define PLUGIN_NAME_102 "PZEM-004Tv30-Multiple" # define P102_PZEM_mode PCONFIG(1) // 0=read value ; 1=reset energy; 2=programm address # define P102_PZEM_ADDR PCONFIG(2) diff --git a/src/_P103_Atlas_EZO_pH_ORP_EC_DO.ino b/src/_P103_Atlas_EZO_pH_ORP_EC_DO.ino index e394c6174c..60d2e19674 100644 --- a/src/_P103_Atlas_EZO_pH_ORP_EC_DO.ino +++ b/src/_P103_Atlas_EZO_pH_ORP_EC_DO.ino @@ -16,7 +16,7 @@ #define PLUGIN_103 #define PLUGIN_ID_103 103 -#define PLUGIN_NAME_103 "Environment - Atlas EZO pH ORP EC DO [TESTING]" +#define PLUGIN_NAME_103 "Environment - Atlas EZO pH ORP EC DO" #define PLUGIN_VALUENAME1_103 "SensorData" #define PLUGIN_VALUENAME2_103 "Voltage" #define UNKNOWN 0 diff --git a/src/_P105_AHT.ino b/src/_P105_AHT.ino index d8fc979e16..c04534c8ee 100644 --- a/src/_P105_AHT.ino +++ b/src/_P105_AHT.ino @@ -37,7 +37,7 @@ # define PLUGIN_105 # define PLUGIN_ID_105 105 -# define PLUGIN_NAME_105 "Environment - AHT10/20/21 [TESTING]" +# define PLUGIN_NAME_105 "Environment - AHT10/20/21" # define PLUGIN_VALUENAME1_105 "Temperature" # define PLUGIN_VALUENAME2_105 "Humidity" diff --git a/src/_P108_DDS238.ino b/src/_P108_DDS238.ino index fd1fa08a5d..1df7842fcb 100644 --- a/src/_P108_DDS238.ino +++ b/src/_P108_DDS238.ino @@ -31,7 +31,7 @@ # define PLUGIN_108 # define PLUGIN_ID_108 108 -# define PLUGIN_NAME_108 "Energy (AC) - DDS238-x ZN [TESTING]" +# define PLUGIN_NAME_108 "Energy (AC) - DDS238-x ZN" # define PLUGIN_VALUENAME1_108 "" diff --git a/src/_P110_VL53L0X.ino b/src/_P110_VL53L0X.ino index 6148742b9a..ba8fb1145e 100644 --- a/src/_P110_VL53L0X.ino +++ b/src/_P110_VL53L0X.ino @@ -16,7 +16,7 @@ #define PLUGIN_110 #define PLUGIN_ID_110 110 -#define PLUGIN_NAME_110 "Distance - VL53L0X (200cm) [TESTING]" +#define PLUGIN_NAME_110 "Distance - VL53L0X (200cm)" #define PLUGIN_VALUENAME1_110 "Distance" diff --git a/src/_P111_RC522_RFID.ino b/src/_P111_RC522_RFID.ino index 9aa6613c79..2a2118edf4 100644 --- a/src/_P111_RC522_RFID.ino +++ b/src/_P111_RC522_RFID.ino @@ -17,7 +17,7 @@ #define PLUGIN_111 #define PLUGIN_ID_111 111 -#define PLUGIN_NAME_111 "RFID - RC522 [TESTING]" +#define PLUGIN_NAME_111 "RFID - RC522" #define PLUGIN_VALUENAME1_111 "Tag" #include "src/PluginStructs/P111_data_struct.h" diff --git a/src/_P113_VL53L1X.ino b/src/_P113_VL53L1X.ino index d51f4e5d65..9b1656d454 100644 --- a/src/_P113_VL53L1X.ino +++ b/src/_P113_VL53L1X.ino @@ -15,7 +15,7 @@ # define PLUGIN_113 # define PLUGIN_ID_113 113 -# define PLUGIN_NAME_113 "Distance - VL53L1X (400cm) [TESTING]" +# define PLUGIN_NAME_113 "Distance - VL53L1X (400cm)" # define PLUGIN_VALUENAME1_113 "Distance" # define PLUGIN_VALUENAME2_113 "Ambient" diff --git a/src/_P114_VEML6075.ino b/src/_P114_VEML6075.ino index f289c70578..86023b5112 100644 --- a/src/_P114_VEML6075.ino +++ b/src/_P114_VEML6075.ino @@ -11,7 +11,7 @@ # define PLUGIN_114 # define PLUGIN_ID_114 114 -# define PLUGIN_NAME_114 "UV - VEML6075 UVA/UVB Sensor [TESTING]" +# define PLUGIN_NAME_114 "UV - VEML6075 UVA/UVB Sensor" # define PLUGIN_VALUENAME1_114 "UVA" # define PLUGIN_VALUENAME2_114 "UVB" # define PLUGIN_VALUENAME3_114 "UVIndex" diff --git a/src/_P115_MAX1704x_v2.ino b/src/_P115_MAX1704x_v2.ino index 1d2cc31325..3f14b1a755 100644 --- a/src/_P115_MAX1704x_v2.ino +++ b/src/_P115_MAX1704x_v2.ino @@ -17,7 +17,7 @@ # define PLUGIN_115 # define PLUGIN_ID_115 115 // plugin id -# define PLUGIN_NAME_115 "Energy - Fuel Gauge MAX1704x [TESTING]" +# define PLUGIN_NAME_115 "Energy - Fuel Gauge MAX1704x" # define PLUGIN_VALUENAME1_115 "Voltage" // Battery voltage # define PLUGIN_VALUENAME2_115 "SOC" // Battery state of charge in percentage # define PLUGIN_VALUENAME3_115 "Alert" // (0 or 1) Alert when the battery SoC gets too low diff --git a/src/_P116_ST77xx.ino b/src/_P116_ST77xx.ino index 444577d852..e2af9db700 100644 --- a/src/_P116_ST77xx.ino +++ b/src/_P116_ST77xx.ino @@ -28,7 +28,7 @@ # define PLUGIN_116 # define PLUGIN_ID_116 116 -# define PLUGIN_NAME_116 "Display - ST77xx TFT [TESTING]" +# define PLUGIN_NAME_116 "Display - ST77xx TFT" # define PLUGIN_VALUENAME1_116 "CursorX" # define PLUGIN_VALUENAME2_116 "CursorY" diff --git a/src/_P117_SCD30.ino b/src/_P117_SCD30.ino index d2d2d153b8..166883251d 100644 --- a/src/_P117_SCD30.ino +++ b/src/_P117_SCD30.ino @@ -28,7 +28,7 @@ # define PLUGIN_117 # define PLUGIN_ID_117 117 -# define PLUGIN_NAME_117 "Gases - CO2 SCD30 [TESTING]" +# define PLUGIN_NAME_117 "Gases - CO2 SCD30" # define PLUGIN_VALUENAME1_117 "CO2" # define PLUGIN_VALUENAME2_117 "Humidity" # define PLUGIN_VALUENAME3_117 "Temperature" diff --git a/src/_P119_ITG3205_Gyro.ino b/src/_P119_ITG3205_Gyro.ino index 970ad61daa..e2280b9f1a 100644 --- a/src/_P119_ITG3205_Gyro.ino +++ b/src/_P119_ITG3205_Gyro.ino @@ -26,7 +26,7 @@ # define PLUGIN_119 # define PLUGIN_ID_119 119 // plugin id -# define PLUGIN_NAME_119 "Gyro - ITG3205 [TESTING]" +# define PLUGIN_NAME_119 "Gyro - ITG3205" # define PLUGIN_VALUENAME1_119 "X" # define PLUGIN_VALUENAME2_119 "Y" # define PLUGIN_VALUENAME3_119 "Z" diff --git a/src/_P120_ADXL345_Accelerometer.ino b/src/_P120_ADXL345_Accelerometer.ino index 7d41eb2b9c..312ee62244 100644 --- a/src/_P120_ADXL345_Accelerometer.ino +++ b/src/_P120_ADXL345_Accelerometer.ino @@ -28,7 +28,7 @@ # define PLUGIN_120 # define PLUGIN_ID_120 120 // plugin id -# define PLUGIN_NAME_120 "Accelerometer - ADXL345 (I2C) [TESTING]" +# define PLUGIN_NAME_120 "Accelerometer - ADXL345 (I2C)" # define PLUGIN_VALUENAME1_120 "X" # define PLUGIN_VALUENAME2_120 "Y" # define PLUGIN_VALUENAME3_120 "Z" diff --git a/src/_P124_MultiRelay.ino b/src/_P124_MultiRelay.ino index a263cedde3..889ec4039d 100644 --- a/src/_P124_MultiRelay.ino +++ b/src/_P124_MultiRelay.ino @@ -23,7 +23,7 @@ # define PLUGIN_124 # define PLUGIN_ID_124 124 -# define PLUGIN_NAME_124 "Output - I2C Multi Relay [TESTING]" +# define PLUGIN_NAME_124 "Output - I2C Multi Relay" # define PLUGIN_VALUENAME1_124 "State" # define PLUGIN_VALUENAME2_124 "Channel" # define PLUGIN_VALUENAME3_124 "Get" diff --git a/src/_P125_ADXL345_SPI.ino b/src/_P125_ADXL345_SPI.ino index 3cb397a0d8..f9e7871f80 100644 --- a/src/_P125_ADXL345_SPI.ino +++ b/src/_P125_ADXL345_SPI.ino @@ -28,7 +28,7 @@ # define PLUGIN_125 # define PLUGIN_ID_125 125 // plugin id -# define PLUGIN_NAME_125 "Accelerometer - ADXL345 (SPI) [TESTING]" +# define PLUGIN_NAME_125 "Accelerometer - ADXL345 (SPI)" # define PLUGIN_VALUENAME1_125 "X" # define PLUGIN_VALUENAME2_125 "Y" # define PLUGIN_VALUENAME3_125 "Z" diff --git a/src/_P126_74HC595.ino b/src/_P126_74HC595.ino index f4afe4c318..bda1dbb0d6 100644 --- a/src/_P126_74HC595.ino +++ b/src/_P126_74HC595.ino @@ -50,7 +50,7 @@ # define PLUGIN_126 # define PLUGIN_ID_126 126 -# define PLUGIN_NAME_126 "Output - Shift registers (74HC595) [TESTING]" +# define PLUGIN_NAME_126 "Output - Shift registers (74HC595)" # define PLUGIN_VALUENAME1_126 "State_A" # define PLUGIN_VALUENAME2_126 "State_B" # define PLUGIN_VALUENAME3_126 "State_C" diff --git a/src/_P127_CDM7160.ino b/src/_P127_CDM7160.ino index 47757136b6..8754640214 100644 --- a/src/_P127_CDM7160.ino +++ b/src/_P127_CDM7160.ino @@ -20,7 +20,7 @@ # define PLUGIN_127 # define PLUGIN_ID_127 127 -# define PLUGIN_NAME_127 "Gases - CO2 CDM7160 [TESTING]" +# define PLUGIN_NAME_127 "Gases - CO2 CDM7160" # define PLUGIN_VALUENAME1_127 "CO2" diff --git a/src/_P128_NeoPixelBusFX.ino b/src/_P128_NeoPixelBusFX.ino index 9d3bc8174b..46c12e2ce8 100644 --- a/src/_P128_NeoPixelBusFX.ino +++ b/src/_P128_NeoPixelBusFX.ino @@ -126,7 +126,7 @@ # define PLUGIN_128 # define PLUGIN_ID_128 128 -# define PLUGIN_NAME_128 "Output - NeoPixel (BusFX) [TESTING]" +# define PLUGIN_NAME_128 "Output - NeoPixel (BusFX)" # define PLUGIN_VALUENAME1_128 "Mode" # define PLUGIN_VALUENAME2_128 "Lastmode" # define PLUGIN_VALUENAME3_128 "Fadetime" diff --git a/src/_P132_INA3221.ino b/src/_P132_INA3221.ino index 45324741c6..b1116c71b9 100644 --- a/src/_P132_INA3221.ino +++ b/src/_P132_INA3221.ino @@ -18,7 +18,7 @@ #define PLUGIN_132 #define PLUGIN_ID_132 132 -#define PLUGIN_NAME_132 "Energy (DC) - INA3221 [TESTING]" +#define PLUGIN_NAME_132 "Energy (DC) - INA3221" #define PLUGIN_VALUENAME1_132 "Value1" #define PLUGIN_VALUENAME2_132 "Value2" #define PLUGIN_VALUENAME3_132 "Value3" diff --git a/src/_P133_LTR390.ino b/src/_P133_LTR390.ino index 82ad317ea8..b8542b7769 100644 --- a/src/_P133_LTR390.ino +++ b/src/_P133_LTR390.ino @@ -11,7 +11,7 @@ # define PLUGIN_133 # define PLUGIN_ID_133 133 -# define PLUGIN_NAME_133 "UV - LTR390 [TESTING]" +# define PLUGIN_NAME_133 "UV - LTR390" # define PLUGIN_VALUENAME1_133 "UV" # define PLUGIN_VALUENAME2_133 "UVIndex" # define PLUGIN_VALUENAME3_133 "Ambient" diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 3f611df8a1..35d744cc53 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1439,8 +1439,8 @@ To create/register a plugin, you have to : // [copied from Playground as of 6 March 2018] // It needs some cleanup as some are ALSO in the main repo, // thus they should have been removed from the Playground repo - // #define USES_P100 // Was SRF01, now Pulse Counter - DS2423 [Testing] - // #define USES_P101 // Was NeoClock, now Wake On Lan [Testing] + // #define USES_P100 // Was SRF01, now Pulse Counter - DS2423 + // #define USES_P101 // Was NeoClock, now Wake On Lan #define USES_P102 // Nodo #define USES_P103 // Event #define USES_P104 // SRF02 From c7844eeb15fc199e8f9ce55dfb1d76756fd821d2 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 22 Jul 2022 21:58:12 +0200 Subject: [PATCH 256/404] [Build] Remove TESTING tag from Stable plugins, fix some plugin names --- src/_P050_TCS34725.ino | 2 +- src/_P076_HLW8012.ino | 2 +- src/_P092_DLbus.ino | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_P050_TCS34725.ino b/src/_P050_TCS34725.ino index cd75f4e15f..c715f4410e 100644 --- a/src/_P050_TCS34725.ino +++ b/src/_P050_TCS34725.ino @@ -24,7 +24,7 @@ #define PLUGIN_050 #define PLUGIN_ID_050 50 -#define PLUGIN_NAME_050 "Color - TCS34725 " +#define PLUGIN_NAME_050 "Color - TCS34725" #define PLUGIN_VALUENAME1_050 "Red" #define PLUGIN_VALUENAME2_050 "Green" #define PLUGIN_VALUENAME3_050 "Blue" diff --git a/src/_P076_HLW8012.ino b/src/_P076_HLW8012.ino index b4df6ddaba..cd7c5aa349 100644 --- a/src/_P076_HLW8012.ino +++ b/src/_P076_HLW8012.ino @@ -24,7 +24,7 @@ HLW8012 *Plugin_076_hlw = nullptr; #define PLUGIN_076 #define PLUGIN_ID_076 76 #define PLUGIN_076_DEBUG true // activate extra log info in the debug -#define PLUGIN_NAME_076 "Energy (AC) - HLW8012/BL0937 " +#define PLUGIN_NAME_076 "Energy (AC) - HLW8012/BL0937" #define PLUGIN_VALUENAME1_076 "Voltage" #define PLUGIN_VALUENAME2_076 "Current" #define PLUGIN_VALUENAME3_076 "Power" diff --git a/src/_P092_DLbus.ino b/src/_P092_DLbus.ino index dfd1ec4b27..8372058ffc 100644 --- a/src/_P092_DLbus.ino +++ b/src/_P092_DLbus.ino @@ -67,7 +67,7 @@ # define PLUGIN_ID_092 92 // #define PLUGIN_092_DEBUG // additional debug messages in the log -# define PLUGIN_NAME_092 "Heating - DL-Bus (Technische Alternative) " +# define PLUGIN_NAME_092 "Heating - DL-Bus (Technische Alternative)" # define PLUGIN_VALUENAME1_092 "Value" // global values needed for all tasks From fa84d95028e96ddd153d732623d7b112e3531d65 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 22 Jul 2022 22:41:08 +0200 Subject: [PATCH 257/404] [Build] Update documentation to use COLLECTION instead of TESTING --- .../Controller/_controller_substitutions.repl | 10 +++++----- docs/source/Plugin/_Plugin.rst | 15 +++++---------- .../Plugin/_plugin_substitutions_p04x.repl | 8 ++++---- .../Plugin/_plugin_substitutions_p05x.repl | 12 ++++++------ .../Plugin/_plugin_substitutions_p06x.repl | 18 +++++++++--------- .../Plugin/_plugin_substitutions_p07x.repl | 10 +++++----- .../Plugin/_plugin_substitutions_p08x.repl | 18 +++++++++--------- .../Plugin/_plugin_substitutions_p09x.repl | 14 +++++++------- .../Plugin/_plugin_substitutions_p10x.repl | 12 ++++++------ .../Plugin/_plugin_substitutions_p11x.repl | 16 ++++++++-------- .../Plugin/_plugin_substitutions_p12x.repl | 12 ++++++------ .../Plugin/_plugin_substitutions_p13x.repl | 2 +- src/_Pxxx_PluginTemplate.ino | 2 +- 13 files changed, 72 insertions(+), 77 deletions(-) diff --git a/docs/source/Controller/_controller_substitutions.repl b/docs/source/Controller/_controller_substitutions.repl index 531852f8f2..5ee958e394 100644 --- a/docs/source/Controller/_controller_substitutions.repl +++ b/docs/source/Controller/_controller_substitutions.repl @@ -114,7 +114,7 @@ .. |C011_name| replace:: :cyan:`Generic HTTP Advanced` .. |C011_type| replace:: :cyan:`Controller` .. |C011_typename| replace:: :cyan:`Controller - Generic HTTP Advanced` -.. |C011_status| replace:: :yellow:`TESTING` +.. |C011_status| replace:: :yellow:`COLLECTION` .. |C011_github| replace:: C011.cpp .. _C011_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C011.cpp .. |C011_usedby| replace:: `.` @@ -125,7 +125,7 @@ .. |C012_name| replace:: :cyan:`Blynk` .. |C012_type| replace:: :cyan:`Controller` .. |C012_typename| replace:: :cyan:`Controller - Blynk` -.. |C012_status| replace:: :yellow:`TESTING` +.. |C012_status| replace:: :yellow:`COLLECTION` .. |C012_github| replace:: C012.cpp .. _C012_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C012.cpp .. |C012_usedby| replace:: `.` @@ -147,7 +147,7 @@ .. |C014_name| replace:: :cyan:`Homie MQTT (Version 3.0.1 & 4.0.0dev)` .. |C014_type| replace:: :cyan:`Controller` .. |C014_typename| replace:: :cyan:`Controller - Homie MQTT convention` -.. |C014_status| replace:: :yellow:`TESTING` +.. |C014_status| replace:: :yellow:`COLLECTION` .. |C014_github| replace:: C014.cpp .. _C014_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C014.cpp .. |C014_usedby| replace:: `.` @@ -169,7 +169,7 @@ .. |C017_name| replace:: :cyan:`Zabbix` .. |C017_type| replace:: :cyan:`Controller` .. |C017_typename| replace:: :cyan:`Controller - Zabbix` -.. |C017_status| replace:: :yellow:`TESTING` +.. |C017_status| replace:: :yellow:`COLLECTION` .. |C017_github| replace:: C017.cpp .. _C017_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C017.cpp .. |C017_usedby| replace:: `.` @@ -180,7 +180,7 @@ .. |C018_name| replace:: :cyan:`LoRa TTN - RN2483/RN2903` .. |C018_type| replace:: :cyan:`Controller` .. |C018_typename| replace:: :cyan:`Controller - LoRa TTN - RN2483/RN2903` -.. |C018_status| replace:: :yellow:`TESTING` +.. |C018_status| replace:: :yellow:`COLLECTION` .. |C018_github| replace:: C018.cpp .. _C018_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C018.cpp .. |C018_usedby| replace:: `.` diff --git a/docs/source/Plugin/_Plugin.rst b/docs/source/Plugin/_Plugin.rst index 5cd45e8150..eb2b2ea655 100644 --- a/docs/source/Plugin/_Plugin.rst +++ b/docs/source/Plugin/_Plugin.rst @@ -207,23 +207,16 @@ See :ref:`Rules: Formatting refered values ` on how this can Just remember such formatting cannot "make up" more decimals than what was set here in the task setup. - - - - - - - List of official plugins ======================== There are different released versions of ESP Easy: -:green:`NORMAL` is the stable release, you can consider these plugins reliable and you can use these in production. +:green:`NORMAL` is the regular set of plugins, you can consider these plugins stable with all secondary features enabled, like I2C multiplexer, RTTL, DEBUG logging, etc. -:yellow:`TESTING` (split into A/B/C/D/E sets) with new plugins that have not yet been fully tested and proven stable. Because of space limitations, this collection is split into 5 sets. When only TESTING is mentioned, the plugin is available in all TESTING builds. +:yellow:`COLLECTION` (split into A/B/C/D/E sets) with plugins that don't fit into the NORMAL builds. Because of space limitations, this collection is split into 5 sets. When only COLLECTION is mentioned, the plugin is available in **all** COLLECTION builds. Also, some features are disabled to save space in the .bin files, like the I2C multiplexer feature, RTTTL, tooltips, and some DEBUG logging. -:red:`DEVELOPMENT` is used for plugins that are still being developed and are not considered stable at all. +:red:`DEVELOPMENT` is used for plugins that are still being developed and are not considered stable at all. Currently there are no DEVELOPMENT builds available. :yellow:`ENERGY` :yellow:`DISPLAY` :yellow:`IR` :yellow:`IRext` :yellow:`NEOPIXEL` are specialized builds holding all Energy-, Display-, Infra Red- (extended) and NeoPixel related plugins. @@ -231,6 +224,8 @@ There are different released versions of ESP Easy: :gray:`RETIRED` plugin has been retired from ESPEasy (though the source code is still available). Not included in any build. +2022-07-22: :yellow:`TESTING` builds renamed to :yellow:`COLLECTION`. + .. csv-table:: :header: "Plugin name", "Build set", "Plugin number" :widths: 10, 8, 5 diff --git a/docs/source/Plugin/_plugin_substitutions_p04x.repl b/docs/source/Plugin/_plugin_substitutions_p04x.repl index 779588b7b8..a24b43cf1c 100644 --- a/docs/source/Plugin/_plugin_substitutions_p04x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p04x.repl @@ -67,7 +67,7 @@ .. |P045_type| replace:: :cyan:`Gyro` .. |P045_typename| replace:: :cyan:`Gyro - MPU 6050` .. |P045_porttype| replace:: `.` -.. |P045_status| replace:: :yellow:`TESTING` +.. |P045_status| replace:: :yellow:`COLLECTION` .. |P045_github| replace:: P045_MPU6050.ino .. _P045_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P045_MPU6050.ino .. |P045_usedby| replace:: `.` @@ -80,7 +80,7 @@ .. |P046_type| replace:: :cyan:`Hardware` .. |P046_typename| replace:: :cyan:`Hardware - Ventus W266` .. |P046_porttype| replace:: `.` -.. |P046_status| replace:: :yellow:`TESTING` +.. |P046_status| replace:: :yellow:`COLLECTION` .. |P046_github| replace:: P046_VentusW266.ino .. _P046_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P046_VentusW266.ino .. |P046_usedby| replace:: :ref:`P046_Ventus_W266_page` @@ -93,7 +93,7 @@ .. |P047_type| replace:: :cyan:`Environment` .. |P047_typename| replace:: :cyan:`Environment - Soil moisture sensor` .. |P047_porttype| replace:: `.` -.. |P047_status| replace:: :yellow:`TESTING` +.. |P047_status| replace:: :yellow:`COLLECTION` .. |P047_github| replace:: P047_i2c-soil-moisture-sensor.ino .. _P047_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P047_i2c-soil-moisture-sensor.ino .. |P047_usedby| replace:: `.` @@ -106,7 +106,7 @@ .. |P048_type| replace:: :cyan:`Motor` .. |P048_typename| replace:: :cyan:`Motor - Adafruit Motorshield v2` .. |P048_porttype| replace:: `.` -.. |P048_status| replace:: :yellow:`TESTING` +.. |P048_status| replace:: :yellow:`COLLECTION` .. |P048_github| replace:: P048_Motorshield_v2.ino .. _P048_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P048_Motorshield_v2.ino .. |P048_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p05x.repl b/docs/source/Plugin/_plugin_substitutions_p05x.repl index 79245a7092..e3ba62afdc 100644 --- a/docs/source/Plugin/_plugin_substitutions_p05x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p05x.repl @@ -2,7 +2,7 @@ .. |P050_type| replace:: :cyan:`Color` .. |P050_typename| replace:: :cyan:`Color - TCS34725` .. |P050_porttype| replace:: `.` -.. |P050_status| replace:: :yellow:`TESTING` +.. |P050_status| replace:: :yellow:`COLLECTION` .. |P050_github| replace:: P050_TCS34725.ino .. _P050_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P050_TCS34725.ino .. |P050_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P051_type| replace:: :cyan:`Environment` .. |P051_typename| replace:: :cyan:`Environment - AM2320` .. |P051_porttype| replace:: `.` -.. |P051_status| replace:: :yellow:`TESTING` +.. |P051_status| replace:: :yellow:`COLLECTION` .. |P051_github| replace:: P051_AM2320.ino .. _P051_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P051_AM2320.ino .. |P051_usedby| replace:: `.` @@ -54,7 +54,7 @@ .. |P054_type| replace:: :cyan:`Communication` .. |P054_typename| replace:: :cyan:`Communication - DMX512 TX` .. |P054_porttype| replace:: `.` -.. |P054_status| replace:: :yellow:`TESTING` +.. |P054_status| replace:: :yellow:`COLLECTION` .. |P054_github| replace:: P054_DMX512.ino .. _P054_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P054_DMX512.ino .. |P054_usedby| replace:: `.` @@ -67,7 +67,7 @@ .. |P055_type| replace:: :cyan:`Notify` .. |P055_typename| replace:: :cyan:`Notify - Chiming` .. |P055_porttype| replace:: `.` -.. |P055_status| replace:: :yellow:`TESTING` +.. |P055_status| replace:: :yellow:`COLLECTION` .. |P055_github| replace:: P055_Chiming.ino .. _P055_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P055_Chiming.ino .. |P055_usedby| replace:: `.` @@ -93,7 +93,7 @@ .. |P057_type| replace:: :cyan:`Display` .. |P057_typename| replace:: :cyan:`Display - HT16K33` .. |P057_porttype| replace:: `.` -.. |P057_status| replace:: :yellow:`DISPLAY, TESTING` +.. |P057_status| replace:: :yellow:`DISPLAY, COLLECTION` .. |P057_github| replace:: P057_HT16K33_LED.ino .. _P057_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P057_HT16K33_LED.ino .. |P057_usedby| replace:: `.` @@ -106,7 +106,7 @@ .. |P058_type| replace:: :cyan:`Keypad` .. |P058_typename| replace:: :cyan:`Keypad - HT16K33` .. |P058_porttype| replace:: `.` -.. |P058_status| replace:: :yellow:`TESTING` +.. |P058_status| replace:: :yellow:`COLLECTION` .. |P058_github| replace:: P058_HT16K33_KeyPad.ino .. _P058_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P058_HT16K33_KeyPad.ino .. |P058_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p06x.repl b/docs/source/Plugin/_plugin_substitutions_p06x.repl index 8af584d657..c2fa42465a 100644 --- a/docs/source/Plugin/_plugin_substitutions_p06x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p06x.repl @@ -2,7 +2,7 @@ .. |P060_type| replace:: :cyan:`Analog input` .. |P060_typename| replace:: :cyan:`Analog input - MCP3221` .. |P060_porttype| replace:: `.` -.. |P060_status| replace:: :yellow:`TESTING` +.. |P060_status| replace:: :yellow:`COLLECTION` .. |P060_github| replace:: P060_MCP3221.ino .. _P060_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P060_MCP3221.ino .. |P060_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P061_type| replace:: :cyan:`Keypad` .. |P061_typename| replace:: :cyan:`Keypad - PCF8574 / MCP23017 / PCA8575` .. |P061_porttype| replace:: `.` -.. |P061_status| replace:: :yellow:`TESTING` +.. |P061_status| replace:: :yellow:`COLLECTION` .. |P061_github| replace:: P061_KeyPad.ino .. _P061_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P061_KeyPad.ino .. |P061_usedby| replace:: `.` @@ -28,7 +28,7 @@ .. |P062_type| replace:: :cyan:`Keypad` .. |P062_typename| replace:: :cyan:`Keypad - MPR121 Touch` .. |P062_porttype| replace:: `.` -.. |P062_status| replace:: :yellow:`TESTING` +.. |P062_status| replace:: :yellow:`COLLECTION` .. |P062_github| replace:: P062_MPR121_KeyPad.ino .. _P062_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P062_MPR121_KeyPad.ino .. |P062_usedby| replace:: `NXP MPR121 I2C controller` @@ -54,7 +54,7 @@ .. |P064_type| replace:: :cyan:`Gesture` .. |P064_typename| replace:: :cyan:`Gesture - APDS9960` .. |P064_porttype| replace:: `.` -.. |P064_status| replace:: :yellow:`TESTING` +.. |P064_status| replace:: :yellow:`COLLECTION` .. |P064_github| replace:: P064_APDS9960.ino .. _P064_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P064_APDS9960.ino .. |P064_usedby| replace:: `.` @@ -67,7 +67,7 @@ .. |P065_type| replace:: :cyan:`Notify` .. |P065_typename| replace:: :cyan:`Notify - DFPlayer-Mini MP3` .. |P065_porttype| replace:: `.` -.. |P065_status| replace:: :yellow:`TESTING` +.. |P065_status| replace:: :yellow:`COLLECTION` .. |P065_github| replace:: P065_DRF0299_MP3.ino .. _P065_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P065_DRF0299_MP3.ino .. |P065_usedby| replace:: `.` @@ -80,7 +80,7 @@ .. |P066_type| replace:: :cyan:`Color` .. |P066_typename| replace:: :cyan:`Color - VEML6040` .. |P066_porttype| replace:: `.` -.. |P066_status| replace:: :yellow:`TESTING` +.. |P066_status| replace:: :yellow:`COLLECTION` .. |P066_github| replace:: P066_VEML6040.ino .. _P066_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P066_VEML6040.ino .. |P066_usedby| replace:: `.` @@ -93,7 +93,7 @@ .. |P067_type| replace:: :cyan:`Weight` .. |P067_typename| replace:: :cyan:`Weight - HX711 Load Cell` .. |P067_porttype| replace:: `.` -.. |P067_status| replace:: :yellow:`TESTING A` +.. |P067_status| replace:: :yellow:`COLLECTION A` .. |P067_github| replace:: P067_HX711_Load_Cell.ino .. _P067_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P067_HX711_Load_Cell.ino .. |P067_usedby| replace:: `.` @@ -106,7 +106,7 @@ .. |P068_type| replace:: :cyan:`Environment` .. |P068_typename| replace:: :cyan:`Environment - SHT30/31/35` .. |P068_porttype| replace:: `.` -.. |P068_status| replace:: :yellow:`TESTING A` +.. |P068_status| replace:: :yellow:`COLLECTION A` .. |P068_github| replace:: P068_SHT3x.ino .. _P068_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P068_SHT3x.ino .. |P068_usedby| replace:: `.` @@ -119,7 +119,7 @@ .. |P069_type| replace:: :cyan:`Environment` .. |P069_typename| replace:: :cyan:`Environment - LM75A` .. |P069_porttype| replace:: `.` -.. |P069_status| replace:: :yellow:`TESTING B` +.. |P069_status| replace:: :yellow:`COLLECTION B` .. |P069_github| replace:: P069_LM75A.ino .. _P069_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P069_LM75A.ino .. |P069_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p07x.repl b/docs/source/Plugin/_plugin_substitutions_p07x.repl index 15925f7c24..484354c30a 100644 --- a/docs/source/Plugin/_plugin_substitutions_p07x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p07x.repl @@ -3,7 +3,7 @@ .. |P070_type| replace:: :cyan:`Output` .. |P070_typename| replace:: :cyan:`Output - NeoPixel Ring Clock` .. |P070_porttype| replace:: `.` -.. |P070_status| replace:: :yellow:`DISPLAY, NEOPIXEL, TESTING A` +.. |P070_status| replace:: :yellow:`DISPLAY, NEOPIXEL, COLLECTION A` .. |P070_github| replace:: P070_NeoPixel_Clock.ino .. _P070_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P070_NeoPixel_Clock.ino .. |P070_usedby| replace:: `.` @@ -16,7 +16,7 @@ .. |P071_type| replace:: :cyan:`Communication` .. |P071_typename| replace:: :cyan:`Communication - Kamstrup Multical 401` .. |P071_porttype| replace:: `Serial` -.. |P071_status| replace:: :yellow:`TESTING A` +.. |P071_status| replace:: :yellow:`COLLECTION A` .. |P071_github| replace:: P071_Kamstrup401.ino .. _P071_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P071_Kamstrup401.ino .. |P071_usedby| replace:: `.` @@ -29,7 +29,7 @@ .. |P072_type| replace:: :cyan:`Environment` .. |P072_typename| replace:: :cyan:`Environment - HDC1080 (I2C)` .. |P072_porttype| replace:: `.` -.. |P072_status| replace:: :yellow:`TESTING A` +.. |P072_status| replace:: :yellow:`COLLECTION A` .. |P072_github| replace:: P072_HDC1080.ino .. _P072_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P072_HDC1080.ino .. |P072_usedby| replace:: `.` @@ -55,7 +55,7 @@ .. |P074_type| replace:: :cyan:`Light/Lux` .. |P074_typename| replace:: :cyan:`Light/Lux - TSL2591` .. |P074_porttype| replace:: `Serial` -.. |P074_status| replace:: :yellow:`TESTING A` +.. |P074_status| replace:: :yellow:`COLLECTION A` .. |P074_github| replace:: P074_TSL2591.ino .. _P074_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P074_TSL2591.ino .. |P074_usedby| replace:: `.` @@ -68,7 +68,7 @@ .. |P075_type| replace:: :cyan:`Display` .. |P075_typename| replace:: :cyan:`Display - Nextion` .. |P075_porttype| replace:: `.` -.. |P075_status| replace:: :yellow:`DISPLAY, TESTING` +.. |P075_status| replace:: :yellow:`DISPLAY, COLLECTION` .. |P075_github| replace:: P075_Nextion.ino .. _P075_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P075_Nextion.ino .. |P075_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p08x.repl b/docs/source/Plugin/_plugin_substitutions_p08x.repl index ea609a8984..1ca69d54dc 100644 --- a/docs/source/Plugin/_plugin_substitutions_p08x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p08x.repl @@ -2,7 +2,7 @@ .. |P080_type| replace:: :cyan:`Switch input` .. |P080_typename| replace:: :cyan:`Switch input - iButton` .. |P080_porttype| replace:: `.` -.. |P080_status| replace:: :yellow:`TESTING A` +.. |P080_status| replace:: :yellow:`COLLECTION A` .. |P080_github| replace:: P080_DallasIButton.ino .. _P080_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P080_DallasIButton.ino .. |P080_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P081_type| replace:: :cyan:`Generic` .. |P081_typename| replace:: :cyan:`Generic - CRON` .. |P081_porttype| replace:: `.` -.. |P081_status| replace:: :yellow:`TESTING` +.. |P081_status| replace:: :yellow:`COLLECTION` .. |P081_github| replace:: P081_Cron.ino .. _P081_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P081_Cron.ino .. |P081_usedby| replace:: `.` @@ -28,7 +28,7 @@ .. |P082_type| replace:: :cyan:`Position` .. |P082_typename| replace:: :cyan:`Position - GPS` .. |P082_porttype| replace:: `Serial` -.. |P082_status| replace:: :yellow:`TESTING` +.. |P082_status| replace:: :yellow:`COLLECTION` .. |P082_github| replace:: P082_GPS.ino .. _P082_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P082_GPS.ino .. |P082_usedby| replace:: :ref:`P082_Neo-6M_page`, :ref:`P082_Neo-7M_page`, :ref:`P082_Neo-M8n_page` @@ -41,7 +41,7 @@ .. |P083_type| replace:: :cyan:`Gasses` .. |P083_typename| replace:: :cyan:`Gasses - SGP30` .. |P083_porttype| replace:: `.` -.. |P083_status| replace:: :yellow:`TESTING A` +.. |P083_status| replace:: :yellow:`COLLECTION A` .. |P083_github| replace:: P083_SGP30.ino .. _P083_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P083_SGP30.ino .. |P083_usedby| replace:: `.` @@ -54,7 +54,7 @@ .. |P084_type| replace:: :cyan:`UV` .. |P084_typename| replace:: :cyan:`UV - VEML6070` .. |P084_porttype| replace:: `.` -.. |P084_status| replace:: :yellow:`TESTING A` +.. |P084_status| replace:: :yellow:`COLLECTION A` .. |P084_github| replace:: P084_VEML6070.ino .. _P084_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P084_VEML6070.ino .. |P084_usedby| replace:: `.` @@ -67,7 +67,7 @@ .. |P085_type| replace:: :cyan:`Energy (DC)` .. |P085_typename| replace:: :cyan:`Energy (DC) - AcuDC243` .. |P085_porttype| replace:: `Serial` -.. |P085_status| replace:: :yellow:`ENERGY, TESTING C` +.. |P085_status| replace:: :yellow:`ENERGY, COLLECTION C` .. |P085_github| replace:: P085_AcuDC243.ino .. _P085_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P085_AcuDC243.ino .. |P085_usedby| replace:: `.` @@ -80,7 +80,7 @@ .. |P086_type| replace:: :cyan:`Generic` .. |P086_typename| replace:: :cyan:`Generic - Homie receiver` .. |P086_porttype| replace:: `.` -.. |P086_status| replace:: :yellow:`TESTING A` +.. |P086_status| replace:: :yellow:`COLLECTION A` .. |P086_github| replace:: P086_Homie.ino .. _P086_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P086_Homie.ino .. |P086_usedby| replace:: `.` @@ -93,7 +93,7 @@ .. |P087_type| replace:: :cyan:`Communication` .. |P087_typename| replace:: :cyan:`Communication - SerialProxy` .. |P087_porttype| replace:: `Serial` -.. |P087_status| replace:: :yellow:`TESTING C` +.. |P087_status| replace:: :yellow:`COLLECTION C` .. |P087_github| replace:: P087_SerialProxy.ino .. _P087_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P087_SerialProxy.ino .. |P087_usedby| replace:: `.` @@ -119,7 +119,7 @@ .. |P089_type| replace:: :cyan:`Communication` .. |P089_typename| replace:: :cyan:`Communication - Ping` .. |P089_porttype| replace:: `.` -.. |P089_status| replace:: :yellow:`TESTING` +.. |P089_status| replace:: :yellow:`COLLECTION` .. |P089_github| replace:: P089_Ping.ino .. _P089_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P089_Ping.ino .. |P089_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p09x.repl b/docs/source/Plugin/_plugin_substitutions_p09x.repl index d63f82d3e6..eafc54714a 100644 --- a/docs/source/Plugin/_plugin_substitutions_p09x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p09x.repl @@ -2,7 +2,7 @@ .. |P090_type| replace:: :cyan:`Gases` .. |P090_typename| replace:: :cyan:`Gases - CCS811 TVOC/eCO2` .. |P090_porttype| replace:: `.` -.. |P090_status| replace:: :yellow:`TESTING A` +.. |P090_status| replace:: :yellow:`COLLECTION A` .. |P090_github| replace:: P090_CCS811.ino .. _P090_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P090_CCS811.ino .. |P090_usedby| replace:: `.` @@ -14,7 +14,7 @@ .. |P091_name| replace:: :cyan:`Serial MCU controlled switch` .. |P091_type| replace:: :cyan:`Gases` .. |P091_typename| replace:: :cyan:`Switch input - Serial MCU controlled switch` -.. |P091_status| replace:: :yellow:`TESTING C` +.. |P091_status| replace:: :yellow:`COLLECTION C` .. |P091_github| replace:: P091_SerSwitch.ino .. _P091_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P091_SerSwitch.ino .. |P091_usedby| replace:: `.` @@ -26,7 +26,7 @@ .. |P092_name| replace:: :cyan:`DL-Bus (Technische Alternative)` .. |P092_type| replace:: :cyan:`Heating` .. |P092_typename| replace:: :cyan:`Heating - DL-Bus (Technische Alternative)` -.. |P092_status| replace:: :yellow:`TESTING C` +.. |P092_status| replace:: :yellow:`COLLECTION C` .. |P092_github| replace:: P092_DLbus.ino .. _P092_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P092_DLbus.ino .. |P092_usedby| replace:: `.` @@ -38,7 +38,7 @@ .. |P093_name| replace:: :cyan:`Mitsubishi Heat Pump` .. |P093_type| replace:: :cyan:`Energy (Heat)` .. |P093_typename| replace:: :cyan:`Energy (Heat) - Mitsubishi Heat Pump` -.. |P093_status| replace:: :yellow:`ENERGY, TESTING D` +.. |P093_status| replace:: :yellow:`ENERGY, COLLECTION D` .. |P093_github| replace:: P093_MitsubishiHP.ino .. _P093_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P093_MitsubishiHP.ino .. |P093_usedby| replace:: `.` @@ -50,7 +50,7 @@ .. |P094_name| replace:: :cyan:`Communication - CUL Reader` .. |P094_type| replace:: :cyan:`Communication` .. |P094_typename| replace:: :cyan:`CUL Reader` -.. |P094_status| replace:: :yellow:`TESTING D` +.. |P094_status| replace:: :yellow:`COLLECTION D` .. |P094_github| replace:: P094_CULReader.ino .. _P094_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P094_CULReader.ino .. |P094_usedby| replace:: `.` @@ -63,7 +63,7 @@ .. |P095_type| replace:: :cyan:`Display` .. |P095_typename| replace:: :cyan:`Display - TFT 2.4 inches ILI9341` .. |P095_porttype| replace:: `.` -.. |P095_status| replace:: :yellow:`DISPLAY, TESTING` +.. |P095_status| replace:: :yellow:`DISPLAY, COLLECTION` .. |P095_github| replace:: _P095_ILI9341.ino .. _P095_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P095_ILI9341.ino .. |P095_usedby| replace:: `.` @@ -76,7 +76,7 @@ .. |P097_type| replace:: :cyan:`Internal` .. |P097_typename| replace:: :cyan:`Internal - Touch ESP32` .. |P097_porttype| replace:: `.` -.. |P097_status| replace:: :yellow:`TESTING A` +.. |P097_status| replace:: :yellow:`COLLECTION A` .. |P097_github| replace:: _P097_Esp32Touch.ino .. _P097_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P097_Esp32Touch.ino .. |P097_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p10x.repl b/docs/source/Plugin/_plugin_substitutions_p10x.repl index 9b69bb7818..58c29dd175 100644 --- a/docs/source/Plugin/_plugin_substitutions_p10x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p10x.repl @@ -2,7 +2,7 @@ .. |P100_type| replace:: :cyan:`Generic` .. |P100_typename| replace:: :cyan:`Pulse Counter - DS2423` .. |P100_porttype| replace:: `.` -.. |P100_status| replace:: :yellow:`TESTING B` +.. |P100_status| replace:: :yellow:`COLLECTION B` .. |P100_github| replace:: P100_CCS811.ino .. _P100_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P100_DS2423_counter.ino .. |P100_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P101_type| replace:: :cyan:`Communication` .. |P101_typename| replace:: :cyan:`Communication - Wake On LAN` .. |P101_porttype| replace:: `.` -.. |P101_status| replace:: :yellow:`TESTING B` +.. |P101_status| replace:: :yellow:`COLLECTION B` .. |P101_github| replace:: P101_WakeOnLan.ino .. _P101_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P101_WakeOnLan.ino .. |P101_usedby| replace:: `.` @@ -79,7 +79,7 @@ .. |P105_type| replace:: :cyan:`Environment` .. |P105_typename| replace:: :cyan:`Environment - AHT10/20/21` .. |P105_porttype| replace:: `.` -.. |P105_status| replace:: :yellow:`TESTING A` +.. |P105_status| replace:: :yellow:`COLLECTION A` .. |P105_github| replace:: P105_AHT.ino .. _P105_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P105_AHT.ino .. |P105_usedby| replace:: `.` @@ -96,7 +96,7 @@ .. |P106_type| replace:: :cyan:`Environment` .. |P106_typename| replace:: :cyan:`Environment - BME680` .. |P106_porttype| replace:: `.` -.. |P106_status| replace:: :yellow:`TESTING B` +.. |P106_status| replace:: :yellow:`COLLECTION B` .. |P106_github| replace:: P106_BME680.ino .. _P106_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P106_BME680.ino .. |P106_usedby| replace:: `.` @@ -109,7 +109,7 @@ .. |P107_type| replace:: :cyan:`UV` .. |P107_typename| replace:: :cyan:`UV - SI1145` .. |P107_porttype| replace:: `.` -.. |P107_status| replace:: :yellow:`TESTING B` +.. |P107_status| replace:: :yellow:`COLLECTION B` .. |P107_github| replace:: P107_Si1145.ino .. _P107_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P107_Si1145.ino .. |P107_usedby| replace:: `.` @@ -122,7 +122,7 @@ .. |P108_type| replace:: :cyan:`Energy (AC)` .. |P108_typename| replace:: :cyan:`Energy (AC) - DDS238-x` .. |P108_porttype| replace:: `.` -.. |P108_status| replace:: :yellow:`ENERGY, TESTING B` +.. |P108_status| replace:: :yellow:`ENERGY, COLLECTION B` .. |P108_github| replace:: P108_DDS238.ino .. _P108_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P108_DDS238.ino .. |P108_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p11x.repl b/docs/source/Plugin/_plugin_substitutions_p11x.repl index db44b3ec54..72e079fd1a 100644 --- a/docs/source/Plugin/_plugin_substitutions_p11x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p11x.repl @@ -2,7 +2,7 @@ .. |P110_type| replace:: :cyan:`Distance` .. |P110_typename| replace:: :cyan:`Distance - VL53L0X (200cm)` .. |P110_porttype| replace:: `.` -.. |P110_status| replace:: :yellow:`TESTING B` +.. |P110_status| replace:: :yellow:`COLLECTION B` .. |P110_github| replace:: P110_VL53L0X.ino .. _P110_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P110_VL53L0X.ino .. |P110_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P111_type| replace:: :cyan:`RFID` .. |P111_typename| replace:: :cyan:`RFID - MFRC522` .. |P111_porttype| replace:: `.` -.. |P111_status| replace:: :yellow:`TESTING C` +.. |P111_status| replace:: :yellow:`COLLECTION C` .. |P111_github| replace:: P111_RC522_RFID.ino .. _P111_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P111_RC522_RFID.ino .. |P111_usedby| replace:: `.` @@ -28,7 +28,7 @@ .. |P113_type| replace:: :cyan:`Distance` .. |P113_typename| replace:: :cyan:`Distance - VL53L1X (400cm)` .. |P113_porttype| replace:: `.` -.. |P113_status| replace:: :yellow:`TESTING B` +.. |P113_status| replace:: :yellow:`COLLECTION B` .. |P113_github| replace:: P113_VL53L1X.ino .. _P113_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P113_VL53L1X.ino .. |P113_usedby| replace:: `.` @@ -41,7 +41,7 @@ .. |P114_type| replace:: :cyan:`UV` .. |P114_typename| replace:: :cyan:`UV - VEML6075` .. |P114_porttype| replace:: `.` -.. |P114_status| replace:: :yellow:`TESTING D` +.. |P114_status| replace:: :yellow:`COLLECTION D` .. |P114_github| replace:: P114_VEML6075.ino .. _P114_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P114_VEML6075.ino .. |P114_usedby| replace:: `.` @@ -54,7 +54,7 @@ .. |P115_type| replace:: :cyan:`Energy` .. |P115_typename| replace:: :cyan:`Energy - MAX1704x` .. |P115_porttype| replace:: `.` -.. |P115_status| replace:: :yellow:`ENERGY, TESTING B` +.. |P115_status| replace:: :yellow:`ENERGY, COLLECTION B` .. |P115_github| replace:: _P115_MAX1704x_v2.ino .. _P115_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P115_MAX1704x_v2.ino .. |P115_usedby| replace:: `.` @@ -80,7 +80,7 @@ .. |P117_type| replace:: :cyan:`Gases` .. |P117_typename| replace:: :cyan:`Gases - SCD30 CO2, Humidity, Temperature` .. |P117_porttype| replace:: `.` -.. |P117_status| replace:: :yellow:`TESTING D` +.. |P117_status| replace:: :yellow:`COLLECTION D` .. |P117_github| replace:: _P117_SCD30.ino .. _P117_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P117_SCD30.ino .. |P117_usedby| replace:: `.` @@ -93,7 +93,7 @@ .. |P118_type| replace:: :cyan:`Communication` .. |P118_typename| replace:: :cyan:`Communication - Itho` .. |P118_porttype| replace:: `.` -.. |P118_status| replace:: :yellow:`TESTING D` +.. |P118_status| replace:: :yellow:`COLLECTION D` .. |P118_github| replace:: _P118_Itho.ino .. _P118_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P118_Itho.ino .. |P118_usedby| replace:: `.` @@ -106,7 +106,7 @@ .. |P119_type| replace:: :cyan:`Gyro` .. |P119_typename| replace:: :cyan:`Gyro - ITG3205` .. |P119_porttype| replace:: `.` -.. |P119_status| replace:: :yellow:`TESTING E` +.. |P119_status| replace:: :yellow:`COLLECTION E` .. |P119_github| replace:: _P119_ITG3205_Gyro.ino .. _P119_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P119_ITG3205_Gyro.ino .. |P119_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p12x.repl b/docs/source/Plugin/_plugin_substitutions_p12x.repl index db5d1734c4..26293c4d09 100644 --- a/docs/source/Plugin/_plugin_substitutions_p12x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p12x.repl @@ -2,7 +2,7 @@ .. |P120_type| replace:: :cyan:`Acceleration` .. |P120_typename| replace:: :cyan:`Acceleration - ADXL345 (I2C)` .. |P120_porttype| replace:: `.` -.. |P120_status| replace:: :yellow:`TESTING E` +.. |P120_status| replace:: :yellow:`COLLECTION E` .. |P120_github| replace:: P120_ADXL345_Accelerometer.ino .. _P120_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P120_ADXL345_Accelerometer.ino .. |P120_usedby| replace:: `.` @@ -15,7 +15,7 @@ .. |P121_type| replace:: :cyan:`Position` .. |P121_typename| replace:: :cyan:`Position - HMC5883L` .. |P121_porttype| replace:: `.` -.. |P121_status| replace:: :yellow:`TESTING E` +.. |P121_status| replace:: :yellow:`COLLECTION E` .. |P121_github| replace:: P121_HMC5883L.ino .. _P121_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P121_HMC5883L.ino .. |P121_usedby| replace:: `.` @@ -28,7 +28,7 @@ .. |P124_type| replace:: :cyan:`Output` .. |P124_typename| replace:: :cyan:`Output - I2C Multi Relay` .. |P124_porttype| replace:: `.` -.. |P124_status| replace:: :yellow:`TESTING D` +.. |P124_status| replace:: :yellow:`COLLECTION D` .. |P124_github| replace:: P124_MultiTelay.ino .. _P124_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P124_MyltiRelay.ino .. |P124_usedby| replace:: `.` @@ -41,7 +41,7 @@ .. |P125_type| replace:: :cyan:`Acceleration` .. |P125_typename| replace:: :cyan:`Acceleration - ADXL345 (SPI)` .. |P125_porttype| replace:: `.` -.. |P125_status| replace:: :yellow:`TESTING E` +.. |P125_status| replace:: :yellow:`COLLECTION E` .. |P125_github| replace:: P125_ADXL345_SPI.ino .. _P125_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P125_ADXL345_SPI.ino .. |P125_usedby| replace:: `.` @@ -54,7 +54,7 @@ .. |P126_type| replace:: :cyan:`Output` .. |P126_typename| replace:: :cyan:`Output - Shift registers (74HC595)` .. |P126_porttype| replace:: `.` -.. |P126_status| replace:: :yellow:`TESTING E` +.. |P126_status| replace:: :yellow:`COLLECTION E` .. |P126_github| replace:: P126_74HC595.ino .. _P126_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P126_74HC595.ino .. |P126_usedby| replace:: `.` @@ -67,7 +67,7 @@ .. |P127_type| replace:: :cyan:`Gases` .. |P127_typename| replace:: :cyan:`Gases - CO2 CDM7160` .. |P127_porttype| replace:: `.` -.. |P127_status| replace:: :yellow:`TESTING D` +.. |P127_status| replace:: :yellow:`COLLECTION D` .. |P127_github| replace:: P127_CDM7160.ino .. _P127_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P127_CDM7160.ino .. |P127_usedby| replace:: `.` diff --git a/docs/source/Plugin/_plugin_substitutions_p13x.repl b/docs/source/Plugin/_plugin_substitutions_p13x.repl index 5a329f68aa..61648f6753 100644 --- a/docs/source/Plugin/_plugin_substitutions_p13x.repl +++ b/docs/source/Plugin/_plugin_substitutions_p13x.repl @@ -15,7 +15,7 @@ .. |P133_type| replace:: :cyan:`UV` .. |P133_typename| replace:: :cyan:`UV - LTR390` .. |P133_porttype| replace:: `.` -.. |P133_status| replace:: :yellow:`TESTING E` +.. |P133_status| replace:: :yellow:`COLLECTION E` .. |P133_github| replace:: P133_LTR390.ino .. _P133_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P133_LTR390.ino .. |P133_usedby| replace:: `.` diff --git a/src/_Pxxx_PluginTemplate.ino b/src/_Pxxx_PluginTemplate.ino index d54f4de33b..522f9be21c 100644 --- a/src/_Pxxx_PluginTemplate.ino +++ b/src/_Pxxx_PluginTemplate.ino @@ -27,7 +27,7 @@ - implement plugin and perform testing - set plugin status to DEVELOPMENT and distribute to other users for testing - after sufficient usage and possible code correction, set plugin status to TESTING and perform testing with more users - - finally, plugin will be accepted in project + - finally, plugin will be accepted in project, then the TESTING tag can be removed. - along with the plugin source code, prepare a wiki page containing: - instructions on how to make the necessary configuration - instructions on commands (if any) From e110526df880524d568c25d89778bef4fcc1e3be Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 22 Jul 2022 23:14:08 +0200 Subject: [PATCH 258/404] [Build] Some documentation improvements --- docs/source/Plugin/_Plugin.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Plugin/_Plugin.rst b/docs/source/Plugin/_Plugin.rst index eb2b2ea655..3c901d6e4c 100644 --- a/docs/source/Plugin/_Plugin.rst +++ b/docs/source/Plugin/_Plugin.rst @@ -214,7 +214,7 @@ There are different released versions of ESP Easy: :green:`NORMAL` is the regular set of plugins, you can consider these plugins stable with all secondary features enabled, like I2C multiplexer, RTTL, DEBUG logging, etc. -:yellow:`COLLECTION` (split into A/B/C/D/E sets) with plugins that don't fit into the NORMAL builds. Because of space limitations, this collection is split into 5 sets. When only COLLECTION is mentioned, the plugin is available in **all** COLLECTION builds. Also, some features are disabled to save space in the .bin files, like the I2C multiplexer feature, RTTTL, tooltips, and some DEBUG logging. +:yellow:`COLLECTION` (split into sets A..) with plugins that don't fit into the NORMAL builds. Because of space limitations, this collection is split into a number of sets. When only :yellow:`COLLECTION` is mentioned, the plugin is available in **all** :yellow:`COLLECTION` builds. Also, some features are disabled to save space in the .bin files, like the I2C multiplexer feature, RTTTL, tooltips, and some DEBUG logging. :red:`DEVELOPMENT` is used for plugins that are still being developed and are not considered stable at all. Currently there are no DEVELOPMENT builds available. From 6e821095a52f25d2db5eacf3f5e37183f191f6d7 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 23 Jul 2022 14:34:53 +0200 Subject: [PATCH 259/404] [Build] Update README.md and fix a documentation typo --- README.md | 85 +++++++++++++++++----------------- docs/source/Plugin/_Plugin.rst | 2 +- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 481960c3aa..9cbc3a4390 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ For ways to *support* us, see [this announcement on the forum](https://www.letsc Introduction and wiki: https://www.letscontrolit.com/wiki/index.php/ESPEasy#Introduction **MEGA** -:warning:This is the development branch of ESPEasy. All new untested features go into this branch. If you want to do a bugfix, do it on the stable branch, we will merge the fix to the development branch as well.:warning: +:warning:This is the development branch of ESPEasy. All new features go into this branch, and it has become the current stable branch. If you want to do a bugfix, do it on this branch:warning: Check here to learn how to use this branch and help us improving ESPEasy: http://www.letscontrolit.com/wiki/index.php/ESPEasy#Source_code_development @@ -29,61 +29,64 @@ The web flasher is using [ESP Web Tools](https://esphome.github.io/esp-web-tools On demand, controlled by the repo owner, our build-bot will build a new binary release: https://github.com/letscontrolit/ESPEasy/releases -The releases are named something like 'mega-20210501' (last number is the build date) +The releases are named something like 'mega-20220626' (last number is the build date) Depending on your needs, we release different types of files: The name is built up from a few key parts: -ESPEasy_mega\__[releasedate]_\__[build-type]_\__[opt-arduino-library]_\__[hardware-type]_\__[flash-size]__[filesystem-size]_\__[opt-build-features]_.bin - -_[build-type]_ can be any of: -Build type | Description | included plugins | -------------|-------------------------------------------|--------------------------------| -custom | Custom predefined set/Defined in Custom.h | Specific | -normal | Standard plugins | Stable | -test_A | Normal + test set A | Stable + Testing base + set A | -test_B | Normal + test set B | Stable + Testing base + set B | -test_C | Normal + test set C | Stable + Testing base + set C | -test_D | Normal + test set D | Stable + Testing base + set D | -test_E | Normal + test set E | Stable + Testing base + set E | -max | All available plugins | All available | -energy | All plugins related to energy measurement | Stable + Energy measurement | -display | All plugins related to displays | Stable + Displays | -hard | hardware specific builds | Minimal | -minimal | minimal plugins for specific use-cases | Switch and Controller | -spec_* | specialized technical builds | Not intended for regular use | -IRext | Infra-red hardware specific | Sending and receiving IR cmd | - - -_[opt-arduino-library]_ (optional) can be any of: +ESPEasy_mega\_*[releasedate]*\_*[build-type]*\_*[opt-arduino-library]*\_*[hardware-type]*\_*[flash-size][filesystem-size]*\_*[opt-build-features]*.bin + +*[build-type]* can be any of: +Build type | Description | included plugins | +-------------|-------------------------------------------|----------------------------------| +custom | Custom predefined set/Defined in Custom.h | Specific | +normal | Standard plugins | Stable | +collection_A | Normal + plugin collection A | Stable + Collection base + set A | +collection_B | Normal + plugin collection B | Stable + Collection base + set B | +collection_C | Normal + plugin collection C | Stable + Collection base + set C | +collection_D | Normal + plugin collection D | Stable + Collection base + set D | +collection_E | Normal + plugin collection E | Stable + Collection base + set E | +max | All available plugins | All available | +energy | All plugins related to energy measurement | Stable + Energy measurement | +display | All plugins related to displays | Stable + Displays | +neopixel | All plugins related to neopixel | Stable + Neopixel | +hard | hardware specific builds | Minimal | +minimal | minimal plugins for specific use-cases | Switch and Controller | +spec_* | specialized technical builds | Not intended for regular use | +IRext | Infra-red hardware specific | Sending and receiving IR cmd | + + +*[opt-arduino-library]* (optional) can be any of: Arduino library | Description | ----------------|------------------------------------| alt_wifi | Alternative WiFi configuration | beta | Arduino Beta release | sdk3 | Arduino SDK v.3 | core_274 | Arduino Core 2.7.4 release | +core_302 | Arduino Core 3.0.2 release | core_274_sdk3 | Arduino Core 2.7.4 SDK v.3 release | -_[hardware-type]_ cn be any of: +*[hardware-type]* can be any of: Hardware type | Description | -----------------|---------------------------------------------| ESP8266 | Espressif ESP8266/ESP8285 generic boards | WROOM02 | Espressif ESP8266 WRoom02 boards | ESP32 | Espressif ESP32 generic boards | +ESP32s2 | Espressif ESP32-S2 generic boards | ESP32-wrover-kit | Espressif ESP32 wrover-kit boards | SONOFF | Sonoff hardware specific | other_POW | Switch with power measurement | Shelly_1 | Shelly 1 switch | Shelly_PLUG_S | Shelly plug S switch with power measurement | Ventus | Ventus W266 weather station | -LCtech | LC-tech serial switch | +LCtech_relay | LC-tech serial switch | N.B. Starting 2022/07/23, 1M ESP8266 builds can also be used on ESP8285 units and thus there is no longer a specific ESP8285 build anymore. -_[flash-size]_ can be any of: +*[flash-size]* can be any of: Flash size | Description | -----------|-----------------------------| 1M | 1 MB with 128 kB filesystem | @@ -94,11 +97,10 @@ Flash size | Description | 16M | 16 MB with 14 MB filesystem | 4M316k | 4 MB with 316 kB filesystem | 16M1M | 16 MB with 1 MB filesystem | -16M2M | 16 MB with 2 MB filesystem | 16M8M | 16 MB with 8 MB filesystem | -_[opt-build-features]_ can be any of: +*[opt-build-features]* can be any of: Build features | Description | ----------------|--------------------------------------------------------------------------| LittleFS | Use LittleFS instead of SPIFFS filesystem (SPIFFS is unstable \> 2 MB) | @@ -106,22 +108,21 @@ VCC | Analog input configured to measure VCC voltage OTA | Arduino OTA (Over The Air) update feature enabled | Domoticz | Only Domoticz controllers (HTTP+MQTT) and plugins included | FHEM_HA | Only FHEM/OpenHAB/Home Assistant (MQTT) controllers and plugins included | -lolin_d32_pro | Specific Lolin hardware options enabled | ETH | Ethernet interface enabled (ESP32 only) | Some example firmware names: -Firmware name | Hardware | Included plugins | ----------------------------------------------------|-------------------------|-------------------------------| -ESPEasy_mega-20210501_normal_ESP8266_1M.bin | ESP8266 with 1MB flash | Stable | -ESPEasy_mega-20210501_normal_ESP8266_4M1M.bin | ESP8266 with 4MB flash | Stable | -ESPEasy_mega-20210501_test_A_ESP8266_4M1M.bin | ESP8266 with 4MB flash | Stable + Testing base + set A | -ESPEasy_mega-20210501_normal_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable | -ESPEasy_mega-20210501_test_A_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable + Testing base + set A | -ESPEasy_mega-20210501_test_B_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable + Testing base + set B | -ESPEasy_mega-20210501_max_ESP32_16M1M.bin | ESP32 with 16MB flash | All available plugins | -ESPEasy_mega-20210501_max_ESP32_16M8M_LittleFS.bin | ESP32 with 16MB flash | All available plugins | - -To see what plugins are included in which testing set, you can find that on the [ESPEasy Plugin overview page](https://espeasy.readthedocs.io/en/latest/Plugin/_Plugin.html) +Firmware name | Hardware | Included plugins | +----------------------------------------------------|--------------------------------|----------------------------------| +ESPEasy_mega-20220626_normal_ESP8266_1M.bin | ESP8266/ESP8285 with 1MB flash | Stable | +ESPEasy_mega-20220626_normal_ESP8266_4M1M.bin | ESP8266 with 4MB flash | Stable | +ESPEasy_mega-20220626_collection_A_ESP8266_4M1M.bin | ESP8266 with 4MB flash | Stable + Collection base + set A | +ESPEasy_mega-20220626_normal_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable | +ESPEasy_mega-20220626_collection_A_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable + Collection base + set A | +ESPEasy_mega-20220626_collection_B_ESP32_4M316k.bin | ESP32 with 4MB flash | Stable + Collection base + set B | +ESPEasy_mega-20220626_max_ESP32_16M1M.bin | ESP32 with 16MB flash | All available plugins | +ESPEasy_mega-20220626_max_ESP32_16M8M_LittleFS.bin | ESP32 with 16MB flash | All available plugins | + +To see what plugins are included in which collection set, you can find that on the [ESPEasy Plugin overview page](https://espeasy.readthedocs.io/en/latest/Plugin/_Plugin.html) ## Documentation & more info diff --git a/docs/source/Plugin/_Plugin.rst b/docs/source/Plugin/_Plugin.rst index 3c901d6e4c..6ea9224120 100644 --- a/docs/source/Plugin/_Plugin.rst +++ b/docs/source/Plugin/_Plugin.rst @@ -214,7 +214,7 @@ There are different released versions of ESP Easy: :green:`NORMAL` is the regular set of plugins, you can consider these plugins stable with all secondary features enabled, like I2C multiplexer, RTTL, DEBUG logging, etc. -:yellow:`COLLECTION` (split into sets A..) with plugins that don't fit into the NORMAL builds. Because of space limitations, this collection is split into a number of sets. When only :yellow:`COLLECTION` is mentioned, the plugin is available in **all** :yellow:`COLLECTION` builds. Also, some features are disabled to save space in the .bin files, like the I2C multiplexer feature, RTTTL, tooltips, and some DEBUG logging. +:yellow:`COLLECTION` (split into sets A..x) with plugins that don't fit into the NORMAL builds. Because of space limitations, this collection is split into a number of sets. When only :yellow:`COLLECTION` is mentioned, the plugin is available in **all** :yellow:`COLLECTION` builds. Also, some features are disabled to save space in the .bin files, like the I2C multiplexer feature, RTTTL, tooltips, and some DEBUG logging. :red:`DEVELOPMENT` is used for plugins that are still being developed and are not considered stable at all. Currently there are no DEVELOPMENT builds available. From 3d785676b07221b0d734cacc19eca1b16a5ed2d5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 25 Jul 2022 21:51:29 +0200 Subject: [PATCH 260/404] [Build] Change FEATURE_SD to use 0/1 state --- README.md | 2 +- platformio_esp82xx_envs.ini | 2 +- src/Custom-sample.h | 2 ++ src/ESPEasy-Globals.h | 2 +- src/ESPEasy_common.h | 2 +- src/src/Commands/InternalCommands.cpp | 4 ++-- src/src/Commands/SDCARD.cpp | 2 +- src/src/Commands/SDCARD.h | 15 +++++++++------ src/src/CustomBuild/define_plugin_sets.h | 7 ++++--- src/src/ESPEasyCore/ESPEasy_Log.cpp | 8 ++++---- src/src/Helpers/AdafruitGFX_helper.cpp | 8 ++++---- src/src/Helpers/Hardware.cpp | 8 ++++---- src/src/Helpers/Misc.cpp | 14 +++++++------- src/src/Helpers/StringProvider.cpp | 8 ++++---- src/src/Helpers/StringProvider.h | 4 ++-- src/src/WebServer/AdvancedConfigPage.cpp | 8 ++++---- src/src/WebServer/FileList.cpp | 8 ++++---- src/src/WebServer/FileList.h | 4 ++-- src/src/WebServer/HardwarePage.cpp | 4 ++-- src/src/WebServer/LoadFromFS.cpp | 12 ++++++------ src/src/WebServer/SysInfoPage.cpp | 4 ++-- src/src/WebServer/ToolsPage.cpp | 4 ++-- src/src/WebServer/WebServer.cpp | 4 ++-- tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 25 files changed, 73 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 9cbc3a4390..488b3cf146 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ For ways to *support* us, see [this announcement on the forum](https://www.letsc Introduction and wiki: https://www.letscontrolit.com/wiki/index.php/ESPEasy#Introduction **MEGA** -:warning:This is the development branch of ESPEasy. All new features go into this branch, and it has become the current stable branch. If you want to do a bugfix, do it on this branch:warning: +This is the development branch of ESPEasy. All new features go into this branch, and it has become the current stable branch. If you want to do a bugfix, do it on this branch. Check here to learn how to use this branch and help us improving ESPEasy: http://www.letscontrolit.com/wiki/index.php/ESPEasy#Source_code_development diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 53973d0ed1..248c63ca61 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -614,7 +614,7 @@ build_flags = ${collection_ESP8266_4M1M.build_flags} ; ${esp8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true ; -DFEATURE_MDNS -; -DFEATURE_SD +; -DFEATURE_SD=1 ; -DLIMIT_BUILD_SIZE ;lib_ignore = ESP32_ping ; ESP32WebServer diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 456a11cc13..56a0e2d93d 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -22,9 +22,11 @@ */ // --- Feature Flagging --------------------------------------------------------- +// Can be set to 1 to enable, 0 to disable, or not set to use the default (usually via define_plugin_sets.h) #define FEATURE_ESPEASY_P2P 1 // (1/0) enables the ESP Easy P2P protocol #define FEATURE_ARDUINO_OTA //enables the Arduino OTA capabilities +// #define FEATURE_SD 1 // Enable SD card support #ifdef BUILD_GIT # undef BUILD_GIT diff --git a/src/ESPEasy-Globals.h b/src/ESPEasy-Globals.h index 6af813f095..5cfe99b12f 100644 --- a/src/ESPEasy-Globals.h +++ b/src/ESPEasy-Globals.h @@ -26,7 +26,7 @@ //#define PLUGIN_BUILD_DEV //add this if you want SD support (add 10k flash) -//#define FEATURE_SD +//#define FEATURE_SD 1 diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index cdbeb8fe10..d9082564a1 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -162,7 +162,7 @@ namespace std #include #include #include -#ifdef FEATURE_SD +#if FEATURE_SD #include #else using namespace fs; diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 33d1655564..80d7336042 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -416,10 +416,10 @@ bool executeInternalCommand(command_case_data & data) } case 's': { COMMAND_CASE_R( "save", Command_Settings_Save, 0); // Settings.h - #ifdef FEATURE_SD + #if FEATURE_SD COMMAND_CASE_R( "sdcard", Command_SD_LS, 0); // SDCARDS.h COMMAND_CASE_R("sdremove", Command_SD_Remove, 1); // SDCARDS.h - #endif // ifdef FEATURE_SD + #endif // if FEATURE_SD if (data.cmd_lc[1] == 'e') { #if FEATURE_ESPEASY_P2P diff --git a/src/src/Commands/SDCARD.cpp b/src/src/Commands/SDCARD.cpp index 1609cb5eef..7478bfad70 100644 --- a/src/src/Commands/SDCARD.cpp +++ b/src/src/Commands/SDCARD.cpp @@ -8,7 +8,7 @@ -#ifdef FEATURE_SD +#if FEATURE_SD #include diff --git a/src/src/Commands/SDCARD.h b/src/src/Commands/SDCARD.h index ca48f61fbf..c090270783 100644 --- a/src/src/Commands/SDCARD.h +++ b/src/src/Commands/SDCARD.h @@ -2,14 +2,17 @@ #define COMMAND_SDCARD_H #include "../../ESPEasy_common.h" -#ifdef FEATURE_SD +#if FEATURE_SD -#include +# include -void printDirectory(fs::File dir, int numTabs); -const __FlashStringHelper * Command_SD_LS(struct EventStruct *event, const char* Line); -String Command_SD_Remove(struct EventStruct *event, const char* Line); +void printDirectory(fs::File dir, + int numTabs); +const __FlashStringHelper* Command_SD_LS(struct EventStruct *event, + const char *Line); +String Command_SD_Remove(struct EventStruct *event, + const char *Line); -#endif +#endif // if FEATURE_SD #endif // COMMAND_SDCARD_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 35d744cc53..83b7e9ed4d 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -22,7 +22,7 @@ To create/register a plugin, you have to : When found stable enough, the maintainer (and only him) will choose to move it to COLLECTION or NORMAL */ -//#define FEATURE_SD +//#define FEATURE_SD 1 /******************************************************************************\ * WebServer pages ********************************************************** @@ -1528,7 +1528,7 @@ To create/register a plugin, you have to : #define USE_SETTINGS_ARCHIVE #endif #ifndef FEATURE_SD - #define FEATURE_SD + #define FEATURE_SD 1 #endif // Plugins @@ -1797,8 +1797,9 @@ To create/register a plugin, you have to : #ifdef USES_C016 #undef USES_C016 // Cache controller #endif - #ifdef FEATURE_SD + #if FEATURE_SD #undef FEATURE_SD // Unlikely on 1M units + #define FEATURE_SD 0 #endif #ifndef LIMIT_BUILD_SIZE #define LIMIT_BUILD_SIZE diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index 25562f2c7c..9b390e7851 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -10,7 +10,7 @@ #include -#ifdef FEATURE_SD +#if FEATURE_SD #include #endif @@ -100,7 +100,7 @@ void updateLogLevelCache() { if (Logging.logActiveRead()) { max_lvl = _max(max_lvl, Settings.WebLogLevel); } -#ifdef FEATURE_SD +#if FEATURE_SD max_lvl = _max(max_lvl, Settings.SDLogLevel); #endif highest_active_log_level = max_lvl; @@ -148,7 +148,7 @@ bool loglevelActiveFor(uint8_t destination, uint8_t logLevel) { break; } case LOG_TO_SDCARD: { - #ifdef FEATURE_SD + #if FEATURE_SD logLevelSettings = Settings.SDLogLevel; #endif break; @@ -263,7 +263,7 @@ void addToSysLog(uint8_t logLevel, const String& string) void addToSDLog(uint8_t logLevel, const String& string) { -#ifdef FEATURE_SD +#if FEATURE_SD if (loglevelActiveFor(LOG_TO_SDCARD, logLevel)) { fs::File logFile = SD.open("log.dat", FILE_WRITE); if (logFile) { diff --git a/src/src/Helpers/AdafruitGFX_helper.cpp b/src/src/Helpers/AdafruitGFX_helper.cpp index a32b621a52..4e3aa3fc24 100644 --- a/src/src/Helpers/AdafruitGFX_helper.cpp +++ b/src/src/Helpers/AdafruitGFX_helper.cpp @@ -5,9 +5,9 @@ # include "../Helpers/StringConverter.h" # include "../WebServer/Markup_Forms.h" -# if defined(FEATURE_SD) && defined(ADAGFX_ENABLE_BMP_DISPLAY) +# if FEATURE_SD && defined(ADAGFX_ENABLE_BMP_DISPLAY) # include -# endif // if defined(FEATURE_SD) && defined(ADAGFX_ENABLE_BMP_DISPLAY) +# endif // if FEATURE_SD && defined(ADAGFX_ENABLE_BMP_DISPLAY) # if ADAGFX_FONTS_INCLUDED # include "src/Static/Fonts/Seven_Segment24pt7b.h" @@ -1828,12 +1828,12 @@ bool AdafruitGFX_helper::showBmp(const String& filename, // Open requested file on storage // Search flash file system first, then SD if present file = tryOpenFile(filename, "r"); - # ifdef FEATURE_SD + # if FEATURE_SD if (!file) { file = SD.open(filename.c_str(), "r"); } - # endif // ifdef FEATURE_SD + # endif // if FEATURE_SD if (!file) { addLog(LOG_LEVEL_ERROR, F("showBmp: file not found")); diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 8958ec0486..007f9eac86 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -45,9 +45,9 @@ #endif // ifdef ESP32 -#ifdef FEATURE_SD +#if FEATURE_SD # include -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD /********************************************************************************************\ * Initialize specific hardware settings (only global ones, others are set through devices) @@ -207,7 +207,7 @@ void hardwareInit() addLog(LOG_LEVEL_INFO, F("INIT : SPI not enabled")); } -#ifdef FEATURE_SD +#if FEATURE_SD if (Settings.Pin_sd_cs >= 0) { @@ -221,7 +221,7 @@ void hardwareInit() addLog(LOG_LEVEL_ERROR, F("SD : Init failed")); } } -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD #ifdef HAS_ETHERNET ethPower(false); #endif diff --git a/src/src/Helpers/Misc.cpp b/src/src/Helpers/Misc.cpp index 81afa55f0e..e859a22b3d 100644 --- a/src/src/Helpers/Misc.cpp +++ b/src/src/Helpers/Misc.cpp @@ -14,7 +14,7 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/StringParser.h" -#ifdef FEATURE_SD +#if FEATURE_SD #include #endif @@ -282,12 +282,12 @@ void FeedSW_watchdog() void SendValueLogger(taskIndex_t TaskIndex) { -#if !defined(BUILD_NO_DEBUG) || defined(FEATURE_SD) +#if !defined(BUILD_NO_DEBUG) || FEATURE_SD bool featureSD = false; String logger; - # ifdef FEATURE_SD + # if FEATURE_SD featureSD = true; - # endif // ifdef FEATURE_SD + # endif // if FEATURE_SD if (featureSD || loglevelActiveFor(LOG_LEVEL_DEBUG)) { const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(TaskIndex); @@ -313,9 +313,9 @@ void SendValueLogger(taskIndex_t TaskIndex) addLog(LOG_LEVEL_DEBUG, logger); } } -#endif // if !defined(BUILD_NO_DEBUG) || defined(FEATURE_SD) +#endif // if !defined(BUILD_NO_DEBUG) || FEATURE_SD -#ifdef FEATURE_SD +#if FEATURE_SD String filename = F("VALUES.CSV"); fs::File logFile = SD.open(filename, FILE_WRITE); @@ -323,7 +323,7 @@ void SendValueLogger(taskIndex_t TaskIndex) logFile.print(logger); } logFile.close(); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD } // ####################################################################################################### diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 245375ef56..c907be600b 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -173,9 +173,9 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::SYSLOG_LOG_LEVEL: return F("Syslog Log Level"); case LabelType::SERIAL_LOG_LEVEL: return F("Serial Log Level"); case LabelType::WEB_LOG_LEVEL: return F("Web Log Level"); - #ifdef FEATURE_SD + #if FEATURE_SD case LabelType::SD_LOG_LEVEL: return F("SD Log Level"); - #endif // ifdef FEATURE_SD + #endif // if FEATURE_SD case LabelType::ESP_CHIP_ID: return F("ESP Chip ID"); case LabelType::ESP_CHIP_FREQ: return F("ESP Chip Frequency"); @@ -396,9 +396,9 @@ String getValue(LabelType::Enum label) { case LabelType::SYSLOG_LOG_LEVEL: return getLogLevelDisplayString(Settings.SyslogLevel); case LabelType::SERIAL_LOG_LEVEL: return getLogLevelDisplayString(getSerialLogLevel()); case LabelType::WEB_LOG_LEVEL: return getLogLevelDisplayString(getWebLogLevel()); - #ifdef FEATURE_SD + #if FEATURE_SD case LabelType::SD_LOG_LEVEL: return getLogLevelDisplayString(Settings.SDLogLevel); - #endif // ifdef FEATURE_SD + #endif // if FEATURE_SD case LabelType::ESP_CHIP_ID: return formatToHex(getChipId()); case LabelType::ESP_CHIP_FREQ: return String(ESP.getCpuFreqMHz()); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 07e8438eb7..da6d6e24b7 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -137,9 +137,9 @@ struct LabelType { SYSLOG_LOG_LEVEL, SERIAL_LOG_LEVEL, WEB_LOG_LEVEL, -#ifdef FEATURE_SD +#if FEATURE_SD SD_LOG_LEVEL, -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD ESP_CHIP_ID, ESP_CHIP_FREQ, diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index e795267cdb..c6dc915c9c 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -57,9 +57,9 @@ void handle_advanced() { setLogLevelFor(LOG_TO_SYSLOG, LabelType::SYSLOG_LOG_LEVEL); setLogLevelFor(LOG_TO_SERIAL, LabelType::SERIAL_LOG_LEVEL); setLogLevelFor(LOG_TO_WEBLOG, LabelType::WEB_LOG_LEVEL); -#ifdef FEATURE_SD +#if FEATURE_SD setLogLevelFor(LOG_TO_SDCARD, LabelType::SD_LOG_LEVEL); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD Settings.UseValueLogger = isFormItemChecked(F("valuelogger")); Settings.BaudRate = getFormItemInt(F("baudrate")); Settings.UseNTP(isFormItemChecked(F("usentp"))); @@ -194,11 +194,11 @@ void handle_advanced() { addFormLogLevelSelect(LabelType::SERIAL_LOG_LEVEL, Settings.SerialLogLevel); addFormLogLevelSelect(LabelType::WEB_LOG_LEVEL, Settings.WebLogLevel); -#ifdef FEATURE_SD +#if FEATURE_SD addFormLogLevelSelect(LabelType::SD_LOG_LEVEL, Settings.SDLogLevel); addFormCheckBox(F("SD Card Value Logger"), F("valuelogger"), Settings.UseValueLogger); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD addFormSubHeader(F("Serial Settings")); diff --git a/src/src/WebServer/FileList.cpp b/src/src/WebServer/FileList.cpp index e3952c8248..3541542c40 100644 --- a/src/src/WebServer/FileList.cpp +++ b/src/src/WebServer/FileList.cpp @@ -19,9 +19,9 @@ #include "../Globals/C016_ControllerCache.h" #endif -#ifdef FEATURE_SD +#if FEATURE_SD #include -#endif +#endif // if FEATURE_SD #ifdef WEBSERVER_NEW_UI @@ -311,7 +311,7 @@ void handle_filelist_buttons(int start_prev, int start_next, bool cacheFilesPres // ******************************************************************************** // Web Interface SD card file and directory list // ******************************************************************************** -#ifdef FEATURE_SD +#if FEATURE_SD void handle_SDfilelist() { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_SDfilelist")); @@ -469,4 +469,4 @@ void handle_SDfilelist() { TXBuffer.endStream(); } -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD diff --git a/src/src/WebServer/FileList.h b/src/src/WebServer/FileList.h index b3222d9f3d..6c0acd652e 100644 --- a/src/src/WebServer/FileList.h +++ b/src/src/WebServer/FileList.h @@ -25,10 +25,10 @@ void handle_filelist_buttons(int start_prev, int start_next, bool cacheFilesPres // ******************************************************************************** // Web Interface SD card file and directory list // ******************************************************************************** -#ifdef FEATURE_SD +#if FEATURE_SD void handle_SDfilelist(); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 856e798491..5464b1518b 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -192,10 +192,10 @@ void handle_hardware() { #endif addFormNote(F("Chip Select (CS) config must be done in the plugin")); -#ifdef FEATURE_SD +#if FEATURE_SD addFormSubHeader(F("SD Card")); addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output(F("SD Card CS")), F("sd"), Settings.Pin_sd_cs); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD #ifdef HAS_ETHERNET addFormSubHeader(F("Ethernet")); diff --git a/src/src/WebServer/LoadFromFS.cpp b/src/src/WebServer/LoadFromFS.cpp index 94cc86bf55..a1b1dd9b0b 100644 --- a/src/src/WebServer/LoadFromFS.cpp +++ b/src/src/WebServer/LoadFromFS.cpp @@ -9,9 +9,9 @@ #include "../WebServer/HTML_wrappers.h" #include "../WebServer/WebServer.h" -#ifdef FEATURE_SD +#if FEATURE_SD # include -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD bool match_ext(const String& path, const __FlashStringHelper *ext) { return path.endsWith(ext) || path.endsWith(String(ext) + F(".gz")); @@ -102,11 +102,11 @@ bool loadFromFS(String path) { // Search flash file system first, then SD if present f = tryOpenFile(path.c_str(), "r"); - #ifdef FEATURE_SD + #if FEATURE_SD if (!f) { f = SD.open(path.c_str(), "r"); } - #endif // ifdef FEATURE_SD + #endif // if FEATURE_SD if (!f) { return false; @@ -139,11 +139,11 @@ size_t streamFromFS(String path, bool htmlEscape) { // Search flash file system first, then SD if present f = tryOpenFile(path.c_str(), "r"); - #ifdef FEATURE_SD + #if FEATURE_SD if (!f) { f = SD.open(path.c_str(), "r"); } - #endif // ifdef FEATURE_SD + #endif // if FEATURE_SD if (!f) { return bytesStreamed; diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 3a07d996c3..7e973b7809 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -513,9 +513,9 @@ void handle_sysinfo_SystemStatus() { addRowLabelValue(LabelType::SYSLOG_LOG_LEVEL); addRowLabelValue(LabelType::SERIAL_LOG_LEVEL); addRowLabelValue(LabelType::WEB_LOG_LEVEL); - # ifdef FEATURE_SD + # if FEATURE_SD addRowLabelValue(LabelType::SD_LOG_LEVEL); - # endif // ifdef FEATURE_SD + # endif // if FEATURE_SD if (Settings.EnableClearHangingI2Cbus()) { addRowLabelValue(LabelType::I2C_BUS_STATE); diff --git a/src/src/WebServer/ToolsPage.cpp b/src/src/WebServer/ToolsPage.cpp index c14aad7c95..08508545cd 100644 --- a/src/src/WebServer/ToolsPage.cpp +++ b/src/src/WebServer/ToolsPage.cpp @@ -169,9 +169,9 @@ void handle_tools() { # ifdef USE_SETTINGS_ARCHIVE addWideButtonPlusDescription(F("/settingsarchive"), F("Settings Archive"), F("Download settings from some archive")); # endif // ifdef USE_SETTINGS_ARCHIVE -# ifdef FEATURE_SD +# if FEATURE_SD addWideButtonPlusDescription(F("SDfilelist"), F("SD Card"), F("Show files on SD-Card")); -# endif // ifdef FEATURE_SD +# endif // if FEATURE_SD html_end_table(); html_end_form(); diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 7e4a2a9071..12bd094fda 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -266,9 +266,9 @@ void WebServerInit() web_server.on(F("/rules/delete"), handle_rules_delete); # endif // WEBSERVER_NEW_RULES #endif // WEBSERVER_RULES -#ifdef FEATURE_SD +#if FEATURE_SD web_server.on(F("/SDfilelist"), handle_SDfilelist); -#endif // ifdef FEATURE_SD +#endif // if FEATURE_SD #ifdef WEBSERVER_SETUP web_server.on(F("/setup"), handle_setup); #endif // ifdef WEBSERVER_SETUP diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 0a9ede0c1b..fa6f315f2b 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -60,7 +60,7 @@ "-DUSES_ESPEASY_NOW", "-DUSE_EXT_RTC", - "-DFEATURE_SD", + "-DFEATURE_SD=1", "-DFEATURE_I2CMULTIPLEXER", "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 92810696ba..e8f40d73de 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -59,7 +59,7 @@ "-DUSES_ESPEASY_NOW", # "-DFEATURE_MDNS", -# "-DFEATURE_SD", +# "-DFEATURE_SD=1", "-DUSE_EXT_RTC", "-DFEATURE_I2CMULTIPLEXER", "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", From 0554d0ac67e983e8610fe926feb49ec4075f0589 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 24 Jul 2022 22:22:51 +0200 Subject: [PATCH 261/404] [Build] Change FEATURE_ARDUINO_OTA to use 0/1 state --- platformio.ini | 2 +- platformio_esp32_envs.ini | 22 +++++++++---------- platformio_esp32s2_envs.ini | 4 ++-- platformio_special_envs.ini | 2 +- src/Custom-sample.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 2 +- .../ESPEasyCore/ESPEasy_backgroundtasks.cpp | 6 ++--- src/src/ESPEasyCore/ESPEasy_setup.cpp | 8 +++---- src/src/Globals/Services.cpp | 4 ++-- src/src/Globals/Services.h | 2 +- src/src/Helpers/OTA.cpp | 6 ++--- src/src/Helpers/OTA.h | 4 ++-- src/src/WebServer/AdvancedConfigPage.cpp | 4 ++-- 13 files changed, 34 insertions(+), 34 deletions(-) diff --git a/platformio.ini b/platformio.ini index cd6f9a84fc..6df1b8988a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -57,7 +57,7 @@ upload_flags_esp8266 = --port=18266 upload_flags_esp32 = --port=3232 -build_flags = -DFEATURE_ARDUINO_OTA +build_flags = -DFEATURE_ARDUINO_OTA=1 upload_port = 192.168.1.152 diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index 473d65c218..d92c9bdfd0 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -94,7 +94,7 @@ extends = esp32_base lib_ignore = ${esp32_always.lib_ignore} ESP32_ping build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_NORMAL_IRext -DCOLLECTION_USE_RTTTL lib_deps = ${esp32_base.lib_deps} @@ -162,7 +162,7 @@ lib_deps = ${esp32_common_LittleFS.lib_deps} extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_ESP32 -DCOLLECTION_USE_RTTTL @@ -170,7 +170,7 @@ build_flags = ${esp32_common.build_flags} extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_B_ESP32 -DCOLLECTION_USE_RTTTL @@ -178,7 +178,7 @@ build_flags = ${esp32_common.build_flags} extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_C_ESP32 -DCOLLECTION_USE_RTTTL @@ -186,7 +186,7 @@ build_flags = ${esp32_common.build_flags} extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_D_ESP32 -DCOLLECTION_USE_RTTTL @@ -194,7 +194,7 @@ build_flags = ${esp32_common.build_flags} extends = esp32_common board = esp32_4M build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_SET_COLLECTION_E_ESP32 -DCOLLECTION_USE_RTTTL @@ -235,7 +235,7 @@ board = esp32_4M lib_deps = ${esp32_common.lib_deps} ServoESP32 build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_ENERGY_COLLECTION [env:display_ESP32_4M316k] @@ -244,7 +244,7 @@ board = esp32_4M lib_deps = ${esp32_common.lib_deps} ServoESP32 build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_DISPLAY_COLLECTION [env:neopixel_ESP32_4M316k] @@ -253,7 +253,7 @@ board = esp32_4M lib_deps = ${esp32_common.lib_deps} ServoESP32 build_flags = ${esp32_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -D PLUGIN_NEOPIXEL_COLLECTION @@ -309,7 +309,7 @@ board_upload.flash_size = 16MB lib_ignore = ${esp32_always.lib_ignore} ESP32_ping build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED @@ -328,7 +328,7 @@ lib_ignore = ${esp32_always.lib_ignore} ESP32_ping build_flags = ${esp32_base.build_flags} -DUSE_LITTLEFS - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED extra_scripts = ${esp32_base.extra_scripts} diff --git a/platformio_esp32s2_envs.ini b/platformio_esp32s2_envs.ini index 24c94bea8c..0104083224 100644 --- a/platformio_esp32s2_envs.ini +++ b/platformio_esp32s2_envs.ini @@ -10,7 +10,7 @@ lib_ignore = ${esp32_always.lib_ignore} HeatpumpIR ESP32 BLE Arduino build_flags = ${esp32_base.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 extra_scripts = ${esp32_base.extra_scripts} lib_deps = ${esp32_base.lib_deps} build_unflags = ${esp32_base.build_unflags} @@ -39,7 +39,7 @@ board = esp32s2 lib_deps = ${esp32s2_common.lib_deps} ServoESP32 build_flags = ${esp32s2_common.build_flags} - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_NEOPIXEL_COLLECTION diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index e9427a0354..c3b9ab8b3e 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -95,7 +95,7 @@ lib_ignore = ${esp32_always.lib_ignore} build_flags = ${esp32_base.build_flags} ${debug_pio.build_flags} -DUSE_LITTLEFS - -DFEATURE_ARDUINO_OTA + -DFEATURE_ARDUINO_OTA=1 -DPLUGIN_BUILD_MAX_ESP32 -DPLUGIN_BUILD_IR_EXTENDED lib_deps = ${esp32_base.lib_deps} diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 56a0e2d93d..ca46b8f382 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -25,7 +25,7 @@ // Can be set to 1 to enable, 0 to disable, or not set to use the default (usually via define_plugin_sets.h) #define FEATURE_ESPEASY_P2P 1 // (1/0) enables the ESP Easy P2P protocol -#define FEATURE_ARDUINO_OTA //enables the Arduino OTA capabilities +#define FEATURE_ARDUINO_OTA 1 //enables the Arduino OTA capabilities // #define FEATURE_SD 1 // Enable SD card support #ifdef BUILD_GIT diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 83b7e9ed4d..1f5610af5d 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1962,7 +1962,7 @@ To create/register a plugin, you have to : #endif #endif -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA #ifndef FEATURE_MDNS #define FEATURE_MDNS #endif diff --git a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp index 44203b0d82..028266b2f4 100644 --- a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp +++ b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp @@ -14,7 +14,7 @@ #include "../Helpers/Networking.h" -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA #include "../Helpers/OTA.h" #endif @@ -91,7 +91,7 @@ void backgroundtasks() } #endif // ifdef FEATURE_DNS_SERVER - #ifdef FEATURE_ARDUINO_OTA + #if FEATURE_ARDUINO_OTA if (Settings.ArduinoOTAEnable) { ArduinoOTA_handle(); @@ -105,7 +105,7 @@ void backgroundtasks() ArduinoOTA_handle(); } - #endif // ifdef FEATURE_ARDUINO_OTA + #endif // if FEATURE_ARDUINO_OTA #ifdef FEATURE_MDNS diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 32ab5079af..de53c27b01 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -33,9 +33,9 @@ # include "../Helpers/PeriodicalActions.h" #endif // ifdef USE_RTOS_MULTITASKING -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA # include "../Helpers/OTA.h" -#endif // ifdef FEATURE_ARDUINO_OTA +#endif // if FEATURE_ARDUINO_OTA #ifdef ESP32 #include @@ -450,12 +450,12 @@ void ESPEasy_setup() ReportStatus(); #endif // ifdef FEATURE_REPORTING - #ifdef FEATURE_ARDUINO_OTA + #if FEATURE_ARDUINO_OTA ArduinoOTAInit(); #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("ArduinoOTAInit()")); #endif - #endif // ifdef FEATURE_ARDUINO_OTA + #endif // if FEATURE_ARDUINO_OTA if (node_time.systemTimePresent()) { node_time.initTime(); diff --git a/src/src/Globals/Services.cpp b/src/src/Globals/Services.cpp index 952e33a50f..52f65b8321 100644 --- a/src/src/Globals/Services.cpp +++ b/src/src/Globals/Services.cpp @@ -1,7 +1,7 @@ #include "../Globals/Services.h" -#ifdef FEATURE_ARDUINO_OTA - bool ArduinoOTAtriggered=false; +#if FEATURE_ARDUINO_OTA + bool ArduinoOTAtriggered = false; #endif diff --git a/src/src/Globals/Services.h b/src/src/Globals/Services.h index 9162479254..2a3ac3450b 100644 --- a/src/src/Globals/Services.h +++ b/src/src/Globals/Services.h @@ -42,7 +42,7 @@ #endif -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA //enable Arduino OTA updating. //Note: This adds around 10kb to the firmware size, and 1kb extra ram. extern bool ArduinoOTAtriggered; diff --git a/src/src/Helpers/OTA.cpp b/src/src/Helpers/OTA.cpp index 39a18c7aa6..de902b1b5c 100644 --- a/src/src/Helpers/OTA.cpp +++ b/src/src/Helpers/OTA.cpp @@ -8,7 +8,7 @@ #include "../Helpers/Hardware.h" #include "../Helpers/Misc.h" -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA //enable Arduino OTA updating. //Note: This adds around 10kb to the firmware size, and 1kb extra ram. #include @@ -47,7 +47,7 @@ bool OTA_possible(uint32_t& maxSketchSize, bool& use2step) { #endif // if defined(ESP8266) } -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA /********************************************************************************************\ Allow updating via the Arduino OTA-protocol. (this allows you to upload directly from platformio) @@ -118,4 +118,4 @@ void ArduinoOTA_handle() ArduinoOTA.handle(); } -#endif // ifdef FEATURE_ARDUINO_OTA +#endif // if FEATURE_ARDUINO_OTA diff --git a/src/src/Helpers/OTA.h b/src/src/Helpers/OTA.h index 20ccc93bdd..46365c6d18 100644 --- a/src/src/Helpers/OTA.h +++ b/src/src/Helpers/OTA.h @@ -6,7 +6,7 @@ bool OTA_possible(uint32_t& maxSketchSize, bool & use2step); -#ifdef FEATURE_ARDUINO_OTA +#if FEATURE_ARDUINO_OTA /********************************************************************************************\ Allow updating via the Arduino OTA-protocol. (this allows you to upload directly from platformio) @@ -16,7 +16,7 @@ void ArduinoOTAInit(); void ArduinoOTA_handle(); -#endif // ifdef FEATURE_ARDUINO_OTA +#endif // if FEATURE_ARDUINO_OTA #endif \ No newline at end of file diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index c6dc915c9c..89a23963f3 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -229,9 +229,9 @@ void handle_advanced() { #ifdef ESP32 addUnit(F("1/80 usec")); #endif - #if defined(FEATURE_ARDUINO_OTA) + #if FEATURE_ARDUINO_OTA addFormCheckBox(F("Enable Arduino OTA"), F("arduinootaenable"), Settings.ArduinoOTAEnable); - #endif // if defined(FEATURE_ARDUINO_OTA) + #endif // if FEATURE_ARDUINO_OTA #if defined(ESP32) addFormCheckBox_disabled(F("Enable RTOS Multitasking"), F("usertosmultitasking"), Settings.UseRTOSMultitasking); #endif // if defined(ESP32) From cbb4798f616146fdaae169a0f35af4f9eaf21be9 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 24 Jul 2022 22:29:56 +0200 Subject: [PATCH 262/404] [Build] Rename USE_DOWNLOAD to FEATURE_DOWNLOAD and use 0/1 state --- src/Custom-sample.h | 3 ++- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/Helpers/ESPEasy_Storage.cpp | 4 ++-- src/src/Helpers/ESPEasy_Storage.h | 4 ++-- src/src/Helpers/Networking.cpp | 8 ++++---- src/src/Helpers/Networking.h | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index ca46b8f382..c56bd789f8 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -26,7 +26,8 @@ #define FEATURE_ESPEASY_P2P 1 // (1/0) enables the ESP Easy P2P protocol #define FEATURE_ARDUINO_OTA 1 //enables the Arduino OTA capabilities -// #define FEATURE_SD 1 // Enable SD card support +// #define FEATURE_SD 1 // Enable SD card support +// #define FEATURE_DOWNLOAD 1 // Enable downloading a file from an url #ifdef BUILD_GIT # undef BUILD_GIT diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 1f5610af5d..c4b2a8884f 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1983,8 +1983,8 @@ To create/register a plugin, you have to : #endif #if defined(USE_SETTINGS_ARCHIVE) || defined(USE_CUSTOM_PROVISIONING) - #ifndef USE_DOWNLOAD - #define USE_DOWNLOAD + #ifndef FEATURE_DOWNLOAD + #define FEATURE_DOWNLOAD 1 #endif #endif diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 7f5fb4b580..bec385f59a 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1747,7 +1747,7 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin #endif // ifdef ESP32 -#ifdef USE_DOWNLOAD +#if FEATURE_DOWNLOAD String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr) { if (!getDownloadFiletypeChecked(filetype, filenr)) { @@ -1825,7 +1825,7 @@ String downloadFileType(const String& url, const String& user, const String& pas return error; } -#endif // ifdef USE_DOWNLOAD +#endif // if FEATURE_DOWNLOAD #ifdef USE_CUSTOM_PROVISIONING diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index e7b4d9221a..7fb3255046 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -292,10 +292,10 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin /********************************************************************************************\ Download ESPEasy file types from HTTP server \*********************************************************************************************/ -#ifdef USE_DOWNLOAD +#if FEATURE_DOWNLOAD String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr = 0); -#endif +#endif // if FEATURE_DOWNLOAD #ifdef USE_CUSTOM_PROVISIONING // Download file type based on settings stored in provisioning.dat file. String downloadFileType(FileType::Enum filetype, unsigned int filenr = 0); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 3069bd7825..8cc405f0ad 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -69,7 +69,7 @@ void etharp_gratuitous_r(struct netif *netif) { #endif // ifdef SUPPORT_ARP -#ifdef USE_DOWNLOAD +#if FEATURE_DOWNLOAD # ifdef ESP8266 # include # endif // ifdef ESP8266 @@ -77,7 +77,7 @@ void etharp_gratuitous_r(struct netif *netif) { # include # include # endif // ifdef ESP32 -#endif // ifdef USE_DOWNLOAD +#endif // if FEATURE_DOWNLOAD #include @@ -1462,7 +1462,7 @@ String send_via_http(const String& logIdentifier, return response; } -#ifdef USE_DOWNLOAD +#if FEATURE_DOWNLOAD // FIXME TD-er: Must set the timeout somewhere # ifndef DOWNLOAD_FILE_TIMEOUT @@ -1728,4 +1728,4 @@ bool downloadFirmware(const String& url, String& error) return false; } -#endif // ifdef USE_DOWNLOAD +#endif // if FEATURE_DOWNLOAD diff --git a/src/src/Helpers/Networking.h b/src/src/Helpers/Networking.h index 096b247342..db3102b5db 100644 --- a/src/src/Helpers/Networking.h +++ b/src/src/Helpers/Networking.h @@ -207,7 +207,7 @@ String send_via_http(const String& logIdentifier, int & httpCode, bool must_check_reply); -#ifdef USE_DOWNLOAD +#if FEATURE_DOWNLOAD // Download a file from a given URL and save to a local file named "file_save" // If the URL ends with a /, the file part will be assumed the same as file_save. @@ -219,7 +219,7 @@ bool downloadFile(const String& url, String file_save, const String& user, const bool downloadFirmware(const String& url, String& error); -#endif +#endif // if FEATURE_DOWNLOAD From 3b3bbc30331088e00d8dbdd43f3e46f511305110 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 25 Jul 2022 21:53:40 +0200 Subject: [PATCH 263/404] [Build] Rename USE_CUSTOM_PROVISIONING to FEATURE_CUSTOM_PROVISIONING and use 0/1 state --- docs/source/Tools/Tools.rst | 8 ++++---- src/Custom-sample.h | 4 ++-- src/src/Commands/InternalCommands.cpp | 2 +- src/src/Commands/Provisioning.cpp | 4 ++-- src/src/Commands/Provisioning.h | 4 ++-- src/src/CustomBuild/ESPEasyDefaults.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/DataStructs/ProvisioningStruct.cpp | 4 ++-- src/src/DataStructs/ProvisioningStruct.h | 4 ++-- src/src/Helpers/ESPEasy_FactoryDefault.cpp | 4 ++-- src/src/Helpers/ESPEasy_Storage.cpp | 8 ++++---- src/src/Helpers/ESPEasy_Storage.h | 4 ++-- src/src/Helpers/ESPEasy_checks.cpp | 4 ++-- src/src/WebServer/SettingsArchive.cpp | 12 ++++++------ tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 16 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/source/Tools/Tools.rst b/docs/source/Tools/Tools.rst index 9b9cfc339a..8d89ba5255 100644 --- a/docs/source/Tools/Tools.rst +++ b/docs/source/Tools/Tools.rst @@ -868,9 +868,9 @@ This would corrupt the settings file. With only ``USE_SETTINGS_ARCHIVE`` defined during build, the URL and credentials cannot be stored. -For this the build must be made with ``USE_CUSTOM_PROVISIONING`` defined. +For this the build must be made with ``FEATURE_CUSTOM_PROVISIONING`` defined. -N.B. ``USE_CUSTOM_PROVISIONING`` is added on 2022/05/03. +N.B. ``FEATURE_CUSTOM_PROVISIONING`` is added on 2022/05/13. (2022/07/24: Renamed from USE_CUSTOM_PROVISIONING to FEATURE_CUSTOM_PROVISIONING) URL with Settings @@ -886,7 +886,7 @@ System variables will be converted into an URL encoded form, which may end up li * ``http://192.168.10.127/A0%3a20%3aA6%3a14%3a84%3a81/rules4.txt`` MAC address: ``A0:20:A6:14:84:81`` -The URL will not be stored, unless the build is made with ``USE_CUSTOM_PROVISIONING`` defined and the option is checked to save the URL. (option only present when ``USE_CUSTOM_PROVISIONING`` defined) +The URL will not be stored, unless the build is made with ``FEATURE_CUSTOM_PROVISIONING`` defined and the option is checked to save the URL. (option only present when ``FEATURE_CUSTOM_PROVISIONING`` defined) Using system variables may allow for multi stage setup of a node, as you could for example fetch a rule which may set a variable to a new value and thus new files may be fetched from a different URL. @@ -909,7 +909,7 @@ Provisioning Added: 2022/05/03 -When the build is made with ``USE_CUSTOM_PROVISIONING`` defined, this Settings Archive screen does allow for more settings helping deployment and remote administration of ESPEasy nodes. +When the build is made with ``FEATURE_CUSTOM_PROVISIONING`` defined, this Settings Archive screen does allow for more settings helping deployment and remote administration of ESPEasy nodes. All Settings on the Settings Archive page can be stored in a file named ``provisioning.dat``. This file also can store the factory default settings like the device model to ease deployment of a large number of nodes. diff --git a/src/Custom-sample.h b/src/Custom-sample.h index c56bd789f8..3e0f81b1ab 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -183,7 +183,7 @@ // This is only allowed for custom builds. // To setup the configuration of the provisioning file, one must also define USE_SETTINGS_ARCHIVE // Default setting is to not allow to configure a node remotely, unless explicitly enabled. -// #define USE_CUSTOM_PROVISIONING +// #define FEATURE_CUSTOM_PROVISIONING 1 #define USES_SSDP @@ -208,7 +208,7 @@ // #define ADAGFX_SUPPORT_7COLOR 0 // Disable the support of 7-color eInk displays by AdafruitGFX_helper -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING // For device models, see src/src/DataTypes/DeviceModel.h // #ifdef ESP32 // #define DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL 0 // DeviceModel_default diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 80d7336042..e8cc3a187c 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -390,7 +390,7 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_A( "pcfpulse", Command_GPIO_Pulse, 3); // GPIO.h } COMMAND_CASE_R("password", Command_Settings_Password, 1); // Settings.h -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING COMMAND_CASE_A( "provisionconfig", Command_Provisioning_Config, 0); // Provisioning.h COMMAND_CASE_A( "provisionsecurity", Command_Provisioning_Security, 0); // Provisioning.h COMMAND_CASE_A( "provisionnotification", Command_Provisioning_Notification, 0); // Provisioning.h diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp index 4ee832fdf4..559dbf545b 100644 --- a/src/src/Commands/Provisioning.cpp +++ b/src/src/Commands/Provisioning.cpp @@ -1,7 +1,7 @@ #include "../Commands/Provisioning.h" -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING # include "../Commands/Common.h" @@ -51,4 +51,4 @@ String Command_Provisioning_Firmware(struct EventStruct *event, const char *Line } -#endif // ifdef USE_CUSTOM_PROVISIONING +#endif // if FEATURE_CUSTOM_PROVISIONING diff --git a/src/src/Commands/Provisioning.h b/src/src/Commands/Provisioning.h index 2911ed0dd8..2b1299cf38 100644 --- a/src/src/Commands/Provisioning.h +++ b/src/src/Commands/Provisioning.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING class String; @@ -21,6 +21,6 @@ String Command_Provisioning_Rules(struct EventStruct *event, String Command_Provisioning_Firmware(struct EventStruct *event, const char *Line); -#endif // ifdef USE_CUSTOM_PROVISIONING +#endif // if FEATURE_CUSTOM_PROVISIONING #endif // ifndef COMMANDS_PROVISIONING_H diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index 7ecec4bcce..49630cf507 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -331,7 +331,7 @@ #endif // --- Defaults to be used for custom automatic provisioning builds ------------------------------------ -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING #ifndef DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL #define DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL 0 // DeviceModel_default #endif @@ -377,7 +377,7 @@ #ifndef DEFAULT_PROVISIONING_PASS #define DEFAULT_PROVISIONING_PASS "" #endif -#endif +#endif // if FEATURE_CUSTOM_PROVISIONING #ifndef BUILD_IN_WEBHEADER #define BUILD_IN_WEBHEADER false diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index c4b2a8884f..aa71763d66 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1982,7 +1982,7 @@ To create/register a plugin, you have to : #endif #endif -#if defined(USE_SETTINGS_ARCHIVE) || defined(USE_CUSTOM_PROVISIONING) +#if defined(USE_SETTINGS_ARCHIVE) || FEATURE_CUSTOM_PROVISIONING #ifndef FEATURE_DOWNLOAD #define FEATURE_DOWNLOAD 1 #endif diff --git a/src/src/DataStructs/ProvisioningStruct.cpp b/src/src/DataStructs/ProvisioningStruct.cpp index 43f2eeddd8..fbbbd209ac 100644 --- a/src/src/DataStructs/ProvisioningStruct.cpp +++ b/src/src/DataStructs/ProvisioningStruct.cpp @@ -1,6 +1,6 @@ #include "../DataStructs/ProvisioningStruct.h" -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING # include "../Helpers/StringConverter.h" # include "../Helpers/Hardware.h" @@ -37,4 +37,4 @@ bool ProvisioningStruct::setUrl(const String& url_str) return safe_strncpy(url, url_str, sizeof(url)); } -#endif // ifdef USE_CUSTOM_PROVISIONING +#endif // if FEATURE_CUSTOM_PROVISIONING diff --git a/src/src/DataStructs/ProvisioningStruct.h b/src/src/DataStructs/ProvisioningStruct.h index 4036e7a45f..7e5f6af2bf 100644 --- a/src/src/DataStructs/ProvisioningStruct.h +++ b/src/src/DataStructs/ProvisioningStruct.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING # include "../CustomBuild/ESPEasyLimits.h" # include "../DataStructs/FactoryDefaultPref.h" @@ -42,6 +42,6 @@ typedef std::shared_ptr ProvisioningStruct_ptr_type; # define AllocatedProvisioningSettings() (ProvisioningStruct_ptr.get() != nullptr) -#endif // ifdef USE_CUSTOM_PROVISIONING +#endif // if FEATURE_CUSTOM_PROVISIONING #endif // ifndef DATASTRUCTS_PROVISIONINGSTRUCT_H diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 8481d413e2..4545f667c2 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -27,7 +27,7 @@ \*********************************************************************************************/ void ResetFactory() { - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING if (ResetFactoryDefaultPreference.getPreference() == 0) { ResetFactoryDefaultPreference.setDeviceModel(static_cast(DEFAULT_FACTORY_DEFAULT_DEVICE_MODEL)); @@ -93,7 +93,7 @@ void ResetFactory() return; } -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING { MakeProvisioningSettings(ProvisioningSettings); if (AllocatedProvisioningSettings()) { diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index bec385f59a..46d81572d3 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -508,7 +508,7 @@ void afterloadSettings() { // Load ResetFactoryDefaultPreference from provisioning.dat if available. uint32_t pref_temp = Settings.ResetFactoryDefaultPreference; - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING if (fileExists(getFileName(FileType::PROVISIONING_DAT))) { MakeProvisioningSettings(ProvisioningSettings); if (AllocatedProvisioningSettings()) { @@ -1059,7 +1059,7 @@ String LoadCustomControllerSettings(controllerIndex_t ControllerIndex, uint8_t * } -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING /********************************************************************************************\ Save Provisioning Settings \*********************************************************************************************/ @@ -1827,7 +1827,7 @@ String downloadFileType(const String& url, const String& user, const String& pas #endif // if FEATURE_DOWNLOAD -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING String downloadFileType(FileType::Enum filetype, unsigned int filenr) { @@ -1849,4 +1849,4 @@ String downloadFileType(FileType::Enum filetype, unsigned int filenr) return downloadFileType(url, user, pass, filetype, filenr); } -#endif // ifdef USE_CUSTOM_PROVISIONING +#endif // if FEATURE_CUSTOM_PROVISIONING diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index 7fb3255046..e9b799d7ed 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -169,7 +169,7 @@ String SaveCustomControllerSettings(controllerIndex_t ControllerIndex, const uin String LoadCustomControllerSettings(controllerIndex_t ControllerIndex, uint8_t *memAddress, int datasize); -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING /********************************************************************************************\ Save Provisioning Settings \*********************************************************************************************/ @@ -296,7 +296,7 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin String downloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr = 0); #endif // if FEATURE_DOWNLOAD -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING // Download file type based on settings stored in provisioning.dat file. String downloadFileType(FileType::Enum filetype, unsigned int filenr = 0); diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index d26d27b4bd..f3aa4864f6 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -16,7 +16,7 @@ #include "../DataStructs/NodeStruct.h" #include "../DataStructs/PortStatusStruct.h" #include "../DataStructs/ProtocolStruct.h" -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING #include "../DataStructs/ProvisioningStruct.h" #endif #include "../DataStructs/RTCStruct.h" @@ -80,7 +80,7 @@ void run_compiletime_checks() { #ifdef ESP8266 const unsigned int SettingsStructSize = (292 + 84 * TASKS_MAX); #endif - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING check_size(); #endif check_size(); diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index c9b30b0bfb..50cac698cf 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -48,7 +48,7 @@ void handle_settingsarchive() { } ResetFactoryDefaultPreference.deleteFirst(isFormItemChecked(F("del"))); -#ifdef USE_CUSTOM_PROVISIONING +#if FEATURE_CUSTOM_PROVISIONING ResetFactoryDefaultPreference.saveURL(isFormItemChecked(F("saveurl"))); ResetFactoryDefaultPreference.allowFetchByCommand(isFormItemChecked(F("allowcommand"))); ResetFactoryDefaultPreference.storeCredentials(isFormItemChecked(F("savecred"))); @@ -56,7 +56,7 @@ void handle_settingsarchive() { applyFactoryDefaultPref(); String error; - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING { MakeProvisioningSettings(ProvisioningSettings); if (AllocatedProvisioningSettings()) { @@ -128,7 +128,7 @@ void handle_settingsarchive() { String url, user, pass; { - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING { MakeProvisioningSettings(ProvisioningSettings); if (AllocatedProvisioningSettings()) { @@ -153,12 +153,12 @@ void handle_settingsarchive() { addFormTextBox(F("URL with settings"), F("url"), url, 256); addFormNote(F("Only HTTP supported. Do not include filename. URL is allowed to contain system variables.")); - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING addFormCheckBox(F("Store URL"), F("saveurl"), ResetFactoryDefaultPreference.saveURL()); #endif addFormTextBox(F("User"), F("user"), user, 64); addFormPasswordBox(F("Pass"), F("pass"), pass, 64); - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING addFormCheckBox(F("Store Credentials"), F("savecred"), ResetFactoryDefaultPreference.storeCredentials()); #endif } @@ -168,7 +168,7 @@ void handle_settingsarchive() { addRowLabel(F("Delete First")); addCheckBox(F("del"), ResetFactoryDefaultPreference.deleteFirst()); addFormNote(F("Needed on filesystem with not enough free space. Use with care!")); - #ifdef USE_CUSTOM_PROVISIONING + #if FEATURE_CUSTOM_PROVISIONING addFormCheckBox(F("Allow Fetch by Command"), F("allowcommand"), ResetFactoryDefaultPreference.allowFetchByCommand()); addFormNote(F("Fetch files via a command does need stored URL (+ credentials)")); #endif diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index fa6f315f2b..cdde3f1beb 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -69,7 +69,7 @@ "-DUSE_SETTINGS_ARCHIVE", "-DFEATURE_ESPEASY_P2P=1", - "-DUSE_CUSTOM_PROVISIONING" + "-DFEATURE_CUSTOM_PROVISIONING=1" ] diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index e8f40d73de..67ef0dadb0 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -63,7 +63,7 @@ "-DUSE_EXT_RTC", "-DFEATURE_I2CMULTIPLEXER", "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", - "-DUSE_CUSTOM_PROVISIONING", + "-DFEATURE_CUSTOM_PROVISIONING=1", "-DFEATURE_ESPEASY_P2P=1", From f215a0e6b9e590bdfa933f312288977e4c146b15 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 24 Jul 2022 23:07:29 +0200 Subject: [PATCH 264/404] [Build] Rename USE_SETTINGS_ARCHIVE to FEATURE_SETTINGS_ARCHIVE and use 0/1 state --- docs/source/Tools/Tools.rst | 5 ++-- memanalyzer.py | 2 +- src/Custom-sample.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 29 +++++++++++++----------- src/src/WebServer/SettingsArchive.cpp | 4 ++-- src/src/WebServer/SettingsArchive.h | 4 ++-- src/src/WebServer/ToolsPage.cpp | 4 ++-- src/src/WebServer/WebServer.cpp | 4 ++-- tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 10 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/source/Tools/Tools.rst b/docs/source/Tools/Tools.rst index 8d89ba5255..fa7c417fa6 100644 --- a/docs/source/Tools/Tools.rst +++ b/docs/source/Tools/Tools.rst @@ -867,7 +867,8 @@ The old settings are still active in memory and if something will be saved, only This would corrupt the settings file. -With only ``USE_SETTINGS_ARCHIVE`` defined during build, the URL and credentials cannot be stored. +With only ``FEATURE_SETTINGS_ARCHIVE`` defined during build, the URL and credentials cannot be stored. +(2022/07/24: Renamed USE_SETTINGS_ARCHIVE to FEATURE_SETTINGS_ARCHIVE) For this the build must be made with ``FEATURE_CUSTOM_PROVISIONING`` defined. N.B. ``FEATURE_CUSTOM_PROVISIONING`` is added on 2022/05/13. (2022/07/24: Renamed from USE_CUSTOM_PROVISIONING to FEATURE_CUSTOM_PROVISIONING) @@ -914,7 +915,7 @@ When the build is made with ``FEATURE_CUSTOM_PROVISIONING`` defined, this Settin All Settings on the Settings Archive page can be stored in a file named ``provisioning.dat``. This file also can store the factory default settings like the device model to ease deployment of a large number of nodes. -N.B. The ``USE_SETTINGS_ARCHIVE`` define is needed to allow to edit the ``provisioning.dat`` file, but it is not needed to use the provisioning feature. +N.B. The ``FEATURE_SETTINGS_ARCHIVE`` define is needed to allow to edit the ``provisioning.dat`` file, but it is not needed to use the provisioning feature. .. image:: images/SettingsArchive_provisioning.png diff --git a/memanalyzer.py b/memanalyzer.py index a2a4566b70..5d158c45ed 100755 --- a/memanalyzer.py +++ b/memanalyzer.py @@ -122,7 +122,7 @@ def analyse_memory(elfFile): plugins.append(buildflag) plugins.append('MQTT_ONLY') - plugins.append('USE_SETTINGS_ARCHIVE') + plugins.append('FEATURE_SETTINGS_ARCHIVE=1') plugins.append('WEBSERVER_RULES_DEBUG=1') plugins.append('WEBSERVER_TIMINGSTATS') plugins.append('WEBSERVER_NEW_UI') diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 3e0f81b1ab..905029748c 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -181,7 +181,7 @@ // Allow for remote provisioning of a node. // This is only allowed for custom builds. -// To setup the configuration of the provisioning file, one must also define USE_SETTINGS_ARCHIVE +// To setup the configuration of the provisioning file, one must also define FEATURE_SETTINGS_ARCHIVE // Default setting is to not allow to configure a node remotely, unless explicitly enabled. // #define FEATURE_CUSTOM_PROVISIONING 1 @@ -200,7 +200,7 @@ -// #define USE_SETTINGS_ARCHIVE +// #define FEATURE_SETTINGS_ARCHIVE 1 // #define FEATURE_I2CMULTIPLEXER // #define USE_TRIGONOMETRIC_FUNCTIONS_RULES // #define PLUGIN_USES_ADAFRUITGFX // Used by Display plugins using Adafruit GFX library diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index aa71763d66..c0bdec4ddc 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -155,14 +155,15 @@ To create/register a plugin, you have to : * Available options ********************************************************** \******************************************************************************/ #if defined(CORE_POST_2_5_0) && !defined(MEMORY_ANALYSIS) && !defined(USE_CUSTOM_H) - #ifndef USE_SETTINGS_ARCHIVE + #ifndef FEATURE_SETTINGS_ARCHIVE // FIXME TD-er: Disabled for now, to reduce binary size -// #define USE_SETTINGS_ARCHIVE - #endif // USE_SETTINGS_ARCHIVE +// #define FEATURE_SETTINGS_ARCHIVE 1 + #endif // ifndef FEATURE_SETTINGS_ARCHIVE #endif -#if defined(USE_SETTINGS_ARCHIVE) && defined(FORCE_PRE_2_5_0) - #undef USE_SETTINGS_ARCHIVE +#if FEATURE_SETTINGS_ARCHIVE && defined(FORCE_PRE_2_5_0) + #undef FEATURE_SETTINGS_ARCHIVE + #define FEATURE_SETTINGS_ARCHIVE 0 #endif @@ -357,9 +358,10 @@ To create/register a plugin, you have to : #define PLUGIN_SET_NONE - #ifdef USE_SETTINGS_ARCHIVE - #undef USE_SETTINGS_ARCHIVE - #endif // USE_SETTINGS_ARCHIVE + #if FEATURE_SETTINGS_ARCHIVE + #undef FEATURE_SETTINGS_ARCHIVE + #define FEATURE_SETTINGS_ARCHIVE 0 + #endif // if FEATURE_SETTINGS_ARCHIVE #ifdef USES_TIMING_STATS #undef USES_TIMING_STATS @@ -1524,8 +1526,8 @@ To create/register a plugin, you have to : #ifndef USE_RTTTL #define USE_RTTTL #endif - #ifndef USE_SETTINGS_ARCHIVE - #define USE_SETTINGS_ARCHIVE + #ifndef FEATURE_SETTINGS_ARCHIVE + #define FEATURE_SETTINGS_ARCHIVE 1 #endif #ifndef FEATURE_SD #define FEATURE_SD 1 @@ -1829,8 +1831,9 @@ To create/register a plugin, you have to : #ifdef FEATURE_I2CMULTIPLEXER #undef FEATURE_I2CMULTIPLEXER #endif - #ifdef USE_SETTINGS_ARCHIVE - #undef USE_SETTINGS_ARCHIVE + #if FEATURE_SETTINGS_ARCHIVE + #undef FEATURE_SETTINGS_ARCHIVE + #define FEATURE_SETTINGS_ARCHIVE 0 #endif #ifdef USE_SERVO @@ -1982,7 +1985,7 @@ To create/register a plugin, you have to : #endif #endif -#if defined(USE_SETTINGS_ARCHIVE) || FEATURE_CUSTOM_PROVISIONING +#if FEATURE_SETTINGS_ARCHIVE || FEATURE_CUSTOM_PROVISIONING #ifndef FEATURE_DOWNLOAD #define FEATURE_DOWNLOAD 1 #endif diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index 50cac698cf..2ccf2b7d60 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -1,6 +1,6 @@ #include "../WebServer/SettingsArchive.h" -#ifdef USE_SETTINGS_ARCHIVE +#if FEATURE_SETTINGS_ARCHIVE #include "../WebServer/WebServer.h" #include "../WebServer/HTML_wrappers.h" @@ -241,4 +241,4 @@ bool tryDownloadFileType(const String& url, const String& user, const String& pa return false; } -#endif // ifdef USE_SETTINGS_ARCHIVE +#endif // if FEATURE_SETTINGS_ARCHIVE diff --git a/src/src/WebServer/SettingsArchive.h b/src/src/WebServer/SettingsArchive.h index 8264415eee..b0a6a94ae4 100644 --- a/src/src/WebServer/SettingsArchive.h +++ b/src/src/WebServer/SettingsArchive.h @@ -3,7 +3,7 @@ #include "../WebServer/common.h" -#ifdef USE_SETTINGS_ARCHIVE +#if FEATURE_SETTINGS_ARCHIVE #include "../DataTypes/ESPEasyFileType.h" @@ -22,6 +22,6 @@ void storeDownloadFiletypeCheckbox(FileType::Enum filetype, unsigned int filenr bool tryDownloadFileType(const String& url, const String& user, const String& pass, FileType::Enum filetype, unsigned int filenr = 0); -#endif // ifdef USE_SETTINGS_ARCHIVE +#endif // if FEATURE_SETTINGS_ARCHIVE #endif \ No newline at end of file diff --git a/src/src/WebServer/ToolsPage.cpp b/src/src/WebServer/ToolsPage.cpp index 08508545cd..13f85faba0 100644 --- a/src/src/WebServer/ToolsPage.cpp +++ b/src/src/WebServer/ToolsPage.cpp @@ -166,9 +166,9 @@ void handle_tools() { addWideButtonPlusDescription(F("filelist"), F("File browser"), F("Show files on internal flash file system")); addWideButtonPlusDescription(F("/factoryreset"), F("Factory Reset"), F("Select pre-defined configuration or full erase of settings")); - # ifdef USE_SETTINGS_ARCHIVE + # if FEATURE_SETTINGS_ARCHIVE addWideButtonPlusDescription(F("/settingsarchive"), F("Settings Archive"), F("Download settings from some archive")); - # endif // ifdef USE_SETTINGS_ARCHIVE + # endif // if FEATURE_SETTINGS_ARCHIVE # if FEATURE_SD addWideButtonPlusDescription(F("SDfilelist"), F("SD Card"), F("Show files on SD-Card")); # endif // if FEATURE_SD diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 12bd094fda..86c49da9d3 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -231,9 +231,9 @@ void WebServerInit() #ifdef WEBSERVER_FACTORY_RESET web_server.on(F("/factoryreset"), handle_factoryreset); #endif // ifdef WEBSERVER_FACTORY_RESET - #ifdef USE_SETTINGS_ARCHIVE + #if FEATURE_SETTINGS_ARCHIVE web_server.on(F("/settingsarchive"), handle_settingsarchive); - #endif // ifdef USE_SETTINGS_ARCHIVE + #endif // if FEATURE_SETTINGS_ARCHIVE web_server.on(F("/favicon.ico"), handle_favicon); #ifdef WEBSERVER_FILELIST web_server.on(F("/filelist"), handle_filelist); diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index cdde3f1beb..8b1cc07bee 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -67,7 +67,7 @@ "-DUSES_PLUGIN_STATS", "-DUSES_CHART_JS", - "-DUSE_SETTINGS_ARCHIVE", + "-DFEATURE_SETTINGS_ARCHIVE=1", "-DFEATURE_ESPEASY_P2P=1", "-DFEATURE_CUSTOM_PROVISIONING=1" ] diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 67ef0dadb0..2a93fdd0d8 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -67,7 +67,7 @@ "-DFEATURE_ESPEASY_P2P=1", - "-DUSE_SETTINGS_ARCHIVE" + "-DFEATURE_SETTINGS_ARCHIVE=1" ] my_flags = env.ParseFlags(env['BUILD_FLAGS']) From 90f4c1b6dfa6ed713195783b9ed9d45ea71fc557 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 20:44:02 +0200 Subject: [PATCH 265/404] [Build] Rename USE_TRIGONOMETRIC_FUNCTIONS_RULES to FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES and use 0/1 state --- src/Custom-sample.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 12 ++++++------ src/src/Helpers/Rules_calculate.cpp | 12 ++++++------ tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 905029748c..cd25277a9b 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -202,7 +202,7 @@ // #define FEATURE_SETTINGS_ARCHIVE 1 // #define FEATURE_I2CMULTIPLEXER -// #define USE_TRIGONOMETRIC_FUNCTIONS_RULES +// #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 // #define PLUGIN_USES_ADAFRUITGFX // Used by Display plugins using Adafruit GFX library // #define ADAGFX_ARGUMENT_VALIDATION 0 // Disable argument validation in AdafruitGFX_helper // #define ADAGFX_SUPPORT_7COLOR 0 // Disable the support of 7-color eInk displays by AdafruitGFX_helper diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index c0bdec4ddc..f9a6848b8e 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -129,8 +129,8 @@ To create/register a plugin, you have to : #ifndef FEATURE_I2CMULTIPLEXER #define FEATURE_I2CMULTIPLEXER #endif - #ifndef USE_TRIGONOMETRIC_FUNCTIONS_RULES - #define USE_TRIGONOMETRIC_FUNCTIONS_RULES + #ifndef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES + #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 #endif #ifndef USE_EXT_RTC #define USE_EXT_RTC @@ -306,8 +306,8 @@ To create/register a plugin, you have to : #ifndef FEATURE_I2CMULTIPLEXER #define FEATURE_I2CMULTIPLEXER #endif - #ifndef USE_TRIGONOMETRIC_FUNCTIONS_RULES - #define USE_TRIGONOMETRIC_FUNCTIONS_RULES + #ifndef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES + #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 #endif #define KEEP_TRIGONOMETRIC_FUNCTIONS_RULES #ifndef USES_PLUGIN_STATS @@ -1874,8 +1874,8 @@ To create/register a plugin, you have to : #ifdef USES_C018 #undef USES_C018 // LoRa TTN - RN2483/RN2903 #endif - #if defined(USE_TRIGONOMETRIC_FUNCTIONS_RULES) && !defined(KEEP_TRIGONOMETRIC_FUNCTIONS_RULES) - #undef USE_TRIGONOMETRIC_FUNCTIONS_RULES + #if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES && !defined(KEEP_TRIGONOMETRIC_FUNCTIONS_RULES) + #undef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES #endif #ifdef USES_SSDP #undef USES_SSDP diff --git a/src/src/Helpers/Rules_calculate.cpp b/src/src/Helpers/Rules_calculate.cpp index 53c61f4970..dab8e5ac5a 100644 --- a/src/src/Helpers/Rules_calculate.cpp +++ b/src/src/Helpers/Rules_calculate.cpp @@ -149,7 +149,7 @@ double RulesCalculate_t::apply_unary_operator(char op, double first) break; } -#ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES const bool useDegree = angleDegree(un_op); // First the trigonometric functions with angle as output @@ -188,7 +188,7 @@ double RulesCalculate_t::apply_unary_operator(char op, double first) default: break; } -#else // ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#else // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES switch (un_op) { case UnaryOperator::Sin: @@ -203,12 +203,12 @@ double RulesCalculate_t::apply_unary_operator(char op, double first) case UnaryOperator::ArcCos_d: case UnaryOperator::ArcTan: case UnaryOperator::ArcTan_d: - addLog(LOG_LEVEL_ERROR, F("USE_TRIGONOMETRIC_FUNCTIONS_RULES not defined in build")); + addLog(LOG_LEVEL_ERROR, F("FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES not defined in build")); break; default: break; } -#endif // ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#endif // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES return ret; } @@ -577,7 +577,7 @@ String RulesCalculate_t::preProces(const String& input) preProcessReplace(preprocessed, UnaryOperator::Sqrt); preProcessReplace(preprocessed, UnaryOperator::Sq); preProcessReplace(preprocessed, UnaryOperator::Round); -#ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES // Try the "arc" functions first, or else "sin" is already replaced when "asin" is tried. if (preprocessed.indexOf(F("sin")) != -1) { @@ -600,7 +600,7 @@ String RulesCalculate_t::preProces(const String& input) preProcessReplace(preprocessed, UnaryOperator::Tan); preProcessReplace(preprocessed, UnaryOperator::Tan_d); } -#endif // ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#endif // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES return preprocessed; } diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 8b1cc07bee..c7959bbfa0 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -62,7 +62,7 @@ "-DUSE_EXT_RTC", "-DFEATURE_SD=1", "-DFEATURE_I2CMULTIPLEXER", - "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", + "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", "-DUSES_PLUGIN_STATS", "-DUSES_CHART_JS", diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 2a93fdd0d8..b905006d6c 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -62,7 +62,7 @@ # "-DFEATURE_SD=1", "-DUSE_EXT_RTC", "-DFEATURE_I2CMULTIPLEXER", - "-DUSE_TRIGONOMETRIC_FUNCTIONS_RULES", + "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", "-DFEATURE_CUSTOM_PROVISIONING=1", "-DFEATURE_ESPEASY_P2P=1", From 89c3b7429169c3b568529e90129552dff9253831 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 21:00:08 +0200 Subject: [PATCH 266/404] [Build] Change FEATURE_I2CMULTIPLEXER to use 0/1 state --- src/Custom-sample.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 7 +-- src/src/Globals/Plugins.cpp | 4 +- src/src/Helpers/Hardware.cpp | 8 ++-- src/src/Helpers/Hardware.h | 4 +- src/src/WebServer/DevicesPage.cpp | 12 ++--- src/src/WebServer/HardwarePage.cpp | 8 ++-- src/src/WebServer/I2C_Scanner.cpp | 56 ++++++++++++------------ src/src/WebServer/I2C_Scanner.h | 12 ++--- src/src/WebServer/JSON.cpp | 4 +- tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 12 files changed, 61 insertions(+), 60 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index cd25277a9b..9a18e5418d 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -201,7 +201,7 @@ // #define FEATURE_SETTINGS_ARCHIVE 1 -// #define FEATURE_I2CMULTIPLEXER +// #define FEATURE_I2CMULTIPLEXER 1 // #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 // #define PLUGIN_USES_ADAFRUITGFX // Used by Display plugins using Adafruit GFX library // #define ADAGFX_ARGUMENT_VALIDATION 0 // Disable argument validation in AdafruitGFX_helper diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index f9a6848b8e..03ca704d89 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -127,7 +127,7 @@ To create/register a plugin, you have to : #define USES_TIMING_STATS #endif #ifndef FEATURE_I2CMULTIPLEXER - #define FEATURE_I2CMULTIPLEXER + #define FEATURE_I2CMULTIPLEXER 1 #endif #ifndef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 @@ -304,7 +304,7 @@ To create/register a plugin, you have to : #define NOTIFIER_SET_STABLE #ifndef FEATURE_I2CMULTIPLEXER - #define FEATURE_I2CMULTIPLEXER + #define FEATURE_I2CMULTIPLEXER 1 #endif #ifndef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 @@ -1828,8 +1828,9 @@ To create/register a plugin, you have to : #ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER #define BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER #endif - #ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER #undef FEATURE_I2CMULTIPLEXER + #define FEATURE_I2CMULTIPLEXER 0 #endif #if FEATURE_SETTINGS_ARCHIVE #undef FEATURE_SETTINGS_ARCHIVE diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 938e6d6bef..89783ec1ac 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -212,11 +212,11 @@ bool prepare_I2C_by_taskIndex(taskIndex_t taskIndex, deviceIndex_t DeviceIndex) if (I2C_state != I2C_bus_state::OK) { return false; // Bus state is not OK, so do not consider task runnable } -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER I2CMultiplexerSelectByTaskIndex(taskIndex); // Output is selected after this write, so now we must make sure the // frequency is set before anything else is sent. -#endif + #endif // if FEATURE_I2CMULTIPLEXER if (bitRead(Settings.I2C_Flags[taskIndex], I2C_FLAGS_SLOW_SPEED)) { I2CSelectLowClockSpeed(); // Set to slow diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 007f9eac86..edeaaadb91 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -251,13 +251,13 @@ void initI2C() { #endif // ifdef ESP32S2 } -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (validGpio(Settings.I2C_Multiplexer_ResetPin)) { // Initialize Reset pin to High if configured pinMode(Settings.I2C_Multiplexer_ResetPin, OUTPUT); digitalWrite(Settings.I2C_Multiplexer_ResetPin, HIGH); } -#endif // ifdef FEATURE_I2CMULTIPLEXER + #endif // if FEATURE_I2CMULTIPLEXER // I2C Watchdog boot status check if (Settings.WDI2CAddress != 0) @@ -339,7 +339,7 @@ void I2CBegin(int8_t sda, int8_t scl, uint32_t clockFreq) { #endif // ifdef ESP32 } -#ifdef FEATURE_I2CMULTIPLEXER +#if FEATURE_I2CMULTIPLEXER // Check if the I2C Multiplexer is enabled bool isI2CMultiplexerEnabled() { @@ -444,7 +444,7 @@ bool I2CMultiplexerPortSelectedForTask(taskIndex_t taskIndex) { || (bitRead(Settings.I2C_Flags[taskIndex], I2C_FLAGS_MUX_MULTICHANNEL) && Settings.I2C_Multiplexer_Channel[taskIndex] != 0); } -#endif // ifdef FEATURE_I2CMULTIPLEXER +#endif // if FEATURE_I2CMULTIPLEXER void checkResetFactoryPin() { static uint8_t factoryResetCounter = 0; diff --git a/src/src/Helpers/Hardware.h b/src/src/Helpers/Hardware.h index 190c7a3ede..a2feab3116 100644 --- a/src/src/Helpers/Hardware.h +++ b/src/src/Helpers/Hardware.h @@ -49,7 +49,7 @@ void I2CBegin(int8_t sda, int8_t scl, uint32_t clockFreq); -#ifdef FEATURE_I2CMULTIPLEXER +#if FEATURE_I2CMULTIPLEXER bool isI2CMultiplexerEnabled(); void I2CMultiplexerSelectByTaskIndex(taskIndex_t taskIndex); @@ -64,7 +64,7 @@ uint8_t I2CMultiplexerMaxChannels(); void I2CMultiplexerReset(); bool I2CMultiplexerPortSelectedForTask(taskIndex_t taskIndex); -#endif // ifdef FEATURE_I2CMULTIPLEXER +#endif // if FEATURE_I2CMULTIPLEXER void checkResetFactoryPin(); diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 5c963b175f..85394f7b91 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -254,7 +254,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task if (Device[DeviceIndex].Type == DEVICE_TYPE_I2C) { bitWrite(flags, 0, isFormItemChecked(F("taskdeviceflags0"))); } -# ifdef FEATURE_I2CMULTIPLEXER + # if FEATURE_I2CMULTIPLEXER if ((Device[DeviceIndex].Type == DEVICE_TYPE_I2C) && isI2CMultiplexerEnabled()) { int multipleMuxPortsOption = getFormItemInt(F("taskdeviceflags1"), 0); @@ -273,7 +273,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task Settings.I2C_Multiplexer_Channel[taskIndex] = getFormItemInt(F("taskdevicei2cmuxport"), 0); } } -# endif // ifdef FEATURE_I2CMULTIPLEXER + # endif // if FEATURE_I2CMULTIPLEXER if (Device[DeviceIndex].Type == DEVICE_TYPE_I2C) { Settings.I2C_Flags[taskIndex] = flags; @@ -774,7 +774,7 @@ void format_originating_node(uint8_t remoteUnit) { void format_I2C_port_description(taskIndex_t x) { addHtml(F("I2C")); -# ifdef FEATURE_I2CMULTIPLEXER + # if FEATURE_I2CMULTIPLEXER if (isI2CMultiplexerEnabled() && I2CMultiplexerPortSelectedForTask(x)) { String mux; @@ -796,7 +796,7 @@ void format_I2C_port_description(taskIndex_t x) } addHtml(mux); } -# endif // ifdef FEATURE_I2CMULTIPLEXER + # endif // if FEATURE_I2CMULTIPLEXER } void format_SPI_port_description(int8_t spi_gpios[3]) @@ -1107,7 +1107,7 @@ void devicePage_show_I2C_config(taskIndex_t taskIndex) PluginCall(PLUGIN_WEBFORM_SHOW_I2C_PARAMS, &TempEvent, dummy); addFormCheckBox(F("Force Slow I2C speed"), F("taskdeviceflags0"), bitRead(Settings.I2C_Flags[taskIndex], I2C_FLAGS_SLOW_SPEED)); -# ifdef FEATURE_I2CMULTIPLEXER + # if FEATURE_I2CMULTIPLEXER // Show selector for an I2C multiplexer port if a multiplexer is configured if (isI2CMultiplexerEnabled()) { @@ -1182,7 +1182,7 @@ void devicePage_show_I2C_config(taskIndex_t taskIndex) taskDeviceI2CMuxPort); } } -# endif // ifdef FEATURE_I2CMULTIPLEXER + # endif // if FEATURE_I2CMULTIPLEXER } void devicePage_show_output_data_type(taskIndex_t taskIndex, deviceIndex_t DeviceIndex) diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 5464b1518b..20d2b63791 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -42,7 +42,7 @@ void handle_hardware() { Settings.Pin_i2c_scl = getFormItemInt(F("pscl")); Settings.I2C_clockSpeed = getFormItemInt(F("pi2csp"), DEFAULT_I2C_CLOCK_SPEED); Settings.I2C_clockSpeed_Slow = getFormItemInt(F("pi2cspslow"), DEFAULT_I2C_CLOCK_SPEED_SLOW); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER Settings.I2C_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype")); if (Settings.I2C_Multiplexer_Type != I2C_MULTIPLEXER_NONE) { Settings.I2C_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr")); @@ -50,7 +50,7 @@ void handle_hardware() { Settings.I2C_Multiplexer_Addr = -1; } Settings.I2C_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset")); -#endif + #endif // if FEATURE_I2CMULTIPLEXER #ifdef ESP32 Settings.InitSPI = getFormItemInt(F("initspi"), static_cast(SPI_Options_e::None)); if (Settings.InitSPI == static_cast(SPI_Options_e::UserDefined)) { // User-define SPI GPIO pins @@ -117,7 +117,7 @@ void handle_hardware() { addFormNote(F("Use 100 kHz for old I2C devices, 400 kHz is max for most.")); addFormNumericBox(F("Slow device Clock Speed"), F("pi2cspslow"), Settings.I2C_clockSpeed_Slow, 100, 3400000); addUnit(F("Hz")); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER addFormSubHeader(F("I2C Multiplexer")); // Select the type of multiplexer to use { @@ -158,7 +158,7 @@ void handle_hardware() { } addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output_optional(F("Reset")), F("pi2cmuxreset"), Settings.I2C_Multiplexer_ResetPin); addFormNote(F("Will be pulled low to force a reset. Reset is not available on PCA9540.")); -#endif + #endif // if FEATURE_I2CMULTIPLEXER // SPI Init addFormSubHeader(F("SPI Interface")); diff --git a/src/src/WebServer/I2C_Scanner.cpp b/src/src/WebServer/I2C_Scanner.cpp index e2dcca2ef6..04c6c049d1 100644 --- a/src/src/WebServer/I2C_Scanner.cpp +++ b/src/src/WebServer/I2C_Scanner.cpp @@ -22,21 +22,21 @@ int scanI2CbusForDevices_json( // Utility function for scanning the I2C bus for int8_t muxAddr , int8_t channel , int nDevices -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER , i2c_addresses_t &excludeDevices -#endif + #endif // if FEATURE_I2CMULTIPLEXER ) { uint8_t error, address; for (address = 1; address <= 127; address++) { -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER bool skipCheck = false; if (channel != -1 && excludeDevices.size() > address) { skipCheck = excludeDevices[address]; } if (!skipCheck) { // Ignore I2C multiplexer and addresses to exclude when scanning its channels -#endif + #endif // if FEATURE_I2CMULTIPLEXER Wire.beginTransmission(address); error = Wire.endTransmission(); delay(1); @@ -45,7 +45,7 @@ int scanI2CbusForDevices_json( // Utility function for scanning the I2C bus for { json_open(); json_prop(F("addr"), String(formatToHex(address))); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (muxAddr != -1) { if (channel == -1){ json_prop(F("I2Cbus"), F("Standard I2C bus")); @@ -56,7 +56,7 @@ int scanI2CbusForDevices_json( // Utility function for scanning the I2C bus for json_prop(F("I2Cbus"), i2cChannel); } } -#endif + #endif // if FEATURE_I2CMULTIPLEXER json_number(F("status"), String(error)); if (error == 4) { @@ -93,9 +93,9 @@ int scanI2CbusForDevices_json( // Utility function for scanning the I2C bus for json_close(); addHtml('\n'); } -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER } -#endif + #endif // if FEATURE_I2CMULTIPLEXER } return nDevices; } @@ -114,18 +114,18 @@ void handle_i2cscanner_json() { int nDevices = 0; I2CSelect_Max100kHz_ClockSpeed(); // Always scan in low speed to also find old/slow devices -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER i2c_addresses_t mainBusDevices; mainBusDevices.resize(128); for (int i = 0; i < 128; i++) { mainBusDevices[i] = false; } nDevices = scanI2CbusForDevices_json(Settings.I2C_Multiplexer_Addr, -1, nDevices, mainBusDevices); // Channel -1 = standard I2C bus -#else + #else // if FEATURE_I2CMULTIPLEXER nDevices = scanI2CbusForDevices_json(-1, -1, nDevices); // Standard scan -#endif + #endif // if FEATURE_I2CMULTIPLEXER -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (isI2CMultiplexerEnabled()) { uint8_t mux_max = I2CMultiplexerMaxChannels(); for (int8_t channel = 0; channel < mux_max; channel++) { @@ -134,7 +134,7 @@ void handle_i2cscanner_json() { } I2CMultiplexerOff(); } -#endif + #endif // if FEATURE_I2CMULTIPLEXER I2CSelectHighClockSpeed(); // Reset bus to standard speed json_close(true); @@ -333,21 +333,21 @@ int scanI2CbusForDevices( // Utility function for scanning the I2C bus for valid int8_t muxAddr , int8_t channel , int nDevices -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER , i2c_addresses_t &excludeDevices -#endif + #endif // if FEATURE_I2CMULTIPLEXER ) { uint8_t error, address; for (address = 1; address <= 127; address++) { -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER bool skipCheck = false; if (channel != -1 && excludeDevices.size() > address) { skipCheck = excludeDevices[address]; } if (!skipCheck) { // Ignore I2C multiplexer and addresses to exclude when scanning its channels -#endif + #endif // if FEATURE_I2CMULTIPLEXER Wire.beginTransmission(address); error = Wire.endTransmission(); delay(1); @@ -356,7 +356,7 @@ int scanI2CbusForDevices( // Utility function for scanning the I2C bus for valid case 0: { html_TR_TD(); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (muxAddr != -1) { if (channel == -1){ addHtml(F("Standard I2C bus")); @@ -367,7 +367,7 @@ int scanI2CbusForDevices( // Utility function for scanning the I2C bus for valid } html_TD(); } -#endif + #endif // if FEATURE_I2CMULTIPLEXER addHtml(formatToHex(address)); html_TD(); String description = getKnownI2Cdevice(address); @@ -398,9 +398,9 @@ int scanI2CbusForDevices( // Utility function for scanning the I2C bus for valid break; } } -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER } -#endif + #endif // if FEATURE_I2CMULTIPLEXER } return nDevices; } @@ -417,29 +417,29 @@ void handle_i2cscanner() { sendHeadandTail_stdtemplate(_HEAD); html_table_class_multirow(); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (isI2CMultiplexerEnabled()) { html_table_header(F("I2C bus")); } -#endif + #endif // if FEATURE_I2CMULTIPLEXER html_table_header(F("I2C Addresses in use")); html_table_header(F("Supported devices")); if (Settings.isI2CEnabled()) { int nDevices = 0; I2CSelect_Max100kHz_ClockSpeed(); // Scan bus using low speed - #ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER i2c_addresses_t mainBusDevices; mainBusDevices.resize(128); for (int i = 0; i < 128; i++) { mainBusDevices[i] = false; } nDevices = scanI2CbusForDevices(Settings.I2C_Multiplexer_Addr, -1, nDevices, mainBusDevices); // Channel -1 = standard I2C bus - #else + #else // if FEATURE_I2CMULTIPLEXER nDevices = scanI2CbusForDevices(-1, -1, nDevices); // Standard scan - #endif + #endif // if FEATURE_I2CMULTIPLEXER - #ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (isI2CMultiplexerEnabled()) { uint8_t mux_max = I2CMultiplexerMaxChannels(); for (int8_t channel = 0; channel < mux_max; channel++) { @@ -448,7 +448,7 @@ void handle_i2cscanner() { } I2CMultiplexerOff(); } - #endif + #endif // if FEATURE_I2CMULTIPLEXER I2CSelectHighClockSpeed(); // By default the bus is in standard speed if (nDevices == 0) { diff --git a/src/src/WebServer/I2C_Scanner.h b/src/src/WebServer/I2C_Scanner.h index afc472d5bf..e609de5b12 100644 --- a/src/src/WebServer/I2C_Scanner.h +++ b/src/src/WebServer/I2C_Scanner.h @@ -7,10 +7,10 @@ #ifdef WEBSERVER_I2C_SCANNER -#ifdef FEATURE_I2CMULTIPLEXER +#if FEATURE_I2CMULTIPLEXER #include typedef std::vector i2c_addresses_t; -#endif +#endif // if FEATURE_I2CMULTIPLEXER #ifdef WEBSERVER_NEW_UI @@ -22,9 +22,9 @@ int scanI2CbusForDevices_json( // Utility function for scanning the I2C bus for int8_t muxAddr , int8_t channel , int nDevices -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER , i2c_addresses_t &excludeDevices -#endif + #endif // if FEATURE_I2CMULTIPLEXER ); void handle_i2cscanner_json(); @@ -37,9 +37,9 @@ int scanI2CbusForDevices( // Utility function for scanning the I2C bus for valid int8_t muxAddr , int8_t channel , int nDevices -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER , i2c_addresses_t &excludeDevices -#endif + #endif // if FEATURE_I2CMULTIPLEXER ); // FIXME TD-er: Query all included plugins for their supported addresses (return name of plugin) diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 5ddfd51ffb..5a23e19130 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -430,7 +430,7 @@ void handle_json() stream_next_json_object_value(F("Type"), getPluginNameFromDeviceIndex(DeviceIndex)); stream_next_json_object_value(F("TaskName"), getTaskDeviceName(TaskIndex)); stream_next_json_object_value(F("TaskDeviceNumber"), Settings.TaskDeviceNumber[TaskIndex]); -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER if (Device[DeviceIndex].Type == DEVICE_TYPE_I2C && isI2CMultiplexerEnabled()) { int8_t channel = Settings.I2C_Multiplexer_Channel[TaskIndex]; if (bitRead(Settings.I2C_Flags[TaskIndex], I2C_FLAGS_MUX_MULTICHANNEL)) { @@ -456,7 +456,7 @@ void handle_json() } } } -#endif + #endif // if FEATURE_I2CMULTIPLEXER } stream_next_json_object_value(F("TaskEnabled"), jsonBool(Settings.TaskDeviceEnabled[TaskIndex])); stream_last_json_object_value(F("TaskNumber"), TaskIndex + 1); diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index c7959bbfa0..0f738272be 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -61,7 +61,7 @@ "-DUSES_ESPEASY_NOW", "-DUSE_EXT_RTC", "-DFEATURE_SD=1", - "-DFEATURE_I2CMULTIPLEXER", + "-DFEATURE_I2CMULTIPLEXER=1", "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", "-DUSES_PLUGIN_STATS", diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index b905006d6c..bc55d0d2ec 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -61,7 +61,7 @@ # "-DFEATURE_MDNS", # "-DFEATURE_SD=1", "-DUSE_EXT_RTC", - "-DFEATURE_I2CMULTIPLEXER", + "-DFEATURE_I2CMULTIPLEXER=1", "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", "-DFEATURE_CUSTOM_PROVISIONING=1", From d53c3da65214506385d7fb7e0a76c2b2be6c95d5 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 21:32:37 +0200 Subject: [PATCH 267/404] [Build] Rename USES_SSDP to FEATURE_SSDP and use 0/1 state --- src/Custom-sample.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 9 +++++---- src/src/Helpers/Networking.cpp | 4 ++-- src/src/Helpers/Networking.h | 4 ++-- src/src/Helpers/PeriodicalActions.cpp | 4 ++-- src/src/WebServer/AdvancedConfigPage.cpp | 8 ++++---- src/src/WebServer/WebServer.cpp | 4 ++-- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 9a18e5418d..5105edd0b0 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -185,7 +185,7 @@ // Default setting is to not allow to configure a node remotely, unless explicitly enabled. // #define FEATURE_CUSTOM_PROVISIONING 1 -#define USES_SSDP +#define FEATURE_SSDP 1 #define USE_EXT_RTC // Support for external RTC clock modules like PCF8563/PCF8523/DS3231/DS1307 @@ -234,7 +234,7 @@ -#define USES_SSDP +#define FEATURE_SSDP 1 /* ####################################################################################################### diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 03ca704d89..1ee38fec6d 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -120,8 +120,8 @@ To create/register a plugin, you have to : #endif #ifndef PLUGIN_BUILD_CUSTOM - #ifndef USES_SSDP - #define USES_SSDP + #ifndef FEATURE_SSDP + #define FEATURE_SSDP 1 #endif #ifndef USES_TIMING_STATS #define USES_TIMING_STATS @@ -1878,8 +1878,9 @@ To create/register a plugin, you have to : #if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES && !defined(KEEP_TRIGONOMETRIC_FUNCTIONS_RULES) #undef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES #endif - #ifdef USES_SSDP - #undef USES_SSDP + #if FEATURE_SSDP + #undef FEATURE_SSDP + #define FEATURE_SSDP 0 #endif #ifdef USES_PLUGIN_STATS #undef USES_PLUGIN_STATS diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 8cc405f0ad..211e56915f 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -501,7 +501,7 @@ void sendSysInfoUDP(uint8_t repeats) #if defined(ESP8266) -# ifdef USES_SSDP +# if FEATURE_SSDP /********************************************************************************************\ Respond to HTTP XML requests for SSDP information @@ -852,7 +852,7 @@ void SSDP_update() { } } -# endif // ifdef USES_SSDP +# endif // if FEATURE_SSDP #endif // if defined(ESP8266) diff --git a/src/src/Helpers/Networking.h b/src/src/Helpers/Networking.h index db3102b5db..5c239f14e0 100644 --- a/src/src/Helpers/Networking.h +++ b/src/src/Helpers/Networking.h @@ -70,7 +70,7 @@ void sendSysInfoUDP(uint8_t repeats); #if defined(ESP8266) -# ifdef USES_SSDP +# if FEATURE_SSDP /********************************************************************************************\ Respond to HTTP XML requests for SSDP information @@ -119,7 +119,7 @@ void SSDP_send(uint8_t method); \*********************************************************************************************/ void SSDP_update(); -# endif // ifdef USES_SSDP +# endif // if FEATURE_SSDP #endif // if defined(ESP8266) diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 4fa3a7c7db..e40b98f791 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -251,11 +251,11 @@ void runEach30Seconds() CPluginCall(CPlugin::Function::CPLUGIN_INTERVAL, 0); #if defined(ESP8266) - #ifdef USES_SSDP + #if FEATURE_SSDP if (Settings.UseSSDP) SSDP_update(); - #endif // USES_SSDP + #endif // if FEATURE_SSDP #endif #if FEATURE_ADC_VCC if (!WiFiEventData.wifiConnectInProgress) { diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index 89a23963f3..d35729c690 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -68,9 +68,9 @@ void handle_advanced() { ); Settings.DST = isFormItemChecked(F("dst")); Settings.WDI2CAddress = getFormItemInt(F("wdi2caddress")); - #ifdef USES_SSDP + #if FEATURE_SSDP Settings.UseSSDP = isFormItemChecked(F("usessdp")); - #endif // USES_SSDP + #endif // if FEATURE_SSDP Settings.WireClockStretchLimit = getFormItemInt(F("wireclockstretchlimit")); Settings.UseRules = isFormItemChecked(F("userules")); Settings.ConnectionFailuresThreshold = getFormItemInt(LabelType::CONNECTION_FAIL_THRESH); @@ -258,9 +258,9 @@ void handle_advanced() { #endif - #ifdef USES_SSDP + #if FEATURE_SSDP addFormCheckBox_disabled(F("Use SSDP"), F("usessdp"), Settings.UseSSDP); - #endif // ifdef USES_SSDP + #endif // if FEATURE_SSDP addFormNumericBox(LabelType::CONNECTION_FAIL_THRESH, Settings.ConnectionFailuresThreshold, 0, 100); #ifdef ESP8266 diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 86c49da9d3..6e99c23232 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -329,7 +329,7 @@ void WebServerInit() #if defined(ESP8266) - # ifdef USES_SSDP + # if FEATURE_SSDP if (Settings.UseSSDP) { @@ -340,7 +340,7 @@ void WebServerInit() }); SSDP_begin(); } - # endif // USES_SSDP + # endif // if FEATURE_SSDP #endif // if defined(ESP8266) } From 799f5f50aedaa7ae172e0e59df11323a044f5f08 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 21:46:14 +0200 Subject: [PATCH 268/404] [Build] Rename USES_TIMING_STATS to FEATURE_TIMING_STATS and use 0/1 state --- src/src/CustomBuild/define_plugin_sets.h | 18 ++++++++++-------- src/src/DataStructs/TimingStats.cpp | 4 ++-- src/src/DataStructs/TimingStats.h | 6 +++--- src/src/ESPEasyCore/ESPEasy_loop.cpp | 4 ++-- src/src/Globals/Plugins.cpp | 12 ++++++------ src/src/Helpers/ESPEasyStatistics.cpp | 4 ++-- src/src/Helpers/ESPEasyStatistics.h | 4 ++-- src/src/WebServer/AdvancedConfigPage.cpp | 4 ++-- src/src/WebServer/JSON.cpp | 4 ++-- src/src/WebServer/TimingStats.cpp | 2 +- src/src/WebServer/TimingStats.h | 2 +- src/src/WebServer/WebServer.cpp | 4 ++-- 12 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 1ee38fec6d..f05374c881 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -123,8 +123,8 @@ To create/register a plugin, you have to : #ifndef FEATURE_SSDP #define FEATURE_SSDP 1 #endif - #ifndef USES_TIMING_STATS - #define USES_TIMING_STATS + #ifndef FEATURE_TIMING_STATS + #define FEATURE_TIMING_STATS 1 #endif #ifndef FEATURE_I2CMULTIPLEXER #define FEATURE_I2CMULTIPLEXER 1 @@ -363,8 +363,9 @@ To create/register a plugin, you have to : #define FEATURE_SETTINGS_ARCHIVE 0 #endif // if FEATURE_SETTINGS_ARCHIVE - #ifdef USES_TIMING_STATS - #undef USES_TIMING_STATS + #if FEATURE_TIMING_STATS + #undef FEATURE_TIMING_STATS + #define FEATURE_TIMING_STATS 0 #endif #ifndef USES_P001 @@ -1891,13 +1892,14 @@ To create/register a plugin, you have to : #endif // Timing stats page needs timing stats -#if defined(WEBSERVER_TIMINGSTATS) && !defined(USES_TIMING_STATS) - #define USES_TIMING_STATS +#if defined(WEBSERVER_TIMINGSTATS) && !FEATURE_TIMING_STATS + #define FEATURE_TIMING_STATS 1 #endif // If timing stats page is not included, there is no need in collecting the stats -#if !defined(WEBSERVER_TIMINGSTATS) && defined(USES_TIMING_STATS) - #undef USES_TIMING_STATS +#if !defined(WEBSERVER_TIMINGSTATS) && FEATURE_TIMING_STATS + #undef FEATURE_TIMING_STATS + #define FEATURE_TIMING_STATS 0 #endif diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index a16c2126e1..ad1699f4dd 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -7,7 +7,7 @@ #include "../Helpers/StringConverter.h" -#ifdef USES_TIMING_STATS +#if FEATURE_TIMING_STATS std::map pluginStats; @@ -266,4 +266,4 @@ String getMiscStatsName(int stat) { return getMiscStatsName_F(stat); } -#endif \ No newline at end of file +#endif // if FEATURE_TIMING_STATS \ No newline at end of file diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 3ffd14906b..28aa0ec84f 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -5,7 +5,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_TIMING_STATS +#if FEATURE_TIMING_STATS #include "../Helpers/ESPEasy_time_calc.h" @@ -148,7 +148,7 @@ extern unsigned long timingstats_last_reset; // Add a timer statistic value in usec. # define ADD_TIMER_STAT(L, T) if (Settings.EnableTimingStats()) { miscStats[L].add(T); } -#else // ifdef USES_TIMING_STATS +#else // if FEATURE_TIMING_STATS # define START_TIMER ; # define STOP_TIMER_TASK(T, F) ; @@ -162,6 +162,6 @@ extern unsigned long timingstats_last_reset; // Meaning we must make sure the forward declaration of the TimingStats class is made, since it is used as an argument in some function. class TimingStats; -#endif // ifdef USES_TIMING_STATS +#endif // if FEATURE_TIMING_STATS #endif // DATASTRUCTS_TIMINGSTATS_H diff --git a/src/src/ESPEasyCore/ESPEasy_loop.cpp b/src/src/ESPEasyCore/ESPEasy_loop.cpp index 0bd2e288bd..813f49f7f6 100644 --- a/src/src/ESPEasyCore/ESPEasy_loop.cpp +++ b/src/src/ESPEasyCore/ESPEasy_loop.cpp @@ -31,9 +31,9 @@ void updateLoopStats() { } const int64_t usecSince = usecPassedSince(lastLoopStart); - #ifdef USES_TIMING_STATS + #if FEATURE_TIMING_STATS miscStats[LOOP_STATS].add(usecSince); - #endif // ifdef USES_TIMING_STATS + #endif // if FEATURE_TIMING_STATS loop_usec_duration_total += usecSince; lastLoopStart = getMicros64(); diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 89783ec1ac..cc6cf3a82c 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -622,11 +622,11 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) descr.reserve(20); descr = F("PluginCall_task_"); descr += (event->TaskIndex + 1); - #ifdef USES_TIMING_STATS + #if FEATURE_TIMING_STATS checkRAM(descr, getPluginFunctionName(Function)); - #else + #else // if FEATURE_TIMING_STATS checkRAM(descr, String(Function)); - #endif + #endif // if FEATURE_TIMING_STATS #endif } if (!prepare_I2C_by_taskIndex(event->TaskIndex, DeviceIndex)) { @@ -747,11 +747,11 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) descr.reserve(20); descr = F("PluginCall_task_"); descr += (event->TaskIndex + 1); - #ifdef USES_TIMING_STATS + #if FEATURE_TIMING_STATS checkRAM(descr, getPluginFunctionName(Function)); - #else + #else // if FEATURE_TIMING_STATS checkRAM(descr, String(Function)); - #endif + #endif // if FEATURE_TIMING_STATS #endif } diff --git a/src/src/Helpers/ESPEasyStatistics.cpp b/src/src/Helpers/ESPEasyStatistics.cpp index 108dc1d622..a013fd7b49 100644 --- a/src/src/Helpers/ESPEasyStatistics.cpp +++ b/src/src/Helpers/ESPEasyStatistics.cpp @@ -1,7 +1,7 @@ #include "../Helpers/ESPEasyStatistics.h" -#ifdef USES_TIMING_STATS +#if FEATURE_TIMING_STATS #include "../DataStructs/TimingStats.h" #include "../WebServer/WebServer.h" @@ -182,4 +182,4 @@ void jsonStatistics(bool clearStats) { } -#endif \ No newline at end of file +#endif // if FEATURE_TIMING_STATS \ No newline at end of file diff --git a/src/src/Helpers/ESPEasyStatistics.h b/src/src/Helpers/ESPEasyStatistics.h index 20a3bdd6c2..f35f28ddba 100644 --- a/src/src/Helpers/ESPEasyStatistics.h +++ b/src/src/Helpers/ESPEasyStatistics.h @@ -5,7 +5,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_TIMING_STATS +#if FEATURE_TIMING_STATS #include "../DataStructs/TimingStats.h" @@ -15,7 +15,7 @@ void stream_json_timing_stats(const TimingStats& stats, long timeSinceLastReset) void jsonStatistics(bool clearStats); -#endif +#endif // if FEATURE_TIMING_STATS #endif diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index d35729c690..fee5d92c33 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -237,9 +237,9 @@ void handle_advanced() { #endif // if defined(ESP32) addFormCheckBox(LabelType::JSON_BOOL_QUOTES, Settings.JSONBoolWithoutQuotes()); - #ifdef USES_TIMING_STATS + #if FEATURE_TIMING_STATS addFormCheckBox(LabelType::ENABLE_TIMING_STATISTICS, Settings.EnableTimingStats()); - #endif + #endif // if FEATURE_TIMING_STATS #ifndef BUILD_NO_RAM_TRACKER addFormCheckBox(LabelType::ENABLE_RAM_TRACKING, Settings.EnableRAMTracking()); #endif diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 5a23e19130..bb0a64e0d7 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -485,9 +485,9 @@ void handle_timingstats_json() { TXBuffer.startJsonStream(); json_init(); json_open(); - # ifdef USES_TIMING_STATS + # if FEATURE_TIMING_STATS jsonStatistics(false); - # endif // ifdef USES_TIMING_STATS + # endif // if FEATURE_TIMING_STATS json_close(); TXBuffer.endStream(); } diff --git a/src/src/WebServer/TimingStats.cpp b/src/src/WebServer/TimingStats.cpp index 43486783a5..05de9048c9 100644 --- a/src/src/WebServer/TimingStats.cpp +++ b/src/src/WebServer/TimingStats.cpp @@ -11,7 +11,7 @@ #include "../Globals/Protocol.h" #include "../Globals/RamTracker.h" -#if defined(WEBSERVER_TIMINGSTATS) && defined(USES_TIMING_STATS) +#if defined(WEBSERVER_TIMINGSTATS) && FEATURE_TIMING_STATS #include "../Globals/Device.h" diff --git a/src/src/WebServer/TimingStats.h b/src/src/WebServer/TimingStats.h index 3aa39fbd1b..352bd353e1 100644 --- a/src/src/WebServer/TimingStats.h +++ b/src/src/WebServer/TimingStats.h @@ -3,7 +3,7 @@ #include "../WebServer/common.h" -#if defined(WEBSERVER_TIMINGSTATS) && defined(USES_TIMING_STATS) +#if defined(WEBSERVER_TIMINGSTATS) && FEATURE_TIMING_STATS #include "../DataStructs/TimingStats.h" diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 6e99c23232..7e58b10f6e 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -83,13 +83,13 @@ void sendHeadandTail(const __FlashStringHelper * tmplName, boolean Tail, boolean // This function is called twice per serving a web page. // So it must keep track of the timer longer than the scope of this function. // Therefore use a local static variable. - #ifdef USES_TIMING_STATS + #if FEATURE_TIMING_STATS static uint64_t statisticsTimerStart = 0; if (!Tail) { statisticsTimerStart = getMicros64(); } - #endif // ifdef USES_TIMING_STATS + #endif // if FEATURE_TIMING_STATS { const String fileName = String(tmplName) + F(".htm"); fs::File f = tryOpenFile(fileName, "r"); From 88e5b8972d5caebc190883e6460b73e5b842cbce Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 25 Jul 2022 22:37:19 +0200 Subject: [PATCH 269/404] [Build] Rename USE_EXT_RTC to FEATURE_EXT_RTC and use 0/1 state --- src/Custom-sample.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 14 ++++---- src/src/Helpers/ESPEasy_time.cpp | 42 ++++++++++++------------ tools/pio/pre_custom_esp32.py | 2 +- tools/pio/pre_custom_esp82xx.py | 2 +- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 5105edd0b0..1fab34708f 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -187,7 +187,7 @@ #define FEATURE_SSDP 1 -#define USE_EXT_RTC // Support for external RTC clock modules like PCF8563/PCF8523/DS3231/DS1307 +#define FEATURE_EXT_RTC 1 // Support for external RTC clock modules like PCF8563/PCF8523/DS3231/DS1307 #define USES_PLUGIN_STATS // Support collecting historic data + computing stats on historic data #ifdef ESP8266 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index f05374c881..0faf36a582 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -132,8 +132,8 @@ To create/register a plugin, you have to : #ifndef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 #endif - #ifndef USE_EXT_RTC - #define USE_EXT_RTC + #ifndef FEATURE_EXT_RTC + #define FEATURE_EXT_RTC 1 #endif #endif @@ -456,8 +456,9 @@ To create/register a plugin, you have to : #ifndef NOTIFIER_SET_NONE #define NOTIFIER_SET_NONE #endif - #ifdef USE_EXT_RTC - #undef USE_EXT_RTC + #if FEATURE_EXT_RTC + #undef FEATURE_EXT_RTC + #define FEATURE_EXT_RTC 0 #endif #endif @@ -1807,8 +1808,9 @@ To create/register a plugin, you have to : #ifndef LIMIT_BUILD_SIZE #define LIMIT_BUILD_SIZE #endif - #ifdef USE_EXT_RTC - #undef USE_EXT_RTC + #if FEATURE_EXT_RTC + #undef FEATURE_EXT_RTC + #define FEATURE_EXT_RTC 0 #endif #endif diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 2342324561..181f8108eb 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -23,7 +23,7 @@ #include -#ifdef USE_EXT_RTC +#if FEATURE_EXT_RTC #include #endif @@ -722,7 +722,7 @@ bool ESPEasy_time::ExtRTC_get(uint32_t &unixtime) return false; case ExtTimeSource_e::DS1307: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC I2CSelect_Max100kHz_ClockSpeed(); // Only supports upto 100 kHz RTC_DS1307 rtc; if (!rtc.begin()) { @@ -734,12 +734,12 @@ bool ESPEasy_time::ExtRTC_get(uint32_t &unixtime) break; } unixtime = rtc.now().unixtime(); - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::DS3231: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_DS3231 rtc; if (!rtc.begin()) { // Not found @@ -750,13 +750,13 @@ bool ESPEasy_time::ExtRTC_get(uint32_t &unixtime) break; } unixtime = rtc.now().unixtime(); - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::PCF8523: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_PCF8523 rtc; if (!rtc.begin()) { // Not found @@ -767,12 +767,12 @@ bool ESPEasy_time::ExtRTC_get(uint32_t &unixtime) break; } unixtime = rtc.now().unixtime(); - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::PCF8563: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_PCF8563 rtc; if (!rtc.begin()) { // Not found @@ -783,7 +783,7 @@ bool ESPEasy_time::ExtRTC_get(uint32_t &unixtime) break; } unixtime = rtc.now().unixtime(); - #endif + #endif // if FEATURE_EXT_RTC break; } @@ -805,69 +805,69 @@ bool ESPEasy_time::ExtRTC_set(uint32_t unixtime) // Do not adjust the external RTC time if we already used it as a time source. return true; } - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC bool timeAdjusted = false; - #endif + #endif // if FEATURE_EXT_RTC switch (Settings.ExtTimeSource()) { case ExtTimeSource_e::None: return false; case ExtTimeSource_e::DS1307: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC I2CSelect_Max100kHz_ClockSpeed(); // Only supports upto 100 kHz RTC_DS1307 rtc; if (rtc.begin()) { rtc.adjust(DateTime(unixtime)); timeAdjusted = true; } - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::DS3231: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_DS3231 rtc; if (rtc.begin()) { rtc.adjust(DateTime(unixtime)); timeAdjusted = true; } - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::PCF8523: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_PCF8523 rtc; if (rtc.begin()) { rtc.adjust(DateTime(unixtime)); rtc.start(); timeAdjusted = true; } - #endif + #endif // if FEATURE_EXT_RTC break; } case ExtTimeSource_e::PCF8563: { - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC RTC_PCF8563 rtc; if (rtc.begin()) { rtc.adjust(DateTime(unixtime)); rtc.start(); timeAdjusted = true; } - #endif + #endif // if FEATURE_EXT_RTC break; } } - #ifdef USE_EXT_RTC + #if FEATURE_EXT_RTC if (timeAdjusted) { String log = F("ExtRTC: External time source set to: "); log += unixtime; addLogMove(LOG_LEVEL_INFO, log); return true; } - #endif + #endif // if FEATURE_EXT_RTC addLog(LOG_LEVEL_ERROR, F("ExtRTC: Cannot set time to external time source")); return false; } diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 0f738272be..a888e4d96c 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -59,7 +59,7 @@ # "-DUSES_C019", # ESPEasy-NOW "-DUSES_ESPEASY_NOW", - "-DUSE_EXT_RTC", + "-DFEATURE_EXT_RTC=1", "-DFEATURE_SD=1", "-DFEATURE_I2CMULTIPLEXER=1", "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index bc55d0d2ec..b89a52a4ef 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -60,7 +60,7 @@ "-DUSES_ESPEASY_NOW", # "-DFEATURE_MDNS", # "-DFEATURE_SD=1", - "-DUSE_EXT_RTC", + "-DFEATURE_EXT_RTC=1", "-DFEATURE_I2CMULTIPLEXER=1", "-DFEATURE_TRIGONOMETRIC_FUNCTIONS_RULES=1", "-DFEATURE_CUSTOM_PROVISIONING=1", From eac623ac4e71608508f6426b40cb7b3efe4e0339 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 22:35:21 +0200 Subject: [PATCH 270/404] [Build] Rename ENABLE_TOOLTIPS to FEATURE_TOOLTIPS and use 0/1 state --- src/_P037_MQTTImport.ino | 6 +- src/src/CustomBuild/define_plugin_sets.h | 11 +- src/src/PluginStructs/P104_data_struct.h | 4 +- src/src/WebServer/Markup.cpp | 110 ++++++++-------- src/src/WebServer/Markup.h | 44 +++---- src/src/WebServer/Markup_Forms.cpp | 152 +++++++++++------------ src/src/WebServer/Markup_Forms.h | 64 +++++----- 7 files changed, 196 insertions(+), 195 deletions(-) diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index 53e7755f1d..5ede6bf2e7 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -166,14 +166,14 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string) } { - # if !defined(LIMIT_BUILD_SIZE) && defined(ENABLE_TOOLTIPS) + # if !defined(LIMIT_BUILD_SIZE) && FEATURE_TOOLTIPS String toolTip = F("0.."); toolTip += P037_MAX_QUEUEDEPTH; toolTip += F(" entries"); addFormNumericBox(F("Max. # entries in event queue"), F("p037_queuedepth"), P037_QUEUEDEPTH_EVENTS, 0, P037_MAX_QUEUEDEPTH, toolTip); - # else // if !defined(LIMIT_BUILD_SIZE) && defined(ENABLE_TOOLTIPS) + # else // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TOOLTIPS addFormNumericBox(F("Max. # entries in event queue"), F("p037_queuedepth"), P037_QUEUEDEPTH_EVENTS, 0, P037_MAX_QUEUEDEPTH); - # endif // if !defined(LIMIT_BUILD_SIZE) && defined(ENABLE_TOOLTIPS) + # endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TOOLTIPS addUnit(F("0 = no check")); # if !defined(LIMIT_BUILD_SIZE) addFormNote(F("New events will be discarded if the event queue has more entries queued.")); diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 0faf36a582..ccde899732 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -147,9 +147,9 @@ To create/register a plugin, you have to : #endif #endif -#ifndef ENABLE_TOOLTIPS - #define ENABLE_TOOLTIPS -#endif // ENABLE_TOOLTIPS +#ifndef FEATURE_TOOLTIPS + #define FEATURE_TOOLTIPS 1 +#endif // ifndef FEATURE_TOOLTIPS /******************************************************************************\ * Available options ********************************************************** @@ -1846,8 +1846,9 @@ To create/register a plugin, you have to : #ifdef USE_RTTTL #undef USE_RTTTL #endif - #ifdef ENABLE_TOOLTIPS - #undef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS + #undef FEATURE_TOOLTIPS + #define FEATURE_TOOLTIPS 0 #endif #ifdef USES_BLYNK #undef USES_BLYNK diff --git a/src/src/PluginStructs/P104_data_struct.h b/src/src/PluginStructs/P104_data_struct.h index fcee6c3255..581fa293e8 100644 --- a/src/src/PluginStructs/P104_data_struct.h +++ b/src/src/PluginStructs/P104_data_struct.h @@ -132,9 +132,9 @@ # endif // ifdef P104_USE_KATAKANA_FONT # endif // ifdef LIMIT_BUILD_SIZE -# if defined(P104_USE_TOOLTIPS) && !defined(ENABLE_TOOLTIPS) +# if defined(P104_USE_TOOLTIPS) && !FEATURE_TOOLTIPS # undef P104_USE_TOOLTIPS -# endif // if defined(P104_USE_TOOLTIPS) && !defined(ENABLE_TOOLTIPS) +# endif // if defined(P104_USE_TOOLTIPS) && !FEATURE_TOOLTIPS # ifdef P104_MINIMAL_ANIMATIONS diff --git a/src/src/WebServer/Markup.cpp b/src/src/WebServer/Markup.cpp index 18e956c2f4..554969567e 100644 --- a/src/src/WebServer/Markup.cpp +++ b/src/src/WebServer/Markup.cpp @@ -61,24 +61,24 @@ void addSelector(const String & id, bool reloadonchange, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String & tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { // FIXME TD-er Change bool to disabled if (reloadonchange) { addSelector_Head_reloadOnChange(id, classname, !enabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } else { do_addSelector_Head(id, classname, EMPTY_STRING, !enabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } addSelector_options(optionCount, options, indices, attr, selectedIndex); @@ -95,17 +95,17 @@ void addSelector_reloadOnChange( const String& onChangeCall, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { // FIXME TD-er Change bool to disabled do_addSelector_Head(id, classname, onChangeCall, !enabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); addSelector_options(optionCount, options, indices, attr, selectedIndex); addSelector_Foot(); @@ -121,24 +121,24 @@ void addSelector(const String & id, bool reloadonchange, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { // FIXME TD-er Change bool to disabled if (reloadonchange) { addSelector_Head_reloadOnChange(id, classname, !enabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } else { do_addSelector_Head(id, classname, EMPTY_STRING, !enabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } addSelector_options(optionCount, options, indices, attr, selectedIndex); @@ -193,9 +193,9 @@ void addSelector_options(int optionCount, const String options[], const int indi void addSelector_Head(const String& id) { do_addSelector_Head(id, F("wide"), EMPTY_STRING, false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , F("") - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -204,33 +204,33 @@ void addSelector_Head_reloadOnChange(const String& id) { } void addSelector_Head_reloadOnChange(const String& id, const String& classname, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { do_addSelector_Head(id, classname, F("return dept_onchange(frmselect)"), disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } void addSelector_Head_reloadOnChange(const String& id, const String& classname, const String& onChangeCall, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { do_addSelector_Head(id, classname, onChangeCall, disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } void do_addSelector_Head(const String& id, const String& classname, const String& onChangeCall, const bool& disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addHtml(F(" 0) { addHtmlAttribute(F("title"), tooltip); } - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS if (value < min) { value = min; @@ -677,18 +677,18 @@ void addNumericBox(const String& id, int value, int min, int max addHtml('>'); } -#ifdef ENABLE_TOOLTIPS +#if FEATURE_TOOLTIPS void addNumericBox(const String& id, int value, int min, int max) { addNumericBox(id, value, min, max, F("widenumber")); } -#endif // ifdef ENABLE_TOOLTIPS +#endif // if FEATURE_TOOLTIPS void addFloatNumberBox(const String& id, float value, float min, float max, unsigned int nrDecimals, float stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { String html; @@ -718,14 +718,14 @@ void addFloatNumberBox(const String& id, float value, float min, float max, unsi html += F(" style='width:7em;' value="); html += toString(value, nrDecimals); - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS if (tooltip.length() > 0) { html += F("title='"); html += tooltip; html += F("' "); } - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS html += '>'; addHtml(html); @@ -745,9 +745,9 @@ void addTextBox(const String & id, bool required, const String & pattern, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addHtml(F(" 0) { addHtmlAttribute(F("title"), tooltip); } - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS addHtml('>'); } @@ -790,9 +790,9 @@ void addTextArea(const String & id, int columns, bool readonly, bool required - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addHtml(F("")); diff --git a/src/src/WebServer/Markup.h b/src/src/WebServer/Markup.h index 8dcab11ac2..d9222ec84a 100644 --- a/src/src/WebServer/Markup.h +++ b/src/src/WebServer/Markup.h @@ -45,10 +45,10 @@ void addSelector(const String & id, bool reloadonchange, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String & tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addSelector(const String& id, @@ -60,10 +60,10 @@ void addSelector(const String& id, bool reloadonchange, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addSelector_reloadOnChange( @@ -76,10 +76,10 @@ void addSelector_reloadOnChange( const String& onChangeCall, bool enabled, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); @@ -101,30 +101,30 @@ void addSelector_Head_reloadOnChange(const String& id); void addSelector_Head_reloadOnChange(const String& id, const String& classname, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addSelector_Head_reloadOnChange(const String& id, const String& classname, const String& onChangeCall, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void do_addSelector_Head(const String& id, const String& classname, const String& onChangeCall, const bool& disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addPinSelector_Item(PinSelectPurpose purpose, @@ -212,10 +212,10 @@ void addFormSubHeader(const String& header); void addCheckBox(const String& id, bool checked, bool disabled = false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addCheckBox(const __FlashStringHelper *id, bool checked, @@ -224,14 +224,14 @@ void addCheckBox(const __FlashStringHelper *id, // ******************************************************************************** // Add a numeric box // ******************************************************************************** -#ifdef ENABLE_TOOLTIPS +#if FEATURE_TOOLTIPS void addNumericBox(const String& id, int value, int min, int max, const String& classname, const String& tooltip = EMPTY_STRING); -#endif // ifdef ENABLE_TOOLTIPS +#endif // if FEATURE_TOOLTIPS void addFloatNumberBox(const String& id, float value, @@ -239,10 +239,10 @@ void addFloatNumberBox(const String& id, float max, unsigned int nrDecimals = 6, float stepsize = 0.0f - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addNumericBox(const __FlashStringHelper *id, int value, @@ -269,10 +269,10 @@ void addTextBox(const String& id, bool required, const String& pattern, const String& classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); // ******************************************************************************** @@ -285,10 +285,10 @@ void addTextArea(const String& id, int columns, bool readonly, bool required - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); // ******************************************************************************** diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index 327ce87df8..8f2886c882 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -57,14 +57,14 @@ void addFormNote(const String& text, const String& id) // ******************************************************************************** void addFormCheckBox_disabled(const String& label, const String& id, bool checked - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormCheckBox(label, id, checked, true - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -81,28 +81,28 @@ void addFormCheckBox(const __FlashStringHelper * label, const String& id, bool c } void addFormCheckBox(const String& label, const String& id, bool checked, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addCheckBox(id, checked, disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } void addFormCheckBox(LabelType::Enum label, bool checked, bool disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormCheckBox(getLabel(label), getInternalLabel(label), checked, disabled - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -114,15 +114,15 @@ void addFormCheckBox_disabled(LabelType::Enum label, bool checked) { // Add a Numeric Box form // ******************************************************************************** void addFormNumericBox(LabelType::Enum label, int value, int min, int max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormNumericBox(getLabel(label), getInternalLabel(label), value, min, max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -131,43 +131,43 @@ void addFormNumericBox(const __FlashStringHelper * label, int value, int min, int max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormNumericBox(String(label), String(id), value, min, max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } void addFormNumericBox(const String& label, const String& id, int value, int min, int max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addNumericBox(id, value, min, max - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , F("widenumber"), tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } void addFormFloatNumberBox(LabelType::Enum label, float value, float min, float max, uint8_t nrDecimals, float stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormFloatNumberBox(getLabel(label), getInternalLabel(label), value, min, max, nrDecimals, stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -178,17 +178,17 @@ void addFormFloatNumberBox(const String& label, float max, uint8_t nrDecimals, float stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addFloatNumberBox(id, value, min, max, nrDecimals, stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -199,17 +199,17 @@ void addFormFloatNumberBox(const __FlashStringHelper * label, float max, uint8_t nrDecimals, float stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addFloatNumberBox(id, value, min, max, nrDecimals, stepsize - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -246,16 +246,16 @@ void addFormTextBox(const String & label, bool readonly, bool required, const String& pattern - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addTextBox(id, value, maxlength, readonly, required, pattern, F("wide") - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -267,17 +267,17 @@ void addFormTextBox(const __FlashStringHelper * classname, bool readonly , bool required , const String& pattern - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addTextBox(id, value, maxlength, readonly, required, pattern, classname - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -291,16 +291,16 @@ void addFormTextArea(const String & label, int columns, bool readonly, bool required - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addTextArea(id, value, maxlength, rows, columns, readonly, required - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -309,9 +309,9 @@ void addFormTextArea(const String & label, // ******************************************************************************** void addFormPasswordBox(const String& label, const String& id, const String& password, int maxlength - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); @@ -322,12 +322,12 @@ void addFormPasswordBox(const String& label, const String& id, const String& pas addHtmlAttribute(F("name"), id); addHtmlAttribute(F("maxlength"), maxlength); - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS if (tooltip.length() > 0) { addHtmlAttribute(F("title"), tooltip); } - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS addHtmlAttribute(F("value"), (password.length() == 0) ? F("") : F("*****")); addHtml('>'); } @@ -433,16 +433,16 @@ void addFormPinSelectI2C(const String& label, const String& id, int choice) } void addFormSelectorI2C(const String& id, int addressCount, const uint8_t addresses[], int selectedIndex - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(F("I2C Address"), id); do_addSelector_Head(id, EMPTY_STRING, EMPTY_STRING, false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); for (uint8_t x = 0; x < addressCount; x++) @@ -483,15 +483,15 @@ void addFormSelector(const String & label, const String options[], const int indices[], int selectedIndex - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormSelector(label, id, optionCount, options, indices, nullptr, selectedIndex, false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -526,15 +526,15 @@ void addFormSelector(const String& label, const int indices[], int selectedIndex, bool reloadonchange - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addFormSelector(label, id, optionCount, options, indices, nullptr, selectedIndex, reloadonchange - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -546,16 +546,16 @@ void addFormSelector(const String & label, const String attr[], int selectedIndex, bool reloadonchange - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); addSelector(id, optionCount, options, indices, attr, selectedIndex, reloadonchange, true, F("wide") - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); } @@ -567,16 +567,16 @@ void addFormSelector_script(const __FlashStringHelper * label, const String attr[], int selectedIndex, const __FlashStringHelper * onChangeCall - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); do_addSelector_Head(id, F("wide"), onChangeCall, false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); addSelector_options(optionCount, options, indices, attr, selectedIndex); addSelector_Foot(); @@ -590,16 +590,16 @@ void addFormSelector_script(const String & label, const String attr[], int selectedIndex, const __FlashStringHelper * onChangeCall - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ) { addRowLabel_tr_id(label, id); do_addSelector_Head(id, F("wide"), onChangeCall, false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , tooltip - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); addSelector_options(optionCount, options, indices, attr, selectedIndex); addSelector_Foot(); diff --git a/src/src/WebServer/Markup_Forms.h b/src/src/WebServer/Markup_Forms.h index f6fbcdd431..2d94c6d1bd 100644 --- a/src/src/WebServer/Markup_Forms.h +++ b/src/src/WebServer/Markup_Forms.h @@ -31,29 +31,29 @@ void addFormNote(const String& text, const String& id = EMPTY_STRING); void addFormCheckBox_disabled(const String& label, const String& id, bool checked - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormCheckBox(const String& label, const String& id, bool checked, bool disabled = false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormCheckBox(LabelType::Enum label, bool checked, bool disabled = false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String & tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormCheckBox_disabled(LabelType::Enum label, @@ -68,10 +68,10 @@ void addFormNumericBox(LabelType::Enum label, int value, int min = INT_MIN, int max = INT_MAX - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String & tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormNumericBox(const __FlashStringHelper * label, @@ -79,10 +79,10 @@ void addFormNumericBox(const __FlashStringHelper * label, int value, int min = INT_MIN, int max = INT_MAX - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormNumericBox(const String& label, @@ -90,10 +90,10 @@ void addFormNumericBox(const String& label, int value, int min = INT_MIN, int max = INT_MAX - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); @@ -103,10 +103,10 @@ void addFormFloatNumberBox(LabelType::Enum label, float max, uint8_t nrDecimals = 6, float stepsize = 0.0f - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormFloatNumberBox(const String& label, @@ -116,10 +116,10 @@ void addFormFloatNumberBox(const String& label, float max, uint8_t nrDecimals = 6, float stepsize = 0.0f - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormFloatNumberBox(const __FlashStringHelper * label, @@ -129,10 +129,10 @@ void addFormFloatNumberBox(const __FlashStringHelper * label, float max, uint8_t nrDecimals = 6, float stepsize = 0.0f - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); @@ -161,10 +161,10 @@ void addFormTextBox(const String& label, bool readonly = false, bool required = false, const String& pattern = EMPTY_STRING - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); void addFormTextBox(const __FlashStringHelper * classname, @@ -175,10 +175,10 @@ void addFormTextBox(const __FlashStringHelper * classname, bool readonly = false, bool required = false, const String& pattern = EMPTY_STRING - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); @@ -190,10 +190,10 @@ void addFormTextArea(const String& label, int columns, bool readonly = false, bool required = false - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); // ******************************************************************************** @@ -204,10 +204,10 @@ void addFormPasswordBox(const String& label, const String& id, const String& password, int maxlength - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING - #endif // ifdef ENABLE_TOOLTIPS + #endif // if FEATURE_TOOLTIPS ); bool getFormPassword(const String& id, @@ -264,7 +264,7 @@ void addFormSelectorI2C(const String& id, int addressCount, const uint8_t addresses[], int selectedIndex - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif @@ -276,7 +276,7 @@ void addFormSelector(const String& label, const String options[], const int indices[], int selectedIndex - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif @@ -312,7 +312,7 @@ void addFormSelector(const String& label, const int indices[], int selectedIndex, bool reloadonchange - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif @@ -326,7 +326,7 @@ void addFormSelector(const String& label, const String attr[], int selectedIndex, bool reloadonchange - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif @@ -340,7 +340,7 @@ void addFormSelector_script(const __FlashStringHelper * label, const String attr[], int selectedIndex, const __FlashStringHelper * onChangeCall - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif @@ -355,7 +355,7 @@ void addFormSelector_script(const String& label, const String attr[], int selectedIndex, const __FlashStringHelper * onChangeCall - #ifdef ENABLE_TOOLTIPS + #if FEATURE_TOOLTIPS , const String& tooltip = EMPTY_STRING #endif From 87b1ec5e27299276e0d18b9bc3fc0a90263f50bd Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 25 Jul 2022 23:01:03 +0200 Subject: [PATCH 271/404] [Build] Fix typo in FEATURE_I2CMULTIPLEXER check --- src/src/Globals/Plugins.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index cc6cf3a82c..34f8dec0e7 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -232,9 +232,9 @@ void post_I2C_by_taskIndex(taskIndex_t taskIndex, deviceIndex_t DeviceIndex) { if (Device[DeviceIndex].Type != DEVICE_TYPE_I2C) { return; } -#ifdef FEATURE_I2CMULTIPLEXER + #if FEATURE_I2CMULTIPLEXER I2CMultiplexerOff(); -#endif + #endif // if FEATURE_I2CMULTIPLEXER if (bitRead(Settings.I2C_Flags[taskIndex], I2C_FLAGS_SLOW_SPEED)) { I2CSelectHighClockSpeed(); // Reset From 75ef238b0db5920ba4f2a82b4f17d6cd0fe7f974 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 26 Jul 2022 21:11:54 +0200 Subject: [PATCH 272/404] [Sysinfo json] Fix compilation error --- src/src/WebServer/SysInfoPage.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 7e973b7809..68a35e194d 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -81,13 +81,13 @@ void handle_sysinfo_json() { 0 # endif // ifndef BUILD_NO_RAM_TRACKER )); - json_prop(F("low_ram_fn"), + json_prop(F("low_ram_fn"), String( # ifndef BUILD_NO_RAM_TRACKER lowestRAMfunction # else // ifndef BUILD_NO_RAM_TRACKER 0 # endif // ifndef BUILD_NO_RAM_TRACKER - ); + )); json_number(F("stack"), String(getCurrentFreeStack())); json_number(F("low_stack"), String( # ifndef BUILD_NO_RAM_TRACKER @@ -96,13 +96,13 @@ void handle_sysinfo_json() { 0 # endif // ifndef BUILD_NO_RAM_TRACKER )); - json_prop(F("low_stack_fn"), + json_prop(F("low_stack_fn"), String( # ifndef BUILD_NO_RAM_TRACKER lowestFreeStackfunction # else // ifndef BUILD_NO_RAM_TRACKER 0 # endif // ifndef BUILD_NO_RAM_TRACKER - ); + )); json_close(); json_open(false, F("boot")); From a4c5bf4a969f141263a105da4c37ac5bef83b235 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 26 Jul 2022 22:46:51 +0200 Subject: [PATCH 273/404] [Build] Add check for renamed #define variables --- src/ESPEasy_common.h | 1 + src/check_defines_custom.h | 70 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/check_defines_custom.h diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index d9082564a1..ed63f42782 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -56,6 +56,7 @@ namespace std // make the compiler show a warning to confirm that this file is inlcuded //#warning "**** Using Settings from Custom.h File ***" #include "Custom.h" + #include "check_defines_custom.h" // Check for replaced #define variables, see https://github.com/letscontrolit/ESPEasy/pull/4153 #else // Set as default // #define PLUGIN_BUILD_NORMAL diff --git a/src/check_defines_custom.h b/src/check_defines_custom.h new file mode 100644 index 0000000000..af11ebe090 --- /dev/null +++ b/src/check_defines_custom.h @@ -0,0 +1,70 @@ +#ifndef CHECK_DEFINES_CUSTOM_H +#define CHECK_DEFINES_CUSTOM_H + +/** + * Check if any of the now renamed #define variables is still used and output a warning during compilation + * + * Changelog: + * ---------- + * 2022-07-26 tonhuisman: Initial checks, disable formatting by Uncrustify as it messes up the url's + */ + +/* *INDENT-OFF* */ + +#ifdef USE_DOWNLOAD +# warning "Custom.h has '#define USE_DOWNLOAD' to be replaced with '#define FEATURE_DOWNLOAD 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_DOWNLOAD 1 // Define correct alternative +# undef USE_DOWNLOAD // remove +#endif // ifdef USE_DOWNLOAD + +#ifdef USE_CUSTOM_PROVISIONING +# warning "Custom.h has '#define USE_CUSTOM_PROVISIONING' to be replaced with '#define FEATURE_CUSTOM_PROVISIONING 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_CUSTOM_PROVISIONING 1 +# undef USE_CUSTOM_PROVISIONING +#endif // ifdef USE_CUSTOM_PROVISIONING + +#ifdef USE_SETTINGS_ARCHIVE +# warning "Custom.h has '#define USE_SETTINGS_ARCHIVE' to be replaced with '#define FEATURE_SETTINGS_ARCHIVE 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_SETTINGS_ARCHIVE 1 +# undef USE_SETTINGS_ARCHIVE +#endif // ifdef USE_SETTINGS_ARCHIVE + +#ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES +# warning "Custom.h has '#define USE_TRIGONOMETRIC_FUNCTIONS_RULES' to be replaced with '#define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 1 +# undef USE_TRIGONOMETRIC_FUNCTIONS_RULES +#endif // ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES + +#if defined(FEATURE_I2CMULTIPLEXER) && (2 - FEATURE_I2CMULTIPLEXER - 2 == 4) // 'Defined but empty' check +# warning "Custom.h has '#define FEATURE_I2CMULTIPLEXER' to be replaced with '#define FEATURE_I2CMULTIPLEXER 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# undef FEATURE_I2CMULTIPLEXER +# define FEATURE_I2CMULTIPLEXER 1 +#endif // if defined(FEATURE_I2CMULTIPLEXER) && (2-FEATURE_I2CMULTIPLEXER-2 == 4) + +#ifdef USE_SSDP +# warning "Custom.h has '#define USE_SSDP' to be replaced with '#define FEATURE_SSDP 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_SSDP 1 +# undef USE_SSDP +#endif // ifdef USE_SSDP + +#ifdef USE_TIMING_STATS +# warning "Custom.h has '#define USE_TIMING_STATS' to be replaced with '#define FEATURE_TIMING_STATS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_TIMING_STATS 1 +# undef USE_TIMING_STATS +#endif // ifdef USE_TIMING_STATS + +#ifdef USE_EXT_RTC +# warning "Custom.h has '#define USE_EXT_RTC' to be replaced with '#define FEATURE_EXT_RTC 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_EXT_RTC 1 +# undef USE_EXT_RTC +#endif // ifdef USE_EXT_RTC + +#ifdef ENABLE_TOOLTIPS +# warning "Custom.h has '#define ENABLE_TOOLTIPS' to be replaced with '#define FEATURE_TOOLTIPS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_TOOLTIPS 1 +# undef ENABLE_TOOLTIPS +#endif // ifdef ENABLE_TOOLTIPS + +/* *INDENT-ON* */ + +#endif // ifndef CHECK_DEFINES_CUSTOM_H From 96804cd935b5a4af9b6666f2c14284361b9f1aed Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 27 Jul 2022 22:00:46 +0200 Subject: [PATCH 274/404] [Build] Rename HAS_ETHERNET to FEATURE_ETHERNET and use 0/1 state --- platformio_esp32_envs.ini | 18 ++++++------- src/check_defines_custom.h | 6 +++++ src/src/Commands/InternalCommands.cpp | 4 +-- src/src/Commands/Networks.cpp | 6 ++--- src/src/CustomBuild/ESPEasyDefaults.h | 2 +- src/src/DataStructs_templ/SettingsStruct.cpp | 8 +++--- src/src/ESPEasyCore/ESPEasyEth.cpp | 4 +-- src/src/ESPEasyCore/ESPEasyEth.h | 4 +-- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 24 ++++++++--------- src/src/ESPEasyCore/ESPEasyNetwork.h | 2 +- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 18 ++++++------- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 14 +++++----- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.h | 4 +-- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 +-- src/src/Globals/ESPEasyWiFiEvent.cpp | 2 +- src/src/Globals/ESPEasyWiFiEvent.h | 4 +-- src/src/Helpers/Hardware.cpp | 24 ++++++++--------- src/src/Helpers/PeriodicalActions.cpp | 6 ++--- src/src/Helpers/StringGenerator_GPIO.cpp | 12 ++++----- src/src/Helpers/StringProvider.cpp | 26 +++++++++---------- src/src/Helpers/StringProvider.h | 8 +++--- src/src/Helpers/SystemVariables.cpp | 8 +++--- src/src/Helpers/SystemVariables.h | 4 +-- src/src/WebServer/ConfigPage.cpp | 14 +++++----- src/src/WebServer/HardwarePage.cpp | 8 +++--- src/src/WebServer/JSON.cpp | 12 ++++----- src/src/WebServer/Markup.cpp | 12 ++++----- src/src/WebServer/RootPage.cpp | 4 +-- src/src/WebServer/SysInfoPage.cpp | 14 +++++----- src/src/WebServer/SysInfoPage.h | 2 +- src/src/WebServer/SysVarPage.cpp | 4 +-- 31 files changed, 145 insertions(+), 137 deletions(-) diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index d92c9bdfd0..23816dfb69 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -260,41 +260,41 @@ build_flags = ${esp32_common.build_flags} [env:custom_ESP32_4M316k_ETH] extends = env:custom_ESP32_4M316k build_flags = ${env:custom_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 [env:normal_ESP32_4M316k_ETH] extends = env:normal_ESP32_4M316k build_flags = ${env:normal_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 [env:collection_A_ESP32_4M316k_ETH] extends = env:collection_A_ESP32_4M316k build_flags = ${env:collection_A_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 -DCOLLECTION_USE_RTTTL [env:collection_B_ESP32_4M316k_ETH] extends = env:collection_B_ESP32_4M316k build_flags = ${env:collection_B_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 -DCOLLECTION_USE_RTTTL [env:collection_C_ESP32_4M316k_ETH] extends = env:collection_C_ESP32_4M316k build_flags = ${env:collection_C_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 -DCOLLECTION_USE_RTTTL [env:collection_D_ESP32_4M316k_ETH] extends = env:collection_D_ESP32_4M316k build_flags = ${env:collection_D_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 -DCOLLECTION_USE_RTTTL [env:collection_E_ESP32_4M316k_ETH] extends = env:collection_E_ESP32_4M316k build_flags = ${env:collection_E_ESP32_4M316k.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 -DCOLLECTION_USE_RTTTL @@ -316,7 +316,7 @@ build_flags = ${esp32_base.build_flags} [env:max_ESP32_16M1M_ETH] extends = env:max_ESP32_16M1M build_flags = ${env:max_ESP32_16M1M.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 ; A Lolin D32 PRO with 16MB Flash, allowing 4MB sketch size, and file storage using LittleFS filesystem @@ -340,7 +340,7 @@ board_build.filesystem = littlefs [env:max_ESP32_16M8M_LittleFS_ETH] extends = env:max_ESP32_16M8M_LittleFS build_flags = ${env:max_ESP32_16M8M_LittleFS.build_flags} - -DHAS_ETHERNET + -DFEATURE_ETHERNET=1 diff --git a/src/check_defines_custom.h b/src/check_defines_custom.h index af11ebe090..02e33737b2 100644 --- a/src/check_defines_custom.h +++ b/src/check_defines_custom.h @@ -65,6 +65,12 @@ # undef ENABLE_TOOLTIPS #endif // ifdef ENABLE_TOOLTIPS +#ifdef HAS_ETHERNET +# warning "Custom.h has '#define HAS_ETHERNET' to be replaced with '#define FEATURE_ETHERNET 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_ETHERNET 1 +# undef HAS_ETHERNET +#endif // ifdef HAS_ETHERNET + /* *INDENT-ON* */ #endif // ifndef CHECK_DEFINES_CUSTOM_H diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index e8cc3a187c..a4687d9459 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -290,7 +290,7 @@ bool executeInternalCommand(command_case_data & data) break; } case 'e': { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET COMMAND_CASE_R( "ethphyadr", Command_ETH_Phy_Addr, 1); // Network Command COMMAND_CASE_R( "ethpinmdc", Command_ETH_Pin_mdc, 1); // Network Command COMMAND_CASE_R( "ethpinmdio", Command_ETH_Pin_mdio, 1); // Network Command @@ -303,7 +303,7 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_R( "ethdns", Command_ETH_DNS, 1); // Network Command COMMAND_CASE_A("ethdisconnect", Command_ETH_Disconnect, 0); // Network Command COMMAND_CASE_R( "ethwifimode", Command_ETH_Wifi_Mode, 1); // Network Command - #endif // HAS_ETHERNET + #endif // FEATURE_ETHERNET #ifdef USES_ESPEASY_NOW COMMAND_CASE_R("espeasynowdisable", Command_ESPEasy_Now_Disable, 0); // ESPEasy_Now_cmd.h COMMAND_CASE_R( "espeasynowenable", Command_ESPEasy_Now_Enable, 0); // ESPEasy_Now_cmd.h diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index f17bbee9ba..7d53c78de5 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -9,7 +9,7 @@ #include "../WebServer/AccessControl.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include #endif @@ -46,7 +46,7 @@ String Command_Subnet (struct EventStruct *event, const char* Line) return Command_GetORSetIP(event, F("Subnet:"), Line, Settings.Subnet, NetworkSubnetMask(), 1); } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET String Command_ETH_Phy_Addr (struct EventStruct *event, const char* Line) { return Command_GetORSetInt8_t(event, F("ETH_Phy_Addr:"), Line, reinterpret_cast(&Settings.ETH_Phy_Addr),1); @@ -134,4 +134,4 @@ String Command_ETH_Disconnect (struct EventStruct *event, const char* Line) return return_command_success(); } -#endif +#endif // if FEATURE_ETHERNET diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index 49630cf507..0ce697935e 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -226,7 +226,7 @@ #define DEFAULT_ETH_CLOCK_MODE EthClockMode_t::Ext_crystal_osc #endif #ifndef DEFAULT_NETWORK_MEDIUM - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET #define DEFAULT_NETWORK_MEDIUM NetworkMedium_t::Ethernet #else #define DEFAULT_NETWORK_MEDIUM NetworkMedium_t::WIFI diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index d051fbdc0d..a050eac980 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -681,7 +681,7 @@ bool SettingsStruct_tmpl::isI2CEnabled() const { template bool SettingsStruct_tmpl::isEthernetPin(int8_t pin) const { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (pin < 0) return false; if (NetworkMedium == NetworkMedium_t::Ethernet) { if (19 == pin) return true; // ETH TXD0 @@ -691,21 +691,21 @@ bool SettingsStruct_tmpl::isEthernetPin(int8_t pin) const { if (26 == pin) return true; // ETH RXD1 if (27 == pin) return true; // ETH CRS_DV } - #endif + #endif // if FEATURE_ETHERNET return false; } template bool SettingsStruct_tmpl::isEthernetPinOptional(int8_t pin) const { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (pin < 0) return false; if (NetworkMedium == NetworkMedium_t::Ethernet) { if (ETH_Pin_mdc == pin) return true; if (ETH_Pin_mdio == pin) return true; if (ETH_Pin_power == pin) return true; } - #endif + #endif // if FEATURE_ETHERNET return false; } diff --git a/src/src/ESPEasyCore/ESPEasyEth.cpp b/src/src/ESPEasyCore/ESPEasyEth.cpp index 2215cbbc2b..4c67e13fe4 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth.cpp @@ -1,6 +1,6 @@ #include "../ESPEasyCore/ESPEasyEth.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include "../CustomBuild/ESPEasyLimits.h" #include "../ESPEasyCore/ESPEasyGPIO.h" @@ -250,4 +250,4 @@ bool ETHConnected() { return false; } -#endif \ No newline at end of file +#endif // if FEATURE_ETHERNET \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyEth.h b/src/src/ESPEasyCore/ESPEasyEth.h index a94619a3ed..bd0764f6ca 100644 --- a/src/src/ESPEasyCore/ESPEasyEth.h +++ b/src/src/ESPEasyCore/ESPEasyEth.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include "../DataStructs/MAC_address.h" @@ -18,5 +18,5 @@ bool ETHConnected(); void ethPower(bool enable); MAC_address ETHMacAddress(); -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET #endif // ifndef ESPEASY_ETH_H diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index a0ce3da168..88b1f15380 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -11,7 +11,7 @@ #include "../Helpers/StringConverter.h" #include "../Helpers/MDNS_Helper.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include #endif @@ -48,7 +48,7 @@ void setNetworkMedium(NetworkMedium_t new_medium) { if (process_exit_active_medium) { switch (active_network_medium) { case NetworkMedium_t::Ethernet: - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET // FIXME TD-er: How to 'end' ETH? // ETH.end(); if (new_medium == NetworkMedium_t::WIFI) { @@ -96,11 +96,11 @@ bool isESPEasy_now_only() { /*********************************************************************************************\ - Ethernet or Wifi Support for ESP32 Build flag HAS_ETHERNET + Ethernet or Wifi Support for ESP32 Build flag FEATURE_ETHERNET \*********************************************************************************************/ void NetworkConnectRelaxed() { if (NetworkConnected()) return; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { if (ETHConnectRelaxed()) { return; @@ -114,7 +114,7 @@ void NetworkConnectRelaxed() { } bool NetworkConnected() { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { return ETHConnected(); } @@ -123,7 +123,7 @@ bool NetworkConnected() { } IPAddress NetworkLocalIP() { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { if(EthEventData.ethInitSuccess) { return ETH.localIP(); @@ -137,7 +137,7 @@ IPAddress NetworkLocalIP() { } IPAddress NetworkSubnetMask() { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { if(EthEventData.ethInitSuccess) { return ETH.subnetMask(); @@ -151,7 +151,7 @@ IPAddress NetworkSubnetMask() { } IPAddress NetworkGatewayIP() { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { if(EthEventData.ethInitSuccess) { return ETH.gatewayIP(); @@ -165,7 +165,7 @@ IPAddress NetworkGatewayIP() { } IPAddress NetworkDnsIP (uint8_t dns_no) { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { if(EthEventData.ethInitSuccess) { return ETH.dnsIP(dns_no); @@ -179,7 +179,7 @@ IPAddress NetworkDnsIP (uint8_t dns_no) { } MAC_address NetworkMacAddress() { - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { return ETHMacAddress(); } @@ -191,7 +191,7 @@ MAC_address NetworkMacAddress() { String NetworkGetHostname() { #ifdef ESP32 - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(Settings.NetworkMedium == NetworkMedium_t::Ethernet && EthEventData.ethInitSuccess) { return String(ETH.getHostname()); } @@ -283,7 +283,7 @@ void CheckRunningServices() { #endif } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET bool EthFullDuplex() { if (EthEventData.ethInitSuccess) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 7ea969bd4d..799d7b5ca3 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -30,7 +30,7 @@ String WifiSTAmacAddress(); void CheckRunningServices(); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET bool EthFullDuplex(); bool EthLinkUp(); uint8_t EthLinkSpeed(); diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 950b249343..e8b77785dd 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -1,6 +1,6 @@ #include "../ESPEasyCore/ESPEasyWiFiEvent.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include #endif @@ -73,12 +73,12 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (active_network_medium == NetworkMedium_t::Ethernet) { EthEventData.markLostIP(); } else - #endif + #endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? @@ -146,7 +146,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_WIFI_SCAN_DONE: WiFiEventData.processedScanDone = false; break; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET case ARDUINO_EVENT_ETH_START: if (ethPrepare()) { addLog(LOG_LEVEL_INFO, F("ETH event: Started")); @@ -176,7 +176,7 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { #endif addLog(LOG_LEVEL_INFO, F("ETH event: Got IP6")); break; -#endif //HAS_ETHERNET +#endif //FEATURE_ETHERNET default: { String log = F("UNKNOWN WIFI/ETH EVENT: "); @@ -206,12 +206,12 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { break; case SYSTEM_EVENT_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (active_network_medium == NetworkMedium_t::Ethernet) { EthEventData.markLostIP(); } else - #endif + #endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? @@ -279,7 +279,7 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { case SYSTEM_EVENT_SCAN_DONE: WiFiEventData.processedScanDone = false; break; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET case SYSTEM_EVENT_ETH_START: if (ethPrepare()) { addLog(LOG_LEVEL_INFO, F("ETH event: Started")); @@ -305,7 +305,7 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { case SYSTEM_EVENT_GOT_IP6: addLog(LOG_LEVEL_INFO, F("ETH event: Got IP6")); break; -#endif //HAS_ETHERNET +#endif //FEATURE_ETHERNET default: { String log = F("UNKNOWN WIFI/ETH EVENT: "); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index f96606309d..0f1ac5abe7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -44,7 +44,7 @@ // ******************************************************************************** void handle_unprocessedNetworkEvents() { -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET if (EthEventData.unprocessedEthEvents()) { // Process disconnect events before connect events. if (!EthEventData.processedDisconnect) { @@ -88,7 +88,7 @@ void handle_unprocessedNetworkEvents() } EthEventData.setEthServicesInitialized(); } -#endif +#endif // if FEATURE_ETHERNET if (WiFiEventData.unprocessedWifiEvents()) { // Process disconnect events before connect events. if (!WiFiEventData.processedDisconnect) { @@ -213,7 +213,7 @@ void handle_unprocessedNetworkEvents() } } } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET // Check if DNS is still valid, as this may have been reset by the WiFi module turned off. if (EthEventData.EthServicesInitialized() && active_network_medium == NetworkMedium_t::Ethernet && @@ -229,7 +229,7 @@ void handle_unprocessedNetworkEvents() } } } -#endif +#endif // if FEATURE_ETHERNET #if FEATURE_ESPEASY_P2P updateUDPport(); @@ -636,7 +636,9 @@ void processScanDone() { } -#ifdef HAS_ETHERNET + + +#if FEATURE_ETHERNET void processEthernetConnected() { if (EthEventData.processedConnect) return; @@ -759,4 +761,4 @@ void processEthernetGotIP() { CheckRunningServices(); } -#endif \ No newline at end of file +#endif // if FEATURE_ETHERNET \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h index cc9397472f..a8b25a7c79 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.h @@ -15,10 +15,10 @@ void processConnectAPmode(); void processDisableAPmode(); void processScanDone(); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET void processEthernetConnected(); void processEthernetDisconnected(); void processEthernetGotIP(); -#endif +#endif // if FEATURE_ETHERNET #endif //ESPEASYWIFI_PROCESSEVENT_H \ No newline at end of file diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index de53c27b01..432fa148d0 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -283,13 +283,13 @@ void ESPEasy_setup() toDisable = disableNotification(toDisable); } } - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET // This ensures, that changing WIFI OR ETHERNET MODE happens properly only after reboot. Changing without reboot would not be a good idea. // This only works after LoadSettings(); // Do not call setNetworkMedium here as that may try to clean up settings. active_network_medium = Settings.NetworkMedium; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET if (active_network_medium == NetworkMedium_t::WIFI) { WiFi_AP_Candidates.load_knownCredentials(); diff --git a/src/src/Globals/ESPEasyWiFiEvent.cpp b/src/src/Globals/ESPEasyWiFiEvent.cpp index bd1c5927cd..c006ab1b08 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.cpp +++ b/src/src/Globals/ESPEasyWiFiEvent.cpp @@ -28,7 +28,7 @@ std::list APModeProbeRequestReceived_list; WiFiEventData_t WiFiEventData; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET EthernetEventData_t EthEventData; #endif diff --git a/src/src/Globals/ESPEasyWiFiEvent.h b/src/src/Globals/ESPEasyWiFiEvent.h index 6e9a5ea37e..d9ed618dbb 100644 --- a/src/src/Globals/ESPEasyWiFiEvent.h +++ b/src/src/Globals/ESPEasyWiFiEvent.h @@ -10,7 +10,7 @@ #include "../DataStructs/WiFiEventData.h" #include "../DataStructs/MAC_address.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include "../DataStructs/EthernetEventData.h" #endif @@ -47,7 +47,7 @@ extern std::list APModeProbeRequestReceived_list extern WiFiEventData_t WiFiEventData; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET extern EthernetEventData_t EthEventData; #endif diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index edeaaadb91..31c84961dc 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -68,7 +68,7 @@ void hardwareInit() if (getGpioPullResistor(gpio, hasPullUp, hasPullDown)) { PinBootState bootState = Settings.getPinBootState(gpio); - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (Settings.ETH_Pin_power == gpio) { @@ -80,7 +80,7 @@ void hardwareInit() bootState = PinBootState::Output_low; } - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET if (bootState != PinBootState::Default_state) { int8_t state = -1; @@ -222,7 +222,7 @@ void hardwareInit() } } #endif // if FEATURE_SD -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET ethPower(false); #endif } @@ -1193,9 +1193,9 @@ String getDeviceModelString(DeviceModel model) { } bool modelMatchingFlashSize(DeviceModel model) { -#if defined(ESP8266) || (defined(ESP32) && defined(HAS_ETHERNET)) +#if defined(ESP8266) || (defined(ESP32) && FEATURE_ETHERNET) const uint32_t size_MB = getFlashRealSizeInBytes() >> 20; -#endif // if defined(ESP8266) || (defined(ESP32) && defined(HAS_ETHERNET)) +#endif // if defined(ESP8266) || (defined(ESP32) && FEATURE_ETHERNET) // TD-er: This also checks for ESP8266/ESP8285/ESP32 switch (model) { @@ -1234,11 +1234,11 @@ bool modelMatchingFlashSize(DeviceModel model) { case DeviceModel::DeviceModel_Olimex_ESP32_GATEWAY: case DeviceModel::DeviceModel_wESP32: case DeviceModel::DeviceModel_WT32_ETH01: -#if defined(ESP32) && defined(HAS_ETHERNET) +#if defined(ESP32) && FEATURE_ETHERNET return size_MB == 4; -#else // if defined(ESP32) && defined(HAS_ETHERNET) +#else // if defined(ESP32) && FEATURE_ETHERNET return false; -#endif // if defined(ESP32) && defined(HAS_ETHERNET) +#endif // if defined(ESP32) && FEATURE_ETHERNET case DeviceModel::DeviceModel_default: case DeviceModel::DeviceModel_MAX: @@ -1376,7 +1376,7 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) } /* - # ifdef HAS_ETHERNET + # if FEATURE_ETHERNET // Check pins used for RMII Ethernet PHY if (NetworkMedium_t::Ethernet == Settings.NetworkMedium) { @@ -1397,7 +1397,7 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) } - # endif // ifdef HAS_ETHERNET + # endif // if FEATURE_ETHERNET */ # else // ifdef ESP32S2 @@ -1449,7 +1449,7 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) warning = true; } - # ifdef HAS_ETHERNET + # if FEATURE_ETHERNET // Check pins used for RMII Ethernet PHY if (NetworkMedium_t::Ethernet == Settings.NetworkMedium) { @@ -1470,7 +1470,7 @@ bool getGpioInfo(int gpio, int& pinnr, bool& input, bool& output, bool& warning) } - # endif // ifdef HAS_ETHERNET + # endif // if FEATURE_ETHERNET # endif // ifdef ESP32S2 diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index e40b98f791..c52a619403 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -221,7 +221,7 @@ void runEach30Seconds() log += F(" FreeMem "); log += FreeMem(); bool logWiFiStatus = true; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { logWiFiStatus = false; log += F( " EthSpeedState "); @@ -229,7 +229,7 @@ void runEach30Seconds() log += F(" ETH status: "); log += EthEventData.ESPEasyEthStatusToString(); } - #endif + #endif // if FEATURE_ETHERNET if (logWiFiStatus) { log += F(" WiFiStatus "); log += ArduinoWifiStatusToString(WiFi.status()); @@ -577,7 +577,7 @@ void prepareShutdown(ESPEasy_Scheduler::IntendedRebootReason_e reason) flushAndDisconnectAllClients(); saveUserVarToRTC(); setWifiMode(WIFI_OFF); - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET ethPower(false); #endif ESPEASY_FS.end(); diff --git a/src/src/Helpers/StringGenerator_GPIO.cpp b/src/src/Helpers/StringGenerator_GPIO.cpp index 9ba40c6053..90bc678cdb 100644 --- a/src/src/Helpers/StringGenerator_GPIO.cpp +++ b/src/src/Helpers/StringGenerator_GPIO.cpp @@ -150,9 +150,9 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose) bool includeI2C = true; bool includeSPI = true; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET bool includeEthernet = true; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET switch (purpose) { case PinSelectPurpose::I2C: @@ -162,9 +162,9 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose) includeSPI = false; break; case PinSelectPurpose::Ethernet: - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET includeEthernet = false; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET break; case PinSelectPurpose::Generic: case PinSelectPurpose::Generic_input: @@ -180,7 +180,7 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose) if (includeSPI && Settings.isSPI_pin(gpio)) { return F("SPI"); } - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (Settings.isEthernetPin(gpio)) { return F("Eth"); @@ -195,7 +195,7 @@ const __FlashStringHelper* getConflictingUse(int gpio, PinSelectPurpose purpose) return F("Eth"); } - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET #ifdef ESP32 if (UsePSRAM()) { diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index c907be600b..bd3135a7df 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -1,8 +1,8 @@ #include "../Helpers/StringProvider.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET # include -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET #include "../../ESPEasy-Globals.h" #include "../../ESPEasy_common.h" @@ -11,7 +11,7 @@ #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET #include "../ESPEasyCore/ESPEasyEth.h" #endif @@ -206,7 +206,7 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::MAX_OTA_SKETCH_SIZE: return F("Max. OTA Sketch Size"); case LabelType::OTA_2STEP: return F("OTA 2-step Needed"); case LabelType::OTA_POSSIBLE: return F("OTA possible"); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET case LabelType::ETH_IP_ADDRESS: return F("Eth IP Address"); case LabelType::ETH_IP_SUBNET: return F("Eth IP Subnet"); case LabelType::ETH_IP_ADDRESS_SUBNET: return F("Eth IP / Subnet"); @@ -218,7 +218,7 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::ETH_STATE: return F("Eth State"); case LabelType::ETH_SPEED_STATE: return F("Eth Speed State"); case LabelType::ETH_CONNECTED: return F("Eth connected"); -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET case LabelType::ETH_WIFI_MODE: return F("Network Type"); case LabelType::SUNRISE: return F("Sunrise"); case LabelType::SUNSET: return F("Sunset"); @@ -343,20 +343,20 @@ String getValue(LabelType::Enum label) { case LabelType::ENCRYPTION_TYPE_STA: return // WiFi_AP_Candidates.getCurrent().encryption_type(); WiFi_encryptionType(WiFiEventData.auth_mode); case LabelType::CONNECTED: - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { return format_msec_duration(EthEventData.lastConnectMoment.millisPassedSince()); } - #endif + #endif // if FEATURE_ETHERNET return format_msec_duration(WiFiEventData.lastConnectMoment.millisPassedSince()); // Use only the nr of seconds to fit it in an int32, plus append '000' to have msec format again. case LabelType::CONNECTED_MSEC: - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { return String(static_cast(EthEventData.lastConnectMoment.millisPassedSince() / 1000ll)) + F("000"); } - #endif + #endif // if FEATURE_ETHERNET return String(static_cast(WiFiEventData.lastConnectMoment.millisPassedSince() / 1000ll)) + F("000"); case LabelType::LAST_DISCONNECT_REASON: return String(WiFiEventData.lastDisconnectReason); case LabelType::LAST_DISC_REASON_STR: return getLastDisconnectReason(); @@ -427,7 +427,7 @@ String getValue(LabelType::Enum label) { case LabelType::MAX_OTA_SKETCH_SIZE: break; case LabelType::OTA_2STEP: break; case LabelType::OTA_POSSIBLE: break; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET case LabelType::ETH_IP_ADDRESS: return NetworkLocalIP().toString(); case LabelType::ETH_IP_SUBNET: return NetworkSubnetMask().toString(); case LabelType::ETH_IP_ADDRESS_SUBNET: return String(getValue(LabelType::ETH_IP_ADDRESS) + F(" / ") + @@ -440,7 +440,7 @@ String getValue(LabelType::Enum label) { case LabelType::ETH_STATE: return EthLinkUp() ? F("Link Up") : F("Link Down"); case LabelType::ETH_SPEED_STATE: return EthLinkUp() ? getEthLinkSpeedState() : F("Link Down"); case LabelType::ETH_CONNECTED: return ETHConnected() ? F("CONNECTED") : F("DISCONNECTED"); // 0=disconnected, 1=connected -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET case LabelType::ETH_WIFI_MODE: return toString(active_network_medium); case LabelType::SUNRISE: return node_time.getSunriseTimeString(':'); case LabelType::SUNSET: return node_time.getSunsetTimeString(':'); @@ -460,7 +460,7 @@ String getValue(LabelType::Enum label) { return F("MissingString"); } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET String getEthSpeed() { String result; @@ -487,7 +487,7 @@ String getEthLinkSpeedState() { return result; } -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET String getExtendedValue(LabelType::Enum label) { switch (label) diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index da6d6e24b7..70f666e6d8 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -164,7 +164,7 @@ struct LabelType { MAX_OTA_SKETCH_SIZE, OTA_2STEP, OTA_POSSIBLE, -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET ETH_IP_ADDRESS, ETH_IP_SUBNET, ETH_IP_ADDRESS_SUBNET, @@ -176,7 +176,7 @@ struct LabelType { ETH_STATE, ETH_SPEED_STATE, ETH_CONNECTED, -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET ETH_WIFI_MODE, SUNRISE, SUNSET, @@ -196,11 +196,11 @@ struct LabelType { }; -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET String getEthSpeed(); String getEthLinkSpeedState(); -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET String getInternalLabel(LabelType::Enum label, char replaceSpace = '_'); diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 8cc8eb50d8..6e7cbde837 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -82,7 +82,7 @@ LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) { case SystemVariables::GATEWAY: label = LabelType::GATEWAY; break; case SystemVariables::CLIENTIP: label = LabelType::CLIENT_IP; break; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET case SystemVariables::ETHWIFIMODE: label = LabelType::ETH_WIFI_MODE; break; // 0=WIFI, 1=ETH case SystemVariables::ETHCONNECTED: label = LabelType::ETH_CONNECTED; break; // 0=disconnected, 1=connected @@ -90,7 +90,7 @@ LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) { case SystemVariables::ETHSPEED: label = LabelType::ETH_SPEED; break; case SystemVariables::ETHSTATE: label = LabelType::ETH_STATE; break; case SystemVariables::ETHSPEEDSTATE: label = LabelType::ETH_SPEED_STATE; break; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET case SystemVariables::LCLTIME: label = LabelType::LOCAL_TIME; break; case SystemVariables::MAC: label = LabelType::STA_MAC; break; case SystemVariables::RSSI: label = LabelType::WIFI_RSSI; break; @@ -329,14 +329,14 @@ const __FlashStringHelper * SystemVariables::toString(SystemVariables::Enum enum case Enum::ISMQTTIMP: return F("%ismqttimp%"); case Enum::ISNTP: return F("%isntp%"); case Enum::ISWIFI: return F("%iswifi%"); - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET case Enum::ETHWIFIMODE: return F("%ethwifimode%"); case Enum::ETHCONNECTED: return F("%ethconnected%"); case Enum::ETHDUPLEX: return F("%ethduplex%"); case Enum::ETHSPEED: return F("%ethspeed%"); case Enum::ETHSTATE: return F("%ethstate%"); case Enum::ETHSPEEDSTATE: return F("%ethspeedstate%"); - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET case Enum::LCLTIME: return F("%lcltime%"); case Enum::LCLTIME_AM: return F("%lcltime_am%"); case Enum::LF: return F("%LF%"); diff --git a/src/src/Helpers/SystemVariables.h b/src/src/Helpers/SystemVariables.h index 05f39c970f..eff786c809 100644 --- a/src/src/Helpers/SystemVariables.h +++ b/src/src/Helpers/SystemVariables.h @@ -26,14 +26,14 @@ class SystemVariables { ISMQTTIMP, ISNTP, ISWIFI, - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET ETHWIFIMODE, ETHCONNECTED, ETHDUPLEX, ETHSPEED, ETHSTATE, ETHSPEEDSTATE, - #endif + #endif // if FEATURE_ETHERNET LCLTIME, LCLTIME_AM, LF, diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index 94299bb000..ebd00e2efe 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -140,12 +140,12 @@ void handle_config() { webArg2ip(F("espgateway"), Settings.Gateway); webArg2ip(F("espsubnet"), Settings.Subnet); webArg2ip(F("espdns"), Settings.DNS); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET webArg2ip(F("espethip"), Settings.ETH_IP); webArg2ip(F("espethgateway"), Settings.ETH_Gateway); webArg2ip(F("espethsubnet"), Settings.ETH_Subnet); webArg2ip(F("espethdns"), Settings.ETH_DNS); -#endif +#endif // if FEATURE_ETHERNET addHtmlError(SaveSettings()); } @@ -181,11 +181,11 @@ void handle_config() { addFormNote(F("When set you can use the Sensor in AP-Mode without being forced to /setup. /setup can still be called.")); addFormCheckBox(F("Do Not Start AP"), F("DoNotStartAP"), Settings.DoNotStartAP()); - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET addFormNote(F("Do not allow to start an AP when unable to connect to configured LAN/WiFi")); - #else + #else // if FEATURE_ETHERNET addFormNote(F("Do not allow to start an AP when configured WiFi cannot be found")); - #endif + #endif // if FEATURE_ETHERNET // TD-er add IP access box F("ipblocklevel") @@ -213,7 +213,7 @@ void handle_config() { addFormIPBox(F("ESP WiFi DNS"), F("espdns"), Settings.DNS); addFormNote(F("Leave empty for DHCP")); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET addFormSubHeader(F("Ethernet IP Settings")); addFormIPBox(F("ESP Ethernet IP"), F("espethip"), Settings.ETH_IP); @@ -221,7 +221,7 @@ void handle_config() { addFormIPBox(F("ESP Ethernet Subnetmask"), F("espethsubnet"), Settings.ETH_Subnet); addFormIPBox(F("ESP Ethernet DNS"), F("espethdns"), Settings.ETH_DNS); addFormNote(F("Leave empty for DHCP")); -#endif +#endif // if FEATURE_ETHERNET #ifdef USES_ESPEASY_NOW addFormSubHeader(F("ESPEasy-NOW")); diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index 20d2b63791..8f3976a05a 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -65,7 +65,7 @@ void handle_hardware() { Settings.InitSPI = isFormItemChecked(F("initspi")); // SPI Init #endif Settings.Pin_sd_cs = getFormItemInt(F("sd")); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET Settings.ETH_Phy_Addr = getFormItemInt(F("ethphy")); Settings.ETH_Pin_mdc = getFormItemInt(F("ethmdc")); Settings.ETH_Pin_mdio = getFormItemInt(F("ethmdio")); @@ -73,7 +73,7 @@ void handle_hardware() { Settings.ETH_Phy_Type = static_cast(getFormItemInt(F("ethtype"))); Settings.ETH_Clock_Mode = static_cast(getFormItemInt(F("ethclock"))); Settings.NetworkMedium = static_cast(getFormItemInt(F("ethwifi"))); -#endif +#endif // if FEATURE_ETHERNET int gpio = 0; while (gpio <= MAX_GPIO) { @@ -197,7 +197,7 @@ void handle_hardware() { addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output(F("SD Card CS")), F("sd"), Settings.Pin_sd_cs); #endif // if FEATURE_SD -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET addFormSubHeader(F("Ethernet")); addRowLabel_tr_id(F("Preferred network medium"), F("ethwifi")); { @@ -253,7 +253,7 @@ void handle_hardware() { }; addSelector(F("ethclock"), 4, ethClockOptions, nullptr, nullptr, static_cast(Settings.ETH_Clock_Mode), false, true); } -#endif // ifdef HAS_ETHERNET +#endif // if FEATURE_ETHERNET addFormSubHeader(F("GPIO boot states")); diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index bb0a64e0d7..16505949c0 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -107,9 +107,9 @@ void handle_json() bool showSystem = true; bool showWifi = true; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET bool showEthernet = true; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET bool showDataAcquisition = true; bool showTaskDetails = true; #if FEATURE_ESPEASY_P2P @@ -121,9 +121,9 @@ void handle_json() if (view == F("sensorupdate")) { showSystem = false; showWifi = false; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET showEthernet = false; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET showDataAcquisition = false; showTaskDetails = false; #if FEATURE_ESPEASY_P2P @@ -265,7 +265,7 @@ void handle_json() stream_comma_newline(); } - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (showEthernet) { addHtml(F("\"Ethernet\":{\n")); @@ -285,7 +285,7 @@ void handle_json() stream_json_object_values(labels); stream_comma_newline(); } - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET #if FEATURE_ESPEASY_P2P if (showNodes) { diff --git a/src/src/WebServer/Markup.cpp b/src/src/WebServer/Markup.cpp index 554969567e..20ebbd6307 100644 --- a/src/src/WebServer/Markup.cpp +++ b/src/src/WebServer/Markup.cpp @@ -265,18 +265,18 @@ void addPinSelector_Item(PinSelectPurpose purpose, const String& gpio_label, int if (getGpioInfo(gpio, pinnr, input, output, warning)) { bool includeI2C = true; bool includeSPI = true; - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET bool includeEthernet = true; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET switch (purpose) { case PinSelectPurpose::SPI: includeSPI = false; break; case PinSelectPurpose::Ethernet: - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET includeEthernet = false; - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET break; case PinSelectPurpose::Generic: @@ -324,12 +324,12 @@ void addPinSelector_Item(PinSelectPurpose purpose, const String& gpio_label, int disabled = true; } - #ifdef HAS_ETHERNET + #if FEATURE_ETHERNET if (Settings.isEthernetPin(gpio) || (includeEthernet && Settings.isEthernetPinOptional(gpio))) { disabled = true; } - #endif // ifdef HAS_ETHERNET + #endif // if FEATURE_ETHERNET } } diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index dffaf1d193..3d3c09bf45 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -194,7 +194,7 @@ void handle_root() { addHtml(html); } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET addRowLabelValue(LabelType::ETH_WIFI_MODE); #endif @@ -211,7 +211,7 @@ void handle_root() { addHtml(html); } -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET if(active_network_medium == NetworkMedium_t::Ethernet) { addRowLabelValue(LabelType::ETH_SPEED_STATE); addRowLabelValue(LabelType::ETH_IP_ADDRESS); diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 68a35e194d..a9b0c98c49 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -134,7 +134,7 @@ void handle_sysinfo_json() { json_prop(F("ssid2"), getValue(LabelType::WIFI_STORED_SSID2)); json_close(); -# ifdef HAS_ETHERNET +# if FEATURE_ETHERNET json_open(false, F("ethernet")); json_prop(F("ethwifimode"), getValue(LabelType::ETH_WIFI_MODE)); json_prop(F("ethconnected"), getValue(LabelType::ETH_CONNECTED)); @@ -143,7 +143,7 @@ void handle_sysinfo_json() { json_prop(F("ethstate"), getValue(LabelType::ETH_STATE)); json_prop(F("ethspeedstate"), getValue(LabelType::ETH_SPEED_STATE)); json_close(); -# endif // ifdef HAS_ETHERNET +# endif // if FEATURE_ETHERNET json_open(false, F("firmware")); json_prop(F("build"), String(BUILD)); @@ -258,9 +258,9 @@ void handle_sysinfo() { handle_sysinfo_Network(); -# ifdef HAS_ETHERNET +# if FEATURE_ETHERNET handle_sysinfo_Ethernet(); -# endif // ifdef HAS_ETHERNET +# endif // if FEATURE_ETHERNET handle_sysinfo_WiFiSettings(); @@ -382,7 +382,7 @@ void handle_sysinfo_memory() { # endif // if defined(ESP32) && defined(BOARD_HAS_PSRAM) } -# ifdef HAS_ETHERNET +# if FEATURE_ETHERNET void handle_sysinfo_Ethernet() { if (active_network_medium == NetworkMedium_t::Ethernet) { addTableSeparator(F("Ethernet"), 2, 3); @@ -396,12 +396,12 @@ void handle_sysinfo_Ethernet() { } } -# endif // ifdef HAS_ETHERNET +# endif // if FEATURE_ETHERNET void handle_sysinfo_Network() { addTableSeparator(F("Network"), 2, 3); - # if defined(HAS_ETHERNET) || defined(USES_ESPEASY_NOW) + # if FEATURE_ETHERNET || defined(USES_ESPEASY_NOW) addRowLabelValue(LabelType::ETH_WIFI_MODE); # endif diff --git a/src/src/WebServer/SysInfoPage.h b/src/src/WebServer/SysInfoPage.h index f592f92c1d..6645b30397 100644 --- a/src/src/WebServer/SysInfoPage.h +++ b/src/src/WebServer/SysInfoPage.h @@ -21,7 +21,7 @@ void handle_sysinfo_basicInfo(); void handle_sysinfo_memory(); -#ifdef HAS_ETHERNET +#if FEATURE_ETHERNET void handle_sysinfo_Ethernet(); #endif diff --git a/src/src/WebServer/SysVarPage.cpp b/src/src/WebServer/SysVarPage.cpp index be4b2b9221..ac250bd8dd 100644 --- a/src/src/WebServer/SysVarPage.cpp +++ b/src/src/WebServer/SysVarPage.cpp @@ -66,7 +66,7 @@ void handle_sysvars() { addSysVar_enum_html(SystemVariables::BSSID); addSysVar_enum_html(SystemVariables::WI_CH); -#ifdef HAS_ETHERNET + #if FEATURE_ETHERNET addTableSeparator(F("Ethernet"), 3, 3); addSysVar_enum_html(SystemVariables::ETHWIFIMODE); addSysVar_enum_html(SystemVariables::ETHCONNECTED); @@ -74,7 +74,7 @@ void handle_sysvars() { addSysVar_enum_html(SystemVariables::ETHSPEED); addSysVar_enum_html(SystemVariables::ETHSTATE); addSysVar_enum_html(SystemVariables::ETHSPEEDSTATE); - #endif + #endif // if FEATURE_ETHERNET addTableSeparator(F("System"), 3, 3); addSysVar_enum_html(SystemVariables::UNIT_sysvar); From 1dbded8f3ed4cec36e9cbcee84178ece350b4501 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Wed, 27 Jul 2022 22:09:49 +0200 Subject: [PATCH 275/404] [Build] Remove unused #define --- src/src/CustomBuild/define_plugin_sets.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index ccde899732..d8b28c4952 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1336,9 +1336,6 @@ To create/register a plugin, you have to : #if !defined(LIMIT_BUILD_SIZE) && (defined(ESP8266) || !(ESP_IDF_VERSION_MAJOR > 3)) #define LIMIT_BUILD_SIZE // Reduce buildsize (on ESP8266 / pre-IDF4.x) to fit in all Display plugins #endif - #ifndef USES_ADAFRUITGFX_HELPER - #define USES_ADAFRUITGFX_HELPER - #endif #ifndef USES_P012 #define USES_P012 // LCD #endif From 6d30954b81053717c649ca4df5b8c853480f978b Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 28 Jul 2022 01:02:38 +0200 Subject: [PATCH 276/404] [ESPEasy-NOW] Fix some include loop dependencies --- src/ESPEasy_common.h | 12 +++++++----- src/_C014.cpp | 3 ++- src/src/DataStructs/NodeStruct.cpp | 19 ++----------------- src/src/DataStructs/NodeStruct.h | 13 +------------ src/src/DataTypes/NodeTypeID.cpp | 17 +++++++++++++++++ src/src/DataTypes/NodeTypeID.h | 17 +++++++++++++++++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- src/src/Helpers/ESPEasy_checks.cpp | 2 -- src/src/Helpers/ESPEasy_now_peermanager.cpp | 1 + src/src/Helpers/Networking.cpp | 1 + src/src/WebServer/ConfigPage.cpp | 6 +++--- src/src/WebServer/DevicesPage.cpp | 2 ++ 12 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 src/src/DataTypes/NodeTypeID.cpp create mode 100644 src/src/DataTypes/NodeTypeID.h diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index a16bd9ccc8..a47d14200f 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -65,11 +65,7 @@ namespace std // Check if any deprecated '#define ' (Custom.h) or '-D' (pre_custom_esp82xx.py/pre_custom_esp32.py) are used #include "./src/CustomBuild/check_defines_custom.h" // Check for replaced #define variables, see https://github.com/letscontrolit/ESPEasy/pull/4153 -#include "src/CustomBuild/ESPEasyDefaults.h" -#include "src/DataStructs/NodeStruct.h" -#include "src/Globals/RamTracker.h" -#include "src/ESPEasyCore/ESPEasy_Log.h" -#include "src/Helpers/ESPEasy_math.h" +#include "src/DataTypes/NodeTypeID.h" #ifndef FS_NO_GLOBALS #define FS_NO_GLOBALS @@ -179,6 +175,12 @@ using namespace fs; #include "src/CustomBuild/ESPEasyLimits.h" #include "src/CustomBuild/define_plugin_sets.h" +#include "src/CustomBuild/ESPEasyDefaults.h" +#include "src/Globals/RamTracker.h" +#include "src/ESPEasyCore/ESPEasy_Log.h" +#include "src/Helpers/ESPEasy_math.h" + + #ifdef ESP32 #include diff --git a/src/_C014.cpp b/src/_C014.cpp index e70b2f7642..23b1f9bb5f 100644 --- a/src/_C014.cpp +++ b/src/_C014.cpp @@ -2,6 +2,7 @@ #ifdef USES_C014 # include "src/Commands/InternalCommands.h" +# include "src/DataTypes/NodeTypeID.h" # include "src/Globals/Device.h" # include "src/Globals/MQTT.h" # include "src/Globals/Plugins.h" @@ -307,7 +308,7 @@ bool CPlugin_014(CPlugin::Function function, struct EventStruct *event, String& errorCounter); // $fw/name Device → Controller Name of the firmware running on the device. Allowed characters are the same as the device ID Yes Yes - CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex, F("$fw/name"), getNodeTypeDisplayString(NODE_TYPE_ID), + CPlugin_014_sendMQTTdevice(pubname, event->TaskIndex, F("$fw/name"), toNodeTypeDisplayString(NODE_TYPE_ID), errorCounter); // $stats/interval Device → Controller Interval in seconds at which the device refreshes its $stats/+: See next section for diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index c93dc0d0b9..5308bf6d21 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -1,6 +1,7 @@ #include "../DataStructs/NodeStruct.h" #include "../../ESPEasy-Globals.h" +#include "../DataTypes/NodeTypeID.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" #include "../Helpers/ESPEasy_time_calc.h" @@ -90,24 +91,8 @@ bool NodeStruct::operator<(const NodeStruct &other) const { } -const __FlashStringHelper * NodeStruct::getNodeTypeDisplayString(uint8_t nodeType) { - switch (nodeType) - { - case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); - case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); - case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); - case NODE_TYPE_ID_ESP_EASY32S2_STD: return F("ESP Easy 32-s2"); - case NODE_TYPE_ID_ESP_EASY32C3_STD: return F("ESP Easy 32-c3"); - case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); - case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); - case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); - } - return F(""); -} - - const __FlashStringHelper * NodeStruct::getNodeTypeDisplayString() const { - return NodeStruct::getNodeTypeDisplayString(nodeType); + return toNodeTypeDisplayString(nodeType); } String NodeStruct::getNodeName() const { diff --git a/src/src/DataStructs/NodeStruct.h b/src/src/DataStructs/NodeStruct.h index 6e2b4c4f56..1b0f430cab 100644 --- a/src/src/DataStructs/NodeStruct.h +++ b/src/src/DataStructs/NodeStruct.h @@ -9,16 +9,6 @@ #include -#define NODE_TYPE_ID_ESP_EASY_STD 1 -#define NODE_TYPE_ID_RPI_EASY_STD 5 // https://github.com/enesbcs/rpieasy -#define NODE_TYPE_ID_ESP_EASYM_STD 17 -#define NODE_TYPE_ID_ESP_EASY32_STD 33 -#define NODE_TYPE_ID_ESP_EASY32S2_STD 34 -#define NODE_TYPE_ID_ESP_EASY32C3_STD 35 -#define NODE_TYPE_ID_ARDUINO_EASY_STD 65 -#define NODE_TYPE_ID_NANO_EASY_STD 81 - - #if FEATURE_ESPEASY_P2P /*********************************************************************************************\ * NodeStruct @@ -38,8 +28,7 @@ struct __attribute__((__packed__)) NodeStruct // - lower load (TODO TD-er) bool operator<(const NodeStruct &other) const; - static const __FlashStringHelper * getNodeTypeDisplayString(uint8_t nodeType); - const __FlashStringHelper * getNodeTypeDisplayString() const; + const __FlashStringHelper * getNodeTypeDisplayString() const; String getNodeName() const; diff --git a/src/src/DataTypes/NodeTypeID.cpp b/src/src/DataTypes/NodeTypeID.cpp new file mode 100644 index 0000000000..4c75be2da8 --- /dev/null +++ b/src/src/DataTypes/NodeTypeID.cpp @@ -0,0 +1,17 @@ +#include "../DataTypes/NodeTypeID.h" + + +const __FlashStringHelper* toNodeTypeDisplayString(uint8_t nodeType) { + switch (nodeType) + { + case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy"); + case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega"); + case NODE_TYPE_ID_ESP_EASY32_STD: return F("ESP Easy 32"); + case NODE_TYPE_ID_ESP_EASY32S2_STD: return F("ESP Easy 32-s2"); + case NODE_TYPE_ID_ESP_EASY32C3_STD: return F("ESP Easy 32-c3"); + case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy"); + case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy"); + case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy"); + } + return F(""); +} diff --git a/src/src/DataTypes/NodeTypeID.h b/src/src/DataTypes/NodeTypeID.h new file mode 100644 index 0000000000..02f41fe9a6 --- /dev/null +++ b/src/src/DataTypes/NodeTypeID.h @@ -0,0 +1,17 @@ +#ifndef DATATYPES_NODETYPEID_H +#define DATATYPES_NODETYPEID_H + +#include + +#define NODE_TYPE_ID_ESP_EASY_STD 1 +#define NODE_TYPE_ID_RPI_EASY_STD 5 // https://github.com/enesbcs/rpieasy +#define NODE_TYPE_ID_ESP_EASYM_STD 17 +#define NODE_TYPE_ID_ESP_EASY32_STD 33 +#define NODE_TYPE_ID_ESP_EASY32S2_STD 34 +#define NODE_TYPE_ID_ESP_EASY32C3_STD 35 +#define NODE_TYPE_ID_ARDUINO_EASY_STD 65 +#define NODE_TYPE_ID_NANO_EASY_STD 81 + +const __FlashStringHelper* toNodeTypeDisplayString(uint8_t nodeType); + +#endif // ifndef DATATYPES_NODETYPEID_H diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index f1c8bb3234..c9b4631de7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1377,7 +1377,7 @@ void setConnectionSpeed() { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } else { WiFiPhyMode_t phyMode = WIFI_PHY_MODE_11G; - #ifdef USE_ESPEASY_NOW + #ifdef USES_ESPEASY_NOW if (active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { phyMode = WIFI_PHY_MODE_11B; } diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index f3aa4864f6..9c8015989e 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -7,13 +7,11 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../DataStructs/DeviceStruct.h" #include "../DataStructs/ESPEasy_EventStruct.h" -#include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataStructs/ExtraTaskSettingsStruct.h" #include "../DataStructs/FactoryDefaultPref.h" #include "../DataStructs/GpioFactorySettingsStruct.h" #include "../DataStructs/LogStruct.h" #include "../DataStructs/NodeStruct.h" -#include "../DataStructs/NodeStruct.h" #include "../DataStructs/PortStatusStruct.h" #include "../DataStructs/ProtocolStruct.h" #if FEATURE_CUSTOM_PROVISIONING diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index 3fa54689a7..2d0bb19372 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -2,6 +2,7 @@ #ifdef USES_ESPEASY_NOW +# include "../DataStructs/NodeStruct.h" # include "../ESPEasyCore/ESPEasy_Log.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../Globals/Nodes.h" diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 211e56915f..e00e83c3ea 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -3,6 +3,7 @@ #include "../../ESPEasy_common.h" #include "../Commands/InternalCommands.h" #include "../CustomBuild/CompiletimeDefines.h" +#include "../DataStructs/NodeStruct.h" #include "../DataStructs/TimingStats.h" #include "../DataTypes/EventValueSource.h" #include "../ESPEasyCore/ESPEasy_Log.h" diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index ebd00e2efe..9a43f3f77d 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -9,6 +9,9 @@ #include "../WebServer/Markup_Forms.h" #include "../WebServer/WebServer.h" +#include "../DataStructs/MAC_address.h" +#include "../DataStructs/NodeStruct.h" + #include "../ESPEasyCore/Controller.h" #include "../ESPEasyCore/ESPEasyNetwork.h" @@ -23,9 +26,6 @@ #include "../Helpers/StringConverter.h" - -#include "../DataStructs/MAC_address.h" - // ******************************************************************************** // Web Interface config page // ******************************************************************************** diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 5ca67edf41..80db37a8a3 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -8,6 +8,8 @@ # include "../WebServer/Markup_Buttons.h" # include "../WebServer/Markup_Forms.h" +# include "../DataStructs/NodeStruct.h" + # include "../Globals/CPlugins.h" # include "../Globals/Device.h" # include "../Globals/ExtraTaskSettings.h" From 7a05a560da239a8bc7140d4957a265d3bf008624 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 28 Jul 2022 01:48:14 +0200 Subject: [PATCH 277/404] [ESPEasy-NOW] Fix include dependencies --- src/src/Commands/ESPEasy_Now_cmd.cpp | 2 - src/src/Commands/ESPEasy_Now_cmd.h | 4 +- src/src/ControllerQueue/C011_queue_element.h | 5 +- src/src/ControllerQueue/C015_queue_element.h | 4 +- src/src/ControllerQueue/C016_queue_element.h | 8 +-- src/src/ControllerQueue/C018_queue_element.h | 4 +- .../ControllerQueue/C019_queue_element.cpp | 6 +++ src/src/ControllerQueue/C019_queue_element.h | 7 +-- .../ControllerDelayHandlerStruct.h | 2 + src/src/ControllerQueue/MQTT_queue_element.h | 5 +- .../DataStructs/ControllerSettingsStruct.h | 3 +- .../DataStructs/ESPEasy_Now_DuplicateCheck.h | 5 +- .../ESPEasy_Now_MQTT_queue_check_packet.h | 6 ++- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 3 ++ src/src/DataStructs/ESPEasy_Now_NTP_query.h | 6 +++ src/src/DataStructs/ESPEasy_Now_packet.cpp | 3 +- src/src/DataStructs/ESPEasy_Now_packet.h | 49 +++++++++---------- .../ESPEasy_now_Node_statistics.cpp | 3 +- src/src/DataStructs/ESPEasy_now_hdr.h | 4 +- src/src/DataStructs/ESPEasy_now_merger.h | 4 +- src/src/DataStructs/NodesHandler.cpp | 2 +- src/src/DataStructs/SettingsStruct.h | 3 +- src/src/DataStructs/TimingStats.h | 3 +- src/src/DataStructs/WiFiEventData.h | 2 + src/src/ESPEasyCore/ESPEasyNetwork.h | 7 --- src/src/Helpers/ESPEasy_now_handler.cpp | 3 +- src/src/Helpers/ESPEasy_now_handler.h | 6 +-- src/src/Helpers/ESPEasy_now_peermanager.h | 3 +- src/src/Helpers/ESPEasy_time.h | 2 + src/src/Helpers/PeriodicalActions.h | 1 - src/src/Helpers/WiFi_AP_CandidatesList.h | 3 +- src/src/Helpers/_CPlugin_Helper_webform.h | 2 + src/src/WebServer/AdvancedConfigPage.cpp | 3 +- src/src/WebServer/AdvancedConfigPage.h | 5 +- src/src/WebServer/ControllerPage.h | 5 +- 35 files changed, 108 insertions(+), 75 deletions(-) diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index 3b4ab64f36..45719393fc 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -1,8 +1,6 @@ #include "../Commands/ESPEasy_Now_cmd.h" -#include "../Globals/ESPEasy_now_state.h" - #include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW diff --git a/src/src/Commands/ESPEasy_Now_cmd.h b/src/src/Commands/ESPEasy_Now_cmd.h index e3ce8d192b..aa07dcc7c6 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.h +++ b/src/src/Commands/ESPEasy_Now_cmd.h @@ -1,10 +1,12 @@ #ifndef COMMANDS_ESPEASY_NOW_CMD_H #define COMMANDS_ESPEASY_NOW_CMD_H -#include "../Globals/ESPEasy_now_state.h" #include "../../ESPEasy_common.h" + #ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_state.h" + class String; String Command_ESPEasy_Now_Disable(struct EventStruct *event, diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h index 12c209f95b..c32e6cae0b 100644 --- a/src/src/ControllerQueue/C011_queue_element.h +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -2,6 +2,9 @@ #define CONTROLLERQUEUE_C011_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + +#ifdef USES_C011 + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../DataStructs/MessageRouteInfo.h" @@ -11,8 +14,6 @@ struct EventStruct; -#ifdef USES_C011 - /*********************************************************************************************\ * C011_queue_element for queueing requests for C011: Generic HTTP Advanced. \*********************************************************************************************/ diff --git a/src/src/ControllerQueue/C015_queue_element.h b/src/src/ControllerQueue/C015_queue_element.h index 61d346230b..eaf0d3bf59 100644 --- a/src/src/ControllerQueue/C015_queue_element.h +++ b/src/src/ControllerQueue/C015_queue_element.h @@ -2,6 +2,9 @@ #define CONTROLLERQUEUE_C015_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + +#ifdef USES_C015 + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -9,7 +12,6 @@ struct EventStruct; -#ifdef USES_C015 /*********************************************************************************************\ * C015_queue_element for queueing requests for 015: Blynk diff --git a/src/src/ControllerQueue/C016_queue_element.h b/src/src/ControllerQueue/C016_queue_element.h index 51919ad204..093b34fd5b 100644 --- a/src/src/ControllerQueue/C016_queue_element.h +++ b/src/src/ControllerQueue/C016_queue_element.h @@ -2,6 +2,11 @@ #define CONTROLLERQUEUE_C016_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + + +#ifdef USES_C016 + + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../DataTypes/ControllerIndex.h" @@ -10,9 +15,6 @@ struct EventStruct; - -#ifdef USES_C016 - /*********************************************************************************************\ * C016_queue_element for queueing requests for C016: Cached HTTP. \*********************************************************************************************/ diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index 7a8e52e0fd..4c994e3488 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -2,6 +2,9 @@ #define CONTROLLERQUEUE_C018_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + +#ifdef USES_C018 + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -9,7 +12,6 @@ struct EventStruct; -#ifdef USES_C018 /*********************************************************************************************\ * C018_queue_element for queueing requests for C018: TTN/RN2483 diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index edc17a00a7..b234b34af0 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -1,5 +1,8 @@ #include "../ControllerQueue/C019_queue_element.h" + +#ifdef USES_C019 + #include "../DataStructs/ESPEasy_EventStruct.h" #include "../ESPEasyCore/ESPEasy_Log.h" @@ -57,3 +60,6 @@ bool C019_queue_element::isDuplicate(const C019_queue_element& other) const { // FIXME TD-er: Must check event too? return false; } + + +#endif \ No newline at end of file diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index aa3b7a41df..ba1aeee182 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -2,14 +2,15 @@ #define CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + +#ifdef USES_C019 + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" -// #ifdef USES_C019 - /*********************************************************************************************\ * C019_queue_element for queueing requests for C019: ESPEasy-NOW \*********************************************************************************************/ @@ -49,7 +50,7 @@ class C019_queue_element { #endif }; -// #endif //USES_C019 +#endif //USES_C019 #endif // CONTROLLERQUEUE_C019_QUEUE_ELEMENT_H diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index e2d64eb7a5..8200308d3c 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -1,6 +1,8 @@ #ifndef CONTROLLERQUEUE_CONTROLLER_DELAY_HANDLER_STRUCT_H #define CONTROLLERQUEUE_CONTROLLER_DELAY_HANDLER_STRUCT_H +#include "../../ESPEasy_common.h" + #include "../DataStructs/ControllerSettingsStruct.h" #include "../DataStructs/TimingStats.h" #include "../DataStructs/MessageRouteInfo.h" diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index 7573650395..c7b039d7de 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -2,10 +2,13 @@ #define CONTROLLERQUEUE_MQTT_QUEUE_ELEMENT_H #include "../../ESPEasy_common.h" + +#ifdef USES_MQTT + + #include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" -#ifdef USES_MQTT /*********************************************************************************************\ * MQTT_queue_element for all MQTT base controllers diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 4348a26de3..44b37991db 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -1,6 +1,8 @@ #ifndef DATASTRUCTS_CONTROLLERSETTINGSSTRUCT_H #define DATASTRUCTS_CONTROLLERSETTINGSSTRUCT_H +#include "../../ESPEasy_common.h" + /*********************************************************************************************\ * ControllerSettingsStruct definition \*********************************************************************************************/ @@ -12,7 +14,6 @@ #include #include -#include "../../ESPEasy_common.h" #include "../Globals/Plugins.h" // Minimum delay between messages for a controller to send in msec. diff --git a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h index acd3ea77e9..be5e58fc2b 100644 --- a/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h +++ b/src/src/DataStructs/ESPEasy_Now_DuplicateCheck.h @@ -1,11 +1,12 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H #define DATASTRUCTS_ESPEASY_NOW_DUPLICATECHECK_H -#include - #include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW + +#include + class ESPEasy_Now_DuplicateCheck { public: diff --git a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h index 9d267bfeba..41e6870c8d 100644 --- a/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h @@ -1,13 +1,15 @@ #ifndef DATASTRUCT_ESPEASY_NOW_MQTT_QUEUE_CHECK_PACKET_H #define DATASTRUCT_ESPEASY_NOW_MQTT_QUEUE_CHECK_PACKET_H +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + #include #include "../Globals/ESPEasy_now_state.h" #include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" -#ifdef USES_ESPEASY_NOW - class ESPEasy_Now_MQTT_queue_check_packet { public: diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 076b8d72e5..70605d67d1 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -1,5 +1,6 @@ #include "../DataStructs/ESPEasy_Now_NTP_query.h" +#ifdef USES_ESPEASY_NOW // Typical time wander for ESP nodes is 0.04 ms/sec @@ -268,3 +269,5 @@ bool ESPEasy_Now_NTP_query::processReply(const ESPEasy_Now_NTP_query& received, reset(true); return true; } + +#endif \ No newline at end of file diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index 3d928ddece..036dd5eae8 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -1,9 +1,14 @@ #ifndef DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H #define DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H +#include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + #include #include + #include "../Globals/ESPEasy_now_state.h" #include "../DataTypes/ESPEasyTimeSource.h" @@ -54,4 +59,5 @@ class ESPEasy_Now_NTP_query { uint8_t _mac_prev_fail[6] = { 0 }; }; +#endif #endif // DATASTRUCT_ESPEASY_NOW_NTP_QUERY_H diff --git a/src/src/DataStructs/ESPEasy_Now_packet.cpp b/src/src/DataStructs/ESPEasy_Now_packet.cpp index 2f672e2678..1cf151e879 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.cpp +++ b/src/src/DataStructs/ESPEasy_Now_packet.cpp @@ -1,12 +1,13 @@ # include "../DataStructs/ESPEasy_Now_packet.h" +#ifdef USES_ESPEASY_NOW + # include "../DataStructs/ESPEasy_now_hdr.h" # include "../Helpers/CRC_functions.h" # include "../Helpers/Memory.h" # define ESPEASY_NOW_MAX_PACKET_SIZE 200 -#ifdef USES_ESPEASY_NOW ESPEasy_Now_packet::ESPEasy_Now_packet(const ESPEasy_now_hdr& header, size_t payloadSize) { diff --git a/src/src/DataStructs/ESPEasy_Now_packet.h b/src/src/DataStructs/ESPEasy_Now_packet.h index fa4f72ed73..dce2669647 100644 --- a/src/src/DataStructs/ESPEasy_Now_packet.h +++ b/src/src/DataStructs/ESPEasy_Now_packet.h @@ -1,25 +1,22 @@ #ifndef DATASTRUCTS_ESPEASY_NOW_PACKET_H #define DATASTRUCTS_ESPEASY_NOW_PACKET_H -#include - -#include "../Globals/ESPEasy_now_state.h" #include "../../ESPEasy_common.h" -#include "../DataStructs/MAC_address.h" +#ifdef USES_ESPEASY_NOW +# include "../DataStructs/MAC_address.h" +# include "../Globals/ESPEasy_now_state.h" -#include -#include -#include +# include +# include +# include +# include -#ifdef USES_ESPEASY_NOW - -class ESPEasy_now_hdr; +class ESPEasy_now_hdr; class ESPEasy_Now_packet { public: - // Constructor for sending a packet // Actual allocated size may be lower than requested. explicit ESPEasy_Now_packet(const ESPEasy_now_hdr& header, @@ -31,35 +28,35 @@ class ESPEasy_Now_packet { ESPEasy_Now_packet(ESPEasy_Now_packet&& other); - ESPEasy_Now_packet& operator=(const ESPEasy_Now_packet& other) = delete; - ESPEasy_Now_packet& operator=(ESPEasy_Now_packet&& other); + ESPEasy_Now_packet & operator=(const ESPEasy_Now_packet& other) = delete; + ESPEasy_Now_packet & operator=(ESPEasy_Now_packet&& other); bool ICACHE_FLASH_ATTR setReceivedPacket(const MAC_address& mac, - const uint8_t *buf, - size_t packetSize); + const uint8_t *buf, + size_t packetSize); // A packet may become invalid if it was not possible to allocate enough memory for the buffer bool ICACHE_FLASH_ATTR valid() const; - bool checksumValid() const; + bool checksumValid() const; - size_t getSize() const; + size_t getSize() const; - size_t getPayloadSize() const; + size_t getPayloadSize() const; - static size_t getMaxPayloadSize(); + static size_t getMaxPayloadSize(); - ESPEasy_now_hdr getHeader() const; + ESPEasy_now_hdr getHeader() const; - void setHeader(ESPEasy_now_hdr header); + void setHeader(ESPEasy_now_hdr header); - void setMac(const MAC_address& mac); + void setMac(const MAC_address& mac); - void setBroadcast(); + void setBroadcast(); - size_t addBinaryData(const uint8_t *data, - size_t length, - size_t & payload_pos); + size_t addBinaryData(const uint8_t *data, + size_t length, + size_t & payload_pos); size_t getBinaryData(uint8_t *data, size_t length, diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index 5fe9d6e375..c38ef836ec 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -1,9 +1,10 @@ #include "../DataStructs/ESPEasy_now_Node_statistics.h" +#ifdef USES_ESPEASY_NOW + #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Helpers/ESPEasy_time_calc.h" -#ifdef USES_ESPEASY_NOW unsigned long ESPEasy_now_Node_statistics_t::getAge() const { diff --git a/src/src/DataStructs/ESPEasy_now_hdr.h b/src/src/DataStructs/ESPEasy_now_hdr.h index 571eb8615e..a0883bff02 100644 --- a/src/src/DataStructs/ESPEasy_now_hdr.h +++ b/src/src/DataStructs/ESPEasy_now_hdr.h @@ -5,11 +5,11 @@ * ESPEasy_now_message_struct \*********************************************************************************************/ -#include "../Globals/ESPEasy_now_state.h" #include "../../ESPEasy_common.h" + #ifdef USES_ESPEASY_NOW -# include +#include "../Globals/ESPEasy_now_state.h" # define ESPEASY_NOW_HEADER_VERSION 2 diff --git a/src/src/DataStructs/ESPEasy_now_merger.h b/src/src/DataStructs/ESPEasy_now_merger.h index 6795defb66..eab83010c1 100644 --- a/src/src/DataStructs/ESPEasy_now_merger.h +++ b/src/src/DataStructs/ESPEasy_now_merger.h @@ -2,13 +2,15 @@ #define DATASTRUCTS_ESPEASY_NOW_MERGER_H #include "../../ESPEasy_common.h" + +#ifdef USES_ESPEASY_NOW + #include "../DataStructs/ESPEasy_now_hdr.h" #include "../DataStructs/ESPEasy_Now_packet.h" #include "../DataStructs/MAC_address.h" #include -#ifdef USES_ESPEASY_NOW // Class to process all incoming messages from a single sender. // One or more packets form a complete message. diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 3a3dfcab82..c23988e0e3 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -5,13 +5,13 @@ #ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_peermanager.h" +#include "../Globals/ESPEasy_now_state.h" #endif #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" #include "../Globals/ESPEasy_time.h" -#include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/MQTT.h" #include "../Globals/NetworkState.h" diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 21c43e8841..76df7731f5 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -2,13 +2,14 @@ #ifndef DATASTRUCTS_SETTINGSSTRUCT_H #define DATASTRUCTS_SETTINGSSTRUCT_H +#include "../../ESPEasy_common.h" + #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/DeviceStruct.h" #include "../DataTypes/EthernetParameters.h" #include "../DataTypes/NetworkMedium.h" #include "../DataTypes/TimeSource.h" #include "../Globals/Plugins.h" -#include "../../ESPEasy_common.h" //we disable SPI if not defined #ifndef DEFAULT_SPI diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 28aa0ec84f..c1dd5c1c19 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -1,12 +1,13 @@ #ifndef DATASTRUCTS_TIMINGSTATS_H #define DATASTRUCTS_TIMINGSTATS_H -#include "../DataTypes/ESPEasy_plugin_functions.h" #include "../../ESPEasy_common.h" #if FEATURE_TIMING_STATS +#include "../DataTypes/ESPEasy_plugin_functions.h" + #include "../Helpers/ESPEasy_time_calc.h" #include "../Globals/Settings.h" diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index 4245a7307e..7334ec79cc 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -1,6 +1,8 @@ #ifndef DATASTRUCTS_WIFIEVENTDATA_H #define DATASTRUCTS_WIFIEVENTDATA_H +#include "../../ESPEasy_common.h" + #include "../../ESPEasy-Globals.h" #include "../DataStructs/MAC_address.h" diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.h b/src/src/ESPEasyCore/ESPEasyNetwork.h index 799d7b5ca3..41f14888ab 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.h +++ b/src/src/ESPEasyCore/ESPEasyNetwork.h @@ -3,13 +3,8 @@ #include "../../ESPEasy_common.h" -#ifndef NETWORK_H -#define NETWORK_H - #include "../DataStructs/MAC_address.h" -#include "../Globals/ESPEasy_now_state.h" - void setNetworkMedium(NetworkMedium_t medium); bool isESPEasy_now_only(); @@ -37,6 +32,4 @@ uint8_t EthLinkSpeed(); void stop_eth_dhcps(); #endif - -#endif #endif \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 986d61f3eb..041da89f48 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1,8 +1,9 @@ #include "../Helpers/ESPEasy_now_handler.h" +#ifdef USES_ESPEASY_NOW + # include "../Helpers/_CPlugin_Helper.h" -#ifdef USES_ESPEASY_NOW # include "../ControllerQueue/MQTT_queue_element.h" diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 087e5559b4..1af19a276a 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -1,14 +1,14 @@ #ifndef HELPERS_ESPEASY_NOW_HANDLER_H #define HELPERS_ESPEASY_NOW_HANDLER_H -#include "../Globals/ESPEasy_now_state.h" - -#include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" +#include "../../ESPEasy_common.h" #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" +# include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" # include "../DataTypes/ControllerIndex.h" +# include "../Globals/ESPEasy_now_state.h" struct ESPEasy_Now_p2p_data; diff --git a/src/src/Helpers/ESPEasy_now_peermanager.h b/src/src/Helpers/ESPEasy_now_peermanager.h index 14447ebba4..0bc148ad21 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.h +++ b/src/src/Helpers/ESPEasy_now_peermanager.h @@ -2,9 +2,10 @@ #define HELPERS_ESPEASY_NOW_PEERMANAGER_H #include "../../ESPEasy_common.h" -#include "../Globals/ESPEasy_now_state.h" #ifdef USES_ESPEASY_NOW + # include "../DataStructs/MAC_address.h" +# include "../Globals/ESPEasy_now_state.h" # include diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index 3f264a875a..a436b773fb 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -1,6 +1,8 @@ #ifndef HELPERS_ESPEASY_TIME_H #define HELPERS_ESPEASY_TIME_H +#include "../../ESPEasy_common.h" + #include #include "../DataTypes/ESPEasyTimeSource.h" diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 4e0935e6b2..5624617196 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -1,7 +1,6 @@ #ifndef HELPERS_PERIODICALACTIONS_H #define HELPERS_PERIODICALACTIONS_H -#include #include "../../ESPEasy_common.h" #include "../DataStructs/MessageRouteInfo.h" diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 16d53fa8d6..36ca574ed7 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -1,9 +1,10 @@ #ifndef HELPERS_WIFI_AP_CANDIDATESLIST_H #define HELPERS_WIFI_AP_CANDIDATESLIST_H -#include "../DataStructs/WiFi_AP_Candidate.h" #include "../../ESPEasy_common.h" +#include "../DataStructs/WiFi_AP_Candidate.h" + #include typedef std::list::const_iterator WiFi_AP_Candidate_const_iterator; diff --git a/src/src/Helpers/_CPlugin_Helper_webform.h b/src/src/Helpers/_CPlugin_Helper_webform.h index faa17ad86b..e667d71a7f 100644 --- a/src/src/Helpers/_CPlugin_Helper_webform.h +++ b/src/src/Helpers/_CPlugin_Helper_webform.h @@ -1,6 +1,8 @@ #ifndef HELPERS__CPLUGIN_HELPER_WEBFORM_H #define HELPERS__CPLUGIN_HELPER_WEBFORM_H +#include "../../ESPEasy_common.h" + #include #include "../DataStructs/ControllerSettingsStruct.h" diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index fee5d92c33..abdf69f726 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -1,5 +1,7 @@ #include "../WebServer/AdvancedConfigPage.h" +#ifdef WEBSERVER_ADVANCED + #include "../WebServer/HTML_wrappers.h" #include "../WebServer/Markup.h" #include "../WebServer/Markup_Buttons.h" @@ -16,7 +18,6 @@ #include "../Helpers/StringConverter.h" -#ifdef WEBSERVER_ADVANCED void setLogLevelFor(uint8_t destination, LabelType::Enum label) { setLogLevelFor(destination, getFormItemInt(getInternalLabel(label))); diff --git a/src/src/WebServer/AdvancedConfigPage.h b/src/src/WebServer/AdvancedConfigPage.h index 6dc6cda32f..421da1d2bb 100644 --- a/src/src/WebServer/AdvancedConfigPage.h +++ b/src/src/WebServer/AdvancedConfigPage.h @@ -3,11 +3,10 @@ #include "../WebServer/common.h" -#include "../DataTypes/TimeSource.h" - - #ifdef WEBSERVER_ADVANCED +#include "../DataTypes/TimeSource.h" + // ******************************************************************************** // Web Interface config page // ******************************************************************************** diff --git a/src/src/WebServer/ControllerPage.h b/src/src/WebServer/ControllerPage.h index 7c9e495b0d..369e9e61e2 100644 --- a/src/src/WebServer/ControllerPage.h +++ b/src/src/WebServer/ControllerPage.h @@ -3,12 +3,9 @@ #include "../WebServer/common.h" -#include "../DataStructs/ControllerSettingsStruct.h" - - - #ifdef WEBSERVER_CONTROLLERS +#include "../DataStructs/ControllerSettingsStruct.h" #include "../Globals/CPlugins.h" // ******************************************************************************** From 0dccb5d84b925e150cff2b7d46ebe051e7c63a1d Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 28 Jul 2022 02:00:10 +0200 Subject: [PATCH 278/404] [ESPEasy-NOW] Fix missing include in ESPEasyNetwork.cpp --- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 88b1f15380..3629f5298e 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -3,6 +3,12 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyEth.h" #include "../ESPEasyCore/ESPEasyWifi.h" + +#ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_state.h" +#include "../Globals/ESPEasy_now_handler.h" +#endif + #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" #include "../Globals/Settings.h" From 4b9d511c5ded6ca0c161da00bb31f16c60db5ecd Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 28 Jul 2022 02:17:13 +0200 Subject: [PATCH 279/404] [ESPEasy-NOW] Fix another include dependency loop --- src/src/Globals/ESPEasy_now_state.h | 2 -- src/src/Helpers/ESPEasy_now_handler.h | 17 ++++++++--------- src/src/Helpers/ESPEasy_time.cpp | 5 +++++ src/src/Helpers/ESPEasy_time.h | 4 ---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/src/Globals/ESPEasy_now_state.h b/src/src/Globals/ESPEasy_now_state.h index 13d6070a80..b1c8f31e98 100644 --- a/src/src/Globals/ESPEasy_now_state.h +++ b/src/src/Globals/ESPEasy_now_state.h @@ -5,8 +5,6 @@ #ifdef USES_ESPEASY_NOW -#include "../Globals/ESPEasy_now_handler.h" - # include extern bool use_EspEasy_now; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 1af19a276a..54c3493cd7 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -6,18 +6,17 @@ #ifdef USES_ESPEASY_NOW # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" -# include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" +# include "../DataStructs/ESPEasy_Now_NTP_query.h" +# include "../DataStructs/ESPEasy_Now_p2p_data.h" +# include "../DataStructs/ESPEasy_now_merger.h" +# include "../DataStructs/ESPEasy_now_traceroute.h" +# include "../DataStructs/MAC_address.h" +# include "../DataStructs/MessageRouteInfo.h" +# include "../DataStructs/WiFi_AP_Candidate.h" # include "../DataTypes/ControllerIndex.h" +# include "../DataTypes/ESPEasy_Now_MQTT_queue_check_state.h" # include "../Globals/ESPEasy_now_state.h" - -struct ESPEasy_Now_p2p_data; -class ESPEasy_now_merger; -struct ESPEasy_now_traceroute_struct; -struct MessageRouteInfo_t; -class MAC_address; -struct WiFi_AP_Candidate; -class ESPEasy_Now_NTP_query; class ESPEasy_now_handler_t { public: diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 181f8108eb..f22d71b30a 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -13,6 +13,11 @@ #include "../Globals/Settings.h" #include "../Globals/TimeZone.h" +#ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_handler.h" +#endif + + #include "../Helpers/Convert.h" #include "../Helpers/Hardware.h" #include "../Helpers/Misc.h" diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index a436b773fb..73f5b4ae92 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -9,10 +9,6 @@ #include -#ifdef USES_ESPEASY_NOW -#include "../Globals/ESPEasy_now_handler.h" -#endif - class ESPEasy_time { public: From 61b4e15f0390689e8d54f68b1b1a46d8174374d1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Jul 2022 21:23:03 +0200 Subject: [PATCH 280/404] [Build] Change FEATURE_MDNS to use 0/1 state --- platformio_esp82xx_envs.ini | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp | 6 +++--- src/src/Globals/Services.h | 2 +- src/src/Helpers/MDNS_Helper.cpp | 4 ++-- src/src/Helpers/OTA.cpp | 2 +- src/src/Helpers/StringProvider.cpp | 8 ++++---- src/src/Helpers/StringProvider.h | 4 ++-- src/src/WebServer/JSON.cpp | 4 ++-- src/src/WebServer/RootPage.cpp | 4 ++-- tools/pio/pre_custom_esp82xx.py | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 11908c9660..235fa7b527 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -613,7 +613,7 @@ build_flags = ${collection_ESP8266_4M1M.build_flags} ;build_flags = ${collection.build_flags} ; ${esp8266_4M1M.build_flags} ; -DFEATURE_ADC_VCC=true -; -DFEATURE_MDNS +; -DFEATURE_MDNS=1 ; -DFEATURE_SD=1 ; -DLIMIT_BUILD_SIZE ;lib_ignore = ESP32_ping diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 2028021e2f..fe4e70af70 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1977,11 +1977,11 @@ To create/register a plugin, you have to : #if FEATURE_ARDUINO_OTA #ifndef FEATURE_MDNS - #define FEATURE_MDNS + #define FEATURE_MDNS 1 #endif #endif -#ifdef FEATURE_MDNS +#if FEATURE_MDNS #ifndef FEATURE_DNS_SERVER #define FEATURE_DNS_SERVER #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index c9b4631de7..7cf42a0682 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1284,7 +1284,7 @@ void setWifiMode(WiFiMode_t wifimode) { setAPinternal(new_mode_AP_enabled); } } - #ifdef FEATURE_MDNS + #if FEATURE_MDNS #ifdef ESP8266 // notifyAPChange() is not present in the ESP32 MDNSResponder MDNS.notifyAPChange(); diff --git a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp index 9f7fd6934b..3708e862d2 100644 --- a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp +++ b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp @@ -53,7 +53,7 @@ void backgroundtasks() lastRunBackgroundTasks = millis(); START_TIMER - #ifdef FEATURE_MDNS + #if FEATURE_MDNS const bool networkConnected = NetworkConnected(); #else NetworkConnected(); @@ -107,7 +107,7 @@ void backgroundtasks() #endif // if FEATURE_ARDUINO_OTA - #ifdef FEATURE_MDNS + #if FEATURE_MDNS // Allow MDNS processing if (networkConnected) { @@ -117,7 +117,7 @@ void backgroundtasks() MDNS.update(); # endif // ifdef ESP8266 } - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS delay(0); diff --git a/src/src/Globals/Services.h b/src/src/Globals/Services.h index 2a3ac3450b..c59cc64679 100644 --- a/src/src/Globals/Services.h +++ b/src/src/Globals/Services.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" -#ifdef FEATURE_MDNS +#if FEATURE_MDNS //enable mDNS mode (adds about 6kb ram and some bytes IRAM) #ifdef ESP8266 #include diff --git a/src/src/Helpers/MDNS_Helper.cpp b/src/src/Helpers/MDNS_Helper.cpp index 9d9fa0bc35..c75b064725 100644 --- a/src/src/Helpers/MDNS_Helper.cpp +++ b/src/src/Helpers/MDNS_Helper.cpp @@ -12,7 +12,7 @@ #include "../Helpers/StringProvider.h" void set_mDNS() { - #ifdef FEATURE_MDNS + #if FEATURE_MDNS if (!WiFiEventData.WiFiServicesInitialized()) { return; } @@ -46,5 +46,5 @@ void set_mDNS() { mDNS_init = false; #endif } - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS } diff --git a/src/src/Helpers/OTA.cpp b/src/src/Helpers/OTA.cpp index de902b1b5c..624bea9835 100644 --- a/src/src/Helpers/OTA.cpp +++ b/src/src/Helpers/OTA.cpp @@ -100,7 +100,7 @@ void ArduinoOTAInit() reboot(ESPEasy_Scheduler::IntendedRebootReason_e::OTA_error); }); - #if defined(ESP8266) && defined(FEATURE_MDNS) + #if defined(ESP8266) && FEATURE_MDNS ArduinoOTA.begin(true); #else ArduinoOTA.begin(); diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 26e87bd9c1..64b1a8d791 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -121,9 +121,9 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::IP_ADDRESS_SUBNET: return F("IP / Subnet"); case LabelType::GATEWAY: return F("Gateway"); case LabelType::CLIENT_IP: return F("Client IP"); - #ifdef FEATURE_MDNS + #if FEATURE_MDNS case LabelType::M_DNS: return F("mDNS"); - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS case LabelType::DNS: return F("DNS"); case LabelType::DNS_1: return F("DNS 1"); case LabelType::DNS_2: return F("DNS 2"); @@ -327,9 +327,9 @@ String getValue(LabelType::Enum label) { case LabelType::GATEWAY: return NetworkGatewayIP().toString(); case LabelType::CLIENT_IP: return formatIP(web_server.client().remoteIP()); - #ifdef FEATURE_MDNS + #if FEATURE_MDNS case LabelType::M_DNS: return String(NetworkGetHostname()) + F(".local"); - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS case LabelType::DNS: return String(getValue(LabelType::DNS_1) + F(" / ") + getValue(LabelType::DNS_2)); case LabelType::DNS_1: return NetworkDnsIP(0).toString(); case LabelType::DNS_2: return NetworkDnsIP(1).toString(); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 9e0dad6c7f..01fc881af1 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -80,9 +80,9 @@ struct LabelType { IP_ADDRESS_SUBNET, // 192.168.1.123 / 255.255.255.0 GATEWAY, // 192.168.1.1 CLIENT_IP, // 192.168.1.67 - #ifdef FEATURE_MDNS + #if FEATURE_MDNS M_DNS, // breadboard.local - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS DNS, // 192.168.1.1 / (IP unset) DNS_1, DNS_2, diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 274434b0ef..a2999209f6 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -212,9 +212,9 @@ void handle_json() static const LabelType::Enum labels[] PROGMEM = { LabelType::HOST_NAME, - #ifdef FEATURE_MDNS + #if FEATURE_MDNS LabelType::M_DNS, - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS LabelType::IP_CONFIG, LabelType::IP_ADDRESS, LabelType::IP_SUBNET, diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 3d3c09bf45..a466b14e53 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -218,7 +218,7 @@ void handle_root() { } #endif - #ifdef FEATURE_MDNS + #if FEATURE_MDNS { addRowLabel(LabelType::M_DNS); String html; @@ -230,7 +230,7 @@ void handle_root() { html += F("
"); addHtml(html); } - #endif // ifdef FEATURE_MDNS + #endif // if FEATURE_MDNS #ifdef USES_MQTT { diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index b89a52a4ef..5cfb672621 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -58,7 +58,7 @@ "-DUSES_C019", # ESPEasy-NOW "-DUSES_ESPEASY_NOW", -# "-DFEATURE_MDNS", +# "-DFEATURE_MDNS=1", # "-DFEATURE_SD=1", "-DFEATURE_EXT_RTC=1", "-DFEATURE_I2CMULTIPLEXER=1", From 92d43bcd31a20df75110747c53502c9ca93aaab0 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 20:30:36 +0200 Subject: [PATCH 281/404] [Build] Add some missing #define featureflag 0 --- src/src/CustomBuild/define_plugin_sets.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index fe4e70af70..20fe6ed4ad 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -390,9 +390,11 @@ To create/register a plugin, you have to : #if FEATURE_SERVO #undef FEATURE_SERVO + #define FEATURE_SERVO 0 #endif #if FEATURE_RTTTL #undef FEATURE_RTTTL + #define FEATURE_RTTTL 0 #endif #endif @@ -1412,10 +1414,12 @@ To create/register a plugin, you have to : #if FEATURE_PLUGIN_STATS && defined(ESP8266) // Does not fit in build #undef FEATURE_PLUGIN_STATS + #define FEATURE_PLUGIN_STATS 0 #endif #if FEATURE_CHART_JS && defined(ESP8266) // Does not fit in build #undef FEATURE_CHART_JS + #define FEATURE_CHART_JS 0 #endif #endif @@ -1845,9 +1849,11 @@ To create/register a plugin, you have to : #if FEATURE_SERVO #undef FEATURE_SERVO + #define FEATURE_SERVO 0 #endif #if FEATURE_RTTTL #undef FEATURE_RTTTL + #define FEATURE_RTTTL 0 #endif #if FEATURE_TOOLTIPS #undef FEATURE_TOOLTIPS @@ -1884,6 +1890,7 @@ To create/register a plugin, you have to : #endif #if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES && !defined(KEEP_TRIGONOMETRIC_FUNCTIONS_RULES) #undef FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES + #define FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES 0 #endif #if FEATURE_SSDP #undef FEATURE_SSDP @@ -1891,9 +1898,11 @@ To create/register a plugin, you have to : #endif #if FEATURE_PLUGIN_STATS #undef FEATURE_PLUGIN_STATS + #define FEATURE_PLUGIN_STATS 0 #endif #if FEATURE_CHART_JS #undef FEATURE_CHART_JS + #define FEATURE_CHART_JS 0 #endif #endif From 680b78c26dfafed974eea072155ee00aa907c628 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Jul 2022 21:25:58 +0200 Subject: [PATCH 282/404] [Build] Rename USES_NOTIFIER to FEATURE_NOTIFIER and use 0/1 state --- src/src/Commands/InternalCommands.cpp | 2 +- src/src/Commands/Notifications.cpp | 2 +- src/src/Commands/Notifications.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 ++-- src/src/Helpers/ESPEasy_FactoryDefault.cpp | 4 ++-- src/src/Helpers/ESPEasy_checks.cpp | 12 ++++++------ src/src/WebServer/NotificationPage.cpp | 5 ++++- src/src/WebServer/NotificationPage.h | 4 ++-- src/src/WebServer/WebServer.cpp | 4 ++-- src/src/WebServer/WebTemplateParser.cpp | 4 ++-- 11 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index e3082fc72e..6831963115 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -372,7 +372,7 @@ bool executeInternalCommand(command_case_data & data) case 'n': { COMMAND_CASE_R( "name", Command_Settings_Name, 1); // Settings.h COMMAND_CASE_R("nosleep", Command_System_NoSleep, 1); // System.h -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER COMMAND_CASE_R( "notify", Command_Notifications_Notify, 2); // Notifications.h #endif COMMAND_CASE_R("ntphost", Command_NTPHost, 1); // Time.h diff --git a/src/src/Commands/Notifications.cpp b/src/src/Commands/Notifications.cpp index e69b6c4602..ca99f4880e 100644 --- a/src/src/Commands/Notifications.cpp +++ b/src/src/Commands/Notifications.cpp @@ -1,6 +1,6 @@ #include "../Commands/Notifications.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../Commands/Common.h" diff --git a/src/src/Commands/Notifications.h b/src/src/Commands/Notifications.h index 817fb29469..03b2bfbd69 100644 --- a/src/src/Commands/Notifications.h +++ b/src/src/Commands/Notifications.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER const __FlashStringHelper * Command_Notifications_Notify(struct EventStruct *event, const char* Line); diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 20fe6ed4ad..372556c723 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1953,8 +1953,8 @@ To create/register a plugin, you have to : // Specific notifier plugins may be enabled via Custom.h, regardless // whether NOTIFIER_SET_NONE is defined #if defined(USES_N001) || defined(USES_N002) - #ifndef USES_NOTIFIER - #define USES_NOTIFIER + #ifndef FEATURE_NOTIFIER + #define FEATURE_NOTIFIER 1 #endif #endif diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 7d580cb0ba..66eae06d3b 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -378,12 +378,12 @@ void ESPEasy_setup() #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("CPluginInit()")); #endif - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER NPluginInit(); #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("NPluginInit()")); #endif - #endif // ifdef USES_NOTIFIER + #endif // if FEATURE_NOTIFIER PluginInit(); #ifndef BUILD_NO_RAM_TRACKER diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 4545f667c2..491d352597 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -109,9 +109,9 @@ void ResetFactory() // pad files with extra zeros for future extensions InitFile(SettingsType::SettingsFileEnum::FILE_CONFIG_type); InitFile(SettingsType::SettingsFileEnum::FILE_SECURITY_type); - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER InitFile(SettingsType::SettingsFileEnum::FILE_NOTIFICATION_type); - #endif + #endif // if FEATURE_NOTIFIER InitFile(getRulesFileName(0), 0); diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 9c8015989e..9840cef746 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -38,10 +38,10 @@ #include "../ControllerQueue/C016_queue_element.h" #endif -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../DataStructs/NotificationStruct.h" #include "../DataStructs/NotificationSettingsStruct.h" -#endif +#endif // if FEATURE_NOTIFIER // ******************************************************************************** @@ -83,9 +83,9 @@ void run_compiletime_checks() { #endif check_size(); check_size(); - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER check_size(); - #endif + #endif // if FEATURE_NOTIFIER check_size(); #if ESP_IDF_VERSION_MAJOR > 3 // String class has increased with 4 bytes @@ -105,9 +105,9 @@ void run_compiletime_checks() { check_size(); // Is not stored check_size(); // Is not stored check_size(); - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER check_size(); - #endif + #endif // if FEATURE_NOTIFIER #if FEATURE_ESPEASY_P2P check_size(); diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index 88048aa5e9..68a46cdf30 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -21,6 +21,9 @@ // ******************************************************************************** // Web Interface notifcations page // ******************************************************************************** + +#if FEATURE_NOTIFIER + #include "../Globals/NPlugins.h" @@ -242,4 +245,4 @@ void handle_notifications() { TXBuffer.endStream(); } -#endif // USES_NOTIFIER +#endif // FEATURE_NOTIFIER diff --git a/src/src/WebServer/NotificationPage.h b/src/src/WebServer/NotificationPage.h index 853fa803bd..8819358b88 100644 --- a/src/src/WebServer/NotificationPage.h +++ b/src/src/WebServer/NotificationPage.h @@ -7,11 +7,11 @@ // Web Interface notifcations page // ******************************************************************************** -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER void handle_notifications(); -#endif // USES_NOTIFIER +#endif // FEATURE_NOTIFIER #endif \ No newline at end of file diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 7e58b10f6e..e650a77386 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -248,9 +248,9 @@ void WebServerInit() web_server.on(F("/csv"), handle_csvval); web_server.on(F("/log"), handle_log); web_server.on(F("/logjson"), handle_log_JSON); // Also part of WEBSERVER_NEW_UI -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER web_server.on(F("/notifications"), handle_notifications); -#endif // ifdef USES_NOTIFIER +#endif // if FEATURE_NOTIFIER #ifdef WEBSERVER_PINSTATES web_server.on(F("/pinstates"), handle_pinstates); #endif // ifdef WEBSERVER_PINSTATES diff --git a/src/src/WebServer/WebTemplateParser.cpp b/src/src/WebServer/WebTemplateParser.cpp index c43fb1fb71..1720a77f8d 100644 --- a/src/src/WebServer/WebTemplateParser.cpp +++ b/src/src/WebServer/WebTemplateParser.cpp @@ -293,12 +293,12 @@ void WebTemplateParser::getWebPageTemplateVar(const String& varName) if ((i == MENU_INDEX_RULES) && !Settings.UseRules) { // hide rules menu item continue; } -#ifndef USES_NOTIFIER +#ifndef FEATURE_NOTIFIER if (i == MENU_INDEX_NOTIFICATIONS) { // hide notifications menu item continue; } -#endif // ifndef USES_NOTIFIER +#endif // ifndef FEATURE_NOTIFIER addHtml(F(" Date: Thu, 28 Jul 2022 20:46:42 +0200 Subject: [PATCH 283/404] [Build] Add check for FEATURE_MDNS and USES_NOTIFIER --- src/src/CustomBuild/check_defines_custom.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index c4f0bc9a2b..92c45bbb66 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -120,6 +120,18 @@ # undef USE_I2C_DEVICE_SCAN #endif // if USE_I2C_DEVICE_SCAN +#if defined(FEATURE_MDNS) && (2 - FEATURE_MDNS - 2 == 4) // 'Defined but empty' check +# warning "Custom.h has '#define FEATURE_MDNS' to be replaced with '#define FEATURE_MDNS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# undef FEATURE_MDNS +# define FEATURE_MDNS 1 +#endif // if defined(FEATURE_MDNS) && (2-FEATURE_MDNS-2 == 4) + +#ifdef USES_NOTIFIER +# warning "Custom.h has '#define USES_NOTIFIER' to be replaced with '#define FEATURE_NOTIFIER 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_NOTIFIER 1 +# undef USES_NOTIFIER +#endif // ifdef USES_NOTIFIER + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H From d30ffdd02bfd787e5c79255ac8204e4d41350440 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Jul 2022 21:26:43 +0200 Subject: [PATCH 284/404] [Build] Rename USES_MODBUS to FEATURE_MODBUS and use 0/1 state --- src/_P108_DDS238.ino | 4 ++-- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/DataStructs/Modbus.cpp | 4 +++- src/src/DataStructs/Modbus.h | 4 ++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/_P108_DDS238.ino b/src/_P108_DDS238.ino index 1df7842fcb..d0fd30dabe 100644 --- a/src/_P108_DDS238.ino +++ b/src/_P108_DDS238.ino @@ -16,9 +16,9 @@ // Written by José Araújo (josemariaaraujo@gmail.com), // with most code copied from plugin 085: _P085_AcuDC243.ino -# ifndef USES_MODBUS +# if !FEATURE_MODBUS # error This code needs MODBUS library, it should be enabled in 'define_plugin_sets.h', or your 'custom.h' -# endif // ifndef USES_MODBUS +# endif // if !FEATURE_MODBUS /* DF - Below doesn't look right; needs a RS485 to TTL(3.3v) level converter (see https://github.com/reaper7/SDM_Energy_Meter) diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index 92c45bbb66..8822c123fd 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -132,6 +132,12 @@ # undef USES_NOTIFIER #endif // ifdef USES_NOTIFIER +#ifdef USES_MODBUS +# warning "Custom.h has '#define USES_MODBUS' to be replaced with '#define FEATURE_MODBUS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_MODBUS 1 +# undef USES_MODBUS +#endif // ifdef USES_MODBUS + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 372556c723..9329812c63 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1759,7 +1759,7 @@ To create/register a plugin, you have to : #if defined(USES_P085) || defined (USES_P052) || defined(USES_P078) || defined(USES_P108) // FIXME TD-er: Is this correct? Those plugins use Modbus_RTU. - #define USES_MODBUS + #define FEATURE_MODBUS 1 #endif #if defined(USES_C001) || defined (USES_C002) || defined(USES_P029) diff --git a/src/src/DataStructs/Modbus.cpp b/src/src/DataStructs/Modbus.cpp index c9c8738fd1..742beda6d7 100644 --- a/src/src/DataStructs/Modbus.cpp +++ b/src/src/DataStructs/Modbus.cpp @@ -5,6 +5,8 @@ #include "../DataStructs/ControllerSettingsStruct.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#if FEATURE_MODBUS + Modbus::Modbus() : ModbusClient(nullptr), errcnt(0), timeout(0), TXRXstate(MODBUS_IDLE), RXavailable(0), payLoad(0) {} @@ -242,4 +244,4 @@ bool Modbus::tryRead(uint8_t ModbusID, uint16_t M_register, MODBUS_registerType return false; } -#endif // USES_MODBUS +#endif // FEATURE_MODBUS diff --git a/src/src/DataStructs/Modbus.h b/src/src/DataStructs/Modbus.h index b8ef4ebfdf..53913139ed 100644 --- a/src/src/DataStructs/Modbus.h +++ b/src/src/DataStructs/Modbus.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_MODBUS +#if FEATURE_MODBUS enum MODBUS_states_t { MODBUS_IDLE, MODBUS_RECEIVE, MODBUS_RECEIVE_PAYLOAD }; enum MODBUS_registerTypes_t { signed16, unsigned16, signed32, unsigned32, signed64, unsigned64 }; @@ -79,6 +79,6 @@ class Modbus { }; -#endif // ifdef USES_MODBUS +#endif // if FEATURE_MODBUS #endif // ifndef DATASTRUCTS_MODBUS_H From 2cd2a9dad3e2139b25939536e7f8e9eb6fb415ec Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 21:08:17 +0200 Subject: [PATCH 285/404] [Build] Rename USE_NON_STANDARD_24_TASKS to FEATURE_NON_STANDARD_24_TASKS and use 0/1 state --- platformio_special_envs.ini | 2 +- src/Custom-sample.h | 2 +- src/src/CustomBuild/ESPEasyLimits.h | 2 +- src/src/CustomBuild/StorageLayout.h | 6 +++--- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/Helpers/ESPEasy_checks.cpp | 2 +- src/src/Helpers/StringGenerator_System.cpp | 4 ++-- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index c3b9ab8b3e..ad53dfe00b 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -121,6 +121,6 @@ extends = esp8266_4M1M platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} lib_ignore = ${regular_platform.lib_ignore} -build_flags = ${esp8266_4M1M.build_flags} -DMEMORY_ANALYSIS -DPLUGIN_BUILD_CUSTOM -w -DUSE_NON_STANDARD_24_TASKS -DTASKS_MAX=24 +build_flags = ${esp8266_4M1M.build_flags} -DMEMORY_ANALYSIS -DPLUGIN_BUILD_CUSTOM -w -DFEATURE_NON_STANDARD_24_TASKS=1 -DTASKS_MAX=24 extra_scripts = pre:tools/pio/pre_memanalyze.py pre:tools/pio/generate-compiletime-defines.py diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 6e9e2ba666..24d499753c 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -293,7 +293,7 @@ static const char DATA_ESPEASY_DEFAULT_MIN_CSS[] PROGMEM = { ####################################################################################################### */ -// #define USE_NON_STANDARD_24_TASKS +// #define FEATURE_NON_STANDARD_24_TASKS 1 /* ####################################################################################################### diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index e89271f760..029f5d1d7b 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -13,7 +13,7 @@ // Performing a 2-stage define assignment using the _TMP defines // See: https://github.com/letscontrolit/ESPEasy/issues/2621 -#ifdef USE_NON_STANDARD_24_TASKS +#if FEATURE_NON_STANDARD_24_TASKS #define TASKS_MAX_TMP 24 #else #define TASKS_MAX_TMP 12 diff --git a/src/src/CustomBuild/StorageLayout.h b/src/src/CustomBuild/StorageLayout.h index 3b3cebfd3f..4e1d4d90ef 100644 --- a/src/src/CustomBuild/StorageLayout.h +++ b/src/src/CustomBuild/StorageLayout.h @@ -118,7 +118,7 @@ #if defined(ESP8266) - # ifdef USE_NON_STANDARD_24_TASKS + # if FEATURE_NON_STANDARD_24_TASKS # ifndef DAT_OFFSET_TASKS # define DAT_OFFSET_TASKS 4096 // 0x1000 each task = 2k, (1024 basic + 1024 bytes custom) # endif // ifndef DAT_OFFSET_TASKS @@ -132,7 +132,7 @@ # define CONFIG_FILE_SIZE 65536 # endif // ifndef CONFIG_FILE_SIZE - # else // ifdef USE_NON_STANDARD_24_TASKS + # else // if FEATURE_NON_STANDARD_24_TASKS # ifndef DAT_OFFSET_TASKS # define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max @@ -153,7 +153,7 @@ # define CONFIG_FILE_SIZE 65536 # endif // ifndef CONFIG_FILE_SIZE # endif - # endif // ifdef USE_NON_STANDARD_24_TASKS + # endif // if FEATURE_NON_STANDARD_24_TASKS #endif // if defined(ESP8266) #if defined(ESP32) diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index 8822c123fd..c3ffda0e6e 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -138,6 +138,12 @@ # undef USES_MODBUS #endif // ifdef USES_MODBUS +#ifdef USE_NON_STANDARD_24_TASKS +# warning "Custom.h has '#define USE_NON_STANDARD_24_TASKS' to be replaced with '#define FEATURE_NON_STANDARD_24_TASKS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_NON_STANDARD_24_TASKS 1 +# undef USE_NON_STANDARD_24_TASKS +#endif // ifdef USE_NON_STANDARD_24_TASKS + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/Helpers/ESPEasy_checks.cpp b/src/src/Helpers/ESPEasy_checks.cpp index 9840cef746..8bdf1f39b5 100644 --- a/src/src/Helpers/ESPEasy_checks.cpp +++ b/src/src/Helpers/ESPEasy_checks.cpp @@ -127,7 +127,7 @@ void run_compiletime_checks() { #endif - #if defined(USE_NON_STANDARD_24_TASKS) && defined(ESP8266) + #if FEATURE_NON_STANDARD_24_TASKS && defined(ESP8266) static_assert(TASKS_MAX == 24, "TASKS_MAX invalid size"); #endif diff --git a/src/src/Helpers/StringGenerator_System.cpp b/src/src/Helpers/StringGenerator_System.cpp index aa6e4a0cd9..15191acae6 100644 --- a/src/src/Helpers/StringGenerator_System.cpp +++ b/src/src/Helpers/StringGenerator_System.cpp @@ -183,9 +183,9 @@ String getPluginDescriptionString() { result += F(PLUGIN_DESCR); result += ']'; #endif // ifdef PLUGIN_DESCR - #ifdef USE_NON_STANDARD_24_TASKS + #if FEATURE_NON_STANDARD_24_TASKS && defined(ESP8266) result += F(" 24tasks"); - #endif // ifdef USE_NON_STANDARD_24_TASKS + #endif // if FEATURE_NON_STANDARD_24_TASKS && defined(ESP8266) result.trim(); return result; } From e0ab33148abd95cc6f754efb5eaa7aafb0fcfaf1 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 21:15:09 +0200 Subject: [PATCH 286/404] [Build] Rename USES_PACKED_RAW_DATA to FEATURE_PACKED_RAW_DATA and use 0/1 state --- src/_P026_Sysinfo.ino | 4 ++-- src/_P082_GPS.ino | 4 ++-- src/_P085_AcuDC243.ino | 4 ++-- src/_P102_PZEM004Tv3.ino | 4 ++-- src/_P108_DDS238.ino | 4 ++-- src/src/ControllerQueue/C018_queue_element.cpp | 4 ++-- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/DataTypes/ESPEasy_plugin_functions.h | 2 +- src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp | 4 ++-- src/src/Helpers/_CPlugin_LoRa_TTN_helper.h | 4 ++-- 11 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/_P026_Sysinfo.ino b/src/_P026_Sysinfo.ino index 2fbb5dbf17..5fa89f7753 100644 --- a/src/_P026_Sysinfo.ino +++ b/src/_P026_Sysinfo.ino @@ -187,7 +187,7 @@ boolean Plugin_026(uint8_t function, struct EventStruct *event, String& string) success = true; break; } -#ifdef USES_PACKED_RAW_DATA +#if FEATURE_PACKED_RAW_DATA case PLUGIN_GET_PACKED_RAW_DATA: { // Matching JS code: @@ -210,7 +210,7 @@ boolean Plugin_026(uint8_t function, struct EventStruct *event, String& string) success = true; break; } -#endif // USES_PACKED_RAW_DATA +#endif // if FEATURE_PACKED_RAW_DATA } return success; } diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index f589492304..362fa4dba5 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -521,7 +521,7 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) break; } -# ifdef USES_PACKED_RAW_DATA +# if FEATURE_PACKED_RAW_DATA case PLUGIN_GET_PACKED_RAW_DATA: { P082_data_struct *P082_data = @@ -550,7 +550,7 @@ boolean Plugin_082(uint8_t function, struct EventStruct *event, String& string) } break; } -# endif // USES_PACKED_RAW_DATA +# endif // if FEATURE_PACKED_RAW_DATA } return success; } diff --git a/src/_P085_AcuDC243.ino b/src/_P085_AcuDC243.ino index ccebfbe3ff..8e8216e47d 100644 --- a/src/_P085_AcuDC243.ino +++ b/src/_P085_AcuDC243.ino @@ -295,7 +295,7 @@ boolean Plugin_085(uint8_t function, struct EventStruct *event, String& string) } break; } -# ifdef USES_PACKED_RAW_DATA +# if FEATURE_PACKED_RAW_DATA case PLUGIN_GET_PACKED_RAW_DATA: { // FIXME TD-er: Same code as in P102, share in LoRa code. @@ -318,7 +318,7 @@ boolean Plugin_085(uint8_t function, struct EventStruct *event, String& string) } break; } -# endif // USES_PACKED_RAW_DATA +# endif // if FEATURE_PACKED_RAW_DATA } return success; } diff --git a/src/_P102_PZEM004Tv3.ino b/src/_P102_PZEM004Tv3.ino index 9a0358adef..87123e40ab 100644 --- a/src/_P102_PZEM004Tv3.ino +++ b/src/_P102_PZEM004Tv3.ino @@ -309,7 +309,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *event, String& string) break; } -#ifdef USES_PACKED_RAW_DATA +#if FEATURE_PACKED_RAW_DATA case PLUGIN_GET_PACKED_RAW_DATA: { // Matching JS code: @@ -337,7 +337,7 @@ boolean Plugin_102(uint8_t function, struct EventStruct *event, String& string) success = true; break; } -#endif // USES_PACKED_RAW_DATA +#endif // if FEATURE_PACKED_RAW_DATA diff --git a/src/_P108_DDS238.ino b/src/_P108_DDS238.ino index d0fd30dabe..33fe527af7 100644 --- a/src/_P108_DDS238.ino +++ b/src/_P108_DDS238.ino @@ -255,7 +255,7 @@ boolean Plugin_108(uint8_t function, struct EventStruct *event, String& string) break; } -# ifdef USES_PACKED_RAW_DATA +# if FEATURE_PACKED_RAW_DATA case PLUGIN_GET_PACKED_RAW_DATA: { // FIXME TD-er: Same code as in P102, share in LoRa code. @@ -278,7 +278,7 @@ boolean Plugin_108(uint8_t function, struct EventStruct *event, String& string) } break; } -# endif // USES_PACKED_RAW_DATA +# endif // if FEATURE_PACKED_RAW_DATA } return success; } diff --git a/src/src/ControllerQueue/C018_queue_element.cpp b/src/src/ControllerQueue/C018_queue_element.cpp index a93c527e20..cb68719870 100644 --- a/src/src/ControllerQueue/C018_queue_element.cpp +++ b/src/src/ControllerQueue/C018_queue_element.cpp @@ -12,7 +12,7 @@ C018_queue_element::C018_queue_element(struct EventStruct *event, uint8_t sample TaskIndex(event->TaskIndex), controller_idx(event->ControllerIndex) { - # ifdef USES_PACKED_RAW_DATA + # if FEATURE_PACKED_RAW_DATA #ifdef USE_SECOND_HEAP // HeapSelectIram ephemeral; #endif @@ -24,7 +24,7 @@ C018_queue_element::C018_queue_element(struct EventStruct *event, uint8_t sample log += packed; addLogMove(LOG_LEVEL_INFO, log); } - # endif // USES_PACKED_RAW_DATA + # endif // if FEATURE_PACKED_RAW_DATA } size_t C018_queue_element::getSize() const { diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index c3ffda0e6e..7ba1ce6277 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -144,6 +144,12 @@ # undef USE_NON_STANDARD_24_TASKS #endif // ifdef USE_NON_STANDARD_24_TASKS +#ifdef USES_PACKED_RAW_DATA +# warning "Custom.h has '#define USES_PACKED_RAW_DATA' to be replaced with '#define FEATURE_PACKED_RAW_DATA 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_PACKED_RAW_DATA 1 +# undef USES_PACKED_RAW_DATA +#endif // ifdef USES_PACKED_RAW_DATA + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 9329812c63..27a41d1a9d 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1748,7 +1748,7 @@ To create/register a plugin, you have to : #if defined(USES_C018) - #define USES_PACKED_RAW_DATA + #define FEATURE_PACKED_RAW_DATA 1 #endif #if defined(USES_C019) diff --git a/src/src/DataTypes/ESPEasy_plugin_functions.h b/src/src/DataTypes/ESPEasy_plugin_functions.h index f7a40e9f73..03ade62de1 100644 --- a/src/src/DataTypes/ESPEasy_plugin_functions.h +++ b/src/src/DataTypes/ESPEasy_plugin_functions.h @@ -39,7 +39,7 @@ #define PLUGIN_MONITOR 30 // Replaces PLUGIN_UNCONDITIONAL_POLL #define PLUGIN_SET_DEFAULTS 31 // Called when assigning a plugin to a task, to set some default config. #define PLUGIN_GET_PACKED_RAW_DATA 32 // Return all data in a compact binary format specific for that plugin. - // Needs USES_PACKED_RAW_DATA + // Needs FEATURE_PACKED_RAW_DATA #define PLUGIN_ONLY_TIMER_IN 33 // Similar to PLUGIN_TIMER_IN, addressed to a plugin instead of a task. #define PLUGIN_WEBFORM_SHOW_I2C_PARAMS 34 // Show I2C parameters like address. #define PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS 35 // When needed, show additional parameters like baudrate or specific serial config diff --git a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp index d76348a081..916860cefb 100644 --- a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp +++ b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.cpp @@ -10,7 +10,7 @@ // # Helper functions to encode data for use on LoRa/TTN network. // ####################################################################################################### -#if defined(USES_PACKED_RAW_DATA) +#if FEATURE_PACKED_RAW_DATA String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount) @@ -104,4 +104,4 @@ float getLoRaAirTime(uint8_t pl, uint8_t sf, uint16_t bw, uint8_t cr, uint8_t n_ return t_air; } -#endif // USES_PACKED_RAW_DATA +#endif // if FEATURE_PACKED_RAW_DATA diff --git a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.h b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.h index e280a75eb2..0183149053 100644 --- a/src/src/Helpers/_CPlugin_LoRa_TTN_helper.h +++ b/src/src/Helpers/_CPlugin_LoRa_TTN_helper.h @@ -8,7 +8,7 @@ // # Helper functions to encode data for use on LoRa/TTN network. // ####################################################################################################### -#if defined(USES_PACKED_RAW_DATA) +#if FEATURE_PACKED_RAW_DATA #include "../DataStructs/ESPEasy_packed_raw_data.h" @@ -32,7 +32,7 @@ float getLoRaAirTime(uint8_t pl, bool header = true, bool crc = true); -#endif // USES_PACKED_RAW_DATA +#endif // if FEATURE_PACKED_RAW_DATA From 60c5cb3a0cde4d95d6c8f2f69292e0e367f1bac4 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 22:06:15 +0200 Subject: [PATCH 287/404] [Build] Rename USES_BLYNK to FEATURE_BLYNK and use 0/1 state --- src/src/Commands/InternalCommands.cpp | 4 ++-- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/CustomBuild/define_plugin_sets.h | 9 +++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 6831963115..105967ef38 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -5,10 +5,10 @@ #include "../../_Plugin_Helper.h" #include "../Globals/Settings.h" -#ifdef USES_BLYNK +#if FEATURE_BLYNK # include "../Commands/Blynk.h" # include "../Commands/Blynk_c015.h" -#endif // ifdef USES_BLYNK +#endif // if FEATURE_BLYNK #include "../Commands/Common.h" #include "../Commands/Controller.h" diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index 7ba1ce6277..15b64f2d4a 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -150,6 +150,12 @@ # undef USES_PACKED_RAW_DATA #endif // ifdef USES_PACKED_RAW_DATA +#ifdef USES_BLYNK +# warning "Custom.h has '#define USES_BLYNK' to be replaced with '#define FEATURE_BLYNK 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# define FEATURE_BLYNK 1 +# undef USES_BLYNK +#endif // ifdef USES_BLYNK + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 27a41d1a9d..84ab3983a6 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1859,8 +1859,9 @@ To create/register a plugin, you have to : #undef FEATURE_TOOLTIPS #define FEATURE_TOOLTIPS 0 #endif - #ifdef USES_BLYNK - #undef USES_BLYNK + #if FEATURE_BLYNK + #undef FEATURE_BLYNK + #define FEATURE_BLYNK 0 #endif #if !defined(PLUGIN_SET_COLLECTION) && !defined(PLUGIN_SET_SONOFF_POW) #ifdef USES_P076 @@ -1947,7 +1948,7 @@ To create/register a plugin, you have to : #endif #if defined(USES_C012) || defined (USES_C015) - #define USES_BLYNK + #define FEATURE_BLYNK 1 #endif // Specific notifier plugins may be enabled via Custom.h, regardless @@ -1975,7 +1976,7 @@ To create/register a plugin, you have to : // It may have gotten undefined to fit a build. Make sure the Blynk controllers are not defined -#ifndef USES_BLYNK +#ifndef FEATURE_BLYNK #ifdef USES_C012 #undef USES_C012 #endif From 32628653fbb88f0cafcfb8730ba8e85c9b937e89 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 22:20:15 +0200 Subject: [PATCH 288/404] [Build] Fix typo in USES_BLYNK to FEATURE_BLYNK --- src/src/CustomBuild/define_plugin_sets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 84ab3983a6..cb96b81f80 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1976,7 +1976,7 @@ To create/register a plugin, you have to : // It may have gotten undefined to fit a build. Make sure the Blynk controllers are not defined -#ifndef FEATURE_BLYNK +#if !FEATURE_BLYNK #ifdef USES_C012 #undef USES_C012 #endif From a349b9d73c49c391959837187b8c076a58e36ba2 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 28 Jul 2022 23:10:54 +0200 Subject: [PATCH 289/404] [Build] Change FEATURE_ADC_VCC to use 1/0 instead of true/false, fix issues with test for FEATURE_ADC_VCC active --- platformio_core_defs.ini | 2 +- platformio_esp82xx_envs.ini | 28 ++++++++++++------------ src/ESPEasy_common.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 2 +- src/src/PluginStructs/P037_data_struct.h | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 52dd0ed67a..efbd558cae 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -6,7 +6,7 @@ ; **** Frequently used build flags: ; Use custom.h file to override default settings for ESPeasy: -D USE_CUSTOM_H -; Set VCC mode to measure Vcc of ESP chip : -D FEATURE_ADC_VCC=true +; Set VCC mode to measure Vcc of ESP chip : -D FEATURE_ADC_VCC=1 ; Build Flags: ; -DUSE_CONFIG_OVERRIDE diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index 235fa7b527..a14911222a 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -252,7 +252,7 @@ platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8266_1M.build_flags} - -D FEATURE_ADC_VCC=true + -D FEATURE_ADC_VCC=1 lib_ignore = ${regular_platform.lib_ignore} SD(esp8266) SD @@ -265,7 +265,7 @@ platform = ${regular_platform_alt_wifi.platform} platform_packages = ${regular_platform_alt_wifi.platform_packages} build_flags = ${regular_platform_alt_wifi.build_flags} ${esp8266_1M.build_flags} - -D FEATURE_ADC_VCC=true + -D FEATURE_ADC_VCC=1 lib_ignore = ${regular_platform_alt_wifi.lib_ignore} SD(esp8266) SD @@ -306,7 +306,7 @@ platform = ${regular_platform.platform} platform_packages = ${regular_platform.platform_packages} build_flags = ${regular_platform.build_flags} ${esp8266_4M1M.build_flags} - -D FEATURE_ADC_VCC=true + -D FEATURE_ADC_VCC=1 [env:normal_alt_wifi_ESP8266_4M1M] extends = esp8266_4M1M @@ -544,63 +544,63 @@ build_flags = ${collection_ESP8266_4M1M.build_flags} [env:collection_A_ESP8266_4M1M_VCC] extends = collection_ESP8266_4M1M build_flags = ${collection_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true + -DFEATURE_ADC_VCC=1 -DCOLLECTION_USE_RTTTL [env:collection_B_ESP8266_4M1M_VCC] extends = collection_ESP8266_4M1M build_flags = ${collection_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true + -DFEATURE_ADC_VCC=1 -DPLUGIN_BUILD_COLLECTION_B [env:collection_C_ESP8266_4M1M_VCC] extends = collection_ESP8266_4M1M build_flags = ${collection_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true + -DFEATURE_ADC_VCC=1 -DPLUGIN_BUILD_COLLECTION_C -DCOLLECTION_USE_RTTTL [env:collection_D_ESP8266_4M1M_VCC] extends = collection_ESP8266_4M1M build_flags = ${collection_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true + -DFEATURE_ADC_VCC=1 -DPLUGIN_BUILD_COLLECTION_D -DCOLLECTION_USE_RTTTL [env:collection_E_ESP8266_4M1M_VCC] extends = collection_ESP8266_4M1M build_flags = ${collection_ESP8266_4M1M.build_flags} - -DFEATURE_ADC_VCC=true + -DFEATURE_ADC_VCC=1 -DPLUGIN_BUILD_COLLECTION_E -DCOLLECTION_USE_RTTTL ;[env:collection_A_alt_wifi_ESP8266_4M1M_VCC] ;extends = collection_alt_wifi_ESP8266_4M1M ;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ;[env:collection_B_alt_wifi_ESP8266_4M1M_VCC] ;extends = collection_alt_wifi_ESP8266_4M1M ;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ; -DPLUGIN_BUILD_COLLECTION_B ;[env:collection_C_alt_wifi_ESP8266_4M1M_VCC] ;extends = collection_alt_wifi_ESP8266_4M1M ;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ; -DPLUGIN_BUILD_COLLECTION_C ;[env:collection_D_alt_wifi_ESP8266_4M1M_VCC] ;extends = collection_alt_wifi_ESP8266_4M1M ;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ; -DPLUGIN_BUILD_COLLECTION_D ;[env:collection_E_alt_wifi_ESP8266_4M1M_VCC] ;extends = collection_alt_wifi_ESP8266_4M1M ;build_flags = ${collection_alt_wifi_ESP8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ; -DPLUGIN_BUILD_COLLECTION_E @@ -612,7 +612,7 @@ build_flags = ${collection_ESP8266_4M1M.build_flags} ;platform_packages = ${collection.platform_packages} ;build_flags = ${collection.build_flags} ; ${esp8266_4M1M.build_flags} -; -DFEATURE_ADC_VCC=true +; -DFEATURE_ADC_VCC=1 ; -DFEATURE_MDNS=1 ; -DFEATURE_SD=1 ; -DLIMIT_BUILD_SIZE diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index a47d14200f..5fb10f0bbe 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -240,7 +240,7 @@ extern const String EMPTY_STRING; // Please note that the TOUT pin has to be disconnected in this mode // Use the "System Info" device to read the VCC value #ifndef FEATURE_ADC_VCC - #define FEATURE_ADC_VCC false + #define FEATURE_ADC_VCC 0 #endif #ifndef ARDUINO_OTA_PORT diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index cb96b81f80..e235e3bc0f 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1788,7 +1788,7 @@ To create/register a plugin, you have to : // VCC builds need a bit more, disable timing stats to make it fit. #ifndef PLUGIN_BUILD_CUSTOM - #if defined(FEATURE_ADC_VCC) && !defined(PLUGIN_SET_MAX) + #if FEATURE_ADC_VCC && !defined(PLUGIN_SET_MAX) #ifndef LIMIT_BUILD_SIZE #define LIMIT_BUILD_SIZE #endif diff --git a/src/src/PluginStructs/P037_data_struct.h b/src/src/PluginStructs/P037_data_struct.h index 8b5ef6c8b1..3c6760afdb 100644 --- a/src/src/PluginStructs/P037_data_struct.h +++ b/src/src/PluginStructs/P037_data_struct.h @@ -40,9 +40,9 @@ # if P037_MAPPING_SUPPORT # undef P037_MAPPING_SUPPORT # endif // if P037_MAPPING_SUPPORT -# if defined(FEATURE_ADC_VCC) && P037_FILTER_SUPPORT +# if FEATURE_ADC_VCC && P037_FILTER_SUPPORT # undef P037_FILTER_SUPPORT -# endif // if defined(FEATURE_ADC_VCC) && P037_FILTER_SUPPORT +# endif // if FEATURE_ADC_VCC && P037_FILTER_SUPPORT // #if P037_JSON_SUPPORT // #undef P037_JSON_SUPPORT From d9875dd3f3182ba83408986fbf342d11a8044492 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 29 Jul 2022 14:28:08 +0200 Subject: [PATCH 290/404] [P037] Fix build errors on more/less limited builds, apply uncrustify improvements --- src/src/PluginStructs/P037_data_struct.cpp | 34 ++++++++++++---------- src/src/PluginStructs/P037_data_struct.h | 5 ++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index f80a408be2..3b3258170f 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -36,9 +36,9 @@ bool P037_data_struct::loadSettings() { String tmp[1]; LoadCustomTaskSettings(_taskIndex, tmp, - 1, 41, offset); - globalTopicPrefix = std::move(tmp[0]); - offset += 41; + 1, 41, offset); + globalTopicPrefix = std::move(tmp[0]); + offset += 41; } @@ -51,34 +51,36 @@ bool P037_data_struct::loadSettings() { String P037_data_struct::saveSettings() { String res; + if (_taskIndex < TASKS_MAX) { size_t offset = 0; res += SaveCustomTaskSettings(_taskIndex, mqttTopics, - VARS_PER_TASK, 41, offset); + VARS_PER_TASK, 41, offset); offset += VARS_PER_TASK * 41; res += SaveCustomTaskSettings(_taskIndex, jsonAttributes, - VARS_PER_TASK, 21, offset); + VARS_PER_TASK, 21, offset); offset += VARS_PER_TASK * 21; { String tmp[1]; tmp[0] = globalTopicPrefix; - res += SaveCustomTaskSettings(_taskIndex, tmp, - 1, 41, offset); + res += SaveCustomTaskSettings(_taskIndex, tmp, + 1, 41, offset); offset += 41; } res += SaveCustomTaskSettings(_taskIndex, valueArray, - P037_ARRAY_SIZE, 0, offset + 1); + P037_ARRAY_SIZE, 0, offset + 1); } return res; } String P037_data_struct::getFullMQTTTopic(uint8_t taskValueIndex) const { String topic; - if (taskValueIndex < VARS_PER_TASK && mqttTopics[taskValueIndex].length() > 0) { + + if ((taskValueIndex < VARS_PER_TASK) && (mqttTopics[taskValueIndex].length() > 0)) { topic.reserve(globalTopicPrefix.length() + mqttTopics[taskValueIndex].length()); topic = globalTopicPrefix; topic.trim(); @@ -88,9 +90,9 @@ String P037_data_struct::getFullMQTTTopic(uint8_t taskValueIndex) const { return topic; } - bool P037_data_struct::shouldSubscribeToMQTTtopic(const String& topic) const { - if (topic.length() == 0) return false; + if (topic.length() == 0) { return false; } + for (uint8_t x = 0; x < VARS_PER_TASK; x++) { if (topic.equalsIgnoreCase(getFullMQTTTopic(x))) { @@ -124,6 +126,9 @@ void P037_data_struct::parseMappings() { _maxFilter = 0; // Initialize to empty # endif // if P037_FILTER_SUPPORT + # if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT + int8_t idx; + # endif // if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT # if P037_MAPPING_SUPPORT int8_t idx = P037_MAX_MAPPINGS; @@ -475,7 +480,6 @@ bool P037_data_struct::webform_load( return success; } // webform_load - bool P037_data_struct::webform_save( # if P037_FILTER_SUPPORT bool filterEnabled @@ -503,8 +507,8 @@ bool P037_data_struct::webform_save( # ifdef P037_JSON_SUPPORT if (jsonEnabled) { - argName = F("attribute"); - argName += (varNr + 1); + argName = F("attribute"); + argName += (varNr + 1); jsonAttributes[varNr] = web_server.arg(argName); } # endif // P037_JSON_SUPPORT @@ -515,6 +519,7 @@ bool P037_data_struct::webform_save( # if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT String left, right; bool firstError; + int8_t idx = 0; # endif // if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT // Mappings are processed first @@ -522,7 +527,6 @@ bool P037_data_struct::webform_save( firstError = true; String operands = P037_OPERAND_LIST; uint8_t mapNr = 1; - int8_t idx = 0; left.reserve(32); right.reserve(32); diff --git a/src/src/PluginStructs/P037_data_struct.h b/src/src/PluginStructs/P037_data_struct.h index 3c6760afdb..4e813ba4b4 100644 --- a/src/src/PluginStructs/P037_data_struct.h +++ b/src/src/PluginStructs/P037_data_struct.h @@ -39,22 +39,27 @@ # endif // ifdef PLUGIN_037_DEBUG # if P037_MAPPING_SUPPORT # undef P037_MAPPING_SUPPORT +# define P037_MAPPING_SUPPORT 0 # endif // if P037_MAPPING_SUPPORT # if FEATURE_ADC_VCC && P037_FILTER_SUPPORT # undef P037_FILTER_SUPPORT +# define P037_FILTER_SUPPORT 0 # endif // if FEATURE_ADC_VCC && P037_FILTER_SUPPORT // #if P037_JSON_SUPPORT // #undef P037_JSON_SUPPORT +// #define P037_JSON_SUPPORT 0 // #endif # endif // if defined(LIMIT_BUILD_SIZE) && !defined(P037_OVERRIDE) # ifdef PLUGIN_DISPLAY_COLLECTION # if P037_FILTER_SUPPORT # undef P037_FILTER_SUPPORT +# define P037_FILTER_SUPPORT 0 # endif // if P037_FILTER_SUPPORT # if P037_REPLACE_BY_COMMA_SUPPORT # undef P037_REPLACE_BY_COMMA_SUPPORT +# define P037_REPLACE_BY_COMMA_SUPPORT 0 # endif // if P037_REPLACE_BY_COMMA_SUPPORT # endif // ifdef PLUGIN_DISPLAY_COLLECTION # endif // ifndef PLUGIN_BUILD_MAX_ESP32 From 489fbfe2fd5e8bf92da4a10055c11740c23008ae Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 29 Jul 2022 15:03:18 +0200 Subject: [PATCH 291/404] [P037] Fix typo --- src/src/PluginStructs/P037_data_struct.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index 3b3258170f..e2b5093119 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -130,7 +130,7 @@ void P037_data_struct::parseMappings() { int8_t idx; # endif // if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT # if P037_MAPPING_SUPPORT - int8_t idx = P037_MAX_MAPPINGS; + idx = P037_MAX_MAPPINGS; for (uint8_t mappingOffset = P037_END_MAPPINGS; mappingOffset >= P037_START_MAPPINGS && _maxIdx == 0; mappingOffset--) { if (!valueArray[mappingOffset].isEmpty()) { From 83e28c58a063e47206b8867641a7cd300e06d10a Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 29 Jul 2022 20:52:39 +0200 Subject: [PATCH 292/404] [Build] Change FEATURE_REPORTING to use 1/0 --- src/ESPEasy-Globals.h | 2 +- src/_Reporting.ino | 6 +++--- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 ++-- src/src/Helpers/PeriodicalActions.cpp | 4 ++-- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/ESPEasy-Globals.h b/src/ESPEasy-Globals.h index 5cfe99b12f..344e5563ab 100644 --- a/src/ESPEasy-Globals.h +++ b/src/ESPEasy-Globals.h @@ -13,7 +13,7 @@ //enable reporting status to ESPEasy developers. //this informs us of crashes and stability issues. // not finished yet! -// #define FEATURE_REPORTING +// #define FEATURE_REPORTING 1 //Select which plugin sets you want to build. //These are normally automaticly set via the Platformio build environment. diff --git a/src/_Reporting.ino b/src/_Reporting.ino index fd35235bbc..0b713fef89 100644 --- a/src/_Reporting.ino +++ b/src/_Reporting.ino @@ -1,6 +1,6 @@ // not finished yet -#ifdef FEATURE_REPORTING +#if defined(FEATURE_REPORTING) && FEATURE_REPORTING #include @@ -8,7 +8,7 @@ // NO, too big: #include #define REPORT_HOST "espeasy.datux.nl" -#define FEATURE_REPORTING +#define FEATURE_REPORTING 1 void ReportStatus() { @@ -94,4 +94,4 @@ void ReportStatus() } */ -#endif // ifdef FEATURE_REPORTING +#endif // if defined(FEATURE_REPORTING) && FEATURE_REPORTING diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index 15b64f2d4a..00462b51b2 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -156,6 +156,12 @@ # undef USES_BLYNK #endif // ifdef USES_BLYNK +#if defined(FEATURE_REPORTING) && (2 - FEATURE_REPORTING - 2 == 4) // 'Defined but empty' check +# warning "Custom.h has '#define FEATURE_REPORTING' to be replaced with '#define FEATURE_REPORTING 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# undef FEATURE_REPORTING +# define FEATURE_REPORTING 1 +#endif // if defined(FEATURE_REPORTING) && (2-FEATURE_REPORTING-2 == 4) + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 66eae06d3b..05a7db2a61 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -464,9 +464,9 @@ void ESPEasy_setup() #endif - #ifdef FEATURE_REPORTING + #if FEATURE_REPORTING ReportStatus(); - #endif // ifdef FEATURE_REPORTING + #endif // if FEATURE_REPORTING #if FEATURE_ARDUINO_OTA ArduinoOTAInit(); diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index e611e166a9..d9b5d8b977 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -262,9 +262,9 @@ void runEach30Seconds() } #endif - #ifdef FEATURE_REPORTING + #if FEATURE_REPORTING ReportStatus(); - #endif + #endif // if FEATURE_REPORTING } From b53b6c2c2f50ca7f886acc388aaf651dcdec592d Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 29 Jul 2022 21:02:09 +0200 Subject: [PATCH 293/404] [Build] Change FEATURE_DNS_SERVER to use 1/0 state --- src/src/CustomBuild/check_defines_custom.h | 6 ++++++ src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/ESPEasyCore/ESPEasyWifi.cpp | 4 ++-- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 ++-- src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp | 4 ++-- src/src/Globals/Services.cpp | 4 ++-- src/src/Globals/Services.h | 4 ++-- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index 00462b51b2..cfd544f545 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -162,6 +162,12 @@ # define FEATURE_REPORTING 1 #endif // if defined(FEATURE_REPORTING) && (2-FEATURE_REPORTING-2 == 4) +#if defined(FEATURE_DNS_SERVER) && (2 - FEATURE_DNS_SERVER - 2 == 4) // 'Defined but empty' check +# warning "Custom.h has '#define FEATURE_DNS_SERVER' to be replaced with '#define FEATURE_DNS_SERVER 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" +# undef FEATURE_DNS_SERVER +# define FEATURE_DNS_SERVER 1 +#endif // if defined(FEATURE_DNS_SERVER) && (2-FEATURE_DNS_SERVER-2 == 4) + /* *INDENT-ON* */ #endif // ifndef CUSTOMBUILD_CHECK_DEFINES_CUSTOM_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index e235e3bc0f..496c4956ad 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1993,14 +1993,14 @@ To create/register a plugin, you have to : #if FEATURE_MDNS #ifndef FEATURE_DNS_SERVER - #define FEATURE_DNS_SERVER + #define FEATURE_DNS_SERVER 1 #endif #endif #ifdef WEBSERVER_SETUP #ifndef PLUGIN_BUILD_MINIMAL_OTA #ifndef FEATURE_DNS_SERVER - #define FEATURE_DNS_SERVER + #define FEATURE_DNS_SERVER 1 #endif #endif #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 7cf42a0682..1ddfd9f26b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1142,12 +1142,12 @@ void setAPinternal(bool enable) #endif // ifdef ESP32 WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); } else { - #ifdef FEATURE_DNS_SERVER + #if FEATURE_DNS_SERVER if (dnsServerActive) { dnsServerActive = false; dnsServer.stop(); } - #endif + #endif // if FEATURE_DNS_SERVER } } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 0f1ac5abe7..6e28e7931d 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -540,7 +540,7 @@ void processConnectAPmode() { addLogMove(LOG_LEVEL_INFO, log); } - #ifdef FEATURE_DNS_SERVER + #if FEATURE_DNS_SERVER // Start DNS, only used if the ESP has no valid WiFi config // It will reply with it's own address on all DNS requests // (captive portal concept) @@ -548,7 +548,7 @@ void processConnectAPmode() { dnsServerActive = true; dnsServer.start(DNS_PORT, "*", apIP); } - #endif + #endif // if FEATURE_DNS_SERVER } // Switch of AP mode when timeout reached and no client connected anymore. diff --git a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp index 3708e862d2..46712664cd 100644 --- a/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp +++ b/src/src/ESPEasyCore/ESPEasy_backgroundtasks.cpp @@ -83,13 +83,13 @@ void backgroundtasks() #endif } - #ifdef FEATURE_DNS_SERVER + #if FEATURE_DNS_SERVER // process DNS, only used if the ESP has no valid WiFi config if (dnsServerActive) { dnsServer.processNextRequest(); } - #endif // ifdef FEATURE_DNS_SERVER + #endif // if FEATURE_DNS_SERVER #if FEATURE_ARDUINO_OTA diff --git a/src/src/Globals/Services.cpp b/src/src/Globals/Services.cpp index 52f65b8321..f3971e2a4b 100644 --- a/src/src/Globals/Services.cpp +++ b/src/src/Globals/Services.cpp @@ -22,8 +22,8 @@ #endif -#ifdef FEATURE_DNS_SERVER +#if FEATURE_DNS_SERVER #include DNSServer dnsServer; bool dnsServerActive = false; -#endif +#endif // if FEATURE_DNS_SERVER diff --git a/src/src/Globals/Services.h b/src/src/Globals/Services.h index c59cc64679..7d4197e519 100644 --- a/src/src/Globals/Services.h +++ b/src/src/Globals/Services.h @@ -49,11 +49,11 @@ #endif -#ifdef FEATURE_DNS_SERVER +#if FEATURE_DNS_SERVER #include extern DNSServer dnsServer; extern bool dnsServerActive; -#endif +#endif // if FEATURE_DNS_SERVER #endif // GLOBALS_SERVICES_H From f491e30470030a47b51d4ab4eed9e175e9f92355 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 29 Jul 2022 21:13:14 +0200 Subject: [PATCH 294/404] [Build] Correct a few FEATURE_flag checks --- src/src/CustomBuild/define_plugin_sets.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 496c4956ad..fa988b0a34 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -318,17 +318,17 @@ To create/register a plugin, you have to : #endif #endif -#ifdef FEATURE_FHEM +#if FEATURE_FHEM #define USES_C009 // FHEM HTTP #endif -#ifdef FEATURE_HOMEASSISTANT_OPENHAB +#if FEATURE_HOMEASSISTANT_OPENHAB #define USES_C005 // Home Assistant (openHAB) MQTT #endif #ifdef PLUGIN_BUILD_MINIMAL_OTA // Disable ESPEasy p2p for minimal OTA builds. - #ifdef FEATURE_ESPEASY_P2P + #if FEATURE_ESPEASY_P2P #undef FEATURE_ESPEASY_P2P #define FEATURE_ESPEASY_P2P 0 #endif From cf4d75d379dc9e683294ab4c890e5d464c69b3bf Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 29 Jul 2022 21:48:16 +0200 Subject: [PATCH 295/404] [ESPEasy-NOW] Fix merge conflicts --- src/src/Commands/InternalCommands.cpp | 4 ++-- src/src/Commands/Provisioning.cpp | 2 +- src/src/Commands/Provisioning.h | 2 +- src/src/ControllerQueue/C019_queue_element.cpp | 8 ++++---- src/src/CustomBuild/check_defines_custom.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 4 ++-- src/src/DataStructs/ESPEasy_EventStruct.h | 2 +- src/src/DataStructs/Modbus.cpp | 3 +-- src/src/DataStructs/NotificationSettingsStruct.cpp | 2 +- src/src/DataStructs/NotificationSettingsStruct.h | 2 +- src/src/DataStructs/NotificationStruct.h | 2 +- src/src/DataTypes/SettingsType.cpp | 4 ++-- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 ++-- src/src/Globals/NPlugins.cpp | 2 +- src/src/Globals/NPlugins.h | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 4 ++-- src/src/Helpers/ESPEasy_Storage.h | 4 ++-- src/src/Helpers/Scheduler.cpp | 6 +++--- src/src/Helpers/Scheduler.h | 4 ++-- src/src/Helpers/_NPlugin_init.cpp | 2 +- src/src/Helpers/_NPlugin_init.h | 2 +- src/src/WebServer/JSON.cpp | 2 +- src/src/WebServer/NotificationPage.cpp | 4 +--- src/src/WebServer/WebTemplateParser.cpp | 4 ++-- 24 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index 105967ef38..e899386617 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -23,7 +23,7 @@ #endif // USES_MQTT #include "../Commands/Networks.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../Commands/Notifications.h" #endif #include "../Commands/Provisioning.h" @@ -395,7 +395,7 @@ bool executeInternalCommand(command_case_data & data) #if FEATURE_CUSTOM_PROVISIONING COMMAND_CASE_A( "provisionconfig", Command_Provisioning_Config, 0); // Provisioning.h COMMAND_CASE_A( "provisionsecurity", Command_Provisioning_Security, 0); // Provisioning.h - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER COMMAND_CASE_A( "provisionnotification", Command_Provisioning_Notification, 0); // Provisioning.h #endif COMMAND_CASE_A( "provisionprovision", Command_Provisioning_Provision, 0); // Provisioning.h diff --git a/src/src/Commands/Provisioning.cpp b/src/src/Commands/Provisioning.cpp index 2dbd1e69b7..66e26615ad 100644 --- a/src/src/Commands/Provisioning.cpp +++ b/src/src/Commands/Provisioning.cpp @@ -19,7 +19,7 @@ String Command_Provisioning_Security(struct EventStruct *event, const char *Line return downloadFileType(FileType::SECURITY_DAT); } -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER String Command_Provisioning_Notification(struct EventStruct *event, const char *Line) { return downloadFileType(FileType::NOTIFICATION_DAT); diff --git a/src/src/Commands/Provisioning.h b/src/src/Commands/Provisioning.h index 85d160f3e0..bc7316d8c8 100644 --- a/src/src/Commands/Provisioning.h +++ b/src/src/Commands/Provisioning.h @@ -11,7 +11,7 @@ String Command_Provisioning_Config(struct EventStruct *event, const char *Line); String Command_Provisioning_Security(struct EventStruct *event, const char *Line); -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER String Command_Provisioning_Notification(struct EventStruct *event, const char *Line); #endif diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index b234b34af0..9325a91dad 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -7,10 +7,10 @@ #include "../ESPEasyCore/ESPEasy_Log.h" -#ifdef USES_PACKED_RAW_DATA +#if FEATURE_PACKED_RAW_DATA String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount); -#endif // USES_PACKED_RAW_DATA +#endif #ifdef USE_SECOND_HEAP C019_queue_element::C019_queue_element(const C019_queue_element& other) : @@ -31,7 +31,7 @@ C019_queue_element::C019_queue_element(struct EventStruct *event_p) : controller_idx(event_p->ControllerIndex) { event.deep_copy(event_p); - #ifdef USES_PACKED_RAW_DATA + #if FEATURE_PACKED_RAW_DATA packed = getPackedFromPlugin(event_p, 0); if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -39,7 +39,7 @@ C019_queue_element::C019_queue_element(struct EventStruct *event_p) : log += packed; addLog(LOG_LEVEL_INFO, log); } - #endif // USES_PACKED_RAW_DATA + #endif // Extra check to make sure sensorType is correct. event.sensorType = event.getSensorType(); diff --git a/src/src/CustomBuild/check_defines_custom.h b/src/src/CustomBuild/check_defines_custom.h index cfd544f545..a626d6f93f 100644 --- a/src/src/CustomBuild/check_defines_custom.h +++ b/src/src/CustomBuild/check_defines_custom.h @@ -126,11 +126,11 @@ # define FEATURE_MDNS 1 #endif // if defined(FEATURE_MDNS) && (2-FEATURE_MDNS-2 == 4) -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER # warning "Custom.h has '#define USES_NOTIFIER' to be replaced with '#define FEATURE_NOTIFIER 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" # define FEATURE_NOTIFIER 1 # undef USES_NOTIFIER -#endif // ifdef USES_NOTIFIER +#endif // if FEATURE_NOTIFIER #ifdef USES_MODBUS # warning "Custom.h has '#define USES_MODBUS' to be replaced with '#define FEATURE_MODBUS 1', see https://github.com/letscontrolit/ESPEasy/pull/4153" diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index fa988b0a34..81bdfb2b84 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2030,8 +2030,8 @@ To create/register a plugin, you have to : #undef USES_C019 #endif -#if defined(USES_C019) && !defined(USES_PACKED_RAW_DATA) - #define USES_PACKED_RAW_DATA +#if defined(USES_C019) && !defined(FEATURE_PACKED_RAW_DATA) + #define FEATURE_PACKED_RAW_DATA 1 #endif diff --git a/src/src/DataStructs/ESPEasy_EventStruct.h b/src/src/DataStructs/ESPEasy_EventStruct.h index 30175f38c7..762d856b39 100644 --- a/src/src/DataStructs/ESPEasy_EventStruct.h +++ b/src/src/DataStructs/ESPEasy_EventStruct.h @@ -65,7 +65,7 @@ struct EventStruct EventValueSource::Enum Source = EventValueSource::Enum::VALUE_SOURCE_NOT_SET; taskIndex_t TaskIndex = INVALID_TASK_INDEX; // index position in TaskSettings array, 0-11 controllerIndex_t ControllerIndex = INVALID_CONTROLLER_INDEX; // index position in Settings.Controller, 0-3 -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER notifierIndex_t NotificationIndex = INVALID_NOTIFIER_INDEX; // index position in Settings.Notification, 0-3 #endif uint8_t BaseVarIndex = 0; diff --git a/src/src/DataStructs/Modbus.cpp b/src/src/DataStructs/Modbus.cpp index 742beda6d7..789b49de23 100644 --- a/src/src/DataStructs/Modbus.cpp +++ b/src/src/DataStructs/Modbus.cpp @@ -1,11 +1,10 @@ #include "../DataStructs/Modbus.h" -#ifdef USES_MODBUS +#if FEATURE_MODBUS #include "../DataStructs/ControllerSettingsStruct.h" #include "../ESPEasyCore/ESPEasy_Log.h" -#if FEATURE_MODBUS Modbus::Modbus() : ModbusClient(nullptr), errcnt(0), timeout(0), TXRXstate(MODBUS_IDLE), RXavailable(0), payLoad(0) {} diff --git a/src/src/DataStructs/NotificationSettingsStruct.cpp b/src/src/DataStructs/NotificationSettingsStruct.cpp index 0087b9fb72..ea07e2a4c0 100644 --- a/src/src/DataStructs/NotificationSettingsStruct.cpp +++ b/src/src/DataStructs/NotificationSettingsStruct.cpp @@ -1,6 +1,6 @@ #include "../DataStructs/NotificationSettingsStruct.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER NotificationSettingsStruct::NotificationSettingsStruct() : Port(0), Pin1(-1), Pin2(-1) { ZERO_FILL(Server); diff --git a/src/src/DataStructs/NotificationSettingsStruct.h b/src/src/DataStructs/NotificationSettingsStruct.h index a0cc26a757..7ee1eaf464 100644 --- a/src/src/DataStructs/NotificationSettingsStruct.h +++ b/src/src/DataStructs/NotificationSettingsStruct.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include #include // For std::shared_ptr diff --git a/src/src/DataStructs/NotificationStruct.h b/src/src/DataStructs/NotificationStruct.h index 455f47bc8e..52e29c0c2b 100644 --- a/src/src/DataStructs/NotificationStruct.h +++ b/src/src/DataStructs/NotificationStruct.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER /*********************************************************************************************\ * NotificationStruct diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index 98bd7e908e..72764cea47 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -16,7 +16,7 @@ const __FlashStringHelper * SettingsType::getSettingsTypeString(Enum settingsTyp case Enum::ControllerSettings_Type: return F("ControllerSettings"); case Enum::CustomControllerSettings_Type: return F("CustomControllerSettings"); case Enum::NotificationSettings_Type: - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER return F("NotificationSettings"); #else break; @@ -83,7 +83,7 @@ bool SettingsType::getSettingsParameters(Enum settingsType, int index, int& max_ } case Enum::NotificationSettings_Type: { -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER max_index = NOTIFICATION_MAX; offset = index * (DAT_NOTIFICATION_SIZE); max_size = DAT_NOTIFICATION_SIZE; diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 05a7db2a61..7c4333982c 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -278,7 +278,7 @@ void ESPEasy_setup() if (toDisable != 0) { toDisable = disableController(toDisable); } - #ifdef USES_NOTIFIER + #if FEATURE_NOTIFIER if (toDisable != 0) { toDisable = disableNotification(toDisable); } @@ -295,7 +295,7 @@ void ESPEasy_setup() if (toDisable != 0) { toDisable = disableAllControllers(toDisable); } -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER if (toDisable != 0) { toDisable = disableAllNotifications(toDisable); } diff --git a/src/src/Globals/NPlugins.cpp b/src/src/Globals/NPlugins.cpp index 9dde4086ca..3dbea1df25 100644 --- a/src/src/Globals/NPlugins.cpp +++ b/src/src/Globals/NPlugins.cpp @@ -1,6 +1,6 @@ #include "../Globals/NPlugins.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataStructs/NotificationStruct.h" diff --git a/src/src/Globals/NPlugins.h b/src/src/Globals/NPlugins.h index 72bfa4b22d..266a684bb6 100644 --- a/src/src/Globals/NPlugins.h +++ b/src/src/Globals/NPlugins.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../CustomBuild/ESPEasyLimits.h" #include "../DataStructs/NotificationStruct.h" diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index f3d663048b..90533735d5 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -660,7 +660,7 @@ uint8_t disableAllControllers(uint8_t bootFailedCount) { /********************************************************************************************\ Disable Notification, based on bootFailedCount \*********************************************************************************************/ -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER uint8_t disableNotification(uint8_t bootFailedCount) { for (uint8_t i = 0; i < NOTIFICATION_MAX && bootFailedCount > 0; ++i) { if (Settings.NotificationEnabled[i]) { @@ -1159,7 +1159,7 @@ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) #endif -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER /********************************************************************************************\ Save Controller settings to file system \*********************************************************************************************/ diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index bbd17d1326..fc3dbd323c 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -89,7 +89,7 @@ uint8_t disableAllControllers(uint8_t bootFailedCount); /********************************************************************************************\ Disable Notification, based on bootFailedCount \*********************************************************************************************/ -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER uint8_t disableNotification(uint8_t bootFailedCount); uint8_t disableAllNotifications(uint8_t bootFailedCount); #endif @@ -195,7 +195,7 @@ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings); -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER /********************************************************************************************\ Save Controller settings to file system \*********************************************************************************************/ diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index 38f1e57978..97083e2ea8 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -79,7 +79,7 @@ const __FlashStringHelper * ESPEasy_Scheduler::toString(ESPEasy_Scheduler::Plugi switch (pluginType) { case PluginPtrType::TaskPlugin: return F("Plugin"); case PluginPtrType::ControllerPlugin: return F("Controller"); -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER case PluginPtrType::NotificationPlugin: return F("Notification"); #endif } @@ -1127,7 +1127,7 @@ void ESPEasy_Scheduler::schedule_mqtt_controller_event_timer(protocolIndex_t P } #endif -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER void ESPEasy_Scheduler::schedule_notification_event_timer(uint8_t NotificationProtocolIndex, NPlugin::Function Function, struct EventStruct&& event) { @@ -1182,7 +1182,7 @@ void ESPEasy_Scheduler::process_system_event_queue() { case PluginPtrType::ControllerPlugin: CPluginCall(Index, static_cast(Function), &ScheduledEventQueue.front().event, tmpString); break; -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER case PluginPtrType::NotificationPlugin: NPlugin_ptr[Index](static_cast(Function), &ScheduledEventQueue.front().event, tmpString); break; diff --git a/src/src/Helpers/Scheduler.h b/src/src/Helpers/Scheduler.h index b4394017d2..16ff5fd3a3 100644 --- a/src/src/Helpers/Scheduler.h +++ b/src/src/Helpers/Scheduler.h @@ -75,7 +75,7 @@ class ESPEasy_Scheduler { enum class PluginPtrType { TaskPlugin, ControllerPlugin -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER ,NotificationPlugin #endif }; @@ -278,7 +278,7 @@ class ESPEasy_Scheduler { #endif // Note: The event will be moved -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER void schedule_notification_event_timer(uint8_t NotificationProtocolIndex, NPlugin::Function Function, struct EventStruct&& event); diff --git a/src/src/Helpers/_NPlugin_init.cpp b/src/src/Helpers/_NPlugin_init.cpp index 05b6106975..597b87d08f 100644 --- a/src/src/Helpers/_NPlugin_init.cpp +++ b/src/src/Helpers/_NPlugin_init.cpp @@ -1,6 +1,6 @@ #include "../Helpers/_NPlugin_init.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../DataStructs/ESPEasy_EventStruct.h" #include "../DataStructs/TimingStats.h" diff --git a/src/src/Helpers/_NPlugin_init.h b/src/src/Helpers/_NPlugin_init.h index c1cbfce8fd..2fc641384c 100644 --- a/src/src/Helpers/_NPlugin_init.h +++ b/src/src/Helpers/_NPlugin_init.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../DataTypes/ESPEasy_plugin_functions.h" diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index a2999209f6..cf5267e420 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -560,7 +560,7 @@ void handle_buildinfo() { } json_close(true); } -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER { json_open(true, F("notifications")); diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index 68a46cdf30..8ff6dece61 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -1,6 +1,6 @@ #include "../WebServer/NotificationPage.h" -#ifdef USES_NOTIFIER +#if FEATURE_NOTIFIER #include "../WebServer/WebServer.h" #include "../WebServer/HTML_wrappers.h" @@ -22,8 +22,6 @@ // Web Interface notifcations page // ******************************************************************************** -#if FEATURE_NOTIFIER - #include "../Globals/NPlugins.h" diff --git a/src/src/WebServer/WebTemplateParser.cpp b/src/src/WebServer/WebTemplateParser.cpp index 1720a77f8d..f61d290293 100644 --- a/src/src/WebServer/WebTemplateParser.cpp +++ b/src/src/WebServer/WebTemplateParser.cpp @@ -293,12 +293,12 @@ void WebTemplateParser::getWebPageTemplateVar(const String& varName) if ((i == MENU_INDEX_RULES) && !Settings.UseRules) { // hide rules menu item continue; } -#ifndef FEATURE_NOTIFIER +#if FEATURE_NOTIFIER==0 if (i == MENU_INDEX_NOTIFICATIONS) { // hide notifications menu item continue; } -#endif // ifndef FEATURE_NOTIFIER +#endif // if FEATURE_NOTIFIER==0 addHtml(F(" Date: Fri, 29 Jul 2022 22:28:46 +0200 Subject: [PATCH 296/404] [ESPEasy-NOW] Fix merge conflicts --- src/src/Commands/InternalCommands.cpp | 12 +++++------ src/src/Commands/MQTT.cpp | 4 ++-- src/src/Commands/MQTT.h | 4 ++-- .../ControllerQueue/DelayQueueElements.cpp | 4 ++-- src/src/ControllerQueue/DelayQueueElements.h | 4 ++-- .../ControllerQueue/MQTT_queue_element.cpp | 4 ++-- src/src/ControllerQueue/MQTT_queue_element.h | 4 ++-- src/src/CustomBuild/define_plugin_sets.h | 6 +++--- src/src/DataStructs/NodesHandler.cpp | 2 +- src/src/ESPEasyCore/Controller.cpp | 12 +++++------ src/src/ESPEasyCore/Controller.h | 8 ++++---- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 8 ++++---- src/src/ESPEasyCore/ESPEasy_loop.cpp | 4 ++-- src/src/Globals/MQTT.cpp | 4 ++-- src/src/Globals/MQTT.h | 4 ++-- src/src/Helpers/ESPEasy_Storage.cpp | 4 ++-- src/src/Helpers/ESPEasy_now_handler.cpp | 8 ++++---- src/src/Helpers/PeriodicalActions.cpp | 20 +++++++++---------- src/src/Helpers/PeriodicalActions.h | 4 ++-- src/src/Helpers/Scheduler.cpp | 12 +++++------ src/src/Helpers/Scheduler.h | 4 ++-- src/src/Helpers/StringGenerator_System.cpp | 4 ++-- src/src/Helpers/StringGenerator_System.h | 4 ++-- src/src/Helpers/SystemVariables.cpp | 10 +++++----- src/src/WebServer/ConfigPage.cpp | 8 ++++---- src/src/WebServer/ControllerPage.cpp | 8 ++++---- src/src/WebServer/RootPage.cpp | 4 ++-- src/src/WebServer/SysInfoPage.cpp | 4 ++-- 28 files changed, 89 insertions(+), 89 deletions(-) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index e899386617..e37e953533 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -18,9 +18,9 @@ #include "../Commands/HTTP.h" #include "../Commands/i2c.h" -#ifdef USES_MQTT +#if FEATURE_MQTT # include "../Commands/MQTT.h" -#endif // USES_MQTT +#endif #include "../Commands/Networks.h" #if FEATURE_NOTIFIER @@ -403,9 +403,9 @@ bool executeInternalCommand(command_case_data & data) COMMAND_CASE_A( "provisionfirmware", Command_Provisioning_Firmware, 1); // Provisioning.h #endif COMMAND_CASE_A( "pulse", Command_GPIO_Pulse, 3); // GPIO.h -#ifdef USES_MQTT +#if FEATURE_MQTT COMMAND_CASE_A( "publish", Command_MQTT_Publish, 2); // MQTT.h -#endif // USES_MQTT +#endif COMMAND_CASE_A( "pwm", Command_GPIO_PWM, 4); // GPIO.h break; } @@ -441,9 +441,9 @@ bool executeInternalCommand(command_case_data & data) } COMMAND_CASE_A("status", Command_GPIO_Status, 2); // GPIO.h COMMAND_CASE_R("subnet", Command_Subnet, 1); // Network Command - #ifdef USES_MQTT + #if FEATURE_MQTT COMMAND_CASE_A("subscribe", Command_MQTT_Subscribe, 1); // MQTT.h - #endif // USES_MQTT + #endif #ifndef BUILD_NO_DIAGNOSTIC_COMMANDS COMMAND_CASE_A( "sysload", Command_SysLoad, 0); // Diagnostic.h #endif // ifndef BUILD_NO_DIAGNOSTIC_COMMANDS diff --git a/src/src/Commands/MQTT.cpp b/src/src/Commands/MQTT.cpp index c519346c35..42bd042a05 100644 --- a/src/src/Commands/MQTT.cpp +++ b/src/src/Commands/MQTT.cpp @@ -1,7 +1,7 @@ #include "../../ESPEasy_common.h" #include "../Globals/MQTT.h" -#ifdef USES_MQTT +#if FEATURE_MQTT @@ -117,4 +117,4 @@ const __FlashStringHelper * Command_MQTT_Subscribe(struct EventStruct *event, co } -#endif // ifdef USES_MQTT +#endif // if FEATURE_MQTT diff --git a/src/src/Commands/MQTT.h b/src/src/Commands/MQTT.h index 93f543aa7a..c3c4566efa 100644 --- a/src/src/Commands/MQTT.h +++ b/src/src/Commands/MQTT.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_MQTT +#if FEATURE_MQTT #include @@ -13,6 +13,6 @@ const __FlashStringHelper * Command_MQTT_Publish(struct EventStruct *event, const __FlashStringHelper * Command_MQTT_Subscribe(struct EventStruct *event, const char* Line); -#endif // ifdef USES_MQTT +#endif // if FEATURE_MQTT #endif // COMMAND_MQTT_H diff --git a/src/src/ControllerQueue/DelayQueueElements.cpp b/src/src/ControllerQueue/DelayQueueElements.cpp index 2342e6cdb0..de67c78757 100644 --- a/src/src/ControllerQueue/DelayQueueElements.cpp +++ b/src/src/ControllerQueue/DelayQueueElements.cpp @@ -5,7 +5,7 @@ #include "../Globals/ESPEasy_Scheduler.h" #include "../Helpers/PeriodicalActions.h" -#ifdef USES_MQTT +#if FEATURE_MQTT ControllerDelayHandlerStruct *MQTTDelayHandler = nullptr; bool init_mqtt_delay_queue(controllerIndex_t ControllerIndex, String& pubname, bool& retainFlag) { @@ -39,7 +39,7 @@ void exit_mqtt_delay_queue() { } } -#endif // USES_MQTT +#endif /*********************************************************************************************\ diff --git a/src/src/ControllerQueue/DelayQueueElements.h b/src/src/ControllerQueue/DelayQueueElements.h index ccaab73f4e..f8a67f97fc 100644 --- a/src/src/ControllerQueue/DelayQueueElements.h +++ b/src/src/ControllerQueue/DelayQueueElements.h @@ -26,13 +26,13 @@ // -#ifdef USES_MQTT +#if FEATURE_MQTT # include "../ControllerQueue/MQTT_queue_element.h" extern ControllerDelayHandlerStruct *MQTTDelayHandler; bool init_mqtt_delay_queue(controllerIndex_t ControllerIndex, String& pubname, bool& retainFlag); void exit_mqtt_delay_queue(); -#endif // USES_MQTT +#endif /*********************************************************************************************\ diff --git a/src/src/ControllerQueue/MQTT_queue_element.cpp b/src/src/ControllerQueue/MQTT_queue_element.cpp index 7c728d7a00..1a04985240 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.cpp +++ b/src/src/ControllerQueue/MQTT_queue_element.cpp @@ -1,6 +1,6 @@ #include "../ControllerQueue/MQTT_queue_element.h" -#ifdef USES_MQTT +#if FEATURE_MQTT MQTT_queue_element::MQTT_queue_element(int ctrl_idx, taskIndex_t TaskIndex, @@ -67,4 +67,4 @@ void MQTT_queue_element::removeEmptyTopics() { _topic.replace(F("//"), F("/")); } } -#endif // USES_MQTT +#endif diff --git a/src/src/ControllerQueue/MQTT_queue_element.h b/src/src/ControllerQueue/MQTT_queue_element.h index b732f1e7d9..6cae072e9a 100644 --- a/src/src/ControllerQueue/MQTT_queue_element.h +++ b/src/src/ControllerQueue/MQTT_queue_element.h @@ -3,7 +3,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_MQTT +#if FEATURE_MQTT #include "../DataStructs/MessageRouteInfo.h" #include "../Globals/CPlugins.h" @@ -58,6 +58,6 @@ class MQTT_queue_element { #endif }; -#endif // USES_MQTT +#endif #endif // CONTROLLERQUEUE_MQTT_QUEUE_ELEMENT_H diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 81bdfb2b84..0de6c5337b 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1944,7 +1944,7 @@ To create/register a plugin, you have to : #endif #if defined(USES_C002) || defined (USES_C005) || defined(USES_C006) || defined(USES_C014) || defined(USES_P037) - #define USES_MQTT + #define FEATURE_MQTT 1 #endif #if defined(USES_C012) || defined (USES_C015) @@ -1967,12 +1967,12 @@ To create/register a plugin, you have to : #endif #endif -#ifdef USES_MQTT +#if FEATURE_MQTT // MQTT_MAX_PACKET_SIZE : Maximum packet size #ifndef MQTT_MAX_PACKET_SIZE #define MQTT_MAX_PACKET_SIZE 1024 // Is also used in PubSubClient #endif -#endif //USES_MQTT +#endif // It may have gotten undefined to fit a build. Make sure the Blynk controllers are not defined diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index c23988e0e3..d1b7b693a7 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -517,7 +517,7 @@ bool NodesHandler::refreshNodeList(unsigned long max_age_allowed, unsigned long& bool NodesHandler::isEndpoint() const { // FIXME TD-er: Must check controller to see if it needs wifi (e.g. LoRa or cache controller do not need it) - #ifdef USES_MQTT + #if FEATURE_MQTT controllerIndex_t enabledMqttController = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(enabledMqttController)) { // FIXME TD-er: Must call updateMQTTclient_connected() and see what effect diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 8aac185a5e..f241481300 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -135,7 +135,7 @@ bool validUserVar(struct EventStruct *event) { return true; } -#ifdef USES_MQTT +#if FEATURE_MQTT /*********************************************************************************************\ * Handle incoming MQTT messages @@ -462,7 +462,7 @@ String getLWT_messageDisconnect(const ControllerSettingsStruct& ControllerSettin return LWTMessageDisconnect; } -#endif // USES_MQTT +#endif /*********************************************************************************************\ * Send status info to request source @@ -502,11 +502,11 @@ void SendStatus(struct EventStruct *event, const String& status) printWebString += status; } break; -#ifdef USES_MQTT +#if FEATURE_MQTT case EventValueSource::Enum::VALUE_SOURCE_MQTT: MQTTStatus(event, status); break; -#endif // USES_MQTT +#endif case EventValueSource::Enum::VALUE_SOURCE_SERIAL: serialPrintln(status); break; @@ -516,7 +516,7 @@ void SendStatus(struct EventStruct *event, const String& status) } } -#ifdef USES_MQTT +#if FEATURE_MQTT bool MQTT_queueFull(controllerIndex_t controller_idx) { if (MQTTDelayHandler == nullptr) { return true; @@ -665,7 +665,7 @@ void MQTTStatus(struct EventStruct *event, const String& status) } } -#endif // USES_MQTT +#endif /*********************************************************************************************\ diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 908ccbd415..2ec46fef40 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -25,7 +25,7 @@ bool validUserVar(struct EventStruct *event); void sendData_checkDuplicates(struct EventStruct *event, const String& compare_key); -#ifdef USES_MQTT +#if FEATURE_MQTT /*********************************************************************************************\ * Handle incoming MQTT messages \*********************************************************************************************/ @@ -57,7 +57,7 @@ String getLWT_messageConnect(const ControllerSettingsStruct& ControllerSettings) String getLWT_messageDisconnect(const ControllerSettingsStruct& ControllerSettings); -#endif // USES_MQTT +#endif /*********************************************************************************************\ * Send status info to request source @@ -68,7 +68,7 @@ bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource); void SendStatus(struct EventStruct *event, const String& status); -#ifdef USES_MQTT +#if FEATURE_MQTT bool MQTT_queueFull(controllerIndex_t controller_idx); #ifdef USES_ESPEASY_NOW @@ -85,7 +85,7 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, Strin * Send status info back to channel where request came from \*********************************************************************************************/ void MQTTStatus(struct EventStruct *event, const String& status); -#endif //USES_MQTT +#endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 6e28e7931d..6a7bab66d2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -443,13 +443,13 @@ void processGotIP() { if (node_time.systemTimePresent()) { node_time.initTime(); } -#ifdef USES_MQTT +#if FEATURE_MQTT mqtt_reconnect_count = 0; MQTTclient_should_reconnect = true; timermqtt_interval = 100; Scheduler.setIntervalTimer(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT); scheduleNextMQTTdelayQueue(); -#endif // USES_MQTT +#endif Scheduler.sendGratuitousARP_now(); if (Settings.UseRules) @@ -740,13 +740,13 @@ void processEthernetGotIP() { if (node_time.systemTimePresent()) { node_time.initTime(); } -#ifdef USES_MQTT +#if FEATURE_MQTT mqtt_reconnect_count = 0; MQTTclient_should_reconnect = true; timermqtt_interval = 100; Scheduler.setIntervalTimer(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT); scheduleNextMQTTdelayQueue(); -#endif // USES_MQTT +#endif Scheduler.sendGratuitousARP_now(); if (Settings.UseRules) diff --git a/src/src/ESPEasyCore/ESPEasy_loop.cpp b/src/src/ESPEasyCore/ESPEasy_loop.cpp index 813f49f7f6..5766d74e0a 100644 --- a/src/src/ESPEasyCore/ESPEasy_loop.cpp +++ b/src/src/ESPEasyCore/ESPEasy_loop.cpp @@ -138,9 +138,9 @@ void ESPEasy_loop() // Deep sleep mode, just run all tasks one (more) time and go back to sleep as fast as possible if ((firstLoopConnectionsEstablished || readyForSleep()) && isDeepSleepEnabled()) { -#ifdef USES_MQTT +#if FEATURE_MQTT runPeriodicalMQTT(); -#endif // USES_MQTT +#endif // Now run all frequent tasks run50TimesPerSecond(); run10TimesPerSecond(); diff --git a/src/src/Globals/MQTT.cpp b/src/src/Globals/MQTT.cpp index 32e9449ce5..ac6da64525 100644 --- a/src/src/Globals/MQTT.cpp +++ b/src/src/Globals/MQTT.cpp @@ -2,7 +2,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_MQTT +#if FEATURE_MQTT // MQTT client @@ -13,7 +13,7 @@ bool MQTTclient_must_send_LWT_connected = false; bool MQTTclient_connected = false; int mqtt_reconnect_count = 0; LongTermTimer MQTTclient_next_connect_attempt; -#endif // USES_MQTT +#endif #ifdef USES_P037 diff --git a/src/src/Globals/MQTT.h b/src/src/Globals/MQTT.h index 4608049788..200011ee27 100644 --- a/src/src/Globals/MQTT.h +++ b/src/src/Globals/MQTT.h @@ -4,7 +4,7 @@ #include "../../ESPEasy_common.h" -#ifdef USES_MQTT +#if FEATURE_MQTT # include # include @@ -19,7 +19,7 @@ extern bool MQTTclient_must_send_LWT_connected; extern bool MQTTclient_connected; extern int mqtt_reconnect_count; extern LongTermTimer MQTTclient_next_connect_attempt; -#endif // USES_MQTT +#endif #ifdef USES_P037 diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 90533735d5..2d4d3cf95b 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -223,7 +223,7 @@ String BuildFixes() } if (Settings.Build <= 20106) { // ClientID is now defined in the controller settings. - #ifdef USES_MQTT + #if FEATURE_MQTT controllerIndex_t controller_idx = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(controller_idx)) { MakeControllerSettings(ControllerSettings); //-V522 @@ -247,7 +247,7 @@ String BuildFixes() SaveControllerSettings(controller_idx, ControllerSettings); } } - #endif // USES_MQTT + #endif } if (Settings.Build < 20107) { Settings.WebserverPort = 80; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 041da89f48..e9e17de671 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1090,7 +1090,7 @@ bool ESPEasy_now_handler_t::sendToMQTT( bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merger& message, bool& mustKeep) { - # ifdef USES_MQTT + # if FEATURE_MQTT // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller @@ -1131,7 +1131,7 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge return success; } - # endif // ifdef USES_MQTT + # endif // if FEATURE_MQTT mustKeep = false; return false; } @@ -1191,7 +1191,7 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_merger& message, bool& mustKeep) { mustKeep = false; - # ifdef USES_MQTT + # if FEATURE_MQTT ESPEasy_Now_MQTT_queue_check_packet query; size_t payload_pos = 0; @@ -1235,7 +1235,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me } } - # endif // ifdef USES_MQTT + # endif // if FEATURE_MQTT return false; } diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index d9b5d8b977..76beac6d15 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -268,7 +268,7 @@ void runEach30Seconds() } -#ifdef USES_MQTT +#if FEATURE_MQTT void scheduleNextMQTTdelayQueue() { @@ -485,7 +485,7 @@ controllerIndex_t firstEnabledMQTT_ControllerIndex() { } -#endif //USES_MQTT +#endif @@ -541,25 +541,25 @@ void updateLoopStats_30sec(uint8_t loglevel) { \*********************************************************************************************/ void flushAndDisconnectAllClients() { if (anyControllerEnabled()) { -#ifdef USES_MQTT +#if FEATURE_MQTT bool mqttControllerEnabled = validControllerIndex(firstEnabledMQTT_ControllerIndex()); -#endif //USES_MQTT +#endif unsigned long timer = millis() + 1000; while (!timeOutReached(timer)) { // call to all controllers (delay queue) to flush all data. CPluginCall(CPlugin::Function::CPLUGIN_FLUSH, 0); -#ifdef USES_MQTT +#if FEATURE_MQTT if (mqttControllerEnabled && MQTTclient.connected()) { MQTTclient.loop(); } -#endif //USES_MQTT +#endif } -#ifdef USES_MQTT +#if FEATURE_MQTT if (mqttControllerEnabled && MQTTclient.connected()) { MQTTclient.disconnect(); updateMQTTclient_connected(); } -#endif //USES_MQTT +#endif saveToRTC(); delay(100); // Flush anything in the network buffers. } @@ -569,9 +569,9 @@ void flushAndDisconnectAllClients() { void prepareShutdown(ESPEasy_Scheduler::IntendedRebootReason_e reason) { -#ifdef USES_MQTT +#if FEATURE_MQTT runPeriodicalMQTT(); // Flush outstanding MQTT messages -#endif // USES_MQTT +#endif process_serialWriteBuffer(); flushAndDisconnectAllClients(); saveUserVarToRTC(); diff --git a/src/src/Helpers/PeriodicalActions.h b/src/src/Helpers/PeriodicalActions.h index 5624617196..19bc56346f 100644 --- a/src/src/Helpers/PeriodicalActions.h +++ b/src/src/Helpers/PeriodicalActions.h @@ -29,7 +29,7 @@ void runOncePerSecond(); \*********************************************************************************************/ void runEach30Seconds(); -#ifdef USES_MQTT +#if FEATURE_MQTT void scheduleNextMQTTdelayQueue(); void schedule_all_MQTTimport_tasks(); @@ -52,7 +52,7 @@ void runPeriodicalMQTT(); controllerIndex_t firstEnabledMQTT_ControllerIndex(); -#endif //USES_MQTT +#endif void logTimerStatistics(); diff --git a/src/src/Helpers/Scheduler.cpp b/src/src/Helpers/Scheduler.cpp index 97083e2ea8..3ef0a9fcd7 100644 --- a/src/src/Helpers/Scheduler.cpp +++ b/src/src/Helpers/Scheduler.cpp @@ -427,9 +427,9 @@ void ESPEasy_Scheduler::process_interval_timer(IntervalTimer_e id, unsigned long case IntervalTimer_e::TIMER_1SEC: runOncePerSecond(); break; case IntervalTimer_e::TIMER_30SEC: runEach30Seconds(); break; case IntervalTimer_e::TIMER_MQTT: -#ifdef USES_MQTT +#if FEATURE_MQTT runPeriodicalMQTT(); -#endif // USES_MQTT +#endif break; case IntervalTimer_e::TIMER_STATISTICS: logTimerStatistics(); break; case IntervalTimer_e::TIMER_GRATUITOUS_ARP: @@ -446,9 +446,9 @@ void ESPEasy_Scheduler::process_interval_timer(IntervalTimer_e id, unsigned long } break; case IntervalTimer_e::TIMER_MQTT_DELAY_QUEUE: -#ifdef USES_MQTT +#if FEATURE_MQTT processMQTTdelayQueue(); -#endif // USES_MQTT +#endif break; case IntervalTimer_e::TIMER_C001_DELAY_QUEUE: #ifdef USES_C001 @@ -1053,7 +1053,7 @@ void ESPEasy_Scheduler::schedule_plugin_task_event_timer(deviceIndex_t DeviceInd } } -#ifdef USES_MQTT +#if FEATURE_MQTT void ESPEasy_Scheduler::schedule_mqtt_plugin_import_event_timer(deviceIndex_t DeviceIndex, taskIndex_t TaskIndex, uint8_t Function, @@ -1100,7 +1100,7 @@ unsigned long ESPEasy_Scheduler::createSystemEventMixedId(PluginPtrType ptr_type return getMixedId(SchedulerTimerType_e::SystemEventQueue, subId); } -#ifdef USES_MQTT +#if FEATURE_MQTT void ESPEasy_Scheduler::schedule_mqtt_controller_event_timer(protocolIndex_t ProtocolIndex, CPlugin::Function Function, char *c_topic, diff --git a/src/src/Helpers/Scheduler.h b/src/src/Helpers/Scheduler.h index 16ff5fd3a3..29b7eec453 100644 --- a/src/src/Helpers/Scheduler.h +++ b/src/src/Helpers/Scheduler.h @@ -254,7 +254,7 @@ class ESPEasy_Scheduler { uint8_t Function, struct EventStruct&& event); -#ifdef USES_MQTT +#if FEATURE_MQTT void schedule_mqtt_plugin_import_event_timer(deviceIndex_t DeviceIndex, taskIndex_t TaskIndex, uint8_t Function, @@ -269,7 +269,7 @@ class ESPEasy_Scheduler { uint8_t Function, struct EventStruct&& event); -#ifdef USES_MQTT +#if FEATURE_MQTT void schedule_mqtt_controller_event_timer(protocolIndex_t ProtocolIndex, CPlugin::Function Function, char *c_topic, diff --git a/src/src/Helpers/StringGenerator_System.cpp b/src/src/Helpers/StringGenerator_System.cpp index 15191acae6..5eea8fdd91 100644 --- a/src/src/Helpers/StringGenerator_System.cpp +++ b/src/src/Helpers/StringGenerator_System.cpp @@ -6,7 +6,7 @@ \*********************************************************************************************/ -#ifdef USES_MQTT +#if FEATURE_MQTT #include #include "../Globals/MQTT.h" @@ -28,7 +28,7 @@ const __FlashStringHelper * getMQTT_state() { return F(""); } -#endif // USES_MQTT +#endif /********************************************************************************************\ Get system information diff --git a/src/src/Helpers/StringGenerator_System.h b/src/src/Helpers/StringGenerator_System.h index a5d9052bbb..bd736d8ec4 100644 --- a/src/src/Helpers/StringGenerator_System.h +++ b/src/src/Helpers/StringGenerator_System.h @@ -10,9 +10,9 @@ ESPEasy specific strings \*********************************************************************************************/ -#ifdef USES_MQTT +#if FEATURE_MQTT const __FlashStringHelper * getMQTT_state(); -#endif // USES_MQTT +#endif /********************************************************************************************\ Get system information diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 6e7cbde837..73293653d4 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -15,9 +15,9 @@ #include "../Globals/CRCValues.h" #include "../Globals/ESPEasy_time.h" #include "../Globals/ESPEasyWiFiEvent.h" -#ifdef USES_MQTT +#if FEATURE_MQTT # include "../Globals/MQTT.h" -#endif // ifdef USES_MQTT +#endif // if FEATURE_MQTT #include "../Globals/NetworkState.h" #include "../Globals/RuntimeData.h" #include "../Globals/Settings.h" @@ -138,11 +138,11 @@ String SystemVariables::getSystemVariable(SystemVariables::Enum enumval) { case BSSID: return String((WiFiEventData.WiFiDisconnected()) ? MAC_address().toString() : WiFi.BSSIDstr()); case CR: return String('\r'); case IP4: return String(static_cast(NetworkLocalIP()[3])); // 4th IP octet - #ifdef USES_MQTT + #if FEATURE_MQTT case ISMQTT: return String(MQTTclient_connected ? 1 : 0); - #else // ifdef USES_MQTT + #else // if FEATURE_MQTT case ISMQTT: return String('0'); - #endif // ifdef USES_MQTT + #endif // if FEATURE_MQTT #ifdef USES_P037 case ISMQTTIMP: return String(P037_MQTTImport_connected ? 1 : 0); diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index 9a43f3f77d..081dd82570 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -53,13 +53,13 @@ void handle_config() { addLog(LOG_LEVEL_INFO, F("Unit Name changed.")); if (CPluginCall(CPlugin::Function::CPLUGIN_GOT_INVALID, 0)) { // inform controllers that the old name will be invalid from now on. -#ifdef USES_MQTT +#if FEATURE_MQTT MQTTDisconnect(); // disconnect form MQTT Server if invalid message was sent succesfull. -#endif // USES_MQTT +#endif } -#ifdef USES_MQTT +#if FEATURE_MQTT MQTTclient_should_reconnect = true; -#endif // USES_MQTT +#endif } // Unit name diff --git a/src/src/WebServer/ControllerPage.cpp b/src/src/WebServer/ControllerPage.cpp index 89fc757000..838943a2f5 100644 --- a/src/src/WebServer/ControllerPage.cpp +++ b/src/src/WebServer/ControllerPage.cpp @@ -375,7 +375,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex { addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PASS); } - # ifdef USES_MQTT + # if FEATURE_MQTT if (Protocol[ProtocolIndex].usesMQTT) { addTableSeparator(F("MQTT"), 2, 3); @@ -387,7 +387,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addFormNote(F("Updated on load of this page")); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_RETAINFLAG); } - # endif // USES_MQTT + # endif if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT) @@ -395,7 +395,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SUBSCRIBE); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PUBLISH); } - # ifdef USES_MQTT + # if FEATURE_MQTT if (Protocol[ProtocolIndex].usesMQTT) { @@ -406,7 +406,7 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_WILL_RETAIN); addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLEAN_SESSION); } - # endif // USES_MQTT + # endif } } diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index a466b14e53..fe3cbb1539 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -27,7 +27,7 @@ #include "../../ESPEasy-Globals.h" -#ifdef USES_MQTT +#if FEATURE_MQTT # include "../Globals/MQTT.h" # include "../Helpers/PeriodicalActions.h" // For finding enabled MQTT controller #endif @@ -232,7 +232,7 @@ void handle_root() { } #endif // if FEATURE_MDNS - #ifdef USES_MQTT + #if FEATURE_MQTT { if (validControllerIndex(firstEnabledMQTT_ControllerIndex())) { addRowLabel(F("MQTT Client Connected")); diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 3bfe7667c9..e6e346b348 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -39,7 +39,7 @@ #include "../Static/WebStaticData.h" -#ifdef USES_MQTT +#if FEATURE_MQTT # include "../Globals/MQTT.h" # include "../Helpers/PeriodicalActions.h" // For finding enabled MQTT controller #endif @@ -547,7 +547,7 @@ void handle_sysinfo_NetworkServices() { addRowLabel(F("NTP Initialized")); addEnabled(statusNTPInitialized); - #ifdef USES_MQTT + #if FEATURE_MQTT if (validControllerIndex(firstEnabledMQTT_ControllerIndex())) { addRowLabel(F("MQTT Client Connected")); addEnabled(MQTTclient_connected); From 81b70417d81401954aa91fb5a12275d6d005cf0e Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 9 Aug 2022 13:23:15 +0200 Subject: [PATCH 297/404] [WiFi] Fix properly disconnecting on ESP8266 * fix WiFiAPmode command Fixes #4118 --- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 2 +- src/src/ESPEasyCore/ESPEasyWifi.cpp | 21 +++++++++++++++++-- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 5 +++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 7ddeb87906..e1c617e832 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -374,7 +374,7 @@ void onWiFiScanDone(void *arg, STATUS status) { } WiFiMode_t mode = WiFi.getMode(); - WiFi.mode(WIFI_OFF); + //WiFi.mode(WIFI_OFF); WiFi.mode(mode); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 66e21c8bad..cb162fece8 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -777,6 +777,11 @@ WiFiConnectionProtocol getConnectionProtocol() { // ******************************************************************************** void WifiDisconnect() { + // Prevent recursion + static bool processingDisconnect = false; + if (processingDisconnect) return; + processingDisconnect = true; + addLog(LOG_LEVEL_INFO, F("WiFi : WifiDisconnect()")); #ifdef ESP32 WiFi.disconnect(); WiFi.removeEvent(wm_event_id); @@ -790,8 +795,9 @@ void WifiDisconnect() #endif #ifdef ESP8266 // Only call disconnect when STA is active - if (WifiIsSTA(WiFiMode())) { + if (WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); +// WiFi.disconnect(); } station_config conf{}; memset(&conf, 0, sizeof(conf)); @@ -805,6 +811,8 @@ void WifiDisconnect() RTC.clearLastWiFi(); } delay(1); + processDisconnect(); + processingDisconnect = false; } // ******************************************************************************** @@ -1056,13 +1064,21 @@ void setAPinternal(bool enable) addLog(LOG_LEVEL_ERROR, F("WIFI : [AP] softAPConfig failed!")); } - if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str())) { + int channel = 1; + if (WifiIsSTA(WiFi.getMode())) { + if (WiFi.isConnected()) + channel = WiFi.channel(); + } + + if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str(), channel)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { eventQueue.add(F("WiFi#APmodeEnabled")); String log(F("WIFI : AP Mode ssid will be ")); log += softAPSSID; log += F(" with address "); log += WiFi.softAPIP().toString(); + log += F(" ch: "); + log += channel; addLogMove(LOG_LEVEL_INFO, log); } } else { @@ -1149,6 +1165,7 @@ void setWifiMode(WiFiMode_t wifimode) { if (wifimode == WIFI_OFF) { WifiDisconnect(); + processDisconnect(); WiFiEventData.markWiFiTurnOn(); delay(100); #if defined(ESP32) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 1dc9d76c33..c55e859c25 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -94,7 +94,7 @@ void handle_unprocessedNetworkEvents() } if (active_network_medium == NetworkMedium_t::WIFI) { - if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents()) { + if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() > 20000) { WiFiEventData.last_wifi_connect_attempt_moment.clear(); @@ -231,6 +231,7 @@ void handle_unprocessedNetworkEvents() // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** void processDisconnect() { + addLog(LOG_LEVEL_INFO, F("WiFi : processDisconnect()")); if (WiFiEventData.processingDisconnect.isSet()) { if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000 || WiFiEventData.processedDisconnect) { WiFiEventData.processingDisconnect.clear(); @@ -265,7 +266,7 @@ void processDisconnect() { // FIXME TD-er: Ignoring the actual setting for now as it seems to be more reliable to always restart WiFi. - bool mustRestartWiFi = true; //Settings.WiFiRestart_connection_lost(); + bool mustRestartWiFi = Settings.WiFiRestart_connection_lost(); if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { mustRestartWiFi = true; } From f6fc22337c83c30cdddc13517da1b48f1c7ada39 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 10 Aug 2022 10:30:40 +0200 Subject: [PATCH 298/404] [WiFi] Use previously used STA channel when starting AP mode --- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 4 +++ src/src/ESPEasyCore/ESPEasyWifi.cpp | 28 +++++++++++-------- src/src/ESPEasyCore/ESPEasyWifi.h | 1 + .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 7 +++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index e1c617e832..fcf85d3911 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -143,6 +143,10 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { WiFiEventData.markDisconnectedAPmode(info.sta_disconnected.mac); #endif break; + case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: + // Assigned an IP to the connected STA client while ESP is in AP mode. + // Not sure if it makes sense to record this information. + break; case ARDUINO_EVENT_WIFI_SCAN_DONE: WiFiEventData.processedScanDone = false; break; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index cb162fece8..6e9d8bb8e3 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -797,7 +797,6 @@ void WifiDisconnect() // Only call disconnect when STA is active if (WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); -// WiFi.disconnect(); } station_config conf{}; memset(&conf, 0, sizeof(conf)); @@ -1051,7 +1050,7 @@ void setAP(bool enable) { } // Only internal scope -void setAPinternal(bool enable) +void setAPinternal(bool enable, int APchannel) { if (enable) { // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! @@ -1064,13 +1063,7 @@ void setAPinternal(bool enable) addLog(LOG_LEVEL_ERROR, F("WIFI : [AP] softAPConfig failed!")); } - int channel = 1; - if (WifiIsSTA(WiFi.getMode())) { - if (WiFi.isConnected()) - channel = WiFi.channel(); - } - - if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str(), channel)) { + if (WiFi.softAP(softAPSSID.c_str(), pwd.c_str(), APchannel)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { eventQueue.add(F("WiFi#APmodeEnabled")); String log(F("WIFI : AP Mode ssid will be ")); @@ -1078,7 +1071,7 @@ void setAPinternal(bool enable) log += F(" with address "); log += WiFi.softAPIP().toString(); log += F(" ch: "); - log += channel; + log += APchannel; addLogMove(LOG_LEVEL_INFO, log); } } else { @@ -1131,6 +1124,16 @@ void setWifiMode(WiFiMode_t wifimode) { return; } + int APchannel = 1; + if (WifiIsSTA(WiFi.getMode()) && WiFi.isConnected()) { + APchannel = WiFi.channel(); + } else { + if (WiFiEventData.usedChannel != 0) { + APchannel = WiFiEventData.usedChannel; + } + } + + if (cur_mode == WIFI_OFF) { WiFiEventData.markWiFiTurnOn(); } @@ -1230,7 +1233,7 @@ void setWifiMode(WiFiMode_t wifimode) { if (WifiIsAP(cur_mode) != new_mode_AP_enabled) { // Mode has changed - setAPinternal(new_mode_AP_enabled); + setAPinternal(new_mode_AP_enabled, APchannel); } #if FEATURE_MDNS #ifdef ESP8266 @@ -1299,7 +1302,8 @@ bool wifiAPmodeActivelyUsed() // AP not active or soon to be disabled in processDisableAPmode() return false; } - return WiFi.softAPgetStationNum() != 0; + if (WiFi.softAPgetStationNum() != 0) return true; + return !WiFiEventData.timerAPoff.timeReached(); // FIXME TD-er: is effectively checking for AP active enough or must really check for connected clients to prevent automatic wifi // reconnect? diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index 7bc1840fee..25734ca0e2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -16,6 +16,7 @@ #include "../Helpers/LongTermTimer.h" #define WIFI_RECONNECT_WAIT 20000 // in milliSeconds +#define WIFI_AP_OFF_TIMER_EXTENSION 60000 // in milliSeconds #define WIFI_AP_OFF_TIMER_DURATION 300000 // in milliSeconds #define WIFI_CONNECTION_CONSIDERED_STABLE 300000 // in milliSeconds #define WIFI_ALLOW_AP_AFTERBOOT_PERIOD 5 // in minutes diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index c55e859c25..fbcc202ff8 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -467,6 +467,13 @@ void processDisconnectAPmode() { if (WiFiEventData.processedDisconnectAPmode) { return; } WiFiEventData.processedDisconnectAPmode = true; + if (WiFi.softAPgetStationNum() == 0) { + if (WiFiEventData.timerAPoff.timeReached()) { + // Extend timer to switch off AP. + WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_EXTENSION); + } + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { const int nrStationsConnected = WiFi.softAPgetStationNum(); String log = F("AP Mode: Client disconnected: "); From e9fdfbab86cf48ed4e08fb6a4d9d6e4abbec066a Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 10 Aug 2022 13:38:54 +0200 Subject: [PATCH 299/404] [WiFi] Fix reconnect when toggling AP mode + disable TX power Disabled any call to set TX power as it seems to seriously do some strange stuff, requiring to reflash the ESP to get it to connect again. --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 11 +++++++++++ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 6e9d8bb8e3..41af0f3cf3 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -360,9 +360,12 @@ void WiFiConnectRelaxed() { // Still need to process WiFi events return; } + +/* if (!WiFiEventData.wifiSetupConnect && wifiAPmodeActivelyUsed()) { return; } + */ // FIXME TD-er: Should not try to prepare when a scan is still busy. @@ -604,6 +607,7 @@ void SetWiFiTXpower(float dBm) { } void SetWiFiTXpower(float dBm, float rssi) { + /* const WiFiMode_t cur_mode = WiFi.getMode(); if (cur_mode == WIFI_OFF) { return; @@ -719,6 +723,7 @@ void SetWiFiTXpower(float dBm, float rssi) { } } #endif + */ } #endif @@ -794,6 +799,8 @@ void WifiDisconnect() } #endif #ifdef ESP8266 + WiFi.disconnect(); + /* // Only call disconnect when STA is active if (WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); @@ -803,6 +810,7 @@ void WifiDisconnect() ETS_UART_INTR_DISABLE(); wifi_station_set_config_current(&conf); ETS_UART_INTR_ENABLE(); + */ #endif // if defined(ESP32) WiFiEventData.setWiFiDisconnected(); WiFiEventData.markDisconnect(WIFI_DISCONNECT_REASON_ASSOC_LEAVE); @@ -1215,6 +1223,7 @@ void setWifiMode(WiFiMode_t wifimode) { #ifdef ESP8266 SetWiFiTXpower(); #endif +/* if (WifiIsSTA(wifimode)) { if (WiFi.getAutoConnect()) { WiFi.setAutoConnect(false); @@ -1223,6 +1232,7 @@ void setWifiMode(WiFiMode_t wifimode) { WiFi.setAutoReconnect(false); } } +*/ delay(100); // Must allow for some time to init. } const bool new_mode_AP_enabled = WifiIsAP(wifimode); @@ -1298,6 +1308,7 @@ bool wifiConnectTimeoutReached() { bool wifiAPmodeActivelyUsed() { + if (!WiFiEventData.processedDisconnectAPmode) return true; if (!WifiIsAP(WiFi.getMode()) || (!WiFiEventData.timerAPoff.isSet())) { // AP not active or soon to be disabled in processDisableAPmode() return false; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index fbcc202ff8..a05d405648 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -231,19 +231,17 @@ void handle_unprocessedNetworkEvents() // These functions are called from Setup() or Loop() and thus may call delay() or yield() // ******************************************************************************** void processDisconnect() { - addLog(LOG_LEVEL_INFO, F("WiFi : processDisconnect()")); if (WiFiEventData.processingDisconnect.isSet()) { if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000 || WiFiEventData.processedDisconnect) { WiFiEventData.processingDisconnect.clear(); } } - if (WiFiEventData.processedDisconnect || WiFiEventData.processingDisconnect.isSet()) { return; } + addLog(LOG_LEVEL_INFO, F("WiFi : processDisconnect()")); WiFiEventData.processingDisconnect.setNow(); WiFiEventData.setWiFiDisconnected(); - WiFiEventData.wifiConnectAttemptNeeded = true; delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 if (Settings.UseRules) { @@ -270,8 +268,9 @@ void processDisconnect() { if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { mustRestartWiFi = true; } - WifiDisconnect(); // Needed or else node may not reconnect reliably. + + WiFiEventData.processedDisconnect = true; if (mustRestartWiFi) { WifiScan(false); delay(100); @@ -283,8 +282,8 @@ void processDisconnect() { } } logConnectionStatus(); - WiFiEventData.processedDisconnect = true; WiFiEventData.processingDisconnect.clear(); + WiFiEventData.wifiConnectAttemptNeeded = true; } void processConnect() { @@ -468,10 +467,7 @@ void processDisconnectAPmode() { WiFiEventData.processedDisconnectAPmode = true; if (WiFi.softAPgetStationNum() == 0) { - if (WiFiEventData.timerAPoff.timeReached()) { - // Extend timer to switch off AP. - WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_EXTENSION); - } + WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_EXTENSION); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -480,6 +476,11 @@ void processDisconnectAPmode() { log += WiFiEventData.lastMacDisconnectedAPmode.toString(); log += F(" Connected devices: "); log += nrStationsConnected; + if (nrStationsConnected == 0) { + log += F(" AP turn off timer: "); + log += WIFI_AP_OFF_TIMER_EXTENSION/1000; + log += 's'; + } addLogMove(LOG_LEVEL_INFO, log); } } From 842d9ae78a0c41092d301f53bca3b3f89fe9a0af Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 19 Aug 2022 00:27:45 +0200 Subject: [PATCH 300/404] [Eth] Fix missing include for ESPEasy Ethernet --- src/src/Helpers/Hardware.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index f41c93f43b..52de3bfd02 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -4,6 +4,7 @@ #include "../DataTypes/SPI_options.h" #include "../ESPEasyCore/ESPEasyGPIO.h" #include "../ESPEasyCore/ESPEasy_Log.h" +#include "../ESPEasyCore/ESPEasyEth.h" #include "../Globals/Device.h" #include "../Globals/ESPEasyWiFiEvent.h" From 3b6d3b7dde57010fe9490fb1b23b22d71665c4a0 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 21 Aug 2022 13:42:43 +0200 Subject: [PATCH 301/404] [Build] Fix merge issues --- src/ESPEasy_common.h | 11 +++++++---- src/_P026_Sysinfo.ino | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ESPEasy_common.h b/src/ESPEasy_common.h index 713d8ff30e..c6c6c5647d 100644 --- a/src/ESPEasy_common.h +++ b/src/ESPEasy_common.h @@ -15,6 +15,8 @@ */ #include + + // User configuration #include "../include/ESPEasy_config.h" #include "./src/CustomBuild/ESPEasyDefaults.h" @@ -38,10 +40,11 @@ # define SUPPORT_ARP #endif -#include "src/DataStructs/NodeStruct.h" -#include "src/Globals/RamTracker.h" -#include "src/ESPEasyCore/ESPEasy_Log.h" -#include "src/Helpers/ESPEasy_math.h" +#include "./src/DataTypes/NodeTypeID.h" +#include "./src/DataStructs/NodeStruct.h" +#include "./src/Globals/RamTracker.h" +#include "./src/ESPEasyCore/ESPEasy_Log.h" +#include "./src/Helpers/ESPEasy_math.h" #if defined(ESP8266) diff --git a/src/_P026_Sysinfo.ino b/src/_P026_Sysinfo.ino index a85eea3ccb..8499b2efd4 100644 --- a/src/_P026_Sysinfo.ino +++ b/src/_P026_Sysinfo.ino @@ -242,6 +242,7 @@ float P026_get_value(int type) return FreeMem2ndHeap(); #else break; + #endif case 14: return p026_read_count; } return 0.0f; From 28ca59e5ac134d81d1e8471a9c910bc289a45650 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 7 Sep 2022 16:47:37 +0200 Subject: [PATCH 302/404] [ESPEasy-NOW] Fix not considering self as preferred node Node may be known via STA and/or AP MAC address. Thus should filter out both own MAC addresses. --- src/src/CustomBuild/define_plugin_sets.h | 3 ++ .../ESPEasy_now_Node_statistics.cpp | 2 +- src/src/DataStructs/NodesHandler.cpp | 12 ++++---- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 4 +-- src/src/Helpers/ESPEasy_now_handler.cpp | 29 ++++++++++--------- src/src/Helpers/ESPEasy_now_peermanager.cpp | 10 ++----- src/src/PluginStructs/P094_data_struct.cpp | 15 ++++++---- 7 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index e0cf299ab1..765aa1395d 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1602,6 +1602,9 @@ To create/register a plugin, you have to : // Add all plugins, controllers and features that don't fit in the COLLECTION set #ifdef PLUGIN_SET_MAX // Features + #ifndef USES_ESPEASY_NOW + #define USES_ESPEASY_NOW + #endif #ifndef FEATURE_SERVO #define FEATURE_SERVO 1 #endif diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index c38ef836ec..b0c797b480 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -32,8 +32,8 @@ void ESPEasy_now_Node_statistics_t::addRoute(uint8_t unit, const ESPEasy_now_tra routes[last_route_index] = route; routes[last_route_index].addUnit(unit); routes[last_route_index].setSuccessRate_last_node(unit, success_rate); - last_update_route[last_route_index] = millis(); last_update = millis(); + last_update_route[last_route_index] = last_update; if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F(ESPEASY_NOW_NAME); diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 4a97c76f7a..058cdcfda6 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -205,17 +205,17 @@ const NodeStruct* NodesHandler::getPreferredNode_notMatching(uint8_t unit_nr) co } const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching) const { - MAC_address this_mac; - - WiFi.macAddress(this_mac.mac); - const NodeStruct *thisNode = getNodeByMac(this_mac); - const NodeStruct *reject = getNodeByMac(not_matching); + const NodeStruct *thisNodeSTA = getNodeByMac(WifiSTAmacAddress()); + const NodeStruct *thisNodeAP = getNodeByMac(WifiSoftAPmacAddress()); + const NodeStruct *reject = getNodeByMac(not_matching); const NodeStruct *res = nullptr; for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { - if ((&(it->second) != reject) && (&(it->second) != thisNode)) { + if ((&(it->second) != reject) && + (&(it->second) != thisNodeSTA) && + (&(it->second) != thisNodeAP)) { bool mustSet = false; if (res == nullptr) { mustSet = true; diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 9e26862d5b..21c0d2c403 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -190,9 +190,7 @@ MAC_address NetworkMacAddress() { return ETHMacAddress(); } #endif - MAC_address mac; - WiFi.macAddress(mac.mac); - return mac; + return WifiSTAmacAddress(); } String NetworkGetHostname() { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index b876004651..61b1490515 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -386,6 +386,8 @@ bool ESPEasy_now_handler_t::loop_process_ESPEasyNOW_in_queue() } } else if (!expired) { // Process it + + // FIXME TD-er: removeMessage has not been changed since construction, is this correct? bool mustKeep = !removeMessage; somethingProcessed = processMessage(it->second, mustKeep); removeMessage = !mustKeep; @@ -492,15 +494,15 @@ bool ESPEasy_now_handler_t::active() const MAC_address ESPEasy_now_handler_t::getActiveESPEasyNOW_MAC() const { - MAC_address this_mac; - if (use_EspEasy_now) { + // FIXME TD-er: Must not check active mode, but rather the intended mode. if (WifiIsAP(WiFi.getMode())) { - WiFi.softAPmacAddress(this_mac.mac); + return WifiSoftAPmacAddress(); } else { - WiFi.macAddress(this_mac.mac); + return WifiSTAmacAddress(); } } + MAC_address this_mac; return this_mac; } @@ -560,11 +562,8 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo // Check if message is sent by this node MAC_address receivedMAC; message.getMac(receivedMAC.mac); - MAC_address tmp; - WiFi.softAPmacAddress(tmp.mac); - if (tmp == receivedMAC) return handled; - WiFi.macAddress(tmp.mac); - if (tmp == receivedMAC) return handled; //-V649 + if (WifiSoftAPmacAddress() == receivedMAC || + WifiSTAmacAddress() == receivedMAC) return handled; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; @@ -1327,11 +1326,13 @@ void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t contr { // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. MakeControllerSettings(ControllerSettings); - LoadControllerSettings(controllerIndex, ControllerSettings); - _enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); - _ClientTimeout = ControllerSettings.ClientTimeout; - _mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); - _controllerIndex = controllerIndex; + if (AllocatedControllerSettings()) { + LoadControllerSettings(controllerIndex, ControllerSettings); + _enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); + _ClientTimeout = ControllerSettings.ClientTimeout; + _mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); + _controllerIndex = controllerIndex; + } } } diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index 2d0bb19372..c726e40b04 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -4,6 +4,7 @@ # include "../DataStructs/NodeStruct.h" # include "../ESPEasyCore/ESPEasy_Log.h" +# include "../ESPEasyCore/ESPEasyNetwork.h" # include "../ESPEasyCore/ESPEasyWifi.h" # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" @@ -37,14 +38,7 @@ bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, con } { // Don't add yourself as a peer - MAC_address this_mac; - WiFi.macAddress(this_mac.mac); - - if (this_mac == mac) { return false; } - - WiFi.softAPmacAddress(this_mac.mac); - - if (this_mac == mac) { return false; } + if (WifiSTAmacAddress() == mac || WifiSoftAPmacAddress() == mac) return false; } bool res = true; diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index cccee2881e..901a40a208 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -12,7 +12,12 @@ #include "../Helpers/StringConverter.h" -P094_data_struct::P094_data_struct() : easySerial(nullptr) {} +P094_data_struct::P094_data_struct() : easySerial(nullptr) { + for (size_t i = 0; i < P094_NR_FILTERS; ++i) { + valueType_index[i] = P094_Filter_Value_Type::P094_not_used; + filter_comp[i] = P094_Filter_Comp::P094_Equal_OR; + } +} P094_data_struct::~P094_data_struct() { reset(); @@ -35,11 +40,11 @@ bool P094_data_struct::init(ESPEasySerialPort port, reset(); easySerial = new (std::nothrow) ESPeasySerial(port, serial_rx, serial_tx); - if (isInitialized()) { - easySerial->begin(baudrate); - return true; + if (easySerial == nullptr) { + return false; } - return false; + easySerial->begin(baudrate); + return true; } void P094_data_struct::post_init() { From eff5dd017779f50360851bec2aadd00b84c4381e Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 11 Sep 2022 11:53:55 +0200 Subject: [PATCH 303/404] [WifiESPNow] Update library to latest version --- lib/WifiEspNow/.clang-format | 12 ++ lib/WifiEspNow/.gitignore | 3 + lib/WifiEspNow/README.md | 12 ++ lib/WifiEspNow/docs/Doxyfile | 20 +++ lib/WifiEspNow/docs/_redirects | 2 + lib/WifiEspNow/docs/build.sh | 8 + .../docs/filter-Doxygen-warning.awk | 14 ++ .../EspNowBroadcast/EspNowBroadcast.ino | 64 +++++-- .../examples/EspNowUnicast/EspNowUnicast.ino | 59 ++++++- lib/WifiEspNow/library.properties | 8 +- lib/WifiEspNow/mk/format-code.sh | 6 + lib/WifiEspNow/src/WifiEspNow.cpp | 162 ++++++++--------- lib/WifiEspNow/src/WifiEspNow.h | 136 ++++++++------- lib/WifiEspNow/src/WifiEspNowBroadcast.cpp | 164 ++++++++++-------- lib/WifiEspNow/src/WifiEspNowBroadcast.h | 87 ++++++---- 15 files changed, 493 insertions(+), 264 deletions(-) create mode 100644 lib/WifiEspNow/.clang-format create mode 100644 lib/WifiEspNow/.gitignore create mode 100644 lib/WifiEspNow/docs/Doxyfile create mode 100644 lib/WifiEspNow/docs/_redirects create mode 100644 lib/WifiEspNow/docs/build.sh create mode 100644 lib/WifiEspNow/docs/filter-Doxygen-warning.awk create mode 100644 lib/WifiEspNow/mk/format-code.sh diff --git a/lib/WifiEspNow/.clang-format b/lib/WifiEspNow/.clang-format new file mode 100644 index 0000000000..2a701e9d44 --- /dev/null +++ b/lib/WifiEspNow/.clang-format @@ -0,0 +1,12 @@ +--- +BasedOnStyle: Mozilla +AllowShortFunctionsOnASingleLine: Empty +BinPackArguments: true +BinPackParameters: true +ColumnLimit: 100 +Cpp11BracedListStyle: true +FixNamespaceComments: true +ReflowComments: false +SortIncludes: true +SortUsingDeclarations: true +SpacesInContainerLiterals: false diff --git a/lib/WifiEspNow/.gitignore b/lib/WifiEspNow/.gitignore new file mode 100644 index 0000000000..12e0396105 --- /dev/null +++ b/lib/WifiEspNow/.gitignore @@ -0,0 +1,3 @@ +/.vscode +/docs/html +/examples/*/build diff --git a/lib/WifiEspNow/README.md b/lib/WifiEspNow/README.md index d1c47aa931..493088cfa1 100644 --- a/lib/WifiEspNow/README.md +++ b/lib/WifiEspNow/README.md @@ -1,8 +1,14 @@ # ESP-NOW Arduino library for ESP8266 and ESP32 +[![GitHub build status](https://img.shields.io/github/workflow/status/yoursunny/WifiEspNow/build)](https://github.com/yoursunny/WifiEspNow/actions) [![GitHub code size](https://img.shields.io/github/languages/code-size/yoursunny/WifiEspNow?style=flat)](https://github.com/yoursunny/WifiEspNow) + **WifiEspNow** is an Arduino library for ESP-NOW, a connectionless WiFi communication protocol defined by Espressif. Refer to [ESP-NOW reference](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/esp_now.html) for more information about how ESP-NOW works and its limitations. +* [Doxygen documentation](https://wifiespnow.yoursunny.dev/) + +## Features + [`WifiEspNow`](src/WifiEspNow.h) is a simple wrapper of ESP-NOW functions in ESP-IDF. On ESP8266, it supports unicast only. On ESP32, it supports both unicast and multicast. @@ -11,3 +17,9 @@ On ESP32, it supports both unicast and multicast. Each device advertises a specific WiFi SSID, and discovers each other through BSSID scanning. Then, messages are transmitted separately toward every peer via ESP-NOW unicast. This is my custom protocol, which differs from `WifiEspNow` multicast. + +## Installation + +1. Clone this repository under `$HOME/Arduino/libraries` directory. +2. Add `#include ` or `#include ` to your sketch. +3. Check out the [examples](examples/) for how to use. diff --git a/lib/WifiEspNow/docs/Doxyfile b/lib/WifiEspNow/docs/Doxyfile new file mode 100644 index 0000000000..74d064ea0d --- /dev/null +++ b/lib/WifiEspNow/docs/Doxyfile @@ -0,0 +1,20 @@ +PROJECT_NAME = WifiEspNow +PROJECT_BRIEF = "ESP-NOW Arduino library for ESP8266 and ESP32" +OUTPUT_DIRECTORY = "." +MARKDOWN_SUPPORT = NO +AUTOLINK_SUPPORT = NO +BUILTIN_STL_SUPPORT = YES +EXTRACT_ALL = YES +EXTRACT_PRIV_VIRTUAL = YES +QUIET = YES +INPUT = "../src" "../examples" +FILE_PATTERNS = "*.h" "*.hpp" "*.c" "*.cpp" "*.ino" +EXTENSION_MAPPING = "ino=C++" +RECURSIVE = YES +PREDEFINED = "ARDUINO=100" "ARDUINO_ARCH_ESP32=1" +HTML_COLORSTYLE_HUE = 82 +HTML_COLORSTYLE_SAT = 255 +HTML_COLORSTYLE_GAMMA = 200 +GENERATE_LATEX = NO +CLASS_DIAGRAMS = NO +HAVE_DOT = NO diff --git a/lib/WifiEspNow/docs/_redirects b/lib/WifiEspNow/docs/_redirects new file mode 100644 index 0000000000..6ef0d8963c --- /dev/null +++ b/lib/WifiEspNow/docs/_redirects @@ -0,0 +1,2 @@ +https://wifiespnow.netlify.app/* https://wifiespnow.yoursunny.dev/:splat 301! +https://wifiespnow.yoursunny.cn/* https://wifiespnow.yoursunny.dev/:splat 301! diff --git a/lib/WifiEspNow/docs/build.sh b/lib/WifiEspNow/docs/build.sh new file mode 100644 index 0000000000..422c404380 --- /dev/null +++ b/lib/WifiEspNow/docs/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -euo pipefail +cd "$( dirname "${BASH_SOURCE[0]}" )" + +doxygen Doxyfile 2>&1 | ./filter-Doxygen-warning.awk 1>&2 + +find html -name '*.html' | xargs sed -i '/<\/head>/ i\ ' +cp _redirects html/ diff --git a/lib/WifiEspNow/docs/filter-Doxygen-warning.awk b/lib/WifiEspNow/docs/filter-Doxygen-warning.awk new file mode 100644 index 0000000000..ab23b479ce --- /dev/null +++ b/lib/WifiEspNow/docs/filter-Doxygen-warning.awk @@ -0,0 +1,14 @@ +#!/usr/bin/gawk -f +/warning: The following parameters? of .* not documented:/ { + skip = 1 + next +} +$0 ~ /^ parameter/ { + if (!skip) { + print + } +} +$0 !~ /^ / { + skip = 0 + print +} \ No newline at end of file diff --git a/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino b/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino index d8fe72ca1b..fcfdde85f6 100644 --- a/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino +++ b/lib/WifiEspNow/examples/EspNowBroadcast/EspNowBroadcast.ino @@ -1,18 +1,46 @@ +/** + * @file + * + * EspNowBroadcast.ino demonstrates how to perform ESP-NOW pseudo broadcast with @c WifiEspNowBroadcast . + * You need two or more ESP8266 or ESP32 devices to run this example. + * + * All devices should run the same program. + * You may need to modify the PIN numbers so that you can observe the effect. + * + * With the program running on several devices: + * @li Press the button to transmit a message. + * @li When a device receives a message, it will toggle its LED between "on" and "off" states. + */ + #include -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) #include #endif -static const int BUTTON_PIN = 0; // "flash" button on NodeMCU, Witty Cloud, etc -static const int LED_PIN = 2; // ESP-12F blue LED +/** + * @brief PIN number of a button. + * + * The default `0` is the "flash" button on NodeMCU, Witty Cloud, Heltec WiFi_Kit_32, etc. + */ +static const int BUTTON_PIN = 0; + +/** + * @brief PIN number of an LED. + * + * The default `2` is the blue LED on ESP-12F. + */ +static const int LED_PIN = 2; int ledState = HIGH; -void processRx(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { - Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - for (int i = 0; i < count; ++i) { +void +processRx(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg) +{ + Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); + for (size_t i = 0; i < count; ++i) { Serial.print(static_cast(buf[i])); } Serial.println(); @@ -21,7 +49,9 @@ void processRx(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cba ledState = 1 - ledState; } -void setup() { +void +setup() +{ Serial.begin(115200); Serial.println(); @@ -31,6 +61,10 @@ void setup() { Serial.println("WifiEspNowBroadcast.begin() failed"); ESP.restart(); } + // WifiEspNowBroadcast.begin() function sets WiFi to AP+STA mode. + // The AP interface is also controlled by WifiEspNowBroadcast. + // You may use the STA interface after calling WifiEspNowBroadcast.begin(). + // For best results, ensure all devices are using the same WiFi channel. WifiEspNowBroadcast.onReceive(processRx, nullptr); @@ -43,9 +77,12 @@ void setup() { Serial.println("Press the button to send a message"); } -void sendMessage() { +void +sendMessage() +{ char msg[60]; - int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", WiFi.softAPmacAddress().c_str(), millis()); + int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", + WiFi.softAPmacAddress().c_str(), millis()); WifiEspNowBroadcast.send(reinterpret_cast(msg), len); Serial.println("Sending message"); @@ -55,12 +92,15 @@ void sendMessage() { WifiEspNowPeerInfo peers[MAX_PEERS]; int nPeers = std::min(WifiEspNow.listPeers(peers, MAX_PEERS), MAX_PEERS); for (int i = 0; i < nPeers; ++i) { - Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X", peers[i].mac[0], peers[i].mac[1], peers[i].mac[2], peers[i].mac[3], peers[i].mac[4], peers[i].mac[5]); + Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X", peers[i].mac[0], peers[i].mac[1], + peers[i].mac[2], peers[i].mac[3], peers[i].mac[4], peers[i].mac[5]); } Serial.println(); } -void loop() { +void +loop() +{ if (digitalRead(BUTTON_PIN) == LOW) { // button is pressed sendMessage(); diff --git a/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino b/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino index b73bd46642..13958cda06 100644 --- a/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino +++ b/lib/WifiEspNow/examples/EspNowUnicast/EspNowUnicast.ino @@ -1,32 +1,70 @@ +/** + * @file + * + * EspNowUnicast.ino demonstrates how to transmit unicast ESP-NOW messages with @c WifiEspNow . + * You need two ESP8266 or ESP32 devices to run this example. + * + * Unicast communication requires the sender to specify the MAC address of the recipient. + * Thus, you must modify this program for each device. + * + * The recommended workflow is: + * @li 1. Flash the program onto device A. + * @li 2. Run the program on device A, look at serial console for its MAC address. + * @li 3. Copy the MAC address of device A, paste it in the @c PEER variable below. + * @li 4. Flash the program that contains A's MAC address onto device B. + * @li 5. Run the program on device A, look at serial console for its MAC address. + * @li 6. Copy the MAC address of device B, paste it in the @c PEER variable below. + * @li 7. Flash the program that contains B's MAC address onto device A. + */ + #include -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) #include #endif -static uint8_t PEER[] {0x5E, 0xCF, 0x7F, 0x90, 0xFA, 0xE8}; +// The recipient MAC address. It must be modified for each device. +static uint8_t PEER[]{0x02, 0x00, 0x00, 0x45, 0x53, 0x50}; -void printReceivedMessage(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg) { - Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - for (int i = 0; i < count; ++i) { +void +printReceivedMessage(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, + void* arg) +{ + Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); + for (int i = 0; i < static_cast(count); ++i) { Serial.print(static_cast(buf[i])); } Serial.println(); } -void setup() { +void +setup() +{ Serial.begin(115200); Serial.println(); WiFi.persistent(false); WiFi.mode(WIFI_AP); + WiFi.disconnect(); WiFi.softAP("ESPNOW", nullptr, 3); WiFi.softAPdisconnect(false); + // WiFi must be powered on to use ESP-NOW unicast. + // It could be either AP or STA mode, and does not have to be connected. + // For best results, ensure both devices are using the same WiFi channel. Serial.print("MAC address of this node is "); Serial.println(WiFi.softAPmacAddress()); + uint8_t mac[6]; + WiFi.softAPmacAddress(mac); + Serial.println(); + Serial.println("You can paste the following into the program for the other device:"); + Serial.printf("static uint8_t PEER[]{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X};\n", mac[0], + mac[1], mac[2], mac[3], mac[4], mac[5]); + Serial.println(); + bool ok = WifiEspNow.begin(); if (!ok) { Serial.println("WifiEspNow.begin() failed"); @@ -42,9 +80,12 @@ void setup() { } } -void loop() { +void +loop() +{ char msg[60]; - int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", WiFi.softAPmacAddress().c_str(), millis()); + int len = snprintf(msg, sizeof(msg), "hello ESP-NOW from %s at %lu", + WiFi.softAPmacAddress().c_str(), millis()); WifiEspNow.send(PEER, reinterpret_cast(msg), len); delay(1000); } diff --git a/lib/WifiEspNow/library.properties b/lib/WifiEspNow/library.properties index 209140506b..6861fc1df8 100644 --- a/lib/WifiEspNow/library.properties +++ b/lib/WifiEspNow/library.properties @@ -1,9 +1,9 @@ name=WifiEspNow -version=0.0.20190814 +version=0.0.20210821 author=Junxiao Shi maintainer=Junxiao Shi sentence=ESP-NOW for ESP8266 and ESP32. -paragraph=This library wraps ESP-NOW functions as an Arduino library. +paragraph=This library supports ESP-NOW, a connectionless WiFi communication protocol defined by Espressif. It contains a simple wrapper of ESP-NOW functions, as well as a custom pseudo broadcast protocol. category=Communication -url=https://yoursunny.com -architectures=esp8266,esp32 \ No newline at end of file +url=https://wifiespnow.yoursunny.dev/ +architectures=esp8266,esp32 diff --git a/lib/WifiEspNow/mk/format-code.sh b/lib/WifiEspNow/mk/format-code.sh new file mode 100644 index 0000000000..8b8b736063 --- /dev/null +++ b/lib/WifiEspNow/mk/format-code.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eo pipefail +cd "$( dirname "${BASH_SOURCE[0]}" )"/.. + +find -name '*.[hc]pp' -or -name '*.ino' | \ + xargs clang-format-11 -i -style=file diff --git a/lib/WifiEspNow/src/WifiEspNow.cpp b/lib/WifiEspNow/src/WifiEspNow.cpp index 0e93474c93..892df918e8 100644 --- a/lib/WifiEspNow/src/WifiEspNow.cpp +++ b/lib/WifiEspNow/src/WifiEspNow.cpp @@ -2,10 +2,10 @@ #include -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include #include -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) #include #else #error "This library supports ESP8266 and ESP32 only." @@ -13,145 +13,151 @@ WifiEspNowClass WifiEspNow; -WifiEspNowClass::WifiEspNowClass() - : m_rxCb(nullptr) - , m_rxCbArg(nullptr) - , m_begin(false) -{ -} - bool WifiEspNowClass::begin() { - m_begin = esp_now_init() == 0 && -#ifdef ESP8266 - esp_now_set_self_role(ESP_NOW_ROLE_COMBO) == 0 && + end(); + m_ready = + esp_now_init() == 0 && +#ifdef ARDUINO_ARCH_ESP8266 + esp_now_set_self_role(ESP_NOW_ROLE_COMBO) == 0 && #endif - esp_now_register_recv_cb(reinterpret_cast(WifiEspNowClass::rx)) == 0 && - esp_now_register_send_cb(reinterpret_cast(WifiEspNowClass::tx)) == 0; - return m_begin; + esp_now_register_recv_cb(reinterpret_cast(WifiEspNowClass::rx)) == 0 && + esp_now_register_send_cb(reinterpret_cast(WifiEspNowClass::tx)) == 0; + return m_ready; } void WifiEspNowClass::end() { - if (m_begin) { - esp_now_deinit(); - m_begin = false; + if (!m_ready) { + return; } + esp_now_deinit(); + m_ready = false; +} + +bool +WifiEspNowClass::setPrimaryKey(const uint8_t key[WIFIESPNOW_KEYLEN]) +{ + return m_ready && key != nullptr && +#if defined(ARDUINO_ARCH_ESP8266) + esp_now_set_kok(const_cast(key), WIFIESPNOW_KEYLEN) == 0; +#elif defined(ARDUINO_ARCH_ESP32) + esp_now_set_pmk(key) == ESP_OK; +#endif } int WifiEspNowClass::listPeers(WifiEspNowPeerInfo* peers, int maxPeers) const { + if (!m_ready) { + return 0; + } int n = 0; - if (m_begin) { -#if defined(ESP8266) - for (u8* mac = esp_now_fetch_peer(true); - mac != nullptr; - mac = esp_now_fetch_peer(false)) { - uint8_t channel = static_cast(esp_now_get_peer_channel(mac)); -#elif defined(ESP32) - // For IDF 4.4 make sure to zero peer - // See: https://github.com/espressif/arduino-esp32/issues/6029 - esp_now_peer_info_t peer; - memset(&peer, 0, sizeof(peer)); - for (esp_err_t e = esp_now_fetch_peer(true, &peer); - e == ESP_OK; - e = esp_now_fetch_peer(false, &peer)) { - uint8_t* mac = peer.peer_addr; - uint8_t channel = peer.channel; +#if defined(ARDUINO_ARCH_ESP8266) + for (u8* mac = esp_now_fetch_peer(true); mac != nullptr; mac = esp_now_fetch_peer(false)) { + uint8_t channel = static_cast(esp_now_get_peer_channel(mac)); +#elif defined(ARDUINO_ARCH_ESP32) + esp_now_peer_info_t peer; + for (esp_err_t e = esp_now_fetch_peer(true, &peer); e == ESP_OK; + e = esp_now_fetch_peer(false, &peer)) { + uint8_t* mac = peer.peer_addr; + uint8_t channel = peer.channel; #endif - if (n < maxPeers) { - memcpy(peers[n].mac, mac, 6); - peers[n].channel = channel; - } - ++n; + if (n < maxPeers) { + memcpy(peers[n].mac, mac, 6); + peers[n].channel = channel; } + ++n; } return n; } bool -WifiEspNowClass::hasPeer(const uint8_t mac[6]) const +WifiEspNowClass::hasPeer(const uint8_t mac[WIFIESPNOW_ALEN]) const { - if (m_begin) { - return esp_now_is_peer_exist(const_cast(mac)); - } - return false; + return m_ready && +#if defined(ARDUINO_ARCH_ESP8266) + esp_now_is_peer_exist(const_cast(mac)) > 0; +#elif defined(ARDUINO_ARCH_ESP32) + esp_now_is_peer_exist(mac); +#endif } -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) bool -WifiEspNowClass::addPeer(const uint8_t mac[6], int channel, const uint8_t key[WIFIESPNOW_KEYLEN]) +WifiEspNowClass::addPeer(const uint8_t mac[WIFIESPNOW_ALEN], int channel, + const uint8_t key[WIFIESPNOW_KEYLEN]) { - if (!m_begin) return false; + if (!m_ready) { + return false; + } + if (this->hasPeer(mac)) { - if (esp_now_get_peer_channel(const_cast(mac)) == channel) { - return true; - } - this->removePeer(mac); + return esp_now_set_peer_channel(const_cast(mac), static_cast(channel)) == 0 && + esp_now_set_peer_key(const_cast(mac), const_cast(key), + key == nullptr ? 0 : WIFIESPNOW_KEYLEN) == 0; } return esp_now_add_peer(const_cast(mac), ESP_NOW_ROLE_SLAVE, static_cast(channel), const_cast(key), key == nullptr ? 0 : WIFIESPNOW_KEYLEN) == 0; } -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) bool -WifiEspNowClass::addPeer(const uint8_t mac[6], int channel, const uint8_t key[WIFIESPNOW_KEYLEN], int netif) +WifiEspNowClass::addPeer(const uint8_t mac[WIFIESPNOW_ALEN], int channel, + const uint8_t key[WIFIESPNOW_KEYLEN], int netif) { - if (!m_begin) return false; - // For IDF 4.4 make sure to zero peer - // See: https://github.com/espressif/arduino-esp32/issues/6029 - esp_now_peer_info_t pi; - memset(&pi, 0, sizeof(pi)); - if (esp_now_get_peer(mac, &pi) == ESP_OK) { - if (pi.channel == static_cast(channel)) { - return true; - } - this->removePeer(mac); + if (!m_ready) { + return false; } - memset(&pi, 0, sizeof(pi)); - memcpy(pi.peer_addr, mac, ESP_NOW_ETH_ALEN); - pi.channel = static_cast(channel); - pi.ifidx = static_cast(netif); + + esp_now_peer_info_t pi{}; + static_assert(WIFIESPNOW_ALEN == sizeof(pi.peer_addr), ""); + std::copy_n(mac, WIFIESPNOW_ALEN, pi.peer_addr); if (key != nullptr) { - memcpy(pi.lmk, key, ESP_NOW_KEY_LEN); + static_assert(WIFIESPNOW_KEYLEN == sizeof(pi.lmk), ""); + std::copy_n(key, WIFIESPNOW_KEYLEN, pi.lmk); pi.encrypt = true; } + pi.channel = static_cast(channel); + pi.ifidx = static_cast(netif); + + if (hasPeer(mac)) { + return esp_now_mod_peer(&pi) == ESP_OK; + } return esp_now_add_peer(&pi) == ESP_OK; } #endif bool -WifiEspNowClass::removePeer(const uint8_t mac[6]) +WifiEspNowClass::removePeer(const uint8_t mac[WIFIESPNOW_ALEN]) { - if (!m_begin) return false; - return esp_now_del_peer(const_cast(mac)) == 0; + return m_ready && esp_now_del_peer(const_cast(mac)) == 0; } void -WifiEspNowClass::onReceive(RxCallback cb, void* cbarg) +WifiEspNowClass::onReceive(RxCallback cb, void* arg) { m_rxCb = cb; - m_rxCbArg = cbarg; + m_rxArg = arg; } bool -WifiEspNowClass::send(const uint8_t mac[6], const uint8_t* buf, size_t count) +WifiEspNowClass::send(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count) { - if (!m_begin) return false; - if (count > WIFIESPNOW_MAXMSGLEN || count == 0) { + if (!m_ready || count > WIFIESPNOW_MAXMSGLEN || count == 0) { return false; } WifiEspNow.m_txRes = WifiEspNowSendStatus::NONE; - return esp_now_send(const_cast(mac), const_cast(buf), static_cast(count)) == 0; + return esp_now_send(const_cast(mac), const_cast(buf), + static_cast(count)) == 0; } void WifiEspNowClass::rx(const uint8_t* mac, const uint8_t* data, uint8_t len) { if (WifiEspNow.m_rxCb != nullptr) { - (*WifiEspNow.m_rxCb)(mac, data, len, WifiEspNow.m_rxCbArg); + (*WifiEspNow.m_rxCb)(mac, data, len, WifiEspNow.m_rxArg); } } diff --git a/lib/WifiEspNow/src/WifiEspNow.h b/lib/WifiEspNow/src/WifiEspNow.h index 8052898d76..fa51097bb2 100644 --- a/lib/WifiEspNow/src/WifiEspNow.h +++ b/lib/WifiEspNow/src/WifiEspNow.h @@ -1,112 +1,127 @@ +/** + * @mainpage WifiEspNow + * + * https://github.com/yoursunny/WifiEspNow + */ + #ifndef WIFIESPNOW_H #define WIFIESPNOW_H -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) #include #endif #include #include -/** \brief Key length. - */ +/** @brief Address length. */ +static const int WIFIESPNOW_ALEN = 6; + +/** @brief Key length. */ static const int WIFIESPNOW_KEYLEN = 16; -/** \brief Maximum message length. - */ +/** @brief Maximum message length. */ static const int WIFIESPNOW_MAXMSGLEN = 250; struct WifiEspNowPeerInfo { - uint8_t mac[6]; + uint8_t mac[WIFIESPNOW_ALEN]; uint8_t channel; }; -/** \brief Result of send operation. - */ +/** @brief Result of send operation. */ enum class WifiEspNowSendStatus : uint8_t { NONE = 0, ///< result unknown, send in progress - OK = 1, ///< sent successfully + OK = 1, ///< unicast message acknowledged by peer; multicast message transmitted FAIL = 2, ///< sending failed }; class WifiEspNowClass { public: - WifiEspNowClass(); - - /** \brief Initialize ESP-NOW. - * \return whether success + /** + * @brief Initialize ESP-NOW. + * @return whether success. */ bool begin(); - /** \brief Stop ESP-NOW. - */ + /** @brief Stop ESP-NOW. */ void end(); - /** \brief List current peers. - * \param[out] peers buffer for peer information - * \param maxPeers buffer size - * \return total number of peers, \p std::min(retval,maxPeers) is written to \p peers + /** + * @brief Set primary key, also known as KOK or PMK. + * @param key primary encryption key. + * @return whether success. + */ + bool + setPrimaryKey(const uint8_t key[WIFIESPNOW_KEYLEN]); + + /** + * @brief List current peers. + * @param[out] peers buffer for peer information. + * @param maxPeers buffer size. + * @return total number of peers, @c std::min(retval,maxPeers) is written to @p peers . */ int listPeers(WifiEspNowPeerInfo* peers, int maxPeers) const; - /** \brief Test whether peer exists. - * \param mac peer MAC address - * \return whether peer exists + /** + * @brief Test whether peer exists. + * @param mac peer MAC address. + * @return whether peer exists. */ bool - hasPeer(const uint8_t mac[6]) const; - - /** \brief Add a peer or change peer channel. - * \param mac peer MAC address - * \param channel peer channel, 0 for current channel - * \param key encryption key, nullptr to disable encryption - * \param netif (ESP32 only) WiFi interface - * \return whether success - * \note To change peer key, remove the peer and re-add. + hasPeer(const uint8_t mac[WIFIESPNOW_ALEN]) const; + + /** + * @brief Add a peer or change peer channel. + * @param mac peer MAC address. + * @param channel peer channel, 0 for current channel. + * @param key encryption key, nullptr to disable encryption. + * @param netif (ESP32 only) WiFi interface. + * @return whether success. */ -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) bool - addPeer(const uint8_t mac[6], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); -#elif defined(ESP32) + addPeer(const uint8_t mac[WIFIESPNOW_ALEN], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr); +#elif defined(ARDUINO_ARCH_ESP32) bool - addPeer(const uint8_t mac[6], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr, int netif = ESP_IF_WIFI_AP); + addPeer(const uint8_t mac[WIFIESPNOW_ALEN], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr, int netif = ESP_IF_WIFI_AP); #endif - /** \brief Remove a peer. - * \param mac peer MAC address - * \return whether success + /** + * @brief Remove a peer. + * @param mac peer MAC address. + * @return whether success. */ bool - removePeer(const uint8_t mac[6]); + removePeer(const uint8_t mac[WIFIESPNOW_ALEN]); - typedef void (*RxCallback)(const uint8_t mac[6], const uint8_t* buf, size_t count, void* cbarg); + using RxCallback = void (*)(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg); - /** \brief Set receive callback. - * \param cb the callback - * \param cbarg an arbitrary argument passed to the callback - * \note Only one callback is allowed; this replaces any previous callback. + /** + * @brief Set receive callback. + * @param cb the callback. + * @param arg an arbitrary argument passed to the callback. + * @note Only one callback is allowed; this replaces any previous callback. */ void - onReceive(RxCallback cb, void* cbarg); - - /** \brief Send a message. - * \param mac destination MAC address, nullptr for all peers - * \param buf payload - * \param count payload size, must not exceed \p WIFIESPNOW_MAXMSGLEN - * \return whether success (message queued for transmission) + onReceive(RxCallback cb, void* arg); + + /** + * @brief Send a message. + * @param mac destination MAC address, nullptr for all peers. + * @param buf payload. + * @param count payload size, must not exceed @p WIFIESPNOW_MAXMSGLEN . + * @return whether success (message queued for transmission). */ bool - send(const uint8_t mac[6], const uint8_t* buf, size_t count); + send(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count); - /** \brief Retrieve status of last sent message. - * \return whether success (unicast message received by peer, multicast message sent) - */ + /** @brief Retrieve status of last sent message. */ WifiEspNowSendStatus getSendStatus() const { @@ -121,12 +136,13 @@ class WifiEspNowClass tx(const uint8_t* mac, uint8_t status); private: - RxCallback m_rxCb; - void* m_rxCbArg; - WifiEspNowSendStatus m_txRes; - bool m_begin = false; + RxCallback m_rxCb = nullptr; + void* m_rxArg = nullptr; + WifiEspNowSendStatus m_txRes = WifiEspNowSendStatus::NONE; + bool m_ready = false; }; +/** @brief ESP-NOW API. */ extern WifiEspNowClass WifiEspNow; #endif // WIFIESPNOW_H diff --git a/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp index 5b97543a26..bfbc31b7ce 100644 --- a/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp +++ b/lib/WifiEspNow/src/WifiEspNowBroadcast.cpp @@ -1,21 +1,29 @@ #include "WifiEspNowBroadcast.h" -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) #include #include -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) #include #include #else #error "This library supports ESP8266 and ESP32 only." #endif -WifiEspNowBroadcastClass WifiEspNowBroadcast; +// #define WIFIESPNOW_DEBUG +#ifdef WIFIESPNOW_DEBUG +#define LOG(...) \ + do { \ + Serial.printf("[WifiEspNowBroadcast] " __VA_ARGS__); \ + Serial.println(); \ + } while (false) +#else +#define LOG(...) \ + do { \ + } while (false) +#endif -WifiEspNowBroadcastClass::WifiEspNowBroadcastClass() - : m_isScanning(false) -{ -} +WifiEspNowBroadcastClass WifiEspNowBroadcast; bool WifiEspNowBroadcastClass::begin(const char* ssid, int channel, int scanFreq) @@ -24,58 +32,69 @@ WifiEspNowBroadcastClass::begin(const char* ssid, int channel, int scanFreq) m_nextScan = 0; m_scanFreq = scanFreq; + // AP mode for announcing our presence, STA mode for scanning WiFi.mode(WIFI_AP_STA); + // disconnect from any previously saved SSID, so that the specified channel can take effect + WiFi.disconnect(); + // establish AP at the specified channel to announce our presence WiFi.softAP(ssid, nullptr, channel); return WifiEspNow.begin(); } +void +WifiEspNowBroadcastClass::end() +{ + WifiEspNow.end(); + WiFi.softAPdisconnect(); + m_ssid = ""; +} + void WifiEspNowBroadcastClass::loop() { if (millis() >= m_nextScan && !m_isScanning && WiFi.scanComplete() != WIFI_SCAN_RUNNING) { this->scan(); } -#ifdef ESP32 +#ifdef ARDUINO_ARCH_ESP32 if (m_isScanning && WiFi.scanComplete() >= 0) { this->processScan(); } #endif } -void -WifiEspNowBroadcastClass::end() -{ - WifiEspNow.end(); - WiFi.softAPdisconnect(); - m_ssid.clear(); -} - bool -WifiEspNowBroadcastClass::send(const uint8_t* buf, size_t count) +WifiEspNowBroadcastClass::setKey(const uint8_t primary[WIFIESPNOW_KEYLEN], + const uint8_t peer[WIFIESPNOW_KEYLEN]) { - return WifiEspNow.send(nullptr, buf, count); + if (peer == nullptr) { + m_hasPeerKey = false; + return true; + } + m_hasPeerKey = true; + std::copy_n(peer, WIFIESPNOW_KEYLEN, m_peerKey); + return WifiEspNow.setPrimaryKey(primary); } void WifiEspNowBroadcastClass::scan() { + LOG("scan()"); m_isScanning = true; -#if defined(ESP8266) - scan_config sc; -#elif defined(ESP32) - wifi_scan_config_t sc; +#if defined(ARDUINO_ARCH_ESP8266) + scan_config sc{}; +#elif defined(ARDUINO_ARCH_ESP32) + wifi_scan_config_t sc{}; #endif - memset(&sc, 0, sizeof(sc)); sc.ssid = reinterpret_cast(const_cast(m_ssid.c_str())); -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) wifi_station_scan(&sc, reinterpret_cast(WifiEspNowBroadcastClass::processScan)); -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) esp_wifi_scan_start(&sc, false); #endif } -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) void WifiEspNowBroadcastClass::processScan(void* result, int status) { @@ -85,83 +104,92 @@ WifiEspNowBroadcastClass::processScan(void* result, int status) void WifiEspNowBroadcastClass::processScan2(void* result, int status) -#define FOREACH_AP(f) \ - do { \ - for (bss_info* it = reinterpret_cast(result); it; it = STAILQ_NEXT(it, next)) { \ - (f)(it->bssid, it->channel); \ - } \ +#define FOREACH_AP(f) \ + do { \ + for (bss_info* it = reinterpret_cast(result); it; it = STAILQ_NEXT(it, next)) { \ + (f)(it->bssid, it->channel); \ + } \ } while (false) -#define DELETE_APS \ - do {} while(false) +#define DELETE_APS \ + do { \ + } while (false) -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) void WifiEspNowBroadcastClass::processScan() // ESP32 WiFiScanClass::_scanDone is always invoked after a scan complete event, so we can use // Arduino's copy of AP records, but we must check SSID, and should not always delete AP records. -#define FOREACH_AP(f) \ - do { \ - int nNetworks = WiFi.scanComplete(); \ - for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ - if (WiFi.SSID(i) != m_ssid) { \ - continue; \ - } \ - (f)(WiFi.BSSID(i), static_cast(WiFi.channel(i))); \ - } \ +#define FOREACH_AP(f) \ + do { \ + int nNetworks = WiFi.scanComplete(); \ + for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ + if (WiFi.SSID(i) != m_ssid) { \ + continue; \ + } \ + (f)(WiFi.BSSID(i), static_cast(WiFi.channel(i))); \ + } \ } while (false) -#define DELETE_APS \ - do { \ - bool hasOtherSsid = false; \ - int nNetworks = WiFi.scanComplete(); \ - for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ - if (WiFi.SSID(i) == m_ssid) { \ - continue; \ - } \ - hasOtherSsid = true; \ - break; \ - } \ - if (!hasOtherSsid) { \ - WiFi.scanDelete(); \ - } \ - } while(false) +#define DELETE_APS \ + do { \ + bool hasOtherSsid = false; \ + int nNetworks = WiFi.scanComplete(); \ + for (uint8_t i = 0; static_cast(i) < nNetworks; ++i) { \ + if (WiFi.SSID(i) == m_ssid) { \ + continue; \ + } \ + hasOtherSsid = true; \ + break; \ + } \ + if (!hasOtherSsid) { \ + WiFi.scanDelete(); \ + } \ + } while (false) #endif { m_isScanning = false; m_nextScan = millis() + m_scanFreq; -#ifdef ESP8266 +#ifdef ARDUINO_ARCH_ESP8266 if (status != 0) { return; } #endif + LOG("processScan()"); + const int MAX_PEERS = 20; WifiEspNowPeerInfo oldPeers[MAX_PEERS]; int nOldPeers = std::min(WifiEspNow.listPeers(oldPeers, MAX_PEERS), MAX_PEERS); const uint8_t PEER_FOUND = 0xFF; // assigned to .channel to indicate peer is matched - FOREACH_AP([&] (const uint8_t* bssid, uint8_t channel) { + FOREACH_AP([&](const uint8_t* bssid, uint8_t channel) { for (int i = 0; i < nOldPeers; ++i) { - if (memcmp(bssid, oldPeers[i].mac, 6) != 0) { - continue; + WifiEspNowPeerInfo* p = &oldPeers[i]; + if (std::equal(p->mac, p->mac + WIFIESPNOW_ALEN, bssid)) { + p->channel = PEER_FOUND; + break; } - oldPeers[i].channel = PEER_FOUND; - break; } }); for (int i = 0; i < nOldPeers; ++i) { - if (oldPeers[i].channel != PEER_FOUND) { - WifiEspNow.removePeer(oldPeers[i].mac); + WifiEspNowPeerInfo* p = &oldPeers[i]; + if (p->channel == PEER_FOUND) { + continue; } + LOG("processScan removePeer(%02x:%02x:%02x:%02x:%02x:%02x)", p->mac[0], p->mac[1], p->mac[2], + p->mac[3], p->mac[4], p->mac[5]); + WifiEspNow.removePeer(p->mac); } - FOREACH_AP([&] (const uint8_t* bssid, uint8_t channel) { - WifiEspNow.addPeer(bssid, channel); + FOREACH_AP([&](const uint8_t* mac, uint8_t channel) { + LOG("processScan addPeer(%02x:%02x:%02x:%02x:%02x:%02x)", mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); + WifiEspNow.addPeer(mac, channel, m_hasPeerKey ? m_peerKey : nullptr); }); DELETE_APS; diff --git a/lib/WifiEspNow/src/WifiEspNowBroadcast.h b/lib/WifiEspNow/src/WifiEspNowBroadcast.h index 496d48f97e..1c48758ce1 100644 --- a/lib/WifiEspNow/src/WifiEspNowBroadcast.h +++ b/lib/WifiEspNow/src/WifiEspNowBroadcast.h @@ -8,74 +8,95 @@ class WifiEspNowBroadcastClass { public: - WifiEspNowBroadcastClass(); - - /** \brief Initialize ESP-NOW with pseudo broadcast. - * \param ssid AP SSID to announce and find peers - * \param channel AP channel, used if there is no STA connection - * \param scanFreq how often to scan for peers, in millis - * \return whether success - * - * In pseudo broadcast mode, every node announces itself as a group member by advertising a - * certain AP SSID. A node periodically scans other BSSIDs announcing the same SSID, and adds - * them as ESP-NOW peers. Messages are sent to all knows peers. - * - * Pseudo broadcast does not depend on ESP-NOW API to support broadcast. + /** + * @brief Initialize ESP-NOW with pseudo broadcast. + * @param ssid AP SSID to announce and find peers. + * @param channel AP channel, used if there is no STA connection. + * @param scanFreq how often to scan for peers (milliseconds). + * @return whether success. */ bool begin(const char* ssid, int channel = 1, int scanFreq = 15000); - /** \brief Refresh peers if scanning is due. + /** @brief Stop ESP-NOW. */ + void + end(); + + /** + * @brief Refresh peers if scanning is due. + * + * This should be invoked in Arduino sketch @c loop() function. */ void loop(); - /** \brief Stop ESP-NOW. + /** + * @brief Set encryption keys. + * @param primary primary key, also known as KOK or PMK. + * @param peer peer key, also known as LMK; nullptr to disable encryption. + * The same peer key is applied to every discovered peer. + * @return whether success. */ - void - end(); + bool + setKey(const uint8_t primary[WIFIESPNOW_KEYLEN], const uint8_t peer[WIFIESPNOW_KEYLEN] = nullptr); - /** \brief Set receive callback. - * \param cb the callback - * \param cbarg an arbitrary argument passed to the callback - * \note Only one callback is allowed; this replaces any previous callback. + /** + * @brief Set receive callback. + * @param cb the callback. + * @param arg an arbitrary argument passed to the callback. + * @note Only one callback is allowed; this replaces any previous callback. */ void - onReceive(WifiEspNowClass::RxCallback cb, void* cbarg) + onReceive(WifiEspNowClass::RxCallback cb, void* arg) { - WifiEspNow.onReceive(cb, cbarg); + WifiEspNow.onReceive(cb, arg); } - /** \brief Broadcast a message. - * \param buf payload - * \param count payload size, must not exceed \p WIFIESPNOW_MAXMSGLEN - * \return whether success (message queued for transmission) + /** + * @brief Broadcast a message. + * @param buf payload. + * @param count payload size, must not exceed @c WIFIESPNOW_MAXMSGLEN . + * @return whether success (message queued for transmission). */ bool - send(const uint8_t* buf, size_t count); + send(const uint8_t* buf, size_t count) + { + return WifiEspNow.send(nullptr, buf, count); + } private: void scan(); -#if defined(ESP8266) +#if defined(ARDUINO_ARCH_ESP8266) static void processScan(void* result, int status); void processScan2(void* result, int status); -#elif defined(ESP32) +#elif defined(ARDUINO_ARCH_ESP32) void processScan(); #endif private: String m_ssid; - int m_scanFreq; - unsigned long m_nextScan; - bool m_isScanning; + uint8_t m_peerKey[WIFIESPNOW_KEYLEN]; + int m_scanFreq = 0; + unsigned long m_nextScan = 0; + bool m_isScanning = false; + bool m_hasPeerKey = false; }; +/** + * @brief ESP-NOW pseudo broadcast. + * + * In pseudo broadcast mode, every node announces itself as a group member by advertising a + * certain AP SSID. A node periodically scans other BSSIDs announcing the same SSID, and adds + * them as ESP-NOW peers. Messages are sent to all known peers. + * + * Pseudo broadcast does not depend on ESP-NOW API to support broadcast. + */ extern WifiEspNowBroadcastClass WifiEspNowBroadcast; #endif // WIFIESPNOW_BROADCAST_H From 31574efee08093efe577444719058a72d0d00e0b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 11 Sep 2022 12:24:00 +0200 Subject: [PATCH 304/404] [ESPEasy-NOW] Fix WiFi connect on ESP32 using ESPEasy-NOW --- src/src/DataStructs/NodeStruct.cpp | 21 +++++----- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 6 +-- src/src/ESPEasyCore/ESPEasyWifi.cpp | 9 ++-- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 42 ++++++++++++++++--- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 +- 5 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/src/DataStructs/NodeStruct.cpp b/src/src/DataStructs/NodeStruct.cpp index 43b949cd60..d9e4c774f8 100644 --- a/src/src/DataStructs/NodeStruct.cpp +++ b/src/src/DataStructs/NodeStruct.cpp @@ -158,17 +158,18 @@ String NodeStruct::getSummary() const { bool NodeStruct::setESPEasyNow_mac(const MAC_address& received_mac) { - if (received_mac.all_zero()) return false; - if (received_mac == sta_mac) { - ESPEasyNowPeer = 1; - useAP_ESPEasyNow = 0; - return true; - } + if (!received_mac.all_zero()) { + if (received_mac == sta_mac) { + ESPEasyNowPeer = 1; + useAP_ESPEasyNow = 0; + return true; + } - if (received_mac == ap_mac) { - ESPEasyNowPeer = 1; - useAP_ESPEasyNow = 1; - return true; + if (received_mac == ap_mac) { + ESPEasyNowPeer = 1; + useAP_ESPEasyNow = 1; + return true; + } } return false; } diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 21c0d2c403..03e06cc3dd 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -111,11 +111,11 @@ void NetworkConnectRelaxed() { if (ETHConnectRelaxed()) { return; } - // Failed to start the Ethernet network, probably not present of wrong parameters. - // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. - setNetworkMedium(NetworkMedium_t::WIFI); } #endif + // Failed to start the Ethernet network, probably not present of wrong parameters. + // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. + setNetworkMedium(NetworkMedium_t::WIFI); WiFiConnectRelaxed(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 827c7c79ba..87957889b6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -995,9 +995,12 @@ void WifiScan(bool async, uint8_t channel) { #ifdef ESP32 RTC.clearLastWiFi(); - WifiDisconnect(); + if (WiFiConnected()) { + const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; + WifiDisconnect(); + WiFiEventData.wifiConnectAttemptNeeded = needReconnect; + } #endif - } // ******************************************************************************** @@ -1099,7 +1102,7 @@ void setAP(bool enable) { } // Only internal scope -void setAPinternal(bool enable, int APchannel) +void setAPinternal(bool enable) { if (enable) { // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index fb7008883e..a4b804bfcd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -101,7 +101,7 @@ void handle_unprocessedNetworkEvents() if (active_network_medium == NetworkMedium_t::WIFI || active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { - if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { + if (WiFi.status() >= WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() > 20000) { WiFiEventData.last_wifi_connect_attempt_moment.clear(); } @@ -144,6 +144,16 @@ void handle_unprocessedNetworkEvents() { if (!WiFiEventData.WiFiServicesInitialized()) { WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) + if (WiFiConnected()) { + if (!WiFiEventData.WiFiGotIP()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Missed gotIP event")); + WiFiEventData.setWiFiGotIP(); + } + if (!WiFiEventData.WiFiConnected()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Missed connected event")); + WiFiEventData.setWiFiConnected(); + } + } WiFiEventData.setWiFiServicesInitialized(); CheckRunningServices(); } @@ -281,12 +291,25 @@ void processDisconnect() { #ifdef USES_ESPEASY_NOW if (use_EspEasy_now) { - mustRestartWiFi = true; +// mustRestartWiFi = true; } #endif WifiDisconnect(); // Needed or else node may not reconnect reliably. WiFiEventData.processedDisconnect = true; + + if (WiFi.status() > WL_DISCONNECTED) { + // In case of an error, where the status reports something like WL_NO_SHIELD + setWifiMode(WIFI_OFF); + initWiFi(); + delay(100); + if (WiFiEventData.unprocessedWifiEvents()) { + handle_unprocessedNetworkEvents(); + } + mustRestartWiFi = false; + } + + if (mustRestartWiFi) { WifiScan(false); delay(100); @@ -615,7 +638,9 @@ void processScanDone() { WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); - if (WiFi_AP_Candidates.addedKnownCandidate()) { + if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { + WiFiEventData.wifiConnectAttemptNeeded = true; + addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); NetworkConnectRelaxed(); } @@ -625,19 +650,24 @@ void processScanDone() { if (!NetworkConnected() && (temp_disable_EspEasy_now_timer == 0 || timeOutReached(temp_disable_EspEasy_now_timer))) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); + if (!WiFiEventData.wifiConnectInProgress) { // if (isESPEasy_now_only() || !ESPEasy_now_handler.active()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect (mesh)")); + WifiDisconnect(); setAP(false); ESPEasy_now_handler.end(); - // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. + // Disable ESPEasy_now for 20 seconds to give opportunity to connect to WiFi. WiFiEventData.wifiConnectAttemptNeeded = true; - temp_disable_EspEasy_now_timer = millis() + 10000; - setSTA(false); + temp_disable_EspEasy_now_timer = millis() + 20000; +// setSTA(false); setNetworkMedium(Settings.NetworkMedium); NetworkConnectRelaxed(); // } + } } else { + temp_disable_EspEasy_now_timer = 0; setNetworkMedium(NetworkMedium_t::ESPEasyNOW_only); } } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 34617365e9..306e1994f9 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -425,8 +425,8 @@ void ESPEasy_setup() #endif #ifdef USES_ESPEASY_NOW - // Disable ESPEasy_now for 10 seconds to give opportunity to connect to WiFi. - temp_disable_EspEasy_now_timer = millis() + 10000; + // Disable ESPEasy_now for 20 seconds to give opportunity to connect to WiFi. + temp_disable_EspEasy_now_timer = millis() + 20000; #endif From 7db1b4df47ff62ba64906e812344a70f5f12626b Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 13 Sep 2022 12:06:56 +0200 Subject: [PATCH 305/404] [ESPEasy-NOW] Only switch to WiFi mode when connecting to AP --- src/src/ESPEasyCore/ESPEasyNetwork.cpp | 1 - src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 03e06cc3dd..7fc9c18dd4 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -115,7 +115,6 @@ void NetworkConnectRelaxed() { #endif // Failed to start the Ethernet network, probably not present of wrong parameters. // So set the runtime active medium to WiFi to try connecting to WiFi or at least start the AP. - setNetworkMedium(NetworkMedium_t::WIFI); WiFiConnectRelaxed(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 87957889b6..77a499cb0c 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -410,6 +410,7 @@ void AttemptWiFiConnect() { } WiFiEventData.markWiFiBegin(); if (prepareWiFi()) { + setNetworkMedium(NetworkMedium_t::WIFI); RTC.clearLastWiFi(); float tx_pwr = 0; // Will be set higher based on RSSI when needed. // FIXME TD-er: Must check WiFiEventData.wifi_connect_attempt to increase TX power From f1b89e5603699c5458552fb30dbad4715024e9a1 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 13 Sep 2022 12:08:08 +0200 Subject: [PATCH 306/404] [ESPEasy-NOW] Add sysvars to use mesh state in rules --- .../ESPEasy_now_Node_statistics.cpp | 6 +- src/src/DataStructs/TimingStats.cpp | 14 ++-- src/src/Helpers/ESPEasy_now_handler.cpp | 72 ++++--------------- src/src/Helpers/ESPEasy_now_peermanager.cpp | 10 +-- src/src/Helpers/StringProvider.cpp | 40 +++++++---- src/src/Helpers/StringProvider.h | 16 +++-- src/src/Helpers/SystemVariables.cpp | 19 ++++- src/src/Helpers/SystemVariables.h | 11 ++- src/src/WebServer/AdvancedConfigPage.cpp | 15 ++-- src/src/WebServer/JSON.cpp | 7 +- src/src/WebServer/SysInfoPage.cpp | 20 ++++-- src/src/WebServer/SysInfoPage.h | 4 ++ src/src/WebServer/SysVarPage.cpp | 10 +++ 13 files changed, 130 insertions(+), 114 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp index b0c797b480..00388b602c 100644 --- a/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp +++ b/src/src/DataStructs/ESPEasy_now_Node_statistics.cpp @@ -4,6 +4,7 @@ #include "../ESPEasyCore/ESPEasy_Log.h" #include "../Helpers/ESPEasy_time_calc.h" +#include "../Helpers/StringConverter.h" unsigned long ESPEasy_now_Node_statistics_t::getAge() const @@ -36,10 +37,7 @@ void ESPEasy_now_Node_statistics_t::addRoute(uint8_t unit, const ESPEasy_now_tra last_update_route[last_route_index] = last_update; if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME); - log += F(": addRoute: "); - log += route.toString(); - addLog(LOG_LEVEL_INFO, log); + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": addRoute: "), route.toString())); } } diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 7615e0a9e6..0edc2c44fc 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -240,14 +240,14 @@ const __FlashStringHelper * getMiscStatsName_F(int stat) { case PARSE_SYSVAR_NOCHANGE: return F("parseSystemVariables() No change"); case HANDLE_SERVING_WEBPAGE: return F("handle webpage"); #ifdef USES_ESPEASY_NOW - case HANDLE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " handle received message"); - case EXPIRED_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete expired"); - case INVALID_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete invalid"); - case RECEIVE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " onReceive()"); - case ESPEASY_NOW_SEND_MSG_SUC: return F(ESPEASY_NOW_NAME " send Message Success"); + case HANDLE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " handle received message"); + case EXPIRED_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete expired"); + case INVALID_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " incomplete invalid"); + case RECEIVE_ESPEASY_NOW_LOOP: return F(ESPEASY_NOW_NAME " onReceive()"); + case ESPEASY_NOW_SEND_MSG_SUC: return F(ESPEASY_NOW_NAME " send Message Success"); case ESPEASY_NOW_SEND_MSG_FAIL: return F(ESPEASY_NOW_NAME " send Message Fail"); - case ESPEASY_NOW_SEND_PCKT: return F(ESPEASY_NOW_NAME " send Packet"); - case ESPEASY_NOW_DEDUP_LOOP: return F(ESPEASY_NOW_NAME " DuplicateCheck loop"); + case ESPEASY_NOW_SEND_PCKT: return F(ESPEASY_NOW_NAME " send Packet"); + case ESPEASY_NOW_DEDUP_LOOP: return F(ESPEASY_NOW_NAME " DuplicateCheck loop"); #endif case WIFI_SCAN_ASYNC: return F("WiFi Scan Async"); case WIFI_SCAN_SYNC: return F("WiFi Scan Sync (blocking)"); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 61b1490515..61cc461b85 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -284,13 +284,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() // We need to give it some time to receive announcement messages and maybe even a traceroute if (timePassedSince(_last_started) > ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(80)) { - log = F(ESPEASY_NOW_NAME); - log += F(": No peers with distance set on channel "); - log += _usedWiFiChannel; - addLog(LOG_LEVEL_INFO, log); - } + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": No peers with distance set on channel "), _usedWiFiChannel)); } end(); @@ -298,13 +292,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() } else { if (channelChanged) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(64)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Move to channel "); - log += ESPEasyNOW_channel; - addLog(LOG_LEVEL_INFO, log); - } + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Move to channel "), ESPEasyNOW_channel)); } } @@ -319,14 +307,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(64)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Inactive due to not receiving trace routes"); - addLog(LOG_LEVEL_INFO, log); - } - } + addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME ": Inactive due to not receiving trace routes")); end(); temp_disable_EspEasy_now_timer = millis() + 10000; WifiScan(true); @@ -477,14 +458,7 @@ bool ESPEasy_now_handler_t::active() const const bool traceroute_sent_timeout = _last_traceroute_sent != 0 && (timePassedSince(_last_traceroute_sent) > ESPEASY_NOW_ACTIVITY_TIMEOUT); const bool first_traceroute_receive_timeout = _last_traceroute_received == 0 && (timePassedSince(_last_started) > ESPEASY_NOW_ACTIVITY_TIMEOUT + 30000); if (traceroute_received_timeout || traceroute_sent_timeout || first_traceroute_receive_timeout) { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(64)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Inactive due to not receiving trace routes"); - addLog(LOG_LEVEL_INFO, log); - } - } + addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME ": Inactive due to not receiving trace routes")); return false; } @@ -536,12 +510,10 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(const WiFi_AP_Candidate& peer) tmpNodeInfo.setESPEasyNow_mac(peer_mac); if (Nodes.addNode(tmpNodeInfo)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": Found node via WiFi scan: "); - log += peer_mac.toString(); - log += F(" "); + String log = concat(F(ESPEASY_NOW_NAME ": Found node via WiFi scan: "), peer_mac.toString()); + log += ' '; log += tmpNodeInfo.getRSSI(); - log += F(" dBm ch: "); - log += tmpNodeInfo.channel; + log += concat(F(" dBm ch: "), tmpNodeInfo.channel); addLog(LOG_LEVEL_INFO, log); } @@ -566,13 +538,7 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo WifiSTAmacAddress() == receivedMAC) return handled; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(75)) { - log = F(ESPEASY_NOW_NAME); - log += F(": received "); - log += message.getLogString(); - addLog(LOG_LEVEL_INFO, log); - } + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": received "), message.getLogString())); } switch (message.getMessageType()) @@ -718,10 +684,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (!received.setESPEasyNow_mac(mac)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log; - log = F(ESPEASY_NOW_NAME ": Received discovery message from MAC not stated in message: "); - log += mac.toString(); - addLog(LOG_LEVEL_ERROR, log); + addLog(LOG_LEVEL_ERROR, concat(F(ESPEASY_NOW_NAME ": Received discovery message from MAC not stated in message: "), mac.toString())); } return false; } @@ -770,13 +733,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (received.distance == 255 && Nodes.getDistance() < 255) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(80)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Send announce back to unit: "); - log += String(received.unit); - addLog(LOG_LEVEL_INFO, log); - } + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Send announce back to unit: "), received.unit)); } sendDiscoveryAnnounce(received.ESPEasy_Now_MAC(), received.channel); @@ -929,9 +886,7 @@ void ESPEasy_now_handler_t::sendNTPquery() if (!_best_NTP_candidate->getMac(mac)) { return; } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": Send NTP query to: "); - log += mac.toString(); - addLog(LOG_LEVEL_INFO, log); + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Send NTP query to: "), mac.toString())); } _best_NTP_candidate->markSendTime(); @@ -1208,10 +1163,7 @@ bool ESPEasy_now_handler_t::handle_MQTTCheckControllerQueue(const ESPEasy_now_me # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { - String log; - log = F(ESPEASY_NOW_NAME ": Received Queue state: "); - log += query.isFull() ? F("Full") : F("not Full"); - addLog(LOG_LEVEL_DEBUG_MORE, log); + addLog(LOG_LEVEL_DEBUG_MORE, concat(F(ESPEASY_NOW_NAME ": Received Queue state: "), query.isFull() ? F("Full") : F("not Full"))); } # endif // ifndef BUILD_NO_DEBUG } diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index c726e40b04..3e447cf1cb 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -9,6 +9,8 @@ # include "../Globals/Nodes.h" # include "../Globals/SecuritySettings.h" +# include "../Helpers/StringConverter.h" + ESPEasy_now_peermanager_t::ESPEasy_now_peermanager_t() { removeAllPeers(); @@ -65,13 +67,7 @@ bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, con activePeers.push_back(mac); } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { - String log; - if (log.reserve(64)) { - log = F(ESPEASY_NOW_NAME); - log += F(": Failed to add peer "); - log += MAC_address(mac).toString(); - addLog(LOG_LEVEL_ERROR, log); - } + addLog(LOG_LEVEL_ERROR, concat(F(ESPEASY_NOW_NAME ": Failed to add peer "), MAC_address(mac).toString())); } } } else { diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 24b29b0c66..0762cc67c3 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -20,6 +20,11 @@ #include "../Globals/ESPEasy_now_state.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/NetworkState.h" + +#if FEATURE_ESPEASY_P2P +#include "../Globals/Nodes.h" +#endif + #include "../Globals/SecuritySettings.h" #include "../Globals/Settings.h" #include "../Globals/WiFi_AP_Candidates.h" @@ -151,14 +156,6 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::FORCE_WIFI_NOSLEEP: return F("Force WiFi No Sleep"); case LabelType::PERIODICAL_GRAT_ARP: return F("Periodical send Gratuitous ARP"); case LabelType::CONNECTION_FAIL_THRESH: return F("Connection Failure Threshold"); - - #ifdef USES_ESPEASY_NOW - case LabelType::USE_ESPEASY_NOW: return F("Enable " ESPEASY_NOW_NAME); - case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F("Temporary disable " ESPEASY_NOW_NAME); - case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return F("Force Channel " ESPEASY_NOW_NAME); - #endif - - case LabelType::BUILD_DESC: return F("Build"); case LabelType::GIT_BUILD: return F("Git Build"); case LabelType::SYSTEM_LIBRARIES: return F("System Libraries"); @@ -212,6 +209,16 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) { case LabelType::MAX_OTA_SKETCH_SIZE: return F("Max. OTA Sketch Size"); case LabelType::OTA_2STEP: return F("OTA 2-step Needed"); case LabelType::OTA_POSSIBLE: return F("OTA possible"); + +#ifdef USES_ESPEASY_NOW + case LabelType::ESPEASY_NOW_ENABLED: return F(ESPEASY_NOW_NAME " Enabled"); + case LabelType::ESPEASY_NOW_CHANNEL: return F(ESPEASY_NOW_NAME " Channel"); + case LabelType::ESPEASY_NOW_MQTT: return F(ESPEASY_NOW_NAME " Route to MQTT broker"); + case LabelType::ESPEASY_NOW_DISTANCE: return F(ESPEASY_NOW_NAME " Distance"); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return F(ESPEASY_NOW_NAME " Temporary disabled"); + case LabelType::ESPEASY_NOW_FORCED_CHANNEL: return F(ESPEASY_NOW_NAME " Forced Channel"); +#endif + #if FEATURE_ETHERNET case LabelType::ETH_IP_ADDRESS: return F("Eth IP Address"); case LabelType::ETH_IP_SUBNET: return F("Eth IP Subnet"); @@ -380,12 +387,6 @@ String getValue(LabelType::Enum label) { case LabelType::PERIODICAL_GRAT_ARP: return jsonBool(Settings.gratuitousARP()); case LabelType::CONNECTION_FAIL_THRESH: return String(Settings.ConnectionFailuresThreshold); - #ifdef USES_ESPEASY_NOW - case LabelType::USE_ESPEASY_NOW: return jsonBool(Settings.UseESPEasyNow()); - case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); - case LabelType::FORCE_ESPEASY_NOW_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); - #endif - case LabelType::BUILD_DESC: return getSystemBuildString(); case LabelType::GIT_BUILD: { @@ -440,6 +441,17 @@ String getValue(LabelType::Enum label) { case LabelType::MAX_OTA_SKETCH_SIZE: break; case LabelType::OTA_2STEP: break; case LabelType::OTA_POSSIBLE: break; + +#ifdef USES_ESPEASY_NOW + case LabelType::ESPEASY_NOW_ENABLED: return jsonBool(Settings.UseESPEasyNow()); + case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); + case LabelType::ESPEASY_NOW_FORCED_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); + case LabelType::ESPEASY_NOW_CHANNEL: return String(WiFi.channel()); // FIXME TD-er: Must send intended channel and what to do when mesh is off? + case LabelType::ESPEASY_NOW_MQTT: return jsonBool(Nodes.getDistance() < 255); // FIXME TD-er: update this when definition of "distance" no longer reflects presence of connected MQTT broker + case LabelType::ESPEASY_NOW_DISTANCE: return String(Nodes.getDistance()); +#endif + + #if FEATURE_ETHERNET case LabelType::ETH_IP_ADDRESS: return NetworkLocalIP().toString(); case LabelType::ETH_IP_SUBNET: return NetworkSubnetMask().toString(); diff --git a/src/src/Helpers/StringProvider.h b/src/src/Helpers/StringProvider.h index 5058dd27bb..e565f2acea 100644 --- a/src/src/Helpers/StringProvider.h +++ b/src/src/Helpers/StringProvider.h @@ -110,12 +110,6 @@ struct LabelType { PERIODICAL_GRAT_ARP, CONNECTION_FAIL_THRESH, - #ifdef USES_ESPEASY_NOW - USE_ESPEASY_NOW, - TEMP_DISABLE_ESPEASY_NOW, - FORCE_ESPEASY_NOW_CHANNEL, - #endif - BUILD_DESC, GIT_BUILD, SYSTEM_LIBRARIES, @@ -164,6 +158,16 @@ struct LabelType { MAX_OTA_SKETCH_SIZE, OTA_2STEP, OTA_POSSIBLE, + +#ifdef USES_ESPEASY_NOW + ESPEASY_NOW_ENABLED, + TEMP_DISABLE_ESPEASY_NOW, + ESPEASY_NOW_FORCED_CHANNEL, + ESPEASY_NOW_CHANNEL, + ESPEASY_NOW_MQTT, + ESPEASY_NOW_DISTANCE, +#endif + #if FEATURE_ETHERNET ETH_IP_ADDRESS, ETH_IP_SUBNET, diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 083db42285..8ab8c8a443 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -90,8 +90,15 @@ LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) { case SystemVariables::GATEWAY: label = LabelType::GATEWAY; break; case SystemVariables::CLIENTIP: label = LabelType::CLIENT_IP; break; - #if FEATURE_ETHERNET + #ifdef USES_ESPEASY_NOW + case SystemVariables::ESPEASY_NOW_ENABLED: label = LabelType::ESPEASY_NOW_ENABLED; break; + case SystemVariables::ESPEASY_NOW_CHANNEL: label = LabelType::ESPEASY_NOW_CHANNEL; break; + case SystemVariables::ESPEASY_NOW_MQTT: label = LabelType::ESPEASY_NOW_MQTT; break; + case SystemVariables::ESPEASY_NOW_DISTANCE: label = LabelType::ESPEASY_NOW_DISTANCE; break; + case SystemVariables::ESPEASY_NOW_FORCED_CHANNEL: label = LabelType::ESPEASY_NOW_FORCED_CHANNEL; break; + #endif + #if FEATURE_ETHERNET case SystemVariables::ETHWIFIMODE: label = LabelType::ETH_WIFI_MODE; break; // 0=WIFI, 1=ETH case SystemVariables::ETHCONNECTED: label = LabelType::ETH_CONNECTED; break; // 0=disconnected, 1=connected case SystemVariables::ETHDUPLEX: label = LabelType::ETH_DUPLEX; break; @@ -99,6 +106,7 @@ LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) { case SystemVariables::ETHSTATE: label = LabelType::ETH_STATE; break; case SystemVariables::ETHSPEEDSTATE: label = LabelType::ETH_SPEED_STATE; break; #endif // if FEATURE_ETHERNET + case SystemVariables::LCLTIME: label = LabelType::LOCAL_TIME; break; case SystemVariables::MAC: label = LabelType::STA_MAC; break; case SystemVariables::RSSI: label = LabelType::WIFI_RSSI; break; @@ -337,6 +345,15 @@ const __FlashStringHelper * SystemVariables::toString(SystemVariables::Enum enum case Enum::ISMQTTIMP: return F("%ismqttimp%"); case Enum::ISNTP: return F("%isntp%"); case Enum::ISWIFI: return F("%iswifi%"); + + #ifdef USES_ESPEASY_NOW + case Enum::ESPEASY_NOW_ENABLED: return F("%mesh_enabled"); + case Enum::ESPEASY_NOW_CHANNEL: return F("%mesh_ch"); + case Enum::ESPEASY_NOW_MQTT: return F("%mesh_mqtt"); + case Enum::ESPEASY_NOW_DISTANCE: return F("%mesh_dist"); + case Enum::ESPEASY_NOW_FORCED_CHANNEL: return F("%mesh_ch_forced"); + #endif + #if FEATURE_ETHERNET case Enum::ETHWIFIMODE: return F("%ethwifimode%"); case Enum::ETHCONNECTED: return F("%ethconnected%"); diff --git a/src/src/Helpers/SystemVariables.h b/src/src/Helpers/SystemVariables.h index eff786c809..0a896dbe94 100644 --- a/src/src/Helpers/SystemVariables.h +++ b/src/src/Helpers/SystemVariables.h @@ -26,6 +26,15 @@ class SystemVariables { ISMQTTIMP, ISNTP, ISWIFI, + + #ifdef USES_ESPEASY_NOW + ESPEASY_NOW_ENABLED, + ESPEASY_NOW_CHANNEL, + ESPEASY_NOW_MQTT, + ESPEASY_NOW_DISTANCE, + ESPEASY_NOW_FORCED_CHANNEL, + #endif + #if FEATURE_ETHERNET ETHWIFIMODE, ETHCONNECTED, @@ -34,6 +43,7 @@ class SystemVariables { ETHSTATE, ETHSPEEDSTATE, #endif // if FEATURE_ETHERNET + LCLTIME, LCLTIME_AM, LF, @@ -107,7 +117,6 @@ class SystemVariables { ESP_CHIP_CORES, ESP_BOARD_NAME, - // Keep UNKNOWN as last UNKNOWN }; diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index 940ab3fc11..e91380e598 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -116,8 +116,8 @@ void handle_advanced() { #endif #ifdef USES_ESPEASY_NOW - Settings.UseESPEasyNow(isFormItemChecked(getInternalLabel(LabelType::USE_ESPEASY_NOW))); - Settings.ForceESPEasyNOWchannel = getFormItemInt(getInternalLabel(LabelType::FORCE_ESPEASY_NOW_CHANNEL)); + Settings.UseESPEasyNow(isFormItemChecked(getInternalLabel(LabelType::ESPEASY_NOW_ENABLED))); + Settings.ForceESPEasyNOWchannel = getFormItemInt(getInternalLabel(LabelType::ESPEASY_NOW_FORCED_CHANNEL)); #endif Settings.EnableRulesCaching(isFormItemChecked(LabelType::ENABLE_RULES_CACHING)); @@ -319,13 +319,12 @@ void handle_advanced() { #ifdef USES_ESPEASY_NOW - addFormCheckBox(LabelType::USE_ESPEASY_NOW, Settings.UseESPEasyNow()); + addFormCheckBox(LabelType::ESPEASY_NOW_ENABLED, Settings.UseESPEasyNow()); { - addFormNumericBox(LabelType::FORCE_ESPEASY_NOW_CHANNEL, Settings.ForceESPEasyNOWchannel, 0, 14); - String note = F("Force channel to use for "); - note += F(ESPEASY_NOW_NAME); - note += F("-only mode (0 = use any channel)"); - addFormNote(note); + addFormNumericBox(LabelType::ESPEASY_NOW_FORCED_CHANNEL, Settings.ForceESPEasyNOWchannel, 0, 14); + addFormNote(F("Force channel to use for " + ESPEASY_NOW_NAME + "-only mode (0 = use any channel)")); } #endif diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index 31fe51d77e..b81d56e4a3 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -256,8 +256,11 @@ void handle_json() LabelType::PERIODICAL_GRAT_ARP, #endif // ifdef SUPPORT_ARP #ifdef USES_ESPEASY_NOW - LabelType::USE_ESPEASY_NOW, - LabelType::FORCE_ESPEASY_NOW_CHANNEL, + LabelType::ESPEASY_NOW_ENABLED, + LabelType::ESPEASY_NOW_CHANNEL, + LabelType::ESPEASY_NOW_FORCED_CHANNEL, + LabelType::ESPEASY_NOW_MQTT, + LabelType::ESPEASY_NOW_DISTANCE, #endif LabelType::CONNECTION_FAIL_THRESH, #ifdef ESP8266 // TD-er: Disable setting TX power on ESP32 as it seems to cause issues on IDF4.4 diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index e36340211b..7e0069d663 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -254,6 +254,10 @@ void handle_sysinfo() { handle_sysinfo_Network(); +#ifdef USES_ESPEASY_NOW + handle_sysinfo_ESPEasyNow(); +#endif + # if FEATURE_ETHERNET handle_sysinfo_Ethernet(); # endif // if FEATURE_ETHERNET @@ -384,6 +388,18 @@ void handle_sysinfo_memory() { } #endif +#ifdef USES_ESPEASY_NOW +void handle_sysinfo_ESPEasyNow() { + addTableSeparator(F(ESPEASY_NOW_NAME), 2, 3); + addRowLabelValue(LabelType::ESPEASY_NOW_ENABLED); + addRowLabelValue(LabelType::ESPEASY_NOW_CHANNEL); + addRowLabelValue(LabelType::ESPEASY_NOW_FORCED_CHANNEL); + addRowLabelValue(LabelType::ESPEASY_NOW_MQTT); + addRowLabelValue(LabelType::ESPEASY_NOW_DISTANCE); +} +#endif + + # if FEATURE_ETHERNET void handle_sysinfo_Ethernet() { if (active_network_medium == NetworkMedium_t::Ethernet) { @@ -481,10 +497,6 @@ void handle_sysinfo_WiFiSettings() { addRowLabelValue(LabelType::WIFI_SEND_AT_MAX_TX_PWR); #endif addRowLabelValue(LabelType::WIFI_NR_EXTRA_SCANS); -#ifdef USES_ESPEASY_NOW - addRowLabelValue(LabelType::USE_ESPEASY_NOW); - addRowLabelValue(LabelType::FORCE_ESPEASY_NOW_CHANNEL); -#endif addRowLabelValue(LabelType::WIFI_USE_LAST_CONN_FROM_RTC); } #endif diff --git a/src/src/WebServer/SysInfoPage.h b/src/src/WebServer/SysInfoPage.h index 6dce9c0eac..5d6dc857a4 100644 --- a/src/src/WebServer/SysInfoPage.h +++ b/src/src/WebServer/SysInfoPage.h @@ -33,6 +33,10 @@ void handle_sysinfo_Network(); void handle_sysinfo_WiFiSettings(); #endif +#ifdef USES_ESPEASY_NOW +void handle_sysinfo_ESPEasyNow(); +#endif + void handle_sysinfo_Firmware(); #ifndef WEBSERVER_SYSINFO_MINIMAL diff --git a/src/src/WebServer/SysVarPage.cpp b/src/src/WebServer/SysVarPage.cpp index b182340150..4e5183a263 100644 --- a/src/src/WebServer/SysVarPage.cpp +++ b/src/src/WebServer/SysVarPage.cpp @@ -68,6 +68,16 @@ void handle_sysvars() { addSysVar_enum_html(SystemVariables::BSSID); addSysVar_enum_html(SystemVariables::WI_CH); + +#ifdef USES_ESPEASY_NOW + addTableSeparator(F(ESPEASY_NOW_NAME), 3, 3); + addSysVar_enum_html(SystemVariables::ESPEASY_NOW_ENABLED); + addSysVar_enum_html(SystemVariables::ESPEASY_NOW_CHANNEL); + addSysVar_enum_html(SystemVariables::ESPEASY_NOW_FORCED_CHANNEL); + addSysVar_enum_html(SystemVariables::ESPEASY_NOW_MQTT); + addSysVar_enum_html(SystemVariables::ESPEASY_NOW_DISTANCE); +#endif + #if FEATURE_ETHERNET addTableSeparator(F("Ethernet"), 3, 3); addSysVar_enum_html(SystemVariables::ETHWIFIMODE); From caa3016e8d7045b753c85f1e1e65971f5ef51ed5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 13 Sep 2022 14:58:55 +0200 Subject: [PATCH 307/404] [ESPEasy_NOW] Report intended channel in mesh discovery messages --- src/src/DataStructs/NodesHandler.cpp | 6 +++++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 13 +++++++++---- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 5 +++-- src/src/Helpers/ESPEasy_now_peermanager.cpp | 3 +++ src/src/Helpers/Networking.cpp | 4 ++-- src/src/Helpers/StringProvider.cpp | 2 +- src/src/Helpers/SystemVariables.cpp | 10 +++++----- src/src/Helpers/SystemVariables.h | 2 +- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 058cdcfda6..c359d9dfd9 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -345,7 +345,11 @@ void NodesHandler::updateThisNode() { } } } + #ifdef USES_ESPEASY_NOW + thisNode.channel = getESPEasyNOW_channel(); + #else thisNode.channel = WiFiEventData.usedChannel; + #endif if (thisNode.channel == 0) { thisNode.channel = WiFi.channel(); } @@ -553,7 +557,7 @@ uint8_t NodesHandler::getESPEasyNOW_channel() const return preferred->channel; } } - return 0; + return WiFiEventData.usedChannel; } #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 77a499cb0c..fbc5ac9b19 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -10,6 +10,7 @@ #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/EventQueue.h" #include "../Globals/NetworkState.h" +#include "../Globals/Nodes.h" #include "../Globals/RTC.h" #include "../Globals/SecuritySettings.h" #include "../Globals/Services.h" @@ -1117,12 +1118,12 @@ void setAPinternal(bool enable) } int channel = 1; - if (WifiIsSTA(WiFi.getMode())) { + if (WifiIsSTA(WiFi.getMode()) && WiFiConnected()) { channel = WiFi.channel(); } else { #ifdef USES_ESPEASY_NOW - if (Settings.UseESPEasyNow() && Settings.ForceESPEasyNOWchannel != 0) { - channel = Settings.ForceESPEasyNOWchannel; + if (Settings.UseESPEasyNow()) { + channel = Nodes.getESPEasyNOW_channel(); } #endif } @@ -1196,9 +1197,13 @@ void setWifiMode(WiFiMode_t wifimode) { if (WiFiEventData.usedChannel != 0) { APchannel = WiFiEventData.usedChannel; } + #ifdef USES_ESPEASY_NOW + else if (Settings.UseESPEasyNow()) { + APchannel = Nodes.getESPEasyNOW_channel(); + } + #endif } - if (cur_mode == WIFI_OFF) { WiFiEventData.markWiFiTurnOn(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index a4b804bfcd..1f306cb4f0 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -548,7 +548,7 @@ void processProbeRequestAPmode() { // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { - ESPEasy_now_handler.sendDiscoveryAnnounce(mac, WiFiEventData.usedChannel); + ESPEasy_now_handler.sendDiscoveryAnnounce(mac, Nodes.getESPEasyNOW_channel()); } #endif } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 61cc461b85..4d0c087ca2 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -773,7 +773,7 @@ void ESPEasy_now_handler_t::sendTraceRoute() // Since we're the end node, claim highest success rate thisTraceRoute.setSuccessRate_last_node(Settings.Unit, 255); - int channel = WiFiEventData.usedChannel; + int channel = Nodes.getESPEasyNOW_channel(); if (channel == 0) { channel = WiFi.channel(); } @@ -787,7 +787,8 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& { for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { - sendTraceRoute(it->second.ESPEasy_Now_MAC(), traceRoute, channel); + const int peer_channel = it->second.channel == 0 ? channel : it->second.channel; + sendTraceRoute(it->second.ESPEasy_Now_MAC(), traceRoute, peer_channel); } } diff --git a/src/src/Helpers/ESPEasy_now_peermanager.cpp b/src/src/Helpers/ESPEasy_now_peermanager.cpp index 3e447cf1cb..83b18379d9 100644 --- a/src/src/Helpers/ESPEasy_now_peermanager.cpp +++ b/src/src/Helpers/ESPEasy_now_peermanager.cpp @@ -71,6 +71,9 @@ bool ESPEasy_now_peermanager_t::addPeer(const MAC_address& mac, int channel, con } } } else { + // Peer exists, but add it anyway to make sure the channel is updated. + WifiEspNow.addPeer(mac.mac, channel); + // Move the MAC address to the back of the list as it is actively used if (activePeers.back() != mac) { auto it = activePeers.begin(); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 3d5376a677..52a5d74a37 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -385,7 +385,7 @@ String formatUnitToIPAddress(uint8_t unit, uint8_t formatCode) { } case 2: // Return "0" { - return F("0"); + return String('0'); } } } @@ -411,7 +411,7 @@ IPAddress getIPAddressForUnit(uint8_t unit) { if (it->second.ip[0] == 0) { return remoteNodeIP; } - remoteNodeIP = it->second.ip; + return IPAddress(it->second.ip); } return remoteNodeIP; } diff --git a/src/src/Helpers/StringProvider.cpp b/src/src/Helpers/StringProvider.cpp index 0762cc67c3..0e27213e34 100644 --- a/src/src/Helpers/StringProvider.cpp +++ b/src/src/Helpers/StringProvider.cpp @@ -446,7 +446,7 @@ String getValue(LabelType::Enum label) { case LabelType::ESPEASY_NOW_ENABLED: return jsonBool(Settings.UseESPEasyNow()); case LabelType::TEMP_DISABLE_ESPEASY_NOW: return jsonBool(temp_disable_EspEasy_now_timer != 0); case LabelType::ESPEASY_NOW_FORCED_CHANNEL: return String(Settings.ForceESPEasyNOWchannel); - case LabelType::ESPEASY_NOW_CHANNEL: return String(WiFi.channel()); // FIXME TD-er: Must send intended channel and what to do when mesh is off? + case LabelType::ESPEASY_NOW_CHANNEL: return String(Nodes.getESPEasyNOW_channel()); // FIXME TD-er: Must send intended channel and what to do when mesh is off? case LabelType::ESPEASY_NOW_MQTT: return jsonBool(Nodes.getDistance() < 255); // FIXME TD-er: update this when definition of "distance" no longer reflects presence of connected MQTT broker case LabelType::ESPEASY_NOW_DISTANCE: return String(Nodes.getDistance()); #endif diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 8ab8c8a443..eea350c560 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -347,11 +347,11 @@ const __FlashStringHelper * SystemVariables::toString(SystemVariables::Enum enum case Enum::ISWIFI: return F("%iswifi%"); #ifdef USES_ESPEASY_NOW - case Enum::ESPEASY_NOW_ENABLED: return F("%mesh_enabled"); - case Enum::ESPEASY_NOW_CHANNEL: return F("%mesh_ch"); - case Enum::ESPEASY_NOW_MQTT: return F("%mesh_mqtt"); - case Enum::ESPEASY_NOW_DISTANCE: return F("%mesh_dist"); - case Enum::ESPEASY_NOW_FORCED_CHANNEL: return F("%mesh_ch_forced"); + case Enum::ESPEASY_NOW_ENABLED: return F("%mesh_enabled"); + case Enum::ESPEASY_NOW_CHANNEL: return F("%mesh_ch"); + case Enum::ESPEASY_NOW_MQTT: return F("%mesh_mqtt"); + case Enum::ESPEASY_NOW_DISTANCE: return F("%mesh_dist"); + case Enum::ESPEASY_NOW_FORCED_CHANNEL: return F("%mesh_forced_ch"); #endif #if FEATURE_ETHERNET diff --git a/src/src/Helpers/SystemVariables.h b/src/src/Helpers/SystemVariables.h index 0a896dbe94..73d6d45741 100644 --- a/src/src/Helpers/SystemVariables.h +++ b/src/src/Helpers/SystemVariables.h @@ -29,10 +29,10 @@ class SystemVariables { #ifdef USES_ESPEASY_NOW ESPEASY_NOW_ENABLED, + ESPEASY_NOW_FORCED_CHANNEL, ESPEASY_NOW_CHANNEL, ESPEASY_NOW_MQTT, ESPEASY_NOW_DISTANCE, - ESPEASY_NOW_FORCED_CHANNEL, #endif #if FEATURE_ETHERNET From ab99783e2842e4c4826c6a410d2657ef41293438 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 29 Sep 2022 20:19:12 +0200 Subject: [PATCH 308/404] [WiFi] Prevent setting same WiFi mode multiple times And thus causing stack overflow --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 24 +++++++------------ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 13 ++++++---- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index dcb676538f..01b5302a84 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1184,24 +1184,15 @@ const __FlashStringHelper * getWifiModeString(WiFiMode_t wifimode) void setWifiMode(WiFiMode_t wifimode) { const WiFiMode_t cur_mode = WiFi.getMode(); - if (cur_mode == wifimode) { return; } - - int APchannel = 1; - if (WifiIsSTA(WiFi.getMode()) && WiFi.isConnected()) { - APchannel = WiFi.channel(); - } else { - if (WiFiEventData.usedChannel != 0) { - APchannel = WiFiEventData.usedChannel; - } - #ifdef USES_ESPEASY_NOW - else if (Settings.UseESPEasyNow()) { - APchannel = Nodes.getESPEasyNOW_channel(); - } - #endif + static WiFiMode_t processing_wifi_mode = cur_mode; + if (processing_wifi_mode == wifimode) { + // Prevent loops + return; } + processing_wifi_mode = wifimode; if (cur_mode == WIFI_OFF) { WiFiEventData.markWiFiTurnOn(); @@ -1217,6 +1208,9 @@ void setWifiMode(WiFiMode_t wifimode) { WiFi.forceSleepWake(); // Make sure WiFi is really active. #endif delay(100); + } else { + WifiDisconnect(); + processDisconnect(); } addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(wifimode))); @@ -1236,8 +1230,6 @@ void setWifiMode(WiFiMode_t wifimode) { if (wifimode == WIFI_OFF) { - WifiDisconnect(); - processDisconnect(); WiFiEventData.markWiFiTurnOn(); delay(100); #if defined(ESP32) diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 1f306cb4f0..a6f7cab272 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -253,6 +253,7 @@ void handle_unprocessedNetworkEvents() void processDisconnect() { if (WiFiEventData.processingDisconnect.isSet()) { if (WiFiEventData.processingDisconnect.millisPassedSince() > 5000 || WiFiEventData.processedDisconnect) { + WiFiEventData.processedDisconnect = true; WiFiEventData.processingDisconnect.clear(); } } @@ -296,21 +297,24 @@ void processDisconnect() { #endif WifiDisconnect(); // Needed or else node may not reconnect reliably. - WiFiEventData.processedDisconnect = true; - if (WiFi.status() > WL_DISCONNECTED) { // In case of an error, where the status reports something like WL_NO_SHIELD + addLog(LOG_LEVEL_ERROR, F("WIFI : WiFi.status() > WL_DISCONNECTED, reset WiFi")); setWifiMode(WIFI_OFF); initWiFi(); delay(100); if (WiFiEventData.unprocessedWifiEvents()) { - handle_unprocessedNetworkEvents(); + WiFiEventData.processedDisconnect = true; + WiFiEventData.processingDisconnect.clear(); } mustRestartWiFi = false; } + WiFiEventData.processedDisconnect = true; + WiFiEventData.processingDisconnect.clear(); if (mustRestartWiFi) { + addLog(LOG_LEVEL_ERROR, F("WIFI : Must restart WiFi")); WifiScan(false); delay(100); setWifiMode(WIFI_OFF); @@ -640,7 +644,8 @@ void processScanDone() { if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { WiFiEventData.wifiConnectAttemptNeeded = true; - addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + if (WiFi_AP_Candidates.addedKnownCandidate()) + addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); NetworkConnectRelaxed(); } From c2c9054093a322247bdca44c4c76a7e89932a60a Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 1 Oct 2022 12:50:55 +0200 Subject: [PATCH 309/404] [SysVars] Fix sunrise/sunset offset (%sunrise-1h%) Broken since last attempt to reduce bin size. --- src/src/Helpers/SystemVariables.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 02acdfd086..2bd376b017 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -329,6 +329,11 @@ SystemVariables::Enum SystemVariables::nextReplacementEnum(const String& str, Sy String SystemVariables::toString(Enum enumval) { + if (enumval == Enum::SUNRISE || enumval == Enum::SUNSET) { + // These need variables, so only prepend a %, not wrap. + return String('%') + SystemVariables::toFlashString(enumval); + } + return wrap_String(SystemVariables::toFlashString(enumval), '%'); } From b4dae42f5ce8c2d0227f4d3e2f64ef80d2983d10 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 1 Oct 2022 16:43:58 +0200 Subject: [PATCH 310/404] [Build] Reduce build size --- src/_P001_Switch.ino | 8 +-- src/_P012_LCD.ino | 2 +- src/_P023_OLED.ino | 2 +- src/_P037_MQTTImport.ino | 2 +- src/_P043_ClkOutput.ino | 4 +- src/_P074_TSL2591.ino | 8 +-- src/_P075_Nextion.ino | 2 +- src/_P094_CULReader.ino | 2 +- src/_P095_ILI9341.ino | 6 +- src/_P096_eInk.ino | 6 +- src/_P109_ThermOLED.ino | 2 +- src/_P116_ST77xx.ino | 6 +- src/_P118_Itho.ino | 6 +- src/_P131_NeoPixelMatrix.ino | 8 +-- src/_Plugin_Helper.cpp | 4 +- src/src/Commands/Common.cpp | 18 ++++-- src/src/Commands/Common.h | 2 + src/src/Commands/Diagnostic.cpp | 7 +-- src/src/Commands/ESPEasy_Now_cmd.cpp | 4 +- src/src/Commands/ESPEasy_Now_cmd.h | 6 +- src/src/Commands/GPIO.cpp | 8 +-- src/src/Commands/Networks.cpp | 7 +-- src/src/Commands/SDCARD.cpp | 12 ++-- src/src/Commands/Servo.cpp | 7 +-- src/src/Commands/Settings.cpp | 18 ++---- src/src/Commands/Settings.h | 2 +- src/src/Commands/Time.cpp | 27 +++------ src/src/Commands/WiFi.cpp | 8 +-- src/src/Commands/wd.cpp | 12 ++-- src/src/CustomBuild/define_plugin_sets.h | 8 +-- src/src/DataStructs/Web_StreamingBuffer.cpp | 10 ++-- src/src/ESPEasyCore/Serial.cpp | 18 +++--- src/src/ESPEasyCore/Serial.h | 1 + src/src/Helpers/Dallas1WireHelper.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 8 +-- src/src/Helpers/Hardware.cpp | 7 +-- src/src/PluginStructs/P002_data_struct.cpp | 2 +- src/src/PluginStructs/P037_data_struct.cpp | 14 ++--- src/src/PluginStructs/P044_data_struct.cpp | 4 +- src/src/PluginStructs/P134_data_struct.cpp | 4 +- src/src/WebServer/404.cpp | 4 +- src/src/WebServer/ConfigPage.cpp | 2 +- src/src/WebServer/DevicesPage.cpp | 22 ++++---- src/src/WebServer/DownloadPage.cpp | 2 +- src/src/WebServer/ESPEasy_WebServer.cpp | 38 +------------ src/src/WebServer/ESPEasy_WebServer.h | 16 ------ src/src/WebServer/FactoryResetPage.cpp | 22 ++++---- src/src/WebServer/FileList.cpp | 2 +- src/src/WebServer/LoadFromFS.cpp | 22 ++++---- src/src/WebServer/NotificationPage.cpp | 2 +- src/src/WebServer/RootPage.cpp | 2 +- src/src/WebServer/Rules.cpp | 16 +++--- src/src/WebServer/SettingsArchive.cpp | 24 ++++---- src/src/WebServer/SetupPage.cpp | 4 +- src/src/WebServer/common.cpp | 61 +++++++++++++++++++++ src/src/WebServer/common.h | 23 ++++++++ 56 files changed, 280 insertions(+), 266 deletions(-) create mode 100644 src/src/WebServer/common.cpp diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 0fb924bead..504126bbec 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -477,9 +477,9 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, - concat(F("SW : GPIO="), CONFIG_PIN1) + + concat(F("SW : GPIO="), static_cast(CONFIG_PIN1)) + concat(F(" State="), state ? '1' : '0') + - concat(output_value == 3 ? F(" Doubleclick=") : F(" Output value="), output_value)); + concat(output_value == 3 ? F(" Doubleclick=") : F(" Output value="), static_cast(output_value))); } # endif // ifndef BUILD_NO_DEBUG @@ -572,9 +572,9 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, - concat(F("SW : LongPress: GPIO= "), CONFIG_PIN1) + + concat(F("SW : LongPress: GPIO= "), static_cast(CONFIG_PIN1)) + concat(F(" State="), state ? '1' : '0') + - concat(F(" Output value="), output_value)); + concat(F(" Output value="), static_cast(output_value))); } # endif // ifndef BUILD_NO_DEBUG diff --git a/src/_P012_LCD.ino b/src/_P012_LCD.ino index 0cf6df070a..0c564135e3 100644 --- a/src/_P012_LCD.ino +++ b/src/_P012_LCD.ino @@ -92,7 +92,7 @@ boolean Plugin_012(uint8_t function, struct EventStruct *event, String& string) String strings[P12_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P12_Nlines, P12_Nchars); - for (uint8_t varNr = 0; varNr < P12_Nlines; varNr++) + for (int varNr = 0; varNr < P12_Nlines; varNr++) { addFormTextBox(concat(F("Line "), varNr + 1), getPluginCustomArgName(varNr), strings[varNr], P12_Nchars); } diff --git a/src/_P023_OLED.ino b/src/_P023_OLED.ino index 4b755b640a..d6fda425dd 100644 --- a/src/_P023_OLED.ino +++ b/src/_P023_OLED.ino @@ -99,7 +99,7 @@ boolean Plugin_023(uint8_t function, struct EventStruct *event, String& string) String strings[P23_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P23_Nlines, P23_Nchars); - for (uint8_t varNr = 0; varNr < 8; varNr++) + for (int varNr = 0; varNr < 8; varNr++) { addFormTextBox(concat(F("Line "), varNr + 1), getPluginCustomArgName(varNr), strings[varNr], 64); } diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index bfad6650a2..a786f63418 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -232,7 +232,7 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string) P037_DEDUPLICATE_EVENTS = isFormItemChecked(F("p037_deduplicate")) ? 1 : 0; P037_QUEUEDEPTH_EVENTS = getFormItemInt(F("p037_queuedepth")); # if P037_REPLACE_BY_COMMA_SUPPORT - String character = web_server.arg(F("p037_replace_char")); + String character = webArg(F("p037_replace_char")); P037_REPLACE_BY_COMMA = character[0]; if (P037_REPLACE_BY_COMMA == 0x20) { // Space -> 0 diff --git a/src/_P043_ClkOutput.ino b/src/_P043_ClkOutput.ino index 5003958b42..e7aa0b2b73 100644 --- a/src/_P043_ClkOutput.ino +++ b/src/_P043_ClkOutput.ino @@ -89,7 +89,7 @@ boolean Plugin_043(uint8_t function, struct EventStruct *event, String& string) options[1] = F("Off"); options[2] = F("On"); - for (uint8_t x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) + for (int x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) { addFormTextBox( concat(F("Day,Time "), x + 1), @@ -111,7 +111,7 @@ boolean Plugin_043(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_SAVE: { - for (uint8_t x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) + for (int x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) { const String plugin1 = webArg(concat(F("p043_clock"), x)); ExtraTaskSettings.TaskDevicePluginConfigLong[x] = string2TimeLong(plugin1); diff --git a/src/_P074_TSL2591.ino b/src/_P074_TSL2591.ino index 1632259f8e..f871491c09 100644 --- a/src/_P074_TSL2591.ino +++ b/src/_P074_TSL2591.ino @@ -189,10 +189,10 @@ boolean Plugin_074(uint8_t function, struct EventStruct *event, String& string) if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log += concat(F("TSL2591: Lux: "), toString(lux)); - log += concat(F(" Full: "), full); - log += concat(F(" Visible: "), visible); - log += concat(F(" IR: "), ir); - log += concat(F(" duration: "), P074_data->duration); + log += concat(F(" Full: "), static_cast(full)); + log += concat(F(" Visible: "), static_cast(visible)); + log += concat(F(" IR: "), static_cast(ir)); + log += concat(F(" duration: "), static_cast(P074_data->duration)); addLogMove(LOG_LEVEL_INFO, log); } diff --git a/src/_P075_Nextion.ino b/src/_P075_Nextion.ino index ddb529f4a2..2661e5ec5a 100644 --- a/src/_P075_Nextion.ino +++ b/src/_P075_Nextion.ino @@ -119,7 +119,7 @@ boolean Plugin_075(uint8_t function, struct EventStruct *event, String& string) if (nullptr != P075_data) { P075_data->loadDisplayLines(event->TaskIndex); - for (uint8_t varNr = 0; varNr < P75_Nlines; varNr++) { + for (int varNr = 0; varNr < P75_Nlines; varNr++) { addFormTextBox(concat(F("Line "), varNr + 1), getPluginCustomArgName(varNr), P075_data->displayLines[varNr], P75_Nchars - 1); } } diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 2b109bc816..fe8b24d3ae 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -388,7 +388,7 @@ void P094_html_show_matchForms(struct EventStruct *event) { if (newLine) { // Label + first parameter ++filterSet; - addRowLabel_tr_id(concat(F("Filter "), filterSet), id); + addRowLabel_tr_id(concat(F("Filter "), static_cast(filterSet)), id); } else { html_B(F("AND")); html_BR(); diff --git a/src/_P095_ILI9341.ino b/src/_P095_ILI9341.ino index fab3f8b726..e78a03aa58 100644 --- a/src/_P095_ILI9341.ino +++ b/src/_P095_ILI9341.ino @@ -385,13 +385,13 @@ boolean Plugin_095(uint8_t function, struct EventStruct *event, String& string) set4BitToUL(lSettings, P095_CONFIG_FLAG_TYPE, getFormItemInt(F("dsptype"))); // Bit 20..24 Hardwaretype P095_CONFIG_FLAGS = lSettings; - String color = web_server.arg(F("pfgcolor")); + String color = webArg(F("pfgcolor")); uint16_t fgcolor = ADAGFX_WHITE; // Default to white when empty if (!color.isEmpty()) { fgcolor = AdaGFXparseColor(color); // Reduce to rgb565 } - color = web_server.arg(F("pbgcolor")); + color = webArg(F("pbgcolor")); uint16_t bgcolor = AdaGFXparseColor(color); P095_CONFIG_COLORS = fgcolor | (bgcolor << 16); // Store as a single setting @@ -399,7 +399,7 @@ boolean Plugin_095(uint8_t function, struct EventStruct *event, String& string) String strings[P095_Nlines]; for (uint8_t varNr = 0; varNr < P095_Nlines; varNr++) { - strings[varNr] = web_server.arg(getPluginCustomArgName(varNr)); + strings[varNr] = webArg(getPluginCustomArgName(varNr)); } String error = SaveCustomTaskSettings(event->TaskIndex, strings, P095_Nlines, 0); diff --git a/src/_P096_eInk.ino b/src/_P096_eInk.ino index 97d9144870..c037b5f21f 100644 --- a/src/_P096_eInk.ino +++ b/src/_P096_eInk.ino @@ -463,13 +463,13 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) P096_CONFIG_FLAGS = lSettings; - String color = web_server.arg(F("p096_foregroundcolor")); + String color = webArg(F("p096_foregroundcolor")); uint16_t fgcolor = static_cast(AdaGFXMonoRedGreyscaleColors::ADAGFXEPD_BLACK); // Default to white when empty if (!color.isEmpty()) { fgcolor = AdaGFXparseColor(color, static_cast(P096_CONFIG_FLAG_GET_COLORDEPTH)); // Reduce to rgb565 } - color = web_server.arg(F("p096_backgroundcolor")); + color = webArg(F("p096_backgroundcolor")); uint16_t bgcolor = AdaGFXparseColor(color, static_cast(P096_CONFIG_FLAG_GET_COLORDEPTH)); P096_CONFIG_COLORS = fgcolor | (bgcolor << 16); // Store as a single setting @@ -478,7 +478,7 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) String error; for (uint8_t varNr = 0; varNr < P096_Nlines; varNr++) { - strings[varNr] = web_server.arg(getPluginCustomArgName(varNr)); + strings[varNr] = webArg(getPluginCustomArgName(varNr)); } error = SaveCustomTaskSettings(event->TaskIndex, strings, P096_Nlines, 0); diff --git a/src/_P109_ThermOLED.ino b/src/_P109_ThermOLED.ino index 849582e265..c1c6430109 100644 --- a/src/_P109_ThermOLED.ino +++ b/src/_P109_ThermOLED.ino @@ -249,7 +249,7 @@ boolean Plugin_109(byte function, struct EventStruct *event, String& string) for (byte varNr = 0; varNr < P109_Nlines; varNr++) { const String argName = getPluginCustomArgName(F("Plugin_109_template"), varNr); - strncpy(P109_deviceTemplate[varNr], web_server.arg(argName).c_str(), sizeof(P109_deviceTemplate[varNr]) - 1); + strncpy(P109_deviceTemplate[varNr], webArg(argName).c_str(), sizeof(P109_deviceTemplate[varNr]) - 1); P109_deviceTemplate[varNr][sizeof(P109_deviceTemplate[varNr]) - 1] = 0; } diff --git a/src/_P116_ST77xx.ino b/src/_P116_ST77xx.ino index e2af9db700..8173a5fc5c 100644 --- a/src/_P116_ST77xx.ino +++ b/src/_P116_ST77xx.ino @@ -242,13 +242,13 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) bitWrite(lSettings, P116_CONFIG_FLAG_BACK_FILL, !isFormItemChecked(F("p116_backfill"))); // Bit 28 Back fill text (inv) P116_CONFIG_FLAGS = lSettings; - String color = web_server.arg(F("p116_foregroundcolor")); + String color = webArg(F("p116_foregroundcolor")); uint16_t fgcolor = ADAGFX_WHITE; // Default to white when empty if (!color.isEmpty()) { fgcolor = AdaGFXparseColor(color); // Reduce to rgb565 } - color = web_server.arg(F("p116_backgroundcolor")); + color = webArg(F("p116_backgroundcolor")); uint16_t bgcolor = AdaGFXparseColor(color); P116_CONFIG_COLORS = fgcolor | (bgcolor << 16); // Store as a single setting @@ -257,7 +257,7 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) String error; for (uint8_t varNr = 0; varNr < P116_Nlines; varNr++) { - strings[varNr] = web_server.arg(getPluginCustomArgName(varNr)); + strings[varNr] = webArg(getPluginCustomArgName(varNr)); } error = SaveCustomTaskSettings(event->TaskIndex, strings, P116_Nlines, 0); diff --git a/src/_P118_Itho.ino b/src/_P118_Itho.ino index 1fd1d28599..afd66371b0 100644 --- a/src/_P118_Itho.ino +++ b/src/_P118_Itho.ino @@ -420,9 +420,9 @@ boolean Plugin_118(byte function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_SAVE: { - strcpy(PLUGIN_118_ExtraSettings.ID1, web_server.arg(F("PLUGIN_118_ID1")).c_str()); - strcpy(PLUGIN_118_ExtraSettings.ID2, web_server.arg(F("PLUGIN_118_ID2")).c_str()); - strcpy(PLUGIN_118_ExtraSettings.ID3, web_server.arg(F("PLUGIN_118_ID3")).c_str()); + strcpy(PLUGIN_118_ExtraSettings.ID1, webArg(F("PLUGIN_118_ID1")).c_str()); + strcpy(PLUGIN_118_ExtraSettings.ID2, webArg(F("PLUGIN_118_ID2")).c_str()); + strcpy(PLUGIN_118_ExtraSettings.ID3, webArg(F("PLUGIN_118_ID3")).c_str()); SaveCustomTaskSettings(event->TaskIndex, (byte *)&PLUGIN_118_ExtraSettings, sizeof(PLUGIN_118_ExtraSettings)); PCONFIG(0) = isFormItemChecked(F("p118_log")); diff --git a/src/_P131_NeoPixelMatrix.ino b/src/_P131_NeoPixelMatrix.ino index c944b5117e..e6f16307d2 100644 --- a/src/_P131_NeoPixelMatrix.ino +++ b/src/_P131_NeoPixelMatrix.ino @@ -268,7 +268,7 @@ boolean Plugin_131(uint8_t function, struct EventStruct *event, String& string) if ((P131_CONFIG_TILE_HEIGHT > 1) && (varNr == P131_CONFIG_TILE_HEIGHT - 1)) { html_TD(); - addUnit(concat(F("Remaining: "), remain)); + addUnit(concat(F("Remaining: "), static_cast(remain))); } } html_end_table(); @@ -313,13 +313,13 @@ boolean Plugin_131(uint8_t function, struct EventStruct *event, String& string) set8BitToUL(P131_CONFIG_FLAGS_B, P131_CONFIG_FLAG_B_BRIGHTNESS, getFormItemInt(F("brightness"))); set8BitToUL(P131_CONFIG_FLAGS_B, P131_CONFIG_FLAG_B_MAXBRIGHT, getFormItemInt(F("maxbright"))); - String color = web_server.arg(F("fgcolor")); + String color = webArg(F("fgcolor")); uint16_t fgcolor = ADAGFX_WHITE; // Default to white when empty if (!color.isEmpty()) { fgcolor = AdaGFXparseColor(color); // Reduce to rgb565 } - color = web_server.arg(F("bgcolor")); + color = webArg(F("bgcolor")); const uint16_t bgcolor = AdaGFXparseColor(color); P131_CONFIG_COLORS = fgcolor | (bgcolor << 16); // Store as a single setting @@ -330,7 +330,7 @@ boolean Plugin_131(uint8_t function, struct EventStruct *event, String& string) for (uint8_t varNr = 0; varNr < prevLines; varNr++) { error.clear(); - error += wrapWithQuotes(web_server.arg(getPluginCustomArgName(varNr))); + error += wrapWithQuotes(webArg(getPluginCustomArgName(varNr))); error += ','; uint32_t optBits = 0; bitWrite(optBits, P131_OPTBITS_SCROLL, isFormItemChecked(getPluginCustomArgName(varNr + 100))); diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 56ddb0b44d..d647a231a1 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -121,8 +121,8 @@ void pluginWebformShowValue(taskIndex_t taskIndex, } pluginWebformShowValue( - label, concat(F("valuename_"), taskIndex) + '_' + varNr, - value, concat(F("value_"), taskIndex) + '_' + varNr, + label, concat(F("valuename_"), static_cast(taskIndex)) + '_' + varNr, + value, concat(F("value_"), static_cast(taskIndex)) + '_' + varNr, addTrailingBreak); } diff --git a/src/src/Commands/Common.cpp b/src/src/Commands/Common.cpp index ca0bb1af60..20859dff63 100644 --- a/src/src/Commands/Common.cpp +++ b/src/src/Commands/Common.cpp @@ -26,6 +26,16 @@ const __FlashStringHelper * return_command_failed() return F("\nFailed"); } +String return_command_success_str() +{ + return return_command_success(); +} + +String return_command_failed_str() +{ + return return_command_failed(); +} + const __FlashStringHelper * return_incorrect_nr_arguments() { return F("Too many arguments, try using quotes!"); @@ -43,6 +53,7 @@ const __FlashStringHelper * return_not_connected() String return_result(struct EventStruct *event, const String& result) { + serialPrintln(); serialPrintln(result); if (event->Source == EventValueSource::Enum::VALUE_SOURCE_SERIAL) { @@ -81,7 +92,6 @@ String Command_GetORSetIP(struct EventStruct *event, } if (!hasArgument) { - serialPrintln(); String result = targetDescription; if (useStaticIP()) { @@ -114,7 +124,6 @@ String Command_GetORSetString(struct EventStruct *event, if (TmpStr1.length() > len) { String result = concat(targetDescription, F(" is too large. max size is ")); result += len; - serialPrintln(); return return_result(event, result); } safe_strncpy(target, TmpStr1, len); @@ -122,7 +131,6 @@ String Command_GetORSetString(struct EventStruct *event, } if (hasArgument) { - serialPrintln(); String result = targetDescription; result += target; return return_result(event, result); @@ -157,9 +165,7 @@ String Command_GetORSetBool(struct EventStruct *event, } if (hasArgument) { - String result = targetDescription; - result += boolToString(*value); - return return_result(event, result); + return return_result(event, concat(targetDescription, boolToString(*value))); } return return_command_success(); } diff --git a/src/src/Commands/Common.h b/src/src/Commands/Common.h index d3e979a84b..beb77d1d85 100644 --- a/src/src/Commands/Common.h +++ b/src/src/Commands/Common.h @@ -10,6 +10,8 @@ class IPAddress; const __FlashStringHelper * return_command_success(); const __FlashStringHelper * return_command_failed(); +String return_command_success_str(); +String return_command_failed_str(); const __FlashStringHelper * return_incorrect_nr_arguments(); const __FlashStringHelper * return_incorrect_source(); const __FlashStringHelper * return_not_connected(); diff --git a/src/src/Commands/Diagnostic.cpp b/src/src/Commands/Diagnostic.cpp index 627a3eecba..21cd83a0ca 100644 --- a/src/src/Commands/Diagnostic.cpp +++ b/src/src/Commands/Diagnostic.cpp @@ -174,9 +174,8 @@ const __FlashStringHelper * Command_JSONPortStatus(struct EventStruct *event, co void createLogPortStatus(std::map::iterator it) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("PortStatus detail: "); - - log += F("Port="); + String log; + log += F("PortStatus detail: Port="); log += getPortFromKey(it->first); log += F(" State="); log += it->second.state; @@ -207,7 +206,7 @@ void debugPortStatus(std::map::iterator it) const __FlashStringHelper * Command_logPortStatus(struct EventStruct *event, const char *Line) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("PortStatus structure: Called from=Rules Count="), globalMapPortStatus.size())); + addLogMove(LOG_LEVEL_INFO, concat(F("PortStatus structure: Called from=Rules Count="), static_cast(globalMapPortStatus.size()))); } for (std::map::iterator it = globalMapPortStatus.begin(); it != globalMapPortStatus.end(); ++it) { diff --git a/src/src/Commands/ESPEasy_Now_cmd.cpp b/src/src/Commands/ESPEasy_Now_cmd.cpp index 45719393fc..fe2410b2f3 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.cpp +++ b/src/src/Commands/ESPEasy_Now_cmd.cpp @@ -8,14 +8,14 @@ #include "../Commands/Common.h" #include "../Globals/ESPEasy_now_handler.h" -String Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line) +const __FlashStringHelper * Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line) { temp_disable_EspEasy_now_timer = millis() + (5*60*1000); ESPEasy_now_handler.end(); return return_command_success(); } -String Command_ESPEasy_Now_Enable(struct EventStruct *event, const char *Line) +const __FlashStringHelper * Command_ESPEasy_Now_Enable(struct EventStruct *event, const char *Line) { // Do not set to 0, but to some moment that will be considered passed when checked the next time. temp_disable_EspEasy_now_timer = millis(); diff --git a/src/src/Commands/ESPEasy_Now_cmd.h b/src/src/Commands/ESPEasy_Now_cmd.h index aa07dcc7c6..7e718c1200 100644 --- a/src/src/Commands/ESPEasy_Now_cmd.h +++ b/src/src/Commands/ESPEasy_Now_cmd.h @@ -6,12 +6,12 @@ #ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_state.h" +#include -class String; -String Command_ESPEasy_Now_Disable(struct EventStruct *event, +const __FlashStringHelper * Command_ESPEasy_Now_Disable(struct EventStruct *event, const char *Line); -String Command_ESPEasy_Now_Enable(struct EventStruct *event, +const __FlashStringHelper * Command_ESPEasy_Now_Enable(struct EventStruct *event, const char *Line); #endif // ifdef USES_ESPEASY_NOW diff --git a/src/src/Commands/GPIO.cpp b/src/src/Commands/GPIO.cpp index 2ab30af98a..7834dd66a5 100644 --- a/src/src/Commands/GPIO.cpp +++ b/src/src/Commands/GPIO.cpp @@ -60,9 +60,7 @@ const __FlashStringHelper * Command_GPIO_Monitor(struct EventStruct *event, cons if (gpio_monitor_helper(event->Par2, event, Line)) { return return_command_success(); } - else { - return return_command_failed(); - } + return return_command_failed(); } const __FlashStringHelper * Command_GPIO_MonitorRange(struct EventStruct *event, const char *Line) @@ -842,8 +840,8 @@ bool mcpgpio_range_pattern_helper(struct EventStruct *event, const char *Line, b createAndSetPortStatus_Mode_State(key, mode, state); String log; log += data.logPrefix; - log += concat(F(": port#"), currentPin); - log += concat(F(": set to "), state); + log += concat(F(": port#"), static_cast(currentPin)); + log += concat(F(": set to "), static_cast(state)); addLog(LOG_LEVEL_INFO, log); SendStatusOnlyIfNeeded(event, SEARCH_PIN_STATE, key, log, 0); } diff --git a/src/src/Commands/Networks.cpp b/src/src/Commands/Networks.cpp index 7d53c78de5..3308fd5e5a 100644 --- a/src/src/Commands/Networks.cpp +++ b/src/src/Commands/Networks.cpp @@ -6,6 +6,7 @@ #include "../ESPEasyCore/ESPEasyEth.h" #include "../Globals/NetworkState.h" #include "../Globals/Settings.h" +#include "../Helpers/StringConverter.h" #include "../WebServer/AccessControl.h" @@ -15,9 +16,7 @@ String Command_AccessInfo_Ls(struct EventStruct *event, const char* Line) { - String result = F("Allowed IP range : "); - result += describeAllowedIPrange(); - return return_result(event, result); + return return_result(event, concat(F("Allowed IP range : "), describeAllowedIPrange())); } String Command_AccessInfo_Clear (struct EventStruct *event, const char* Line) @@ -131,7 +130,7 @@ String Command_ETH_Disconnect (struct EventStruct *event, const char* Line) setNetworkMedium(NetworkMedium_t::Ethernet); ETHConnectRelaxed(); - return return_command_success(); + return return_command_success_str(); } #endif // if FEATURE_ETHERNET diff --git a/src/src/Commands/SDCARD.cpp b/src/src/Commands/SDCARD.cpp index 7478bfad70..1a95297afa 100644 --- a/src/src/Commands/SDCARD.cpp +++ b/src/src/Commands/SDCARD.cpp @@ -2,14 +2,14 @@ #include "../../ESPEasy_common.h" #include "../Commands/Common.h" -#include "../ESPEasyCore/Serial.h" -#include "../Globals/Settings.h" - - #if FEATURE_SD +#include "../ESPEasyCore/Serial.h" +#include "../Globals/Settings.h" +#include "../Helpers/StringConverter.h" + #include @@ -55,9 +55,7 @@ String Command_SD_Remove(struct EventStruct *event, const char* Line) // FIXME TD-er: This one is not using parseString* function String fname = Line; fname = fname.substring(9); - String result = F("Removing:"); - result += fname; SD.remove((char*)fname.c_str()); - return return_result(event, result); + return return_result(event, concat(F("Removing:"), fname)); } #endif diff --git a/src/src/Commands/Servo.cpp b/src/src/Commands/Servo.cpp index 8d5fd3b7e0..83518bfdfd 100644 --- a/src/src/Commands/Servo.cpp +++ b/src/src/Commands/Servo.cpp @@ -12,6 +12,7 @@ #include "../Globals/GlobalMapPortStatus.h" #include "../Helpers/Hardware.h" #include "../Helpers/PortStatus.h" +#include "../Helpers/StringConverter.h" // Needed also here for PlatformIO's library finder as the .h file // is in a directory which is excluded in the src_filter @@ -39,8 +40,7 @@ const __FlashStringHelper * Command_Servo(struct EventStruct *event, const char // So the next command should be part of each command: tempStatus = globalMapPortStatus[key]; - String log = F("Servo : GPIO "); - log += event->Par2; + String log = concat(F("Servo : GPIO "), event->Par2); // SPECIAL CASE TO ALLOW SERVO TO BE DETATTCHED AND SAVE POWER. if (event->Par3 >= 9000) { @@ -59,8 +59,7 @@ const __FlashStringHelper * Command_Servo(struct EventStruct *event, const char tempStatus.monitor = 0; tempStatus.command = 0; savePortStatus(key, tempStatus); - log += F(" Servo detached"); - addLog(LOG_LEVEL_INFO, log); + addLog(LOG_LEVEL_INFO, concat(log, F(" Servo detached"))); return return_command_success(); } diff --git a/src/src/Commands/Settings.cpp b/src/src/Commands/Settings.cpp index 17ef70b6d0..183c469bea 100644 --- a/src/src/Commands/Settings.cpp +++ b/src/src/Commands/Settings.cpp @@ -23,14 +23,11 @@ String Command_Settings_Build(struct EventStruct *event, const char* Line) { if (HasArgv(Line, 2)) { - Settings.Build = event->Par1; + Settings.Build = event->Par1; } else { - serialPrintln(); - String result = F("Build:"); - result += Settings.Build; - return return_result(event, result); + return return_result(event, concat(F("Build:"), static_cast(Settings.Build))); } - return return_command_success(); + return return_command_success_str(); } String Command_Settings_Unit(struct EventStruct *event, const char* Line) @@ -38,12 +35,9 @@ String Command_Settings_Unit(struct EventStruct *event, const char* Line) if (HasArgv(Line, 2)) { Settings.Unit = event->Par1; }else { - serialPrintln(); - String result = F("Unit:"); - result += Settings.Unit; - return return_result(event, result); + return return_result(event, concat(F("Unit:"), static_cast(Settings.Unit))); } - return return_command_success(); + return return_command_success_str(); } String Command_Settings_Name(struct EventStruct *event, const char* Line) @@ -65,7 +59,7 @@ String Command_Settings_Password(struct EventStruct *event, const char* Line) ); } -String Command_Settings_Password_Clear(struct EventStruct *event, const char* Line) +const __FlashStringHelper * Command_Settings_Password_Clear(struct EventStruct *event, const char* Line) { const String storedPassword = SecuritySettings.getPassword(); if (storedPassword.length() > 0) { diff --git a/src/src/Commands/Settings.h b/src/src/Commands/Settings.h index bf39baf2a4..d5bdd5ce63 100644 --- a/src/src/Commands/Settings.h +++ b/src/src/Commands/Settings.h @@ -7,7 +7,7 @@ String Command_Settings_Build(struct EventStruct *event, const char* Line); String Command_Settings_Unit(struct EventStruct *event, const char* Line); String Command_Settings_Name(struct EventStruct *event, const char* Line); String Command_Settings_Password(struct EventStruct *event, const char* Line); -String Command_Settings_Password_Clear(struct EventStruct *event, const char* Line); +const __FlashStringHelper * Command_Settings_Password_Clear(struct EventStruct *event, const char* Line); const __FlashStringHelper * Command_Settings_Save(struct EventStruct *event, const char* Line); const __FlashStringHelper * Command_Settings_Load(struct EventStruct *event, const char* Line); const __FlashStringHelper * Command_Settings_Print(struct EventStruct *event, const char* Line); diff --git a/src/src/Commands/Time.cpp b/src/src/Commands/Time.cpp index a30923c113..dd8a7311f9 100644 --- a/src/src/Commands/Time.cpp +++ b/src/src/Commands/Time.cpp @@ -31,12 +31,9 @@ String Command_useNTP(struct EventStruct *event, const char *Line) if (HasArgv(Line, 2)) { Settings.UseNTP(event->Par1); } else { - serialPrintln(); - String result = F("UseNTP:"); - result += boolToString(Settings.UseNTP()); - return return_result(event, result); + return return_result(event, concat(F("UseNTP:"), boolToString(Settings.UseNTP()))); } - return return_command_success(); + return return_command_success_str(); } String Command_TimeZone(struct EventStruct *event, const char *Line) @@ -44,12 +41,9 @@ String Command_TimeZone(struct EventStruct *event, const char *Line) if (HasArgv(Line, 2)) { Settings.TimeZone = event->Par1; } else { - serialPrintln(); - String result = F("TimeZone:"); - result += Settings.TimeZone; - return return_result(event, result); + return return_result(event, concat(F("TimeZone:"), static_cast(Settings.TimeZone))); } - return return_command_success(); + return return_command_success_str(); } String Command_DST(struct EventStruct *event, const char *Line) @@ -57,12 +51,9 @@ String Command_DST(struct EventStruct *event, const char *Line) if (HasArgv(Line, 2)) { Settings.DST = event->Par1; } else { - serialPrintln(); - String result = F("DST:"); - result += boolToString(Settings.DST); - return return_result(event, result); + return return_result(event, concat(F("DST:"), boolToString(Settings.DST))); } - return return_command_success(); + return return_command_success_str(); } String Command_DateTime(struct EventStruct *event, const char *Line) @@ -93,9 +84,7 @@ String Command_DateTime(struct EventStruct *event, const char *Line) node_time.setExternalTimeSource(makeTime(newtime), timeSource_t::Manual_set); } else { // serialPrintln(); - String result = F("Datetime:"); - result += node_time.getDateTimeString('-', ':', ' '); - return return_result(event, result); + return return_result(event, concat(F("Datetime:"), node_time.getDateTimeString('-', ':', ' '))); } - return return_command_success(); + return return_command_success_str(); } \ No newline at end of file diff --git a/src/src/Commands/WiFi.cpp b/src/src/Commands/WiFi.cpp index 07b83d15b3..365e5ae0ea 100644 --- a/src/src/Commands/WiFi.cpp +++ b/src/src/Commands/WiFi.cpp @@ -108,16 +108,12 @@ String Command_Wifi_Mode(struct EventStruct *event, const char *Line) if ((mode >= WIFI_OFF) && (mode < WIFI_MODE_MAX)) { setWifiMode(mode); } else { - serialPrintln(); return return_result(event, F("Wifi Mode: invalid arguments")); } } else { - serialPrintln(); - String result = F("WiFi Mode:"); - result += getWifiModeString(WiFi.getMode()); - return return_result(event, result); + return return_result(event, concat(F("WiFi Mode:"), getWifiModeString(WiFi.getMode()))); } - return return_command_success(); + return return_command_success_str(); } const __FlashStringHelper * Command_Wifi_AllowAP(struct EventStruct *event, const char* Line) diff --git a/src/src/Commands/wd.cpp b/src/src/Commands/wd.cpp index 165eb42867..39a508a0e7 100644 --- a/src/src/Commands/wd.cpp +++ b/src/src/Commands/wd.cpp @@ -29,14 +29,12 @@ String Command_WD_Read(EventStruct *event, const char* Line) if ( Wire.requestFrom(static_cast(event->Par1), static_cast(1)) == 1 ) { uint8_t value = Wire.read(); - serialPrintln(); - String result = F("I2C Read address "); - result += formatToHex(event->Par1); - result += F(" Value "); - result += formatToHex(value); - return return_result(event, result); + return return_result( + event, + concat(F("I2C Read address "), formatToHex(event->Par1)) + + concat(F(" Value "), formatToHex(value))); } - return return_command_success(); + return return_command_success_str(); } #endif \ No newline at end of file diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 3c9cf71d47..cd34997713 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2321,11 +2321,11 @@ To create/register a plugin, you have to : #endif #ifndef FEATURE_AUTO_DARK_MODE - // #ifdef LIMIT_BUILD_SIZE - // #define FEATURE_AUTO_DARK_MODE 0 - // #else + #ifdef LIMIT_BUILD_SIZE + #define FEATURE_AUTO_DARK_MODE 0 + #else #define FEATURE_AUTO_DARK_MODE 1 - // #endif + #endif #endif #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index 7ef05347b9..ea48845922 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -221,7 +221,7 @@ void Web_StreamingBuffer::startStream(bool allowOriginAll, if (beforeTXRam < 3000) { lowMemorySkip = true; - web_server.send(200, F("text/plain"), F("Low memory. Cannot display webpage :-(")); + web_server.send_P(200, (PGM_P)F("text/plain"), (PGM_P)F("Low memory. Cannot display webpage :-(")); #if defined(ESP8266) tcpCleanup(); #endif // if defined(ESP8266) @@ -370,12 +370,12 @@ void Web_StreamingBuffer::sendHeaderBlocking(bool allowOriginAll, #if defined(ESP8266) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) web_server.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_server.sendHeader(F("Accept-Ranges"), F("none")); - web_server.sendHeader(F("Cache-Control"), F("no-cache")); - web_server.sendHeader(F("Transfer-Encoding"), F("chunked")); + sendHeader(F("Accept-Ranges"), F("none")); + sendHeader(F("Cache-Control"), F("no-cache")); + sendHeader(F("Transfer-Encoding"), F("chunked")); if (allowOriginAll) { - web_server.sendHeader(F("Access-Control-Allow-Origin"), "*"); + sendHeader(F("Access-Control-Allow-Origin"), "*"); } web_server.send(httpCode, content_type, EMPTY_STRING); #else // if defined(ESP8266) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) diff --git a/src/src/ESPEasyCore/Serial.cpp b/src/src/ESPEasyCore/Serial.cpp index 1fe890cd91..78d2d81bc8 100644 --- a/src/src/ESPEasyCore/Serial.cpp +++ b/src/src/ESPEasyCore/Serial.cpp @@ -95,6 +95,11 @@ int getRoomLeft() { return roomLeft; } +void addToSerialBuffer(const __FlashStringHelper * line) +{ + addToSerialBuffer(String(line)); +} + void addToSerialBuffer(const String& line) { process_serialWriteBuffer(); // Try to make some room first. { @@ -111,6 +116,7 @@ void addToSerialBuffer(const String& line) { ++it; } } + process_serialWriteBuffer(); } void addNewlineToSerialBuffer() { @@ -149,25 +155,21 @@ void process_serialWriteBuffer() { // For now, only send it to the serial buffer and try to process it. // Later we may want to wrap it into a log. void serialPrint(const __FlashStringHelper * text) { - addToSerialBuffer(String(text)); - process_serialWriteBuffer(); + addToSerialBuffer(text); } void serialPrint(const String& text) { addToSerialBuffer(text); - process_serialWriteBuffer(); } void serialPrintln(const __FlashStringHelper * text) { - addToSerialBuffer(String(text)); - addNewlineToSerialBuffer(); - process_serialWriteBuffer(); + addToSerialBuffer(text); + serialPrintln(); } void serialPrintln(const String& text) { addToSerialBuffer(text); - addNewlineToSerialBuffer(); - process_serialWriteBuffer(); + serialPrintln(); } void serialPrintln() { diff --git a/src/src/ESPEasyCore/Serial.h b/src/src/ESPEasyCore/Serial.h index 7674c61e55..4c219b80fb 100644 --- a/src/src/ESPEasyCore/Serial.h +++ b/src/src/ESPEasyCore/Serial.h @@ -13,6 +13,7 @@ void initSerial(); void serial(); +void addToSerialBuffer(const __FlashStringHelper * line); void addToSerialBuffer(const String& line); void addNewlineToSerialBuffer(); diff --git a/src/src/Helpers/Dallas1WireHelper.cpp b/src/src/Helpers/Dallas1WireHelper.cpp index 531eb5677d..2ab6735154 100644 --- a/src/src/Helpers/Dallas1WireHelper.cpp +++ b/src/src/Helpers/Dallas1WireHelper.cpp @@ -233,7 +233,7 @@ void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex, int8_t gpio_pin_rx uint8_t addr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; for (uint8_t var_index = 0; var_index < nrVariables; ++var_index) { - const String id = concat(F("dallas_addr"), var_index); + const String id = concat(F("dallas_addr"), static_cast(var_index)); const int selection = getFormItemInt(id, -1); if (selection != -1) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4d0c087ca2..696a1928ef 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -284,7 +284,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() // We need to give it some time to receive announcement messages and maybe even a traceroute if (timePassedSince(_last_started) > ESPEASY_NOW_CHANNEL_SEARCH_TIMEOUT) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": No peers with distance set on channel "), _usedWiFiChannel)); + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": No peers with distance set on channel "), static_cast(_usedWiFiChannel))); } end(); @@ -292,7 +292,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() } else { if (channelChanged) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Move to channel "), ESPEasyNOW_channel)); + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Move to channel "), static_cast(ESPEasyNOW_channel))); } } @@ -513,7 +513,7 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(const WiFi_AP_Candidate& peer) String log = concat(F(ESPEASY_NOW_NAME ": Found node via WiFi scan: "), peer_mac.toString()); log += ' '; log += tmpNodeInfo.getRSSI(); - log += concat(F(" dBm ch: "), tmpNodeInfo.channel); + log += concat(F(" dBm ch: "), static_cast(tmpNodeInfo.channel)); addLog(LOG_LEVEL_INFO, log); } @@ -733,7 +733,7 @@ bool ESPEasy_now_handler_t::handle_DiscoveryAnnounce(const ESPEasy_now_merger& m if (received.distance == 255 && Nodes.getDistance() < 255) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Send announce back to unit: "), received.unit)); + addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Send announce back to unit: "), static_cast(received.unit))); } sendDiscoveryAnnounce(received.ESPEasy_Now_MAC(), received.channel); diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 222a1833ca..a3b5aa3b82 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -1295,10 +1295,9 @@ const __FlashStringHelper* getDeviceModelTypeString(DeviceModel model) } String getDeviceModelString(DeviceModel model) { - String result = getDeviceModelBrandString(model); - - result += getDeviceModelTypeString(model); - return result; + return concat( + getDeviceModelBrandString(model), + getDeviceModelTypeString(model)); } bool modelMatchingFlashSize(DeviceModel model) { diff --git a/src/src/PluginStructs/P002_data_struct.cpp b/src/src/PluginStructs/P002_data_struct.cpp index 0a04391677..27181caf32 100644 --- a/src/src/PluginStructs/P002_data_struct.cpp +++ b/src/src/PluginStructs/P002_data_struct.cpp @@ -700,7 +700,7 @@ String P002_data_struct::webformSave(struct EventStruct *event) // Store nr of lines that were saved, so no 'old' data will be read when nr of multi-point items has changed. lines[P002_SAVED_NR_LINES] = String(nr_lines); - if (web_server.hasArg(getPluginCustomArgName(P002_LINE_INDEX_FORMULA))) { + if (hasArg(getPluginCustomArgName(P002_LINE_INDEX_FORMULA))) { lines[P002_LINE_INDEX_FORMULA] = webArg(getPluginCustomArgName(P002_LINE_INDEX_FORMULA)); } diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index d461c26805..f3842b7d8d 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -502,19 +502,19 @@ bool P037_data_struct::webform_save( String argName = F("template"); argName += (varNr + 1); - mqttTopics[varNr] = web_server.arg(argName); + mqttTopics[varNr] = webArg(argName); # ifdef P037_JSON_SUPPORT if (jsonEnabled) { argName = F("attribute"); argName += (varNr + 1); - jsonAttributes[varNr] = web_server.arg(argName); + jsonAttributes[varNr] = webArg(argName); } # endif // P037_JSON_SUPPORT } - globalTopicPrefix = web_server.arg(F("topicprefix")); + globalTopicPrefix = webArg(F("topicprefix")); # if P037_MAPPING_SUPPORT || P037_FILTER_SUPPORT String left, right; @@ -532,10 +532,10 @@ bool P037_data_struct::webform_save( for (uint8_t mappingOffset = P037_START_MAPPINGS; mappingOffset <= P037_END_MAPPINGS; mappingOffset++) { left.clear(); - left += web_server.arg(getPluginCustomArgName(idx + 0)); + left += webArg(getPluginCustomArgName(idx + 0)); left.trim(); right.clear(); - right += web_server.arg(getPluginCustomArgName(idx + 2)); + right += webArg(getPluginCustomArgName(idx + 2)); right.trim(); if (!left.isEmpty() || !right.isEmpty()) { @@ -575,9 +575,9 @@ bool P037_data_struct::webform_save( idx = 0; for (uint8_t filterOffset = P037_START_FILTERS; filterOffset <= P037_END_FILTERS; filterOffset++) { - left = web_server.arg(getPluginCustomArgName(idx + 100 + 0)); + left = webArg(getPluginCustomArgName(idx + 100 + 0)); left.trim(); - right = web_server.arg(getPluginCustomArgName(idx + 100 + 2)); + right = webArg(getPluginCustomArgName(idx + 100 + 2)); right.trim(); if (!left.isEmpty() || !right.isEmpty() diff --git a/src/src/PluginStructs/P044_data_struct.cpp b/src/src/PluginStructs/P044_data_struct.cpp index 59de51d23b..76886aa2fb 100644 --- a/src/src/PluginStructs/P044_data_struct.cpp +++ b/src/src/PluginStructs/P044_data_struct.cpp @@ -43,9 +43,9 @@ void P044_Task::startServer(uint16_t portnumber) { P1GatewayServer->begin(); if (serverActive(P1GatewayServer)) { - addLog(LOG_LEVEL_INFO, concat(F("P1 : WiFi server started at port "), portnumber)); + addLog(LOG_LEVEL_INFO, concat(F("P1 : WiFi server started at port "), static_cast(portnumber))); } else { - addLog(LOG_LEVEL_ERROR, concat(F("P1 : WiFi server start failed at port "), portnumber) + F(", retrying...")); + addLog(LOG_LEVEL_ERROR, concat(F("P1 : WiFi server start failed at port "), static_cast(portnumber)) + F(", retrying...")); } } } diff --git a/src/src/PluginStructs/P134_data_struct.cpp b/src/src/PluginStructs/P134_data_struct.cpp index d7d732d46c..fd0e7abe2f 100644 --- a/src/src/PluginStructs/P134_data_struct.cpp +++ b/src/src/PluginStructs/P134_data_struct.cpp @@ -97,13 +97,13 @@ bool P134_data_struct::plugin_read(struct EventStruct *event) { UserVar[event->BaseVarIndex] = static_cast(measuredDistance); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLogMove(LOG_LEVEL_INFO, concat(F("A02YYUW: Distance value = "), measuredDistance)); + addLogMove(LOG_LEVEL_INFO, concat(F("A02YYUW: Distance value = "), static_cast(measuredDistance))); } success = true; } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; - log += concat(F("A02YYUW: Error status = "), static_cast(measurementStatus)); + log += concat(F("A02YYUW: Error status = "), static_cast(measurementStatus)); # ifndef LIMIT_BUILD_SIZE log += concat(F(", "), toString(measurementStatus)); # endif // ifndef LIMIT_BUILD_SIZE diff --git a/src/src/WebServer/404.cpp b/src/src/WebServer/404.cpp index bd19b96725..dd32b7985f 100644 --- a/src/src/WebServer/404.cpp +++ b/src/src/WebServer/404.cpp @@ -25,7 +25,7 @@ void handleNotFound() { // if Wifi setup, launch setup wizard if AP_DONT_FORCE_SETUP is not set. if (WiFiEventData.wifiSetup && !Settings.ApDontForceSetup()) { - web_server.send(200, F("text/html"), F("")); + web_server.send_P(200, (PGM_P)F("text/html"), (PGM_P)F("")); return; } @@ -45,6 +45,7 @@ void handleNotFound() { addHtml(F("\nArguments: ")); addHtmlInt(web_server.args()); +#ifndef BUILD_NO_DEBUG for (uint8_t i = 0; i < web_server.args(); i++) { addHtml('\n'); addHtml(F(" NAME:")); @@ -52,7 +53,6 @@ void handleNotFound() { addHtml(F("\n VALUE:")); addHtml(webArg(i)); } -#ifndef BUILD_NO_DEBUG addHtml(F("\nHeaders: ")); for (int i = web_server.headers(); i >= 0; --i) { if (!web_server.headerName(i).isEmpty()) { diff --git a/src/src/WebServer/ConfigPage.cpp b/src/src/WebServer/ConfigPage.cpp index c864a66b3d..0fe61e2d50 100644 --- a/src/src/WebServer/ConfigPage.cpp +++ b/src/src/WebServer/ConfigPage.cpp @@ -119,7 +119,7 @@ void handle_config() { for (int peer = 0; peer < ESPEASY_NOW_PEER_MAX; ++peer) { String id = F("peer"); id += String(peer); - String peer_mac = web_server.arg(id); + String peer_mac = webArg(id); if (peer_mac.length() == 0) { peer_mac = F("00:00:00:00:00:00"); } diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 66d8b84bc3..4b5e0d3ad8 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -52,7 +52,7 @@ void handle_devices() { pluginID_t taskdevicenumber; - if (web_server.hasArg(F("del"))) { + if (hasArg(F("del"))) { taskdevicenumber = 0; } else { @@ -186,7 +186,7 @@ void handle_devices() { # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) { - addLogMove(LOG_LEVEL_DEBUG_DEV, concat(F("DEBUG: String size:"), TXBuffer.sentBytes)); + addLogMove(LOG_LEVEL_DEBUG_DEV, concat(F("DEBUG: String size:"), static_cast(TXBuffer.sentBytes))); } # endif // ifndef BUILD_NO_DEBUG sendHeadandTail_stdtemplate(_TAIL); @@ -266,7 +266,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task if (multipleMuxPortsOption == 1) { uint8_t selectedPorts = 0; - for (uint8_t x = 0; x < I2CMultiplexerMaxChannels(); x++) { + for (int x = 0; x < I2CMultiplexerMaxChannels(); ++x) { bitWrite(selectedPorts, x, isFormItemChecked(concat(F("taskdeviceflag1ch"), x))); } Settings.I2C_Multiplexer_Channel[taskIndex] = selectedPorts; @@ -490,11 +490,11 @@ void handle_devicess_ShowAllTasksTable(uint8_t page) html_add_button_prefix(); } { - addHtml(concat(F("devices?index="), x + 1)); - addHtml(concat(F("&page="), page)); + addHtml(concat(F("devices?index="), static_cast(x + 1))); + addHtml(concat(F("&page="), static_cast(page))); addHtml('\'', '>'); addHtml(pluginID_set ? F("Edit") : F("Add")); - addHtml(concat(F(""), x + 1)); + addHtml(concat(F(""), static_cast(x + 1))); html_TD(); } @@ -582,7 +582,7 @@ void handle_devicess_ShowAllTasksTable(uint8_t page) if (validProtocolIndex(ProtocolIndex)) { if (Protocol[ProtocolIndex].usesID && (Settings.Protocol[controllerNr] != 0)) { - addHtml(concat(F(" ("), Settings.TaskDeviceID[controllerNr][x])); + addHtml(concat(F(" ("), static_cast(Settings.TaskDeviceID[controllerNr][x]))); addHtml(')'); if (Settings.TaskDeviceID[controllerNr][x] == 0) { @@ -783,7 +783,7 @@ void format_I2C_port_description(taskIndex_t x) } } } else { // Single channel - mux = concat(F("
Multiplexer channel "), Settings.I2C_Multiplexer_Channel[x]); + mux = concat(F("
Multiplexer channel "), static_cast(Settings.I2C_Multiplexer_Channel[x])); } addHtml(mux); } @@ -869,7 +869,7 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, uint8_t page) // show selected device name and delete button addHtml(getPluginNameFromDeviceIndex(DeviceIndex)); - addHelpButton(concat(F("Plugin"), Settings.TaskDeviceNumber[taskIndex])); + addHelpButton(concat(F("Plugin"), static_cast(Settings.TaskDeviceNumber[taskIndex]))); addRTDPluginButton(Settings.TaskDeviceNumber[taskIndex]); addFormTextBox(F("Name"), F("TDN"), getTaskDeviceName(taskIndex), NAME_FORMULA_LENGTH_MAX); // ="taskdevicename" @@ -1136,7 +1136,7 @@ void devicePage_show_I2C_config(taskIndex_t taskIndex) html_table_header(F("Channel")); html_table_header(F("Enable")); - for (uint8_t x = 0; x < I2CMultiplexerMaxChannels(); x++) { + for (int x = 0; x < I2CMultiplexerMaxChannels(); x++) { if (x % 2 == 0) { html_TR(); } // Start a new row for every 2 channels html_TD(); addHtml(concat(F("Channel "), x)); @@ -1153,7 +1153,7 @@ void devicePage_show_I2C_config(taskIndex_t taskIndex) i2c_mux_portchoices[mux_opt] = -1; uint8_t mux_max = I2CMultiplexerMaxChannels(); - for (int8_t x = 0; x < mux_max; x++) { + for (int x = 0; x < mux_max; x++) { mux_opt++; i2c_mux_portoptions[mux_opt] = concat(F("Channel "), x); i2c_mux_portchoices[mux_opt] = x; diff --git a/src/src/WebServer/DownloadPage.cpp b/src/src/WebServer/DownloadPage.cpp index 384ffdd65f..fe7c0cecb5 100644 --- a/src/src/WebServer/DownloadPage.cpp +++ b/src/src/WebServer/DownloadPage.cpp @@ -45,7 +45,7 @@ void handle_download() } str += F(".dat"); - web_server.sendHeader(F("Content-Disposition"), str); + sendHeader(F("Content-Disposition"), str); web_server.streamFile(dataFile, F("application/octet-stream")); dataFile.close(); } diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index dc65f6dff9..595a73494b 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -72,7 +72,7 @@ void safe_strncpy_webserver_arg(char *dest, const String& arg, size_t max_size) { - if (web_server.hasArg(arg)) { + if (hasArg(arg)) { safe_strncpy(dest, webArg(arg).c_str(), max_size); } } @@ -173,7 +173,7 @@ bool captivePortal() { redirectURL += F("/setup"); } #endif - web_server.sendHeader(F("Location"), redirectURL, true); + sendHeader(F("Location"), redirectURL, true); web_server.send(302, F("text/plain"), EMPTY_STRING); // Empty content inhibits Content-length header so we have to close the socket ourselves. web_server.client().stop(); // Stop is needed because we sent no content length return true; @@ -1086,37 +1086,3 @@ void getPartitionTableSVG(uint8_t pType, unsigned int partitionColor) { bool webArg2ip(const __FlashStringHelper * arg, uint8_t *IP) { return str2ip(webArg(arg), IP); } - -#ifdef ESP8266 -const String& webArg(const __FlashStringHelper * arg) -{ - return web_server.arg(String(arg)); -} - -const String& webArg(const String& arg) -{ - return web_server.arg(arg); -} - -const String& webArg(int i) -{ - return web_server.arg(i); -} -#endif - -#ifdef ESP32 -String webArg(const __FlashStringHelper * arg) -{ - return web_server.arg(String(arg)); -} - -String webArg(const String& arg) -{ - return web_server.arg(arg); -} - -String webArg(int i) -{ - return web_server.arg(i); -} -#endif \ No newline at end of file diff --git a/src/src/WebServer/ESPEasy_WebServer.h b/src/src/WebServer/ESPEasy_WebServer.h index 45104660b3..a12747537a 100644 --- a/src/src/WebServer/ESPEasy_WebServer.h +++ b/src/src/WebServer/ESPEasy_WebServer.h @@ -195,20 +195,4 @@ bool webArg2ip(const __FlashStringHelper * arg, uint8_t *IP); -// Separate wrapper to get web_server.arg() -// 1) To allow to have a __FlashStringHelper call -> reduce build size -// 2) ESP32 does not return a const String &, but a temporary copy, thus we _must_ copy before using it. - -#ifdef ESP8266 -const String& webArg(const __FlashStringHelper * arg); -const String& webArg(const String& arg); -const String& webArg(int i); -#endif - -#ifdef ESP32 -String webArg(const __FlashStringHelper * arg); -String webArg(const String& arg); -String webArg(int i); -#endif - #endif // ifndef WEBSERVER_ESPEASY_WEBSERVER_H \ No newline at end of file diff --git a/src/src/WebServer/FactoryResetPage.cpp b/src/src/WebServer/FactoryResetPage.cpp index 6709e9aadb..970aa4ce9a 100644 --- a/src/src/WebServer/FactoryResetPage.cpp +++ b/src/src/WebServer/FactoryResetPage.cpp @@ -36,7 +36,7 @@ void handle_factoryreset() { addFormHeader(F("Factory Reset")); #ifndef LIMIT_BUILD_SIZE - if (web_server.hasArg(F("fdm"))) { + if (hasArg(F("fdm"))) { DeviceModel model = static_cast(getFormItemInt(F("fdm"))); if (modelMatchingFlashSize(model)) { @@ -45,7 +45,7 @@ void handle_factoryreset() { } - if (web_server.hasArg(F("savepref"))) { + if (hasArg(F("savepref"))) { // User choose a pre-defined config and wants to save it as the new default. ResetFactoryDefaultPreference.keepUnitName(isFormItemChecked(F("kun"))); ResetFactoryDefaultPreference.keepWiFi(isFormItemChecked(F("kw"))); @@ -57,7 +57,7 @@ void handle_factoryreset() { } #endif - if (web_server.hasArg(F("performfactoryreset"))) { + if (hasArg(F("performfactoryreset"))) { // User confirmed to really perform the reset. applyFactoryDefaultPref(); @@ -132,7 +132,7 @@ void handle_factoryreset_json() { TXBuffer.startJsonStream(); addHtml('{'); #ifndef LIMIT_BUILD_SIZE - if (web_server.hasArg(F("fdm"))) { + if (hasArg(F("fdm"))) { DeviceModel model = static_cast(getFormItemInt(F("fdm"))); if (modelMatchingFlashSize(model)) { @@ -140,23 +140,23 @@ void handle_factoryreset_json() { } } - if (web_server.hasArg(F("kun"))) { + if (hasArg(F("kun"))) { ResetFactoryDefaultPreference.keepUnitName(isFormItemChecked(F("kun"))); } - if (web_server.hasArg(F("kw"))) { + if (hasArg(F("kw"))) { ResetFactoryDefaultPreference.keepWiFi(isFormItemChecked(F("kw"))); } - if (web_server.hasArg(F("knet"))) { + if (hasArg(F("knet"))) { ResetFactoryDefaultPreference.keepNetwork(isFormItemChecked(F("knet"))); } - if (web_server.hasArg(F("kntp"))) { + if (hasArg(F("kntp"))) { ResetFactoryDefaultPreference.keepNTP(isFormItemChecked(F("kntp"))); } - if (web_server.hasArg(F("klog"))) { + if (hasArg(F("klog"))) { ResetFactoryDefaultPreference.keepLogSettings(isFormItemChecked(F("klog"))); } #endif @@ -164,12 +164,12 @@ void handle_factoryreset_json() { bool performReset = false; bool savePref = false; - if (web_server.hasArg(F("savepref"))) { + if (hasArg(F("savepref"))) { // User choose a pre-defined config and wants to save it as the new default. savePref = true; } - if (web_server.hasArg(F("performfactoryreset"))) { + if (hasArg(F("performfactoryreset"))) { // User confirmed to really perform the reset. performReset = true; savePref = true; diff --git a/src/src/WebServer/FileList.cpp b/src/src/WebServer/FileList.cpp index c09b415085..6274bcae3a 100644 --- a/src/src/WebServer/FileList.cpp +++ b/src/src/WebServer/FileList.cpp @@ -155,7 +155,7 @@ void handle_filelist() { } # ifdef USES_C016 - if (web_server.hasArg(F("delcache"))) { + if (hasArg(F("delcache"))) { while (C016_deleteOldestCacheBlock()) { delay(1); } diff --git a/src/src/WebServer/LoadFromFS.cpp b/src/src/WebServer/LoadFromFS.cpp index cb5e5a1360..7780fdfd3d 100644 --- a/src/src/WebServer/LoadFromFS.cpp +++ b/src/src/WebServer/LoadFromFS.cpp @@ -136,7 +136,7 @@ bool reply_304_not_modified(const String& path) { #ifndef BUILD_NO_DEBUG if (res) { - addLog(LOG_LEVEL_INFO, concat(F("Serve 304: "), etag_num) + ' ' + path); + addLog(LOG_LEVEL_INFO, concat(F("Serve 304: "), String(etag_num)) + ' ' + path); } #endif // ifndef BUILD_NO_DEBUG @@ -229,24 +229,24 @@ bool loadFromFS(String path) { // prevent reloading stuff on every click if (static_file) { - web_server.sendHeader(F("Cache-Control"), F("public, max-age=31536000, immutable")); + sendHeader(F("Cache-Control"), F("public, max-age=31536000, immutable")); - // web_server.sendHeader(F("Cache-Control"), F("max-age=86400")); - web_server.sendHeader(F("Expires"), F("-1")); + // sendHeader(F("Cache-Control"), F("max-age=86400")); + sendHeader(F("Expires"), F("-1")); if (fileEmbedded && !fileExists(path)) { - web_server.sendHeader(F("Last-Modified"), get_build_date_RFC1123()); + sendHeader(F("Last-Modified"), get_build_date_RFC1123()); } - web_server.sendHeader(F("Age"), F("100")); - web_server.sendHeader(F("ETag"), wrap_String(String(Cache.fileCacheClearMoment) + F("-a"), '"')); // added "-a" to the ETag to + sendHeader(F("Age"), F("100")); + sendHeader(F("ETag"), wrap_String(String(Cache.fileCacheClearMoment) + F("-a"), '"')); // added "-a" to the ETag to // match the same encoding } else { - web_server.sendHeader(F("Cache-Control"), F("no-cache")); - web_server.sendHeader(F("ETag"), F("\"2.0.0\"")); + sendHeader(F("Cache-Control"), F("no-cache")); + sendHeader(F("ETag"), F("\"2.0.0\"")); } - web_server.sendHeader(F("Vary"), "*"); + sendHeader(F("Vary"), "*"); if (path.endsWith(F(".dat"))) { - web_server.sendHeader(F("Content-Disposition"), F("attachment;")); + sendHeader(F("Content-Disposition"), F("attachment;")); } if (serve_304) { diff --git a/src/src/WebServer/NotificationPage.cpp b/src/src/WebServer/NotificationPage.cpp index 3398cb5813..555393b81d 100644 --- a/src/src/WebServer/NotificationPage.cpp +++ b/src/src/WebServer/NotificationPage.cpp @@ -84,7 +84,7 @@ void handle_notifications() { addHtmlError(SaveNotificationSettings(notificationindex, reinterpret_cast(&NotificationSettings), sizeof(NotificationSettingsStruct))); addHtmlError(SaveSettings()); - if (web_server.hasArg(F("test"))) { + if (hasArg(F("test"))) { // Perform tests with the settings in the form. nprotocolIndex_t NotificationProtocolIndex = getNProtocolIndex_from_NotifierIndex(notificationindex); diff --git a/src/src/WebServer/RootPage.cpp b/src/src/WebServer/RootPage.cpp index 476ce7c51c..acd9c4d3c3 100644 --- a/src/src/WebServer/RootPage.cpp +++ b/src/src/WebServer/RootPage.cpp @@ -70,7 +70,7 @@ void handle_root() { // if Wifi setup, launch setup wizard if AP_DONT_FORCE_SETUP is not set. if (WiFiEventData.wifiSetup && !Settings.ApDontForceSetup()) { - web_server.send(200, F("text/html"), F("")); + web_server.send_P(200, (PGM_P)F("text/html"), (PGM_P)F("")); return; } diff --git a/src/src/WebServer/Rules.cpp b/src/src/WebServer/Rules.cpp index 9b29240b53..1e8370200f 100644 --- a/src/src/WebServer/Rules.cpp +++ b/src/src/WebServer/Rules.cpp @@ -359,7 +359,7 @@ void handle_rules_delete() { if (removed) { - web_server.sendHeader(F("Location"), F("/rules"), true); + sendHeader(F("Location"), F("/rules"), true); web_server.send(302, F("text/plain"), EMPTY_STRING); } else @@ -449,7 +449,7 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { isAddNew = true; isOverwrite = true; } - else if (!web_server.hasArg(F("rules"))) + else if (!hasArg(F("rules"))) { error = F("Data was not saved, rules argument missing or corrupted"); addLog(LOG_LEVEL_ERROR, error); @@ -476,7 +476,7 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { } if (isAddNew) { - web_server.sendHeader(F("Location"), F("/rules"), true); + sendHeader(F("Location"), F("/rules"), true); web_server.send(302, F("text/plain"), EMPTY_STRING); return true; } @@ -584,10 +584,10 @@ bool Rule_Download(const String& path) String filename = path + String(F(".txt")); filename.replace(RULE_FILE_SEPARAROR, '_'); String str = String(F("attachment; filename=")) + filename; - web_server.sendHeader(F("Content-Disposition"), str); - web_server.sendHeader(F("Cache-Control"), F("max-age=3600, public")); - web_server.sendHeader(F("Vary"), "*"); - web_server.sendHeader(F("ETag"), F("\"2.0.0\"")); + sendHeader(F("Content-Disposition"), str); + sendHeader(F("Cache-Control"), F("max-age=3600, public")); + sendHeader(F("Vary"), "*"); + sendHeader(F("ETag"), F("\"2.0.0\"")); web_server.streamFile(dataFile, F("application/octet-stream")); dataFile.close(); @@ -595,7 +595,7 @@ bool Rule_Download(const String& path) } void Goto_Rules_Root() { - web_server.sendHeader(F("Location"), F("/rules"), true); + sendHeader(F("Location"), F("/rules"), true); web_server.send(302, F("text/plain"), EMPTY_STRING); } diff --git a/src/src/WebServer/SettingsArchive.cpp b/src/src/WebServer/SettingsArchive.cpp index d1c08cf50e..4bffc07350 100644 --- a/src/src/WebServer/SettingsArchive.cpp +++ b/src/src/WebServer/SettingsArchive.cpp @@ -34,7 +34,7 @@ void handle_settingsarchive() { html_TR(); addFormHeader(F("Settings Archive")); - if (web_server.hasArg(F("savepref")) || web_server.hasArg(F("download"))) { + if (hasArg(F("savepref")) || hasArg(F("download"))) { // User choose a pre-defined config and wants to save it as the new default. for (int i = 0; i < FileType::MAX_FILETYPE; ++i) { const FileType::Enum ft = static_cast(i); @@ -62,11 +62,11 @@ void handle_settingsarchive() { if (AllocatedProvisioningSettings()) { ProvisioningSettings.ResetFactoryDefaultPreference = ResetFactoryDefaultPreference.getPreference(); if (ResetFactoryDefaultPreference.saveURL()) { - ProvisioningSettings.setUrl(web_server.arg(F("url"))); + ProvisioningSettings.setUrl(webArg(F("url"))); } if (ResetFactoryDefaultPreference.storeCredentials()) { - ProvisioningSettings.setUser(web_server.arg(F("user"))); - ProvisioningSettings.setPass(web_server.arg(F("pass"))); + ProvisioningSettings.setUser(webArg(F("user"))); + ProvisioningSettings.setPass(webArg(F("pass"))); } } error = saveProvisioningSettings(ProvisioningSettings); @@ -79,7 +79,7 @@ void handle_settingsarchive() { bool showOptions = true; - if (web_server.hasArg(F("download"))) { + if (hasArg(F("download"))) { // Try downloading files. // Don't use the ProvisioningSettings, as not all may be stored. const String url = webArg(F("url")); @@ -115,7 +115,7 @@ void handle_settingsarchive() { addSubmitButton(F("Reboot"), F("reboot"), F("red")); addFormNote(F("If settings files are updated you MUST reboot first!")); } - } else if (web_server.hasArg(F("reboot"))) { + } else if (hasArg(F("reboot"))) { showOptions = false; reboot(ESPEasy_Scheduler::IntendedRebootReason_e::RestoreSettings); } @@ -140,14 +140,14 @@ void handle_settingsarchive() { } #endif - if (web_server.arg(F("url")).length() != 0) { - url = web_server.arg(F("url")); + if (webArg(F("url")).length() != 0) { + url = webArg(F("url")); } - if (web_server.arg(F("user")).length() != 0) { - user = web_server.arg(F("user")); + if (webArg(F("user")).length() != 0) { + user = webArg(F("user")); } - if (web_server.arg(F("pass")).length() != 0) { - pass = web_server.arg(F("pass")); + if (webArg(F("pass")).length() != 0) { + pass = webArg(F("pass")); } } diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index 720fe65eee..8061872d09 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -59,7 +59,7 @@ void handle_setup() { sendHeadandTail(F("TmplAP")); } - const bool clearButtonPressed = web_server.hasArg(F("performclearcredentials")); + const bool clearButtonPressed = hasArg(F("performclearcredentials")); const bool clearWiFiCredentials = isFormItemChecked(F("clearcredentials")) && clearButtonPressed; @@ -87,7 +87,7 @@ void handle_setup() { passwordGiven = !password.isEmpty(); } const bool emptyPassAllowed = isFormItemChecked(F("emptypass")); - const bool performRescan = web_server.hasArg(F("performrescan")); + const bool performRescan = hasArg(F("performrescan")); if (performRescan) { WiFiEventData.lastScanMoment.clear(); WifiScan(false); diff --git a/src/src/WebServer/common.cpp b/src/src/WebServer/common.cpp new file mode 100644 index 0000000000..03276b10cd --- /dev/null +++ b/src/src/WebServer/common.cpp @@ -0,0 +1,61 @@ +#include "../WebServer/common.h" + +void sendHeader(const String& name, const String& value, bool first) +{ + web_server.sendHeader(name, value, first); +} + +void sendHeader(const __FlashStringHelper * name, const String& value, bool first) +{ + web_server.sendHeader(name, value, first); +} + +void sendHeader(const __FlashStringHelper * name, const __FlashStringHelper * value, bool first) +{ + web_server.sendHeader(name, value, first); +} + + +#ifdef ESP8266 +const String& webArg(const __FlashStringHelper * arg) +{ + return web_server.arg(String(arg)); +} + +const String& webArg(const String& arg) +{ + return web_server.arg(arg); +} + +const String& webArg(int i) +{ + return web_server.arg(i); +} +#endif + +#ifdef ESP32 +String webArg(const __FlashStringHelper * arg) +{ + return web_server.arg(String(arg)); +} + +String webArg(const String& arg) +{ + return web_server.arg(arg); +} + +String webArg(int i) +{ + return web_server.arg(i); +} +#endif + +bool hasArg(const __FlashStringHelper * arg) +{ + return web_server.hasArg(arg); +} + +bool hasArg(const String& arg) +{ + return web_server.hasArg(arg); +} diff --git a/src/src/WebServer/common.h b/src/src/WebServer/common.h index d12569cab3..7de1c3aa7c 100644 --- a/src/src/WebServer/common.h +++ b/src/src/WebServer/common.h @@ -21,4 +21,27 @@ #include "../Globals/TXBuffer.h" #include "../Helpers/StringProvider.h" +void sendHeader(const String& name, const String& value, bool first = false); +void sendHeader(const __FlashStringHelper * name, const String& value, bool first = false); +void sendHeader(const __FlashStringHelper * name, const __FlashStringHelper * value, bool first = false); + +// Separate wrapper to get web_server.arg() +// 1) To allow to have a __FlashStringHelper call -> reduce build size +// 2) ESP32 does not return a const String &, but a temporary copy, thus we _must_ copy before using it. + +#ifdef ESP8266 +const String& webArg(const __FlashStringHelper * arg); +const String& webArg(const String& arg); +const String& webArg(int i); +#endif + +#ifdef ESP32 +String webArg(const __FlashStringHelper * arg); +String webArg(const String& arg); +String webArg(int i); +#endif + +bool hasArg(const __FlashStringHelper * arg); +bool hasArg(const String& arg); + #endif \ No newline at end of file From b3f61ed0a1a8cf4d81783997e01517c68df8b0c5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 2 Oct 2022 17:11:22 +0200 Subject: [PATCH 311/404] [WiFi] Change Espressif SDK to SDK221 This actually does advertise the correct WiFi modes for 802.11n --- platformio_core_defs.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 5268a1d79c..93de4a78cc 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -135,7 +135,7 @@ platform = espressif8266@2.6.3 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.4 build_flags = ${esp82xx_2_6_x.build_flags} - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK221 -Wno-deprecated-declarations lib_ignore = ${esp82xx_defaults.lib_ignore} IRremoteESP8266 From c1780f47dbd6c1a5f2e4325d93cddf09b8a160ab Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 Oct 2022 11:42:04 +0200 Subject: [PATCH 312/404] [WiFi] Prevent reconnect loop --- src/src/CustomBuild/define_plugin_sets.h | 14 +++++++ src/src/DataStructs/WiFiEventData.cpp | 4 +- src/src/DataStructs/WiFi_AP_Candidate.cpp | 41 ++++++++++++++++-- src/src/DataStructs/WiFi_AP_Candidate.h | 25 +++++++---- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 14 ++++++- src/src/ESPEasyCore/ESPEasyWiFiEvent.h | 2 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 42 ++++++++++++------- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 26 ++++++++---- src/src/ESPEasyCore/ESPEasy_setup.cpp | 2 +- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 9 ++++ src/src/Helpers/WiFi_AP_CandidatesList.h | 5 +++ 11 files changed, 143 insertions(+), 41 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index cd34997713..92c9b7195e 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2328,4 +2328,18 @@ To create/register a plugin, you have to : #endif #endif +#ifndef FEATURE_ESP8266_DIRECT_WIFI_SCAN + // Feature still in development, do not yet use. + #define FEATURE_ESP8266_DIRECT_WIFI_SCAN 0 +#endif + +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN + #ifdef ESP32 + // ESP8266 only feature + #undef FEATURE_ESP8266_DIRECT_WIFI_SCAN + #define FEATURE_ESP8266_DIRECT_WIFI_SCAN 0 + #endif +#endif + + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index fa61e17f44..29f4110e4a 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -62,7 +62,7 @@ bool WiFiEventData_t::unprocessedWifiEvents() { void WiFiEventData_t::clearAll() { markWiFiTurnOn(); lastGetScanMoment.clear(); - last_wifi_connect_attempt_moment.clear(); +// last_wifi_connect_attempt_moment.clear(); timerAPstart.clear(); lastWiFiResetMoment.setNow(); @@ -72,7 +72,7 @@ void WiFiEventData_t::clearAll() { void WiFiEventData_t::markWiFiTurnOn() { setWiFiDisconnected(); - lastDisconnectMoment.clear(); +// lastDisconnectMoment.clear(); lastConnectMoment.clear(); lastGetIPmoment.clear(); wifi_considered_stable = false; diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index c46408bcbf..f0d666c91b 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -47,23 +47,46 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { #endif // ifdef ESP8266 #ifdef ESP32 isHidden = ssid.isEmpty(); + wifi_ap_record_t* it = reinterpret_cast(WiFi.getScanInfoByIndex(i)); + if (it) { + phy_11b = it->phy_11b; + phy_11g = it->phy_11g; + phy_11n = it->phy_11n; + wps = it->wps; + // FIXME TD-er: Maybe also add other info like 2nd channel, ftm and phy_lr support? + } #endif // ifdef ESP32 last_seen = millis(); } #ifdef ESP8266 +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidate::WiFi_AP_Candidate(const bss_info& ap) : rssi(ap.rssi), channel(ap.channel), bssid(ap.bssid), - index(0), enc_type(ap.authmode), isHidden(ap.is_hidden) + index(0), enc_type(0), isHidden(ap.is_hidden), + phy_11b(ap.phy_11b), phy_11g(ap.phy_11g), phy_11n(ap.phy_11n), + wps(ap.wps) { last_seen = millis(); - ssid.reserve(ap.ssid_len); - for (int i = 0; i < ap.ssid_len; ++i) { - ssid += ap.ssid[i]; + + switch(ap.authmode) { + case AUTH_OPEN: enc_type = ENC_TYPE_NONE; break; + case AUTH_WEP: enc_type = ENC_TYPE_WEP; break; + case AUTH_WPA_PSK: enc_type = ENC_TYPE_TKIP; break; + case AUTH_WPA2_PSK: enc_type = ENC_TYPE_CCMP; break; + case AUTH_WPA_WPA2_PSK: enc_type = ENC_TYPE_AUTO; break; + case AUTH_MAX: break; } + char tmp[33]; //ssid can be up to 32chars, => plus null term + const size_t ssid_len = std::min(static_cast(ap.ssid_len), sizeof(ap.ssid)); + memcpy(tmp, ap.ssid, ssid_len); + tmp[ssid_len] = 0; // nullterm marking end of string + + ssid = String(reinterpret_cast(tmp)); } #endif +#endif bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { @@ -157,9 +180,19 @@ String WiFi_AP_Candidate::toString(const String& separator) const { } result += encryption_type(); + if (phy_known()) { + result += ' '; + if (phy_11b) result += 'b'; + if (phy_11g) result += 'g'; + if (phy_11n) result += 'n'; + } return result; } String WiFi_AP_Candidate::encryption_type() const { return WiFi_encryptionType(enc_type); } + +bool WiFi_AP_Candidate::phy_known() const { + return phy_11b || phy_11g || phy_11n; +} \ No newline at end of file diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index 1ad7cb23eb..f7d55a9759 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -17,8 +17,10 @@ struct WiFi_AP_Candidate { // Construct using index from WiFi scan result WiFi_AP_Candidate(uint8_t networkItem); #ifdef ESP8266 + #if FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidate(const bss_info& ap); #endif + #endif WiFi_AP_Candidate() = default; @@ -52,18 +54,25 @@ struct WiFi_AP_Candidate { String encryption_type() const; + bool phy_known() const; + String ssid; String key; unsigned long last_seen = 0; - int32_t rssi = 0; - int32_t channel = 0; - MAC_address bssid; - uint8_t index = 0; // Index of the matching credentials - uint8_t enc_type = 0; // Encryption used (e.g. WPA2) - bool isHidden = false; // Hidden SSID - bool lowPriority = false; // Try as last attempt - bool isEmergencyFallback = false; + int32_t rssi = 0; + int32_t channel = 0; + MAC_address bssid; + uint8_t index = 0; // Index of the matching credentials + uint8_t enc_type = 0; // Encryption used (e.g. WPA2) + bool isHidden = false; // Hidden SSID + bool lowPriority = false; // Try as last attempt + bool isEmergencyFallback = false; + bool phy_11b = false; + bool phy_11g = false; + bool phy_11n = false; + bool wps = false; + }; #endif // ifndef DATASTRUCTS_WIFI_AP_CANDIDATES_H diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 31b1cddda9..1d6623135b 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -366,6 +366,7 @@ void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& eve WiFiEventData.setAuthMode(event.newMode); } +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN void onWiFiScanDone(void *arg, STATUS status) { if (status == OK) { auto *head = reinterpret_cast(arg); @@ -376,17 +377,26 @@ void onWiFiScanDone(void *arg, STATUS status) { } WiFi_AP_Candidates.after_process_WiFiscan(); WiFiEventData.lastGetScanMoment.setNow(); - WiFiEventData.processedScanDone = true; +// WiFiEventData.processedScanDone = true; if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("WiFi : Scan finished, found: "); + String log = F("WiFi : Scan finished (ESP8266), found: "); log += scanCount; addLogMove(LOG_LEVEL_INFO, log); } + WiFi_AP_Candidates.load_knownCredentials(); + if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { + WiFiEventData.wifiConnectAttemptNeeded = true; + if (WiFi_AP_Candidates.addedKnownCandidate()) + addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + NetworkConnectRelaxed(); + } + } WiFiMode_t mode = WiFi.getMode(); //WiFi.mode(WIFI_OFF); WiFi.mode(mode); } +#endif #endif // ifdef ESP8266 diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h index 7f35d7c686..d430c0501e 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.h +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.h @@ -66,7 +66,9 @@ void onProbeRequestAPmode(const WiFiEventSoftAPModeProbeRequestReceived& event); void onStationModeAuthModeChanged(const WiFiEventStationModeAuthModeChanged& event); +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN void onWiFiScanDone(void *arg, STATUS status); +#endif #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 01b5302a84..d68caff08e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -324,6 +324,9 @@ bool WiFiConnected() { WiFiEventData.wifiConnectAttemptNeeded = true; //} WiFiEventData.wifiConnectInProgress = false; + if (!WiFiEventData.WiFiDisconnected()) { + WifiDisconnect(); + } } delay(0); STOP_TIMER(WIFI_NOTCONNECTED_STATS); @@ -339,6 +342,7 @@ void WiFiConnectRelaxed() { // Scan is still active, so do not yet connect. return; } + if (WiFiEventData.unprocessedWifiEvents()) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Connecting not possible, unprocessed WiFi events: "); @@ -360,12 +364,6 @@ void WiFiConnectRelaxed() { return; } - - if (WiFiEventData.unprocessedWifiEvents()) { - // Still need to process WiFi events - return; - } - /* if (!WiFiEventData.wifiSetupConnect && wifiAPmodeActivelyUsed()) { return; @@ -399,6 +397,12 @@ void AttemptWiFiConnect() { } } + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { + if (WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() < 1000) { + return; + } + } + if (WiFi_AP_Candidates.getNext(WiFiScanAllowed())) { const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); @@ -462,7 +466,7 @@ bool prepareWiFi() { addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings")); WiFiEventData.warnedNoValidWiFiSettings = true; } - WiFiEventData.last_wifi_connect_attempt_moment.clear(); +// WiFiEventData.last_wifi_connect_attempt_moment.clear(); WiFiEventData.wifi_connect_attempt = 1; WiFiEventData.wifiConnectAttemptNeeded = false; @@ -869,9 +873,6 @@ bool WiFiScanAllowed() { if (!WiFiEventData.processedScanDone) { processScanDone(); } - if (WiFiEventData.unprocessedWifiEvents()) { - handle_unprocessedNetworkEvents(); - } if (WiFiEventData.unprocessedWifiEvents()) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Scan not allowed, unprocessed WiFi events: "); @@ -901,9 +902,11 @@ bool WiFiScanAllowed() { if (WiFiEventData.wifiConnectInProgress) { return false; } - if (NetworkConnected() && WiFi_AP_Candidates.getBestCandidate().usable()) { - addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not needed, good candidate present")); - return false; + if (WiFiEventData.lastScanMoment.isSet()) { + if (NetworkConnected() && WiFi_AP_Candidates.getBestCandidate().usable()) { + addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not needed, good candidate present")); + return false; + } } if (WiFiEventData.lastDisconnectMoment.isSet() && WiFiEventData.lastDisconnectMoment.millisPassedSince() < WIFI_RECONNECT_WAIT) { @@ -958,7 +961,7 @@ void WifiScan(bool async, uint8_t channel) { } --nrScans; #ifdef ESP8266 - /* +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN { static bool FIRST_SCAN = true; @@ -967,7 +970,7 @@ void WifiScan(bool async, uint8_t channel) { config.ssid = nullptr; config.bssid = nullptr; config.channel = channel; - config.show_hidden = 1; + config.show_hidden = show_hidden ? 1 : 0;; config.scan_type = WIFI_SCAN_TYPE_ACTIVE; if (FIRST_SCAN) { config.scan_time.active.min = 100; @@ -978,11 +981,18 @@ void WifiScan(bool async, uint8_t channel) { } FIRST_SCAN = false; wifi_station_scan(&config, &onWiFiScanDone); + if (!async) { + // will resume when SYSTEM_EVENT_SCAN_DONE event is fired + do { + delay(0); + } while (!WiFiEventData.processedScanDone); + } } - */ +#else WiFi.scanNetworks(async, show_hidden, channel); #endif +#endif #ifdef ESP32 const bool passive = false; const uint32_t max_ms_per_chan = 300; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index dc34ea6f9d..bacd0551f7 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -114,8 +114,10 @@ void handle_unprocessedNetworkEvents() // WiFi connection is not yet available, so introduce some extra delays to // help the background tasks managing wifi connections delay(0); - - NetworkConnectRelaxed(); + + if (!WiFiEventData.wifiConnectInProgress) { + NetworkConnectRelaxed(); + } if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG @@ -287,7 +289,8 @@ void processDisconnect() { // FIXME TD-er: Ignoring the actual setting for now as it seems to be more reliable to always restart WiFi. bool mustRestartWiFi = Settings.WiFiRestart_connection_lost(); if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { - mustRestartWiFi = true; + if (!WiFi_AP_Candidates.getBestCandidate().usable()) + mustRestartWiFi = true; } #ifdef USES_ESPEASY_NOW @@ -295,7 +298,7 @@ void processDisconnect() { // mustRestartWiFi = true; } #endif - WifiDisconnect(); // Needed or else node may not reconnect reliably. + //WifiDisconnect(); // Needed or else node may not reconnect reliably. if (WiFi.status() > WL_DISCONNECTED) { // In case of an error, where the status reports something like WL_NO_SHIELD @@ -320,10 +323,8 @@ void processDisconnect() { setWifiMode(WIFI_OFF); initWiFi(); delay(100); - if (WiFiEventData.unprocessedWifiEvents()) { - handle_unprocessedNetworkEvents(); - } } + delay(500); logConnectionStatus(); WiFiEventData.processingDisconnect.clear(); WiFiEventData.wifiConnectAttemptNeeded = true; @@ -336,6 +337,11 @@ void processConnect() { return; } WiFiEventData.processedConnect = true; + if (WiFi.status() == WL_DISCONNECTED) { + // Apparently not really connected + return; + } + WiFiEventData.setWiFiConnected(); ++WiFiEventData.wifi_reconnects; @@ -597,6 +603,7 @@ void processDisableAPmode() { } void processScanDone() { + // FIXME TD-er: This is only being called on ESP32 as scan results are processed immediately on ESP8266 WiFi_AP_Candidates.load_knownCredentials(); if (WiFiEventData.processedScanDone) { return; } @@ -632,9 +639,12 @@ void processScanDone() { addLogMove(LOG_LEVEL_INFO, log); } +#if !FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); +#endif + WiFi_AP_Candidates.load_knownCredentials(); - if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { + if (WiFi_AP_Candidates.addedKnownCandidate() && !NetworkConnected()) { WiFiEventData.wifiConnectAttemptNeeded = true; if (WiFi_AP_Candidates.addedKnownCandidate()) addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 306e1994f9..23a22301ea 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -330,7 +330,7 @@ void ESPEasy_setup() // Always perform WiFi scan // It appears reconnecting from RTC may take just as long to be able to send first packet as performing a scan first and then connect. // Perhaps the WiFi radio needs some time to stabilize first? - WifiScan(true); + WifiScan(false); } #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("WifiScan()")); diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index a6a1a8dfd5..0b3a5e4993 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -107,6 +107,7 @@ void WiFi_AP_CandidatesList::purge_expired() { } } +#if !FEATURE_ESP8266_DIRECT_WIFI_SCAN void WiFi_AP_CandidatesList::process_WiFiscan(uint8_t scancount) { // Append or update found APs from scan. for (uint8_t i = 0; i < scancount; ++i) { @@ -117,13 +118,16 @@ void WiFi_AP_CandidatesList::process_WiFiscan(uint8_t scancount) { after_process_WiFiscan(); } +#endif #ifdef ESP8266 +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN void WiFi_AP_CandidatesList::process_WiFiscan(const bss_info& ap) { WiFi_AP_Candidate tmp(ap); scanned_new.push_back(tmp); } #endif +#endif void WiFi_AP_CandidatesList::after_process_WiFiscan() { scanned_new.sort(); @@ -227,6 +231,11 @@ int8_t WiFi_AP_CandidatesList::scanComplete() const { ++found; } } + for (auto scan = scanned_new.begin(); scan != scanned_new.end(); ++scan) { + if (!scan->expired()) { + ++found; + } + } if (found > 0) { return found; } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 00da215682..82b8c2c80c 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -26,10 +26,15 @@ struct WiFi_AP_CandidatesList { void purge_expired(); +#if !FEATURE_ESP8266_DIRECT_WIFI_SCAN // Add found WiFi access points to the list if they are possible candidates. void process_WiFiscan(uint8_t scancount); +#endif + #ifdef ESP8266 +#if FEATURE_ESP8266_DIRECT_WIFI_SCAN void process_WiFiscan(const bss_info& ap); +#endif #endif void after_process_WiFiscan(); From 39203369245dc366e6f6b0f703bda122d6dc86d9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 4 Oct 2022 11:58:27 +0200 Subject: [PATCH 313/404] [WiFi] Fix ESP32 build --- src/src/DataStructs/WiFi_AP_Candidate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index f0d666c91b..e25cd6082f 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -47,7 +47,7 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { #endif // ifdef ESP8266 #ifdef ESP32 isHidden = ssid.isEmpty(); - wifi_ap_record_t* it = reinterpret_cast(WiFi.getScanInfoByIndex(i)); + wifi_ap_record_t* it = reinterpret_cast(WiFi.getScanInfoByIndex(networkItem)); if (it) { phy_11b = it->phy_11b; phy_11g = it->phy_11g; From 1944f6bcaa44100c8f79ee9f899a8ebbafe88fe5 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 Oct 2022 15:44:22 +0200 Subject: [PATCH 314/404] [WiFi] Prevent reconnect loop --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index d68caff08e..7abcf2aa82 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -364,11 +364,9 @@ void WiFiConnectRelaxed() { return; } -/* if (!WiFiEventData.wifiSetupConnect && wifiAPmodeActivelyUsed()) { return; } - */ // FIXME TD-er: Should not try to prepare when a scan is still busy. From 87a3a67d24342adff039ee221d5106fe867e846f Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 Oct 2022 15:46:04 +0200 Subject: [PATCH 315/404] [WiFi] Check scan results for known candidates --- src/src/DataStructs/WiFiEventData.cpp | 4 +++ src/src/DataStructs/WiFiEventData.h | 1 + src/src/ESPEasyCore/ESPEasyWifi.cpp | 29 +++++++++++----------- src/src/ESPEasyCore/ESPEasy_setup.cpp | 2 ++ src/src/Helpers/WiFi_AP_CandidatesList.cpp | 1 - 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 29f4110e4a..587a1579a3 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -76,7 +76,11 @@ void WiFiEventData_t::markWiFiTurnOn() { lastConnectMoment.clear(); lastGetIPmoment.clear(); wifi_considered_stable = false; + + clear_processed_flags(); +} +void WiFiEventData_t::clear_processed_flags() { // Mark all flags to default to prevent handling old events. processedConnect = true; processedDisconnect = true; diff --git a/src/src/DataStructs/WiFiEventData.h b/src/src/DataStructs/WiFiEventData.h index a77e5b986d..3aa89e22e5 100644 --- a/src/src/DataStructs/WiFiEventData.h +++ b/src/src/DataStructs/WiFiEventData.h @@ -37,6 +37,7 @@ struct WiFiEventData_t { void clearAll(); void markWiFiTurnOn(); + void clear_processed_flags(); void markWiFiBegin(); bool WiFiDisconnected() const; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 7abcf2aa82..f7623c129f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -517,7 +517,7 @@ bool checkAndResetWiFi() { break; case STATION_IDLE: case STATION_CONNECTING: - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(15000)) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { return false; } break; @@ -529,7 +529,7 @@ bool checkAndResetWiFi() { return false; //} } - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(15000)) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && !WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { return false; } #endif @@ -1190,22 +1190,22 @@ const __FlashStringHelper * getWifiModeString(WiFiMode_t wifimode) return F("Unknown"); } -void setWifiMode(WiFiMode_t wifimode) { +void setWifiMode(WiFiMode_t new_mode) { const WiFiMode_t cur_mode = WiFi.getMode(); - if (cur_mode == wifimode) { + if (cur_mode == new_mode) { return; } static WiFiMode_t processing_wifi_mode = cur_mode; - if (processing_wifi_mode == wifimode) { + if (processing_wifi_mode == new_mode) { // Prevent loops return; } - processing_wifi_mode = wifimode; + processing_wifi_mode = new_mode; if (cur_mode == WIFI_OFF) { WiFiEventData.markWiFiTurnOn(); } - if (wifimode != WIFI_OFF) { + if (new_mode != WIFI_OFF) { #if defined(ESP32) // Needs to be set before calling WiFi.mode() on ESP32 WiFi.hostname(NetworkCreateRFCCompliantHostname()); @@ -1219,25 +1219,26 @@ void setWifiMode(WiFiMode_t wifimode) { } else { WifiDisconnect(); processDisconnect(); + WiFiEventData.clear_processed_flags(); } - addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(wifimode))); + addLog(LOG_LEVEL_INFO, concat(F("WIFI : Set WiFi to "), getWifiModeString(new_mode))); int retry = 2; - while (!WiFi.mode(wifimode) && retry > 0) { + while (!WiFi.mode(new_mode) && retry > 0) { addLog(LOG_LEVEL_INFO, F("WIFI : Cannot set mode!!!!!")); delay(100); --retry; } retry = 2; - while (WiFi.getMode() != wifimode && retry > 0) { + while (WiFi.getMode() != new_mode && retry > 0) { addLog(LOG_LEVEL_INFO, F("WIFI : mode not yet set")); delay(100); --retry; } - if (wifimode == WIFI_OFF) { + if (new_mode == WIFI_OFF) { WiFiEventData.markWiFiTurnOn(); delay(100); #if defined(ESP32) @@ -1250,7 +1251,7 @@ void setWifiMode(WiFiMode_t wifimode) { } else { // Only set power mode when AP is not enabled // When AP is enabled, the sleep mode is already set to WIFI_NONE_SLEEP - if (!WifiIsAP(wifimode)) { + if (!WifiIsAP(new_mode)) { if (Settings.WifiNoneSleep()) { #ifdef ESP8266 WiFi.setSleepMode(WIFI_NONE_SLEEP); @@ -1296,7 +1297,7 @@ void setWifiMode(WiFiMode_t wifimode) { */ delay(100); // Must allow for some time to init. } - const bool new_mode_AP_enabled = WifiIsAP(wifimode); + const bool new_mode_AP_enabled = WifiIsAP(new_mode); if (WifiIsAP(cur_mode) && !new_mode_AP_enabled) { eventQueue.add(F("WiFi#APmodeDisabled")); @@ -1367,7 +1368,7 @@ bool wifiConnectTimeoutReached() { if (WifiIsAP(WiFi.getMode())) { // FIXME TD-er: What to do here when using ESPEasy-NOW mode? // Initial setup of WiFi, may take much longer since accesspoint is still active. - return WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(20000); + return WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(2 * DEFAULT_WIFI_CONNECTION_TIMEOUT); } // wait until it connects + add some device specific random offset to prevent diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 23a22301ea..2856dba467 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -135,6 +135,7 @@ void ESPEasy_setup() #endif // ifndef BUILD_NO_RAM_TRACKER initWiFi(); + WiFiEventData.clearAll(); #ifndef BUILD_MINIMAL_OTA run_compiletime_checks(); @@ -318,6 +319,7 @@ void ESPEasy_setup() if (active_network_medium == NetworkMedium_t::WIFI) { WiFi_AP_Candidates.load_knownCredentials(); + setSTA(true); if (!WiFi_AP_Candidates.hasKnownCredentials()) { WiFiEventData.wifiSetup = true; RTC.clearLastWiFi(); // Must scan all channels diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 0b3a5e4993..ce6a86a0ac 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -45,7 +45,6 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { known.clear(); candidates.clear(); _addedKnownCandidate = false; -// addFromRTC(); { // Add the known SSIDs From 572cc4c4241e37bdd43b02714c0199d570886584 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 5 Oct 2022 15:49:23 +0200 Subject: [PATCH 316/404] [WiFi] Make WiFi reconnect more predictable --- platformio_core_defs.ini | 2 +- src/src/DataStructs/WiFiEventData.cpp | 19 ++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 77 +++++++-- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 155 +++++++++--------- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 34 ++-- src/src/Helpers/WiFi_AP_CandidatesList.h | 5 + 6 files changed, 185 insertions(+), 107 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 93de4a78cc..2d431d2aa6 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -135,7 +135,7 @@ platform = espressif8266@2.6.3 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.4 build_flags = ${esp82xx_2_6_x.build_flags} - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK221 + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190313 -Wno-deprecated-declarations lib_ignore = ${esp82xx_defaults.lib_ignore} IRremoteESP8266 diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index 587a1579a3..e881409c27 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -22,6 +22,12 @@ bool WiFiEventData_t::WiFiConnectAllowed() const { if (!wifiConnectAttemptNeeded) return false; if (wifiSetupConnect) return true; + if (wifiConnectInProgress) { + if (last_wifi_connect_attempt_moment.isSet() && + !last_wifi_connect_attempt_moment.timeoutReached(WIFI_PROCESS_EVENTS_TIMEOUT)) { + return false; + } + } if (lastDisconnectMoment.isSet()) { // TODO TD-er: Make this time more dynamic. if (!lastDisconnectMoment.timeoutReached(1000)) { @@ -62,7 +68,7 @@ bool WiFiEventData_t::unprocessedWifiEvents() { void WiFiEventData_t::clearAll() { markWiFiTurnOn(); lastGetScanMoment.clear(); -// last_wifi_connect_attempt_moment.clear(); + last_wifi_connect_attempt_moment.clear(); timerAPstart.clear(); lastWiFiResetMoment.setNow(); @@ -104,7 +110,7 @@ void WiFiEventData_t::markWiFiBegin() { usedChannel = 0; ++wifi_connect_attempt; if (!timerAPstart.isSet()) { - timerAPstart.setMillisFromNow(WIFI_RECONNECT_WAIT); + timerAPstart.setMillisFromNow(3 * WIFI_RECONNECT_WAIT); } #ifdef USES_ESPEASY_NOW temp_disable_EspEasy_now_timer = millis() + WIFI_RECONNECT_WAIT; @@ -134,10 +140,12 @@ void WiFiEventData_t::setWiFiDisconnected() { void WiFiEventData_t::setWiFiGotIP() { bitSet(wifiStatus, ESPEASY_WIFI_GOT_IP); + processedGotIP = true; } void WiFiEventData_t::setWiFiConnected() { bitSet(wifiStatus, ESPEASY_WIFI_CONNECTED); + processedConnect = true; } void WiFiEventData_t::setWiFiServicesInitialized() { @@ -170,6 +178,13 @@ void WiFiEventData_t::markLostIP() { } void WiFiEventData_t::markDisconnect(WiFiDisconnectReason reason) { +/* + #if defined(ESP32) + if ((WiFi.getMode() & WIFI_MODE_STA) == 0) return; + #else // if defined(ESP32) + if ((WiFi.getMode() & WIFI_STA) == 0) return; + #endif // if defined(ESP32) +*/ lastDisconnectMoment.setNow(); usedChannel = 0; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index f7623c129f..bc696b70c6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -296,14 +296,18 @@ bool WiFiConnected() { } if ((WiFiEventData.timerAPstart.isSet()) && WiFiEventData.timerAPstart.timeReached()) { - // Timer reached, so enable AP mode. - if (!WifiIsAP(WiFi.getMode())) { - if (!Settings.DoNotStartAP()) { - WifiScan(false); - setAP(true); + if (WiFiEventData.timerAPoff.isSet() && !WiFiEventData.timerAPoff.timeReached()) { + // Timer reached, so enable AP mode. + if (!WifiIsAP(WiFi.getMode())) { + if (!Settings.DoNotStartAP()) { + WifiScan(false); + setAP(true); + } } + } else { + WiFiEventData.timerAPstart.clear(); + WiFiEventData.timerAPoff.clear(); } - WiFiEventData.timerAPstart.clear(); } @@ -343,6 +347,10 @@ void WiFiConnectRelaxed() { return; } + if (!WiFiEventData.processedDisconnect) { + processDisconnect(); + } + if (WiFiEventData.unprocessedWifiEvents()) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Connecting not possible, unprocessed WiFi events: "); @@ -360,6 +368,7 @@ void WiFiConnectRelaxed() { } addLogMove(LOG_LEVEL_ERROR, log); + logConnectionStatus(); } return; } @@ -396,11 +405,17 @@ void AttemptWiFiConnect() { } if (WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - if (WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() < 1000) { + if (!WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { return; } } + if (WiFiEventData.unprocessedWifiEvents()) { + return; + } + + setSTA(true); + if (WiFi_AP_Candidates.getNext(WiFiScanAllowed())) { const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); @@ -597,6 +612,7 @@ void initWiFi() // The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections, // those WiFi connections will take a long time to make or sometimes will not work at all. WiFi.disconnect(true); + WifiScan(false); setWifiMode(WIFI_OFF); #if defined(ESP32) @@ -616,6 +632,7 @@ void initWiFi() #endif #endif + delay(100); } // ******************************************************************************** @@ -858,7 +875,6 @@ void WifiDisconnect() } delay(1); processDisconnect(); - processingDisconnect = false; } // ******************************************************************************** @@ -871,6 +887,14 @@ bool WiFiScanAllowed() { if (!WiFiEventData.processedScanDone) { processScanDone(); } + if (!WiFiEventData.processedDisconnect) { + processDisconnect(); + } + + if (WiFiEventData.wifiConnectInProgress) { + return false; + } + if (WiFiEventData.unprocessedWifiEvents()) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Scan not allowed, unprocessed WiFi events: "); @@ -888,6 +912,7 @@ bool WiFiScanAllowed() { } addLogMove(LOG_LEVEL_ERROR, log); + logConnectionStatus(); } return false; } @@ -923,6 +948,7 @@ bool WiFiScanAllowed() { void WifiScan(bool async, uint8_t channel) { + setSTA(true); if (!WiFiScanAllowed()) { return; } @@ -1192,10 +1218,10 @@ const __FlashStringHelper * getWifiModeString(WiFiMode_t wifimode) void setWifiMode(WiFiMode_t new_mode) { const WiFiMode_t cur_mode = WiFi.getMode(); + static WiFiMode_t processing_wifi_mode = cur_mode; if (cur_mode == new_mode) { return; } - static WiFiMode_t processing_wifi_mode = cur_mode; if (processing_wifi_mode == new_mode) { // Prevent loops return; @@ -1218,6 +1244,7 @@ void setWifiMode(WiFiMode_t new_mode) { delay(100); } else { WifiDisconnect(); +// delay(100); processDisconnect(); WiFiEventData.clear_processed_flags(); } @@ -1307,7 +1334,7 @@ void setWifiMode(WiFiMode_t new_mode) { // Mode has changed if (new_mode_AP_enabled) { // Check if we should start internal AP - if (!WifiIsSTA(wifimode)) { + if (!WifiIsSTA(new_mode)) { bool mustStartInternalAP = !Settings.DoNotStartAP(); if (mustStartInternalAP && (WiFiEventData.wifiConnectInProgress || WiFiConnected())) { mustStartInternalAP = false; @@ -1410,17 +1437,31 @@ bool wifiAPmodeActivelyUsed() void setConnectionSpeed() { #ifdef ESP8266 - if (!Settings.ForceWiFi_bg_mode() || (WiFiEventData.wifi_connect_attempt > 10)) { - WiFi.setPhyMode(WIFI_PHY_MODE_11N); + WiFiPhyMode_t phyMode = WIFI_PHY_MODE_11G; + const bool forcedByAPmode = WifiIsAP(WiFi.getMode()); + if (!forcedByAPmode) { + // ESP8266 only supports 802.11g mode when running in STA+AP +// const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); + + bool useAlternate = WiFi_AP_Candidates.attemptsLeft == 0; + if (Settings.ForceWiFi_bg_mode() == useAlternate) { + phyMode = WIFI_PHY_MODE_11N; + } } else { - WiFiPhyMode_t phyMode = WIFI_PHY_MODE_11G; - #ifdef USES_ESPEASY_NOW - if (active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { - phyMode = WIFI_PHY_MODE_11B; + // No need to perform a next attempt. + WiFi_AP_Candidates.markAttempt(); + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = concat(F("WIFI : Set to 802.11"), (WIFI_PHY_MODE_11G == phyMode) ? 'g' : 'n'); + if (forcedByAPmode) { + log += (F(" (AP+STA mode)")); } - #endif - WiFi.setPhyMode(phyMode); + if (Settings.ForceWiFi_bg_mode()) { + log += F(" Force B/G mode"); + } + addLogMove(LOG_LEVEL_INFO, log); } + WiFi.setPhyMode(phyMode); #endif // ifdef ESP8266 // Does not (yet) work, so commented out. diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index bacd0551f7..2d3cff3658 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -89,6 +89,32 @@ void handle_unprocessedNetworkEvents() EthEventData.setEthServicesInitialized(); } #endif // if FEATURE_ETHERNET + if (active_network_medium == NetworkMedium_t::WIFI) { + const bool should_be_initialized = (WiFiEventData.WiFiGotIP() && WiFiEventData.WiFiConnected()) || NetworkConnected(); + if (WiFiEventData.WiFiServicesInitialized() != should_be_initialized) + { + if (!WiFiEventData.WiFiServicesInitialized()) { + WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) + if (WiFiConnected()) { + if (!WiFiEventData.WiFiGotIP()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Missed gotIP event")); + WiFiEventData.processedGotIP = false; + processGotIP(); + } + if (!WiFiEventData.WiFiConnected()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Missed connected event")); + WiFiEventData.processedConnect = false; + processConnect(); + } + // Apparently we are connected, so no need to process any late disconnect event + WiFiEventData.processedDisconnect = true; + } + WiFiEventData.setWiFiServicesInitialized(); + CheckRunningServices(); + } + } + } + if (WiFiEventData.unprocessedWifiEvents()) { // Process disconnect events before connect events. if (!WiFiEventData.processedDisconnect) { @@ -99,26 +125,12 @@ void handle_unprocessedNetworkEvents() } } - if (active_network_medium == NetworkMedium_t::WIFI || active_network_medium == NetworkMedium_t::ESPEasyNOW_only) { - if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents() || WiFiEventData.wifiConnectAttemptNeeded) { - if (WiFi.status() >= WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { - if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && WiFiEventData.last_wifi_connect_attempt_moment.millisPassedSince() > 20000) { - WiFiEventData.last_wifi_connect_attempt_moment.clear(); - } - if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - WiFiEventData.wifiConnectInProgress = false; - } - delay(10); - } - + if (active_network_medium == NetworkMedium_t::WIFI) { + if ((!WiFiEventData.WiFiServicesInitialized()) || WiFiEventData.unprocessedWifiEvents()) { // WiFi connection is not yet available, so introduce some extra delays to // help the background tasks managing wifi connections delay(0); - if (!WiFiEventData.wifiConnectInProgress) { - NetworkConnectRelaxed(); - } - if (!WiFiEventData.processedConnect) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("WIFI : Entering processConnect()")); @@ -134,33 +146,31 @@ void handle_unprocessedNetworkEvents() } if (!WiFiEventData.processedDHCPTimeout) { - #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG, F("WIFI : DHCP timeout, Calling disconnect()")); - #endif // ifndef BUILD_NO_DEBUG +// #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, F("WIFI : DHCP timeout, Calling disconnect()")); +// #endif // ifndef BUILD_NO_DEBUG WiFiEventData.processedDHCPTimeout = true; WifiDisconnect(); } - } - const bool should_be_initialized = (WiFiEventData.WiFiGotIP() && WiFiEventData.WiFiConnected()) || NetworkConnected(); - if (WiFiEventData.WiFiServicesInitialized() != should_be_initialized) - { - if (!WiFiEventData.WiFiServicesInitialized()) { - WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) - if (WiFiConnected()) { - if (!WiFiEventData.WiFiGotIP()) { - addLog(LOG_LEVEL_INFO, F("WiFi : Missed gotIP event")); - WiFiEventData.setWiFiGotIP(); - } - if (!WiFiEventData.WiFiConnected()) { - addLog(LOG_LEVEL_INFO, F("WiFi : Missed connected event")); - WiFiEventData.setWiFiConnected(); - } + + if (WiFi.status() == WL_DISCONNECTED && WiFiEventData.wifiConnectInProgress) { + if (WiFiEventData.last_wifi_connect_attempt_moment.isSet() && + WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT)) { + logConnectionStatus(); + resetWiFi(); } - WiFiEventData.setWiFiServicesInitialized(); - CheckRunningServices(); + if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { + WiFiEventData.wifiConnectInProgress = false; + } + delay(10); + } + + if (!WiFiEventData.wifiConnectInProgress) { + NetworkConnectRelaxed(); } } + if (WiFiEventData.WiFiDisconnected()) { #ifndef BUILD_NO_DEBUG @@ -262,14 +272,6 @@ void processDisconnect() { if (WiFiEventData.processedDisconnect || WiFiEventData.processingDisconnect.isSet()) { return; } - addLog(LOG_LEVEL_INFO, F("WiFi : processDisconnect()")); - WiFiEventData.processingDisconnect.setNow(); - WiFiEventData.setWiFiDisconnected(); - delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 - - if (Settings.UseRules) { - eventQueue.add(F("WiFi#Disconnected")); - } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WIFI : Disconnected! Reason: '"); @@ -284,10 +286,24 @@ void processDisconnect() { } addLogMove(LOG_LEVEL_INFO, log); } + logConnectionStatus(); + addLog(LOG_LEVEL_INFO, F("WiFi : processDisconnect()")); + WiFiEventData.processingDisconnect.setNow(); + WiFiEventData.setWiFiDisconnected(); + delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 - // FIXME TD-er: Ignoring the actual setting for now as it seems to be more reliable to always restart WiFi. + if (Settings.UseRules) { + eventQueue.add(F("WiFi#Disconnected")); + } + + + #ifdef ESP8266 bool mustRestartWiFi = Settings.WiFiRestart_connection_lost(); + #else + // FIXME TD-er: Ignoring the actual setting for now as it seems to be more reliable to always restart WiFi. + bool mustRestartWiFi = true; + #endif if (WiFiEventData.lastConnectedDuration_us > 0 && (WiFiEventData.lastConnectedDuration_us / 1000) < 5000) { if (!WiFi_AP_Candidates.getBestCandidate().usable()) mustRestartWiFi = true; @@ -300,31 +316,16 @@ void processDisconnect() { #endif //WifiDisconnect(); // Needed or else node may not reconnect reliably. - if (WiFi.status() > WL_DISCONNECTED) { - // In case of an error, where the status reports something like WL_NO_SHIELD - addLog(LOG_LEVEL_ERROR, F("WIFI : WiFi.status() > WL_DISCONNECTED, reset WiFi")); - setWifiMode(WIFI_OFF); - initWiFi(); - delay(100); - if (WiFiEventData.unprocessedWifiEvents()) { - WiFiEventData.processedDisconnect = true; - WiFiEventData.processingDisconnect.clear(); - } - mustRestartWiFi = false; - } - WiFiEventData.processedDisconnect = true; - WiFiEventData.processingDisconnect.clear(); - - if (mustRestartWiFi) { - addLog(LOG_LEVEL_ERROR, F("WIFI : Must restart WiFi")); - WifiScan(false); - delay(100); - setWifiMode(WIFI_OFF); - initWiFi(); - delay(100); - } - delay(500); + WiFiEventData.processedDisconnect = true; + resetWiFi(); +// WifiScan(false); +// delay(100); +// setWifiMode(WIFI_OFF); +// initWiFi(); +// delay(100); + } +// delay(500); logConnectionStatus(); WiFiEventData.processingDisconnect.clear(); WiFiEventData.wifiConnectAttemptNeeded = true; @@ -393,6 +394,8 @@ void processConnect() { addLogMove(LOG_LEVEL_INFO, log); } +// WiFiEventData.last_wifi_connect_attempt_moment.clear(); + if (Settings.UseRules) { if (WiFiEventData.bssid_changed) { eventQueue.add(F("WiFi#ChangedAccesspoint")); @@ -493,7 +496,6 @@ void processGotIP() { } if ((WiFiEventData.WiFiConnected() || WiFi.isConnected()) && hasIPaddr()) { - WiFiEventData.processedGotIP = true; WiFiEventData.setWiFiGotIP(); } #if FEATURE_ESPEASY_P2P @@ -603,7 +605,6 @@ void processDisableAPmode() { } void processScanDone() { - // FIXME TD-er: This is only being called on ESP32 as scan results are processed immediately on ESP8266 WiFi_AP_Candidates.load_knownCredentials(); if (WiFiEventData.processedScanDone) { return; } @@ -645,10 +646,14 @@ void processScanDone() { WiFi_AP_Candidates.load_knownCredentials(); if (WiFi_AP_Candidates.addedKnownCandidate() && !NetworkConnected()) { - WiFiEventData.wifiConnectAttemptNeeded = true; - if (WiFi_AP_Candidates.addedKnownCandidate()) - addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); - NetworkConnectRelaxed(); + if (!WiFiEventData.wifiConnectInProgress) { + WiFiEventData.wifiConnectAttemptNeeded = true; + if (WiFi_AP_Candidates.addedKnownCandidate()) + addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + + setSTA(false); + NetworkConnectRelaxed(); + } } #ifdef USES_ESPEASY_NOW diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index ce6a86a0ac..01c11a809c 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -44,7 +44,9 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { _mustLoadCredentials = false; known.clear(); candidates.clear(); +// attemptsLeft = 1; _addedKnownCandidate = false; +// addFromRTC(); { // Add the known SSIDs @@ -133,6 +135,7 @@ void WiFi_AP_CandidatesList::after_process_WiFiscan() { scanned_new.unique(); _mustLoadCredentials = true; WiFi.scanDelete(); + attemptsLeft = 1; } bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { @@ -143,12 +146,12 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { return false; } loadCandidatesFromScanned(); + attemptsLeft = 1; if (candidates.empty()) { return false; } } - bool mustPop = true; - currentCandidate = candidates.front(); + bool mustPop = true; if (currentCandidate.isHidden) { // Iterate over the known credentials to try them all @@ -166,18 +169,23 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { } if (mustPop) { - if (currentCandidate.isHidden) { - // We tried to connect to hidden SSIDs in 1 run, so pop all hidden candidates. - for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->isHidden; ) { - cand_it = candidates.erase(cand_it); + if (attemptsLeft == 0) { + if (currentCandidate.isHidden) { + // We tried to connect to hidden SSIDs in 1 run, so pop all hidden candidates. + for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->isHidden; ) { + cand_it = candidates.erase(cand_it); + } + } else { + if (!candidates.empty()) { + candidates.pop_front(); + } } + + known_it = known.begin(); + attemptsLeft = 1; } else { - if (!candidates.empty()) { - candidates.pop_front(); - } + markAttempt(); } - - known_it = known.begin(); } return currentCandidate.usable(); } @@ -186,6 +194,10 @@ const WiFi_AP_Candidate& WiFi_AP_CandidatesList::getCurrent() const { return currentCandidate; } +void WiFi_AP_CandidatesList::markAttempt() { + if (attemptsLeft > 0) attemptsLeft--; +} + WiFi_AP_Candidate WiFi_AP_CandidatesList::getBestCandidate() const { for (auto it = candidates.begin(); it != candidates.end(); ++it) { if (it->rssi < -1) { return *it; } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.h b/src/src/Helpers/WiFi_AP_CandidatesList.h index 82b8c2c80c..b2020ef4f7 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.h +++ b/src/src/Helpers/WiFi_AP_CandidatesList.h @@ -44,6 +44,9 @@ struct WiFi_AP_CandidatesList { bool getNext(bool scanAllowed); const WiFi_AP_Candidate& getCurrent() const; + + // Decrease attemptsLeft + void markAttempt(); WiFi_AP_Candidate getBestCandidate() const; @@ -96,6 +99,8 @@ struct WiFi_AP_CandidatesList { bool _mustLoadCredentials = true; bool _addedKnownCandidate = false; +public: + int attemptsLeft = 1; }; #endif // ifndef HELPERS_WIFI_AP_CANDIDATESLIST_H From d798636d72128e84d0ec7e796f3bce8c21f35d23 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 6 Oct 2022 11:52:04 +0200 Subject: [PATCH 317/404] [WiFi] Fix WiFi connect timeout handling --- src/src/DataStructs/WiFiEventData.cpp | 3 + src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 24 ++++---- src/src/ESPEasyCore/ESPEasyWifi.cpp | 56 ++++++------------- src/src/ESPEasyCore/ESPEasyWifi.h | 1 - .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 9 +++ 5 files changed, 40 insertions(+), 53 deletions(-) diff --git a/src/src/DataStructs/WiFiEventData.cpp b/src/src/DataStructs/WiFiEventData.cpp index e881409c27..89ae420119 100644 --- a/src/src/DataStructs/WiFiEventData.cpp +++ b/src/src/DataStructs/WiFiEventData.cpp @@ -20,6 +20,9 @@ #define CONNECT_TIMEOUT_MAX 4000 // in milliSeconds bool WiFiEventData_t::WiFiConnectAllowed() const { + if (WiFi.status() == WL_IDLE_STATUS) { + return false; + } if (!wifiConnectAttemptNeeded) return false; if (wifiSetupConnect) return true; if (wifiConnectInProgress) { diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 1d6623135b..1d834bf944 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -60,16 +60,16 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { // ESP32 WiFi ready break; case ARDUINO_EVENT_WIFI_STA_START: - addLog(LOG_LEVEL_INFO, F("WiFi : STA Started")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); break; case ARDUINO_EVENT_WIFI_STA_STOP: - addLog(LOG_LEVEL_INFO, F("WiFi : STA Stopped")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); break; case ARDUINO_EVENT_WIFI_AP_START: - addLog(LOG_LEVEL_INFO, F("WiFi : AP Started")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); break; case ARDUINO_EVENT_WIFI_AP_STOP: - addLog(LOG_LEVEL_INFO, F("WiFi : AP Stopped")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 @@ -82,13 +82,13 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { WiFiEventData.markLostIP(); addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? - F("ETH : Lost IP") : F("WiFi : Lost IP")); + F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); break; case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - addLog(LOG_LEVEL_INFO, F("WiFi : AP got probed")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: @@ -197,16 +197,16 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { // ESP32 WiFi ready break; case SYSTEM_EVENT_STA_START: - addLog(LOG_LEVEL_INFO, F("WiFi : STA Started")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); break; case SYSTEM_EVENT_STA_STOP: - addLog(LOG_LEVEL_INFO, F("WiFi : STA Stopped")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); break; case SYSTEM_EVENT_AP_START: - addLog(LOG_LEVEL_INFO, F("WiFi : AP Started")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); break; case SYSTEM_EVENT_AP_STOP: - addLog(LOG_LEVEL_INFO, F("WiFi : AP Stopped")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); break; case SYSTEM_EVENT_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 @@ -219,13 +219,13 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { WiFiEventData.markLostIP(); addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? - F("ETH : Lost IP") : F("WiFi : Lost IP")); + F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); break; case SYSTEM_EVENT_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 - addLog(LOG_LEVEL_INFO, F("WiFi : AP got probed")); + addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); break; case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index bc696b70c6..846984b85f 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -322,13 +322,17 @@ bool WiFiConnected() { } } - if (wifiConnectTimeoutReached() && !WiFiEventData.wifiSetup) { + const bool timeoutReached = WiFiEventData.last_wifi_connect_attempt_moment.isSet() && + WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(2 * DEFAULT_WIFI_CONNECTION_TIMEOUT); + + if (timeoutReached && !WiFiEventData.wifiSetup) { // It took too long to make a connection, set flag we need to try again //if (!wifiAPmodeActivelyUsed()) { WiFiEventData.wifiConnectAttemptNeeded = true; //} WiFiEventData.wifiConnectInProgress = false; if (!WiFiEventData.WiFiDisconnected()) { + addLog(LOG_LEVEL_INFO, F("WiFi : wifiConnectTimeoutReached")); WifiDisconnect(); } } @@ -838,6 +842,10 @@ WiFiConnectionProtocol getConnectionProtocol() { // ******************************************************************************** void WifiDisconnect() { + if (!WiFiEventData.processedDisconnect || + WiFiEventData.processingDisconnect.isSet()) { + return; + } // Prevent recursion static bool processingDisconnect = false; if (processingDisconnect) return; @@ -855,8 +863,6 @@ void WifiDisconnect() } #endif #ifdef ESP8266 - WiFi.disconnect(); - /* // Only call disconnect when STA is active if (WifiIsSTA(WiFi.getMode())) { wifi_station_disconnect(); @@ -866,15 +872,17 @@ void WifiDisconnect() ETS_UART_INTR_DISABLE(); wifi_station_set_config_current(&conf); ETS_UART_INTR_ENABLE(); - */ #endif // if defined(ESP32) WiFiEventData.setWiFiDisconnected(); WiFiEventData.markDisconnect(WIFI_DISCONNECT_REASON_ASSOC_LEAVE); if (!Settings.UseLastWiFiFromRTC()) { RTC.clearLastWiFi(); } - delay(1); + delay(100); + WiFiEventData.processingDisconnect.clear(); + WiFiEventData.processedDisconnect = false; processDisconnect(); + processingDisconnect = false; } // ******************************************************************************** @@ -1032,6 +1040,8 @@ void WifiScan(bool async, uint8_t channel) { #ifdef ESP32 RTC.clearLastWiFi(); if (WiFiConnected()) { + addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); + const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; WifiDisconnect(); WiFiEventData.wifiConnectAttemptNeeded = needReconnect; @@ -1312,8 +1322,7 @@ void setWifiMode(WiFiMode_t new_mode) { #ifdef ESP8266 SetWiFiTXpower(); #endif -/* - if (WifiIsSTA(wifimode)) { + if (WifiIsSTA(new_mode)) { if (WiFi.getAutoConnect()) { WiFi.setAutoConnect(false); } @@ -1321,7 +1330,6 @@ void setWifiMode(WiFiMode_t new_mode) { WiFi.setAutoReconnect(false); } } -*/ delay(100); // Must allow for some time to init. } const bool new_mode_AP_enabled = WifiIsAP(new_mode); @@ -1377,38 +1385,6 @@ bool useStaticIP() { return Settings.IP[0] != 0 && Settings.IP[0] != 255; } -bool wifiConnectTimeoutReached() { - // For the first attempt, do not wait to start connecting. - if (WiFiEventData.wifi_connect_attempt == 0) { return true; } - if (!WiFiEventData.wifiConnectInProgress) { return true; } - - if (!WiFiEventData.last_wifi_connect_attempt_moment.isSet()) { - // No attempt made - return true; - } - - if (WiFiEventData.lastDisconnectMoment.isSet()) { - // Connection attempt was already ended. - return true; - } - - if (WifiIsAP(WiFi.getMode())) { - // FIXME TD-er: What to do here when using ESPEasy-NOW mode? - // Initial setup of WiFi, may take much longer since accesspoint is still active. - return WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(2 * DEFAULT_WIFI_CONNECTION_TIMEOUT); - } - - // wait until it connects + add some device specific random offset to prevent - // all nodes overloading the access point when turning on at the same time. - #if defined(ESP8266) - const unsigned int randomOffset_in_msec = (WiFiEventData.wifi_connect_attempt == 1) ? 0 : 1000 * ((ESP.getChipId() & 0xF)); - #endif // if defined(ESP8266) - #if defined(ESP32) - const unsigned int randomOffset_in_msec = (WiFiEventData.wifi_connect_attempt == 1) ? 0 : 1000 * ((ESP.getEfuseMac() & 0xF)); - #endif // if defined(ESP32) - return WiFiEventData.last_wifi_connect_attempt_moment.timeoutReached(DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_msec); -} - bool wifiAPmodeActivelyUsed() { if (!WiFiEventData.processedDisconnectAPmode) return true; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.h b/src/src/ESPEasyCore/ESPEasyWifi.h index 25734ca0e2..f1b64cc34b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.h +++ b/src/src/ESPEasyCore/ESPEasyWifi.h @@ -132,7 +132,6 @@ void setWifiMode(WiFiMode_t wifimode); bool WifiIsAP(WiFiMode_t wifimode); bool WifiIsSTA(WiFiMode_t wifimode); bool useStaticIP(); -bool wifiConnectTimeoutReached(); bool wifiAPmodeActivelyUsed(); void setConnectionSpeed(); void setupStaticIPconfig(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 2d3cff3658..7a2bf08a9a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -166,6 +166,7 @@ void handle_unprocessedNetworkEvents() } if (!WiFiEventData.wifiConnectInProgress) { + WiFiEventData.wifiConnectAttemptNeeded = true; NetworkConnectRelaxed(); } } @@ -309,6 +310,11 @@ void processDisconnect() { mustRestartWiFi = true; } + if (WiFi.status() == WL_IDLE_STATUS) { + mustRestartWiFi = true; + } + + #ifdef USES_ESPEASY_NOW if (use_EspEasy_now) { // mustRestartWiFi = true; @@ -653,6 +659,9 @@ void processScanDone() { setSTA(false); NetworkConnectRelaxed(); +#ifdef USES_ESPEASY_NOW + temp_disable_EspEasy_now_timer = millis() + 20000; +#endif } } From 7b280f156cd062a9cd9f10aff8dc96aff6260625 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 6 Oct 2022 12:08:36 +0200 Subject: [PATCH 318/404] [ESPEasy-NOW] Prevent WiFi power off when enabling mesh --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 846984b85f..27e875765a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -495,7 +495,15 @@ bool prepareWiFi() { return false; } WiFiEventData.warnedNoValidWiFiSettings = false; + #ifdef USES_ESPEASY_NOW + if (Settings.UseESPEasyNow()) { + setWifiMode(WIFI_AP_STA); + } else { + setSTA(true); + } + #else setSTA(true); + #endif #if defined(ESP8266) wifi_station_set_hostname(NetworkCreateRFCCompliantHostname().c_str()); From c23b40cf3bea99fdc009233ca98b355806ec97c8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 01:51:46 +0200 Subject: [PATCH 319/404] [WiFi] Limit WiFi logs on size challenged builds --- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 31 ++++++++++++++++++- src/src/ESPEasyCore/ESPEasyWifi.cpp | 18 +++++++++++ .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 18 ++++++++--- src/src/Helpers/WiFi_AP_CandidatesList.cpp | 2 ++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 1d834bf944..7d49b205ab 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -60,16 +60,24 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { // ESP32 WiFi ready break; case ARDUINO_EVENT_WIFI_STA_START: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); + #endif break; case ARDUINO_EVENT_WIFI_STA_STOP: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); + #endif break; case ARDUINO_EVENT_WIFI_AP_START: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); + #endif break; case ARDUINO_EVENT_WIFI_AP_STOP: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); + #endif break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 @@ -80,15 +88,19 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { else #endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); + #endif break; case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); + #endif break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: @@ -197,16 +209,24 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { // ESP32 WiFi ready break; case SYSTEM_EVENT_STA_START: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Started")); + #endif break; case SYSTEM_EVENT_STA_STOP: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event STA Stopped")); + #endif break; case SYSTEM_EVENT_AP_START: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Started")); + #endif break; case SYSTEM_EVENT_AP_STOP: + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP Stopped")); + #endif break; case SYSTEM_EVENT_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0 @@ -217,15 +237,19 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) { else #endif // if FEATURE_ETHERNET WiFiEventData.markLostIP(); + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, active_network_medium == NetworkMedium_t::Ethernet ? F("ETH : Event Lost IP") : F("WiFi : Event Lost IP")); + #endif break; case SYSTEM_EVENT_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); + #endif break; case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: @@ -378,16 +402,21 @@ void onWiFiScanDone(void *arg, STATUS status) { WiFi_AP_Candidates.after_process_WiFiscan(); WiFiEventData.lastGetScanMoment.setNow(); // WiFiEventData.processedScanDone = true; +# ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WiFi : Scan finished (ESP8266), found: "); log += scanCount; addLogMove(LOG_LEVEL_INFO, log); } +#endif WiFi_AP_Candidates.load_knownCredentials(); if (WiFi_AP_Candidates.addedKnownCandidate() || !NetworkConnected()) { WiFiEventData.wifiConnectAttemptNeeded = true; - if (WiFi_AP_Candidates.addedKnownCandidate()) + # ifndef BUILD_NO_DEBUG + if (WiFi_AP_Candidates.addedKnownCandidate()) { addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + } + #endif NetworkConnectRelaxed(); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index 27e875765a..e4bb8af93e 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -332,7 +332,9 @@ bool WiFiConnected() { //} WiFiEventData.wifiConnectInProgress = false; if (!WiFiEventData.WiFiDisconnected()) { + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : wifiConnectTimeoutReached")); + #endif WifiDisconnect(); } } @@ -356,6 +358,7 @@ void WiFiConnectRelaxed() { } if (WiFiEventData.unprocessedWifiEvents()) { + # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Connecting not possible, unprocessed WiFi events: "); if (!WiFiEventData.processedConnect) { @@ -374,6 +377,7 @@ void WiFiConnectRelaxed() { addLogMove(LOG_LEVEL_ERROR, log); logConnectionStatus(); } + #endif return; } @@ -560,6 +564,7 @@ bool checkAndResetWiFi() { return false; } #endif + # ifndef BUILD_NO_DEBUG String log = F("WiFi : WiFiConnected() out of sync: "); log += WiFiEventData.ESPeasyWifiStatusToString(); log += F(" RSSI: "); @@ -568,10 +573,13 @@ bool checkAndResetWiFi() { log += F(" status: "); log += SDKwifiStatusToString(status); #endif + #endif // Call for reset first, to make sure a syslog call will not try to send. resetWiFi(); + # ifndef BUILD_NO_DEBUG addLogMove(LOG_LEVEL_INFO, log); + #endif return true; } @@ -858,7 +866,9 @@ void WifiDisconnect() static bool processingDisconnect = false; if (processingDisconnect) return; processingDisconnect = true; + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : WifiDisconnect()")); + #endif #ifdef ESP32 WiFi.disconnect(); WiFi.removeEvent(wm_event_id); @@ -912,6 +922,7 @@ bool WiFiScanAllowed() { } if (WiFiEventData.unprocessedWifiEvents()) { + # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("WiFi : Scan not allowed, unprocessed WiFi events: "); if (!WiFiEventData.processedConnect) { @@ -930,6 +941,7 @@ bool WiFiScanAllowed() { addLogMove(LOG_LEVEL_ERROR, log); logConnectionStatus(); } + #endif return false; } /* @@ -943,7 +955,9 @@ bool WiFiScanAllowed() { } if (WiFiEventData.lastScanMoment.isSet()) { if (NetworkConnected() && WiFi_AP_Candidates.getBestCandidate().usable()) { + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, F("WiFi : Scan not needed, good candidate present")); + #endif return false; } } @@ -978,6 +992,7 @@ void WifiScan(bool async, uint8_t channel) { START_TIMER; WiFiEventData.lastScanMoment.setNow(); + # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { if (channel == 0) { addLog(LOG_LEVEL_INFO, F("WiFi : Start network scan all channels")); @@ -988,6 +1003,7 @@ void WifiScan(bool async, uint8_t channel) { addLogMove(LOG_LEVEL_INFO, log); } } + #endif bool show_hidden = true; WiFiEventData.processedScanDone = false; WiFiEventData.lastGetScanMoment.setNow(); @@ -1048,7 +1064,9 @@ void WifiScan(bool async, uint8_t channel) { #ifdef ESP32 RTC.clearLastWiFi(); if (WiFiConnected()) { + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); + #endif const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; WifiDisconnect(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 7a2bf08a9a..f515ae15f2 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -97,12 +97,16 @@ void handle_unprocessedNetworkEvents() WiFiEventData.processedDHCPTimeout = true; // FIXME TD-er: Find out when this happens (happens on ESP32 sometimes) if (WiFiConnected()) { if (!WiFiEventData.WiFiGotIP()) { - addLog(LOG_LEVEL_INFO, F("WiFi : Missed gotIP event")); + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed gotIP event")); + #endif WiFiEventData.processedGotIP = false; processGotIP(); } if (!WiFiEventData.WiFiConnected()) { - addLog(LOG_LEVEL_INFO, F("WiFi : Missed connected event")); + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, F("WiFi : Missed connected event")); + #endif WiFiEventData.processedConnect = false; processConnect(); } @@ -627,7 +631,9 @@ void processScanDone() { case -1: // WIFI_SCAN_RUNNING // FIXME TD-er: Set timeout... if (WiFiEventData.lastGetScanMoment.timeoutReached(5000)) { + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout")); + #endif WiFiEventData.processedScanDone = true; } return; @@ -639,12 +645,13 @@ void processScanDone() { WiFiEventData.lastGetScanMoment.setNow(); WiFiEventData.processedScanDone = true; - +# ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("WiFi : Scan finished, found: "); log += scanCompleteStatus; addLogMove(LOG_LEVEL_INFO, log); } +#endif #if !FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidates.process_WiFiscan(scanCompleteStatus); @@ -654,8 +661,11 @@ void processScanDone() { if (WiFi_AP_Candidates.addedKnownCandidate() && !NetworkConnected()) { if (!WiFiEventData.wifiConnectInProgress) { WiFiEventData.wifiConnectAttemptNeeded = true; - if (WiFi_AP_Candidates.addedKnownCandidate()) + # ifndef BUILD_NO_DEBUG + if (WiFi_AP_Candidates.addedKnownCandidate()) { addLog(LOG_LEVEL_INFO, F("WiFi : Added known candidate, try to connect")); + } + #endif setSTA(false); NetworkConnectRelaxed(); diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 01c11a809c..d1d18660f4 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -350,6 +350,7 @@ void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { ++scan; } } + # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { const WiFi_AP_Candidate bestCandidate = getBestCandidate(); if (bestCandidate.usable()) { @@ -358,6 +359,7 @@ void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { addLogMove(LOG_LEVEL_INFO, log); } } + #endif candidates.sort(); candidates.unique(); addFromRTC(); From 52b539427b9a6a4f160c7520cca06ef3783bd312 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 09:15:09 +0200 Subject: [PATCH 320/404] [Commands] Fix accepting invalid commands --- src/src/Commands/InternalCommands.cpp | 6 +++++- src/src/DataStructs/PluginStats.cpp | 4 ++-- src/src/Globals/CPlugins.cpp | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/src/Commands/InternalCommands.cpp b/src/src/Commands/InternalCommands.cpp index c06b36936c..f21c12eee4 100644 --- a/src/src/Commands/InternalCommands.cpp +++ b/src/src/Commands/InternalCommands.cpp @@ -643,6 +643,7 @@ bool ExecuteCommand(taskIndex_t taskIndex, } if (handled) { +// addLog(LOG_LEVEL_INFO, F("executeInternalCommand accepted")); return true; } } @@ -657,6 +658,7 @@ bool ExecuteCommand(taskIndex_t taskIndex, // alter the string. String tmpAction(action); bool handled = PluginCall(PLUGIN_WRITE, &TempEvent, tmpAction); +// if (handled) addLog(LOG_LEVEL_INFO, F("PLUGIN_WRITE accepted")); #ifndef BUILD_NO_DEBUG if (!tmpAction.equals(action)) { @@ -673,7 +675,7 @@ bool ExecuteCommand(taskIndex_t taskIndex, if (!handled) { // Try a controller handled = CPluginCall(CPlugin::Function::CPLUGIN_WRITE, &TempEvent, tmpAction); - +// if (handled) addLog(LOG_LEVEL_INFO, F("CPLUGIN_WRITE accepted")); } if (handled) { @@ -685,6 +687,8 @@ bool ExecuteCommand(taskIndex_t taskIndex, if (tryRemoteConfig) { if (remoteConfig(&TempEvent, action)) { SendStatus(&TempEvent, return_command_success()); +// addLog(LOG_LEVEL_INFO, F("remoteConfig accepted")); + return true; } } diff --git a/src/src/DataStructs/PluginStats.cpp b/src/src/DataStructs/PluginStats.cpp index 831bfa83f5..62e64db1e2 100644 --- a/src/src/DataStructs/PluginStats.cpp +++ b/src/src/DataStructs/PluginStats.cpp @@ -289,15 +289,15 @@ bool PluginStats_array::plugin_write_base(struct EventStruct *event, const Strin const bool clearSamples = cmd.equals(F("clearsamples")); // Command: "taskname.clearSamples" if (resetPeaks || clearSamples) { - success = true; - for (size_t i = 0; i < VARS_PER_TASK; ++i) { if (_plugin_stats[i] != nullptr) { if (resetPeaks) { + success = true; _plugin_stats[i]->resetPeaks(); } if (clearSamples) { + success = true; _plugin_stats[i]->clearSamples(); } } diff --git a/src/src/Globals/CPlugins.cpp b/src/src/Globals/CPlugins.cpp index 83ec9d5ac3..bde5b12295 100644 --- a/src/src/Globals/CPlugins.cpp +++ b/src/src/Globals/CPlugins.cpp @@ -97,6 +97,9 @@ bool CPluginCall(CPlugin::Function Function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_TEN_PER_SECOND: case CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND: case CPlugin::Function::CPLUGIN_WRITE: + { + // Only CPLUGIN_WRITE might return a false + bool success = Function != CPlugin::Function::CPLUGIN_WRITE; if (Function == CPlugin::Function::CPLUGIN_INIT_ALL) { Function = CPlugin::Function::CPLUGIN_INIT; @@ -107,13 +110,14 @@ bool CPluginCall(CPlugin::Function Function, struct EventStruct *event, String& protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(x); event->ControllerIndex = x; String dummy; - const bool success = CPluginCall(ProtocolIndex, Function, event, dummy); + success = CPluginCall(ProtocolIndex, Function, event, dummy); if (success && Function == CPlugin::Function::CPLUGIN_WRITE) { return success; } } } - return true; + return success; + } // calls to specific controller case CPlugin::Function::CPLUGIN_INIT: From 6752949b070c01ece323b7e09ad67777eb2adc13 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 08:47:41 +0200 Subject: [PATCH 321/404] [Cleanup] Reduce bin size when using timing stats Reduce macro code --- src/src/DataStructs/TimingStats.cpp | 28 +++++++++++++++++++++++----- src/src/DataStructs/TimingStats.h | 14 ++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/src/DataStructs/TimingStats.cpp b/src/src/DataStructs/TimingStats.cpp index 0edc2c44fc..a8f2773cb9 100644 --- a/src/src/DataStructs/TimingStats.cpp +++ b/src/src/DataStructs/TimingStats.cpp @@ -258,13 +258,31 @@ const __FlashStringHelper * getMiscStatsName_F(int stat) { String getMiscStatsName(int stat) { if (stat >= C001_DELAY_QUEUE && stat <= C025_DELAY_QUEUE) { - String result; - result.reserve(16); - result = F("Delay queue "); - result += get_formatted_Controller_number(static_cast(stat - C001_DELAY_QUEUE + 1)); - return result; + return concat( + F("Delay queue "), + get_formatted_Controller_number(static_cast(stat - C001_DELAY_QUEUE + 1))); } return getMiscStatsName_F(stat); } +void stopTimerTask(int T, int F, uint64_t statisticsTimerStart) +{ + if (mustLogFunction(F)) pluginStats[(T) * 256 + (F)].add(usecPassedSince(statisticsTimerStart)); +} + +void stopTimerController(int T, CPlugin::Function F, uint64_t statisticsTimerStart) +{ + if (mustLogCFunction(F)) controllerStats[(T) * 256 + static_cast(F)].add(usecPassedSince(statisticsTimerStart)); +} + +void stopTimer(int L, uint64_t statisticsTimerStart) +{ + if (Settings.EnableTimingStats()) { miscStats[L].add(usecPassedSince(statisticsTimerStart)); } +} + +void addMiscTimerStat(int L, int64_t T) +{ + if (Settings.EnableTimingStats()) { miscStats[L].add(T); } +} + #endif // if FEATURE_TIMING_STATS \ No newline at end of file diff --git a/src/src/DataStructs/TimingStats.h b/src/src/DataStructs/TimingStats.h index 06088be8c6..6f59cc6cc8 100644 --- a/src/src/DataStructs/TimingStats.h +++ b/src/src/DataStructs/TimingStats.h @@ -129,6 +129,10 @@ const __FlashStringHelper * getCPluginCFunctionName(CPlugin::Function function); bool mustLogCFunction(CPlugin::Function function); String getMiscStatsName(int stat); +void stopTimerTask(int T, int F, uint64_t statisticsTimerStart); +void stopTimerController(int T, CPlugin::Function F, uint64_t statisticsTimerStart); +void stopTimer(int L, uint64_t statisticsTimerStart); +void addMiscTimerStat(int L, int64_t T); extern std::map pluginStats; extern std::map controllerStats; @@ -136,16 +140,14 @@ extern std::map miscStats; extern unsigned long timingstats_last_reset; # define START_TIMER const uint64_t statisticsTimerStart(getMicros64()); -# define STOP_TIMER_TASK(T, F) \ - if (mustLogFunction(F)) pluginStats[(T) * 256 + (F)].add(usecPassedSince(statisticsTimerStart)); -# define STOP_TIMER_CONTROLLER(T, F) \ - if (mustLogCFunction(F)) controllerStats[(T) * 256 + static_cast(F)].add(usecPassedSince(statisticsTimerStart)); +# define STOP_TIMER_TASK(T, F) stopTimerTask(T, F, statisticsTimerStart); +# define STOP_TIMER_CONTROLLER(T, F) stopTimerController(T, F, statisticsTimerStart); // #define STOP_TIMER_LOADFILE miscStats[LOADFILE_STATS].add(usecPassedSince(statisticsTimerStart)); -# define STOP_TIMER(L) if (Settings.EnableTimingStats()) { miscStats[L].add(usecPassedSince(statisticsTimerStart)); } +# define STOP_TIMER(L) stopTimer(L, statisticsTimerStart); // Add a timer statistic value in usec. -# define ADD_TIMER_STAT(L, T) if (Settings.EnableTimingStats()) { miscStats[L].add(T); } +# define ADD_TIMER_STAT(L, T) addMiscTimerStat(L, T); #else // if FEATURE_TIMING_STATS From 6a602a68f536692395f3b41f5b120bd491b20118 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 13:23:04 +0200 Subject: [PATCH 322/404] [Serial] Make Serial port for ESPEasy console/log configurable --- src/src/CustomBuild/define_plugin_sets.h | 3 +++ src/src/DataStructs_templ/SettingsStruct.cpp | 4 ++-- src/src/ESPEasyCore/Serial.h | 6 ++++++ src/src/WebServer/AdvancedConfigPage.cpp | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 92c9b7195e..e3e47ca35a 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2341,5 +2341,8 @@ To create/register a plugin, you have to : #endif #endif +#ifndef FEATURE_DEFINE_SERIAL_CONSOLE_PORT + #define FEATURE_DEFINE_SERIAL_CONSOLE_PORT 0 +#endif #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 9a2d6504f1..6ff91e9cbc 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -491,8 +491,8 @@ void SettingsStruct_tmpl::clearMisc() { deepSleep_wakeTime = 0; CustomCSS = false; WDI2CAddress = 0; - UseRules = false; - UseSerial = true; + UseRules = DEFAULT_USE_RULES; + UseSerial = DEFAULT_USE_SERIAL; UseSSDP = false; WireClockStretchLimit = 0; I2C_clockSpeed = 400000; diff --git a/src/src/ESPEasyCore/Serial.h b/src/src/ESPEasyCore/Serial.h index 4c219b80fb..7ce885cf76 100644 --- a/src/src/ESPEasyCore/Serial.h +++ b/src/src/ESPEasyCore/Serial.h @@ -43,5 +43,11 @@ void serialPrintln(); void serialPrintln(unsigned long value); */ +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT + #define ESPEASY_SERIAL_CONSOLE_PORT +#else + // Using the standard Serial0 HW serial port. + #define ESPEASY_SERIAL_CONSOLE_PORT Serial +#endif #endif // ifndef ESPEASYCORE_SERIAL_H diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index f9b5212c86..d575f46c3c 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -207,7 +207,7 @@ void handle_advanced() { addFormSubHeader(F("Serial Settings")); - addFormCheckBox(F("Enable Serial port"), F("useserial"), Settings.UseSerial); + addFormCheckBox(F("Enable Serial Port Console"), F("useserial"), Settings.UseSerial); addFormNumericBox(F("Baud Rate"), F("baudrate"), Settings.BaudRate, 0, 1000000); From a01f861ed2a703ae7d7347c184d8c77c6e3fb13c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 13:30:22 +0200 Subject: [PATCH 323/404] [Serial] Rename Serial. to ESPEASY_SERIAL_CONSOLE_PORT. --- src/ESPEasy.ino | 2 +- src/_P040_ID12.ino | 8 +- src/_P077_CSE7766.ino | 6 +- src/_P091_SerSwitch.ino | 148 ++++++++++----------- src/_Plugin_Helper.h | 1 + src/src/ESPEasyCore/ESPEasy_Log.cpp | 4 +- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 +- src/src/ESPEasyCore/Serial.cpp | 20 +-- src/src/Helpers/Misc.cpp | 10 +- src/src/Helpers/Networking.cpp | 5 +- src/src/Helpers/OTA.cpp | 2 +- src/src/PluginStructs/P077_data_struct.cpp | 4 +- src/src/PluginStructs/P090_data_struct.cpp | 18 +-- src/src/WebServer/Rules.cpp | 53 ++++---- 14 files changed, 144 insertions(+), 141 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index d81f72b92b..daf64129e1 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -127,7 +127,7 @@ void preinit(); void preinit() { system_phy_set_powerup_option(3); // Global WiFi constructors are not called yet - // (global class instances like WiFi, Serial... are not yet initialized).. + // (global class instances like WiFi, Serial.... are not yet initialized).. // No global object methods or C++ exceptions can be called in here! // The below is a static class method, which is similar to a function, so it's ok. #ifndef CORE_POST_3_0_0 diff --git a/src/_P040_ID12.ino b/src/_P040_ID12.ino index 3e6b17db2f..5731bd2672 100644 --- a/src/_P040_ID12.ino +++ b/src/_P040_ID12.ino @@ -50,7 +50,7 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { Plugin_040_init = true; - Serial.begin(9600); + ESPEASY_SERIAL_CONSOLE_PORT.begin(9600); success = true; break; } @@ -77,12 +77,12 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) uint8_t bytesread = 0; uint8_t tempbyte = 0; - if ((val = Serial.read()) == 2) + if ((val = ESPEASY_SERIAL_CONSOLE_PORT.read()) == 2) { // check for header bytesread = 0; while (bytesread < 12) { // read 10 digit code + 2 digit checksum - if ( Serial.available() > 0) { - val = Serial.read(); + if ( ESPEASY_SERIAL_CONSOLE_PORT.available() > 0) { + val = ESPEASY_SERIAL_CONSOLE_PORT.read(); if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { // if header or stop bytes before the 10 digit reading break; diff --git a/src/_P077_CSE7766.ino b/src/_P077_CSE7766.ino index da96da5d83..8752dfb044 100644 --- a/src/_P077_CSE7766.ino +++ b/src/_P077_CSE7766.ino @@ -96,8 +96,8 @@ boolean Plugin_077(uint8_t function, struct EventStruct *event, String& string) disableSerialLog(); // disable logging on serial port (used for CSE7766 // communication) Settings.BaudRate = 4800; // set BaudRate for CSE7766 - Serial.flush(); - Serial.begin(Settings.BaudRate, SERIAL_8E1); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.begin(Settings.BaudRate, SERIAL_8E1); success = true; break; } @@ -214,7 +214,7 @@ boolean Plugin_077(uint8_t function, struct EventStruct *event, String& string) log += '/'; log += P077_data->count_max; log += '/'; - log += Serial.available(); + log += ESPEASY_SERIAL_CONSOLE_PORT.available(); addLogMove(LOG_LEVEL_DEBUG, log); log = F("CSE: nr "); log += P077_data->count_pkt; diff --git a/src/_P091_SerSwitch.ino b/src/_P091_SerSwitch.ino index 7dd017d5e4..43c526ba45 100644 --- a/src/_P091_SerSwitch.ino +++ b/src/_P091_SerSwitch.ino @@ -225,13 +225,13 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) Plugin_091_ownindex = event->TaskIndex; Settings.UseSerial = true; // make sure that serial enabled Settings.SerialLogLevel = 0; // and logging disabled - Serial.setDebugOutput(false); // really, disable it! + ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(false); // really, disable it! log = F("SerSW : Init "); if (PCONFIG(0) == SER_SWITCH_YEWE) { Plugin_091_numrelay = PCONFIG(1); - Serial.begin(9600, SERIAL_8N1); - Serial.setRxBufferSize(BUFFER_SIZE); // Arduino core for ESP8266 WiFi chip 2.4.0 + ESPEASY_SERIAL_CONSOLE_PORT.begin(9600, SERIAL_8N1); + ESPEASY_SERIAL_CONSOLE_PORT.setRxBufferSize(BUFFER_SIZE); // Arduino core for ESP8266 WiFi chip 2.4.0 delay(1); getmcustate(); // request status on startup log += F(" Yewe "); @@ -241,7 +241,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (PCONFIG(0) == SER_SWITCH_SONOFFDUAL) { Plugin_091_numrelay = 3; // 3rd button is the "wifi" button - Serial.begin(19230, SERIAL_8N1); + ESPEASY_SERIAL_CONSOLE_PORT.begin(19230, SERIAL_8N1); log += F(" Sonoff Dual"); } if (PCONFIG(0) == SER_SWITCH_LCTECH) @@ -280,7 +280,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) break; } } - Serial.begin(Plugin_091_speed, SERIAL_8N1); + ESPEASY_SERIAL_CONSOLE_PORT.begin(Plugin_091_speed, SERIAL_8N1); log += F(" LCTech "); log += Plugin_091_speed; log += F(" baud "); @@ -292,7 +292,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) Plugin_091_numrelay = 2; // 2nd button is the dimvalue Plugin_091_switchstate[1] = 255; Plugin_091_ostate[1] = 255; - Serial.begin(9600, SERIAL_8N1); + ESPEASY_SERIAL_CONSOLE_PORT.begin(9600, SERIAL_8N1); log += F(" Wifi Dimmer"); } @@ -329,10 +329,10 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (Plugin_091_init) { - while (Serial.available() > 0) { + while (ESPEASY_SERIAL_CONSOLE_PORT.available() > 0) { yield(); if (bytes_read < BUFFER_SIZE) { - serial_buf[bytes_read] = Serial.read(); + serial_buf[bytes_read] = ESPEASY_SERIAL_CONSOLE_PORT.read(); if (bytes_read == 0) { // packet start @@ -543,7 +543,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) bytes_read++; } } else - Serial.read(); // if buffer full, dump incoming + ESPEASY_SERIAL_CONSOLE_PORT.read(); // if buffer full, dump incoming } } // plugin initialized end success = true; @@ -826,14 +826,14 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) } void getmcustate() { - Serial.write(0x55); // Tuya header 55AA - Serial.write(0xAA); - Serial.write(0x00); // version 00 - Serial.write(0x08); // Tuya command 08 - request status - Serial.write(0x00); - Serial.write(0x00); - Serial.write(0x07); - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA + ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 + ESPEASY_SERIAL_CONSOLE_PORT.write(0x08); // Tuya command 08 - request status + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x07); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); } void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum_mode) // btnnum=0,1,2, state=0/1 @@ -844,19 +844,19 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum { case SER_SWITCH_YEWE: { - Serial.write(0x55); // Tuya header 55AA - Serial.write(0xAA); - Serial.write(0x00); // version 00 - Serial.write(0x06); // Tuya command 06 - send order - Serial.write(0x00); - Serial.write(0x05); // following data length 0x05 - Serial.write( (btnnum + 1) ); // relay number 1,2,3 - Serial.write(0x01); // ? - Serial.write(0x00); // ? - Serial.write(0x01); // ? - Serial.write( state ); // status - Serial.write((13 + btnnum + state)); // checksum:sum of all bytes in packet mod 256 - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA + ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 + ESPEASY_SERIAL_CONSOLE_PORT.write(0x06); // Tuya command 06 - send order + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x05); // following data length 0x05 + ESPEASY_SERIAL_CONSOLE_PORT.write( (btnnum + 1) ); // relay number 1,2,3 + ESPEASY_SERIAL_CONSOLE_PORT.write(0x01); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write(0x01); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write( state ); // status + ESPEASY_SERIAL_CONSOLE_PORT.write((13 + btnnum + state)); // checksum:sum of all bytes in packet mod 256 + ESPEASY_SERIAL_CONSOLE_PORT.flush(); break; } case SER_SWITCH_SONOFFDUAL: @@ -872,11 +872,11 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum Plugin_091_switchstate[1] = state; } sstate = Plugin_091_switchstate[0] + (Plugin_091_switchstate[1] << 1) + (Plugin_091_switchstate[2] << 2); - Serial.write(0xA0); - Serial.write(0x04); - Serial.write( sstate ); - Serial.write(0xA1); - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xA0); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x04); + ESPEASY_SERIAL_CONSOLE_PORT.write( sstate ); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xA1); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); break; } case SER_SWITCH_LCTECH: @@ -892,23 +892,23 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum delay(1); } if (Plugin_091_ipd) { - Serial.write(0x0D); - Serial.write(0x0A); - Serial.write(0x2B); - Serial.write(0x49); - Serial.write(0x50); - Serial.write(0x44); - Serial.write(0x2C); - Serial.write(0x30); - Serial.write(0x2C); - Serial.write(0x34); - Serial.write(0x3A); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x0D); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x0A); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x2B); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x49); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x50); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x44); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x2C); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x30); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x2C); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x34); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x3A); } - Serial.write(0xA0); - Serial.write((0x01 + btnnum)); - Serial.write((0x00 + state)); - Serial.write((0xA1 + state + btnnum)); - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xA0); + ESPEASY_SERIAL_CONSOLE_PORT.write((0x01 + btnnum)); + ESPEASY_SERIAL_CONSOLE_PORT.write((0x00 + state)); + ESPEASY_SERIAL_CONSOLE_PORT.write((0xA1 + state + btnnum)); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); } break; @@ -952,33 +952,33 @@ void sendmcudim(uint8_t dimvalue, uint8_t swtype) { case SER_SWITCH_YEWE: { - Serial.write(0x55); // Tuya header 55AA - Serial.write(0xAA); - Serial.write(0x00); // version 00 - Serial.write(0x06); // Tuya command 06 - send order - Serial.write(0x00); - Serial.write(0x08); // following data length 0x08 - Serial.write(Plugin_091_numrelay); // dimmer order-id? select it at plugin settings 2/3!!! - Serial.write(0x02); // type=value - Serial.write(0x00); // length hi - Serial.write(0x04); // length low - Serial.write(0x00); // ? - Serial.write(0x00); // ? - Serial.write(0x00); // ? - Serial.write( dimvalue ); // dim value (0-255) - Serial.write( uint8_t(19 + Plugin_091_numrelay + dimvalue) ); // checksum:sum of all bytes in packet mod 256 - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA + ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 + ESPEASY_SERIAL_CONSOLE_PORT.write(0x06); // Tuya command 06 - send order + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x08); // following data length 0x08 + ESPEASY_SERIAL_CONSOLE_PORT.write(Plugin_091_numrelay); // dimmer order-id? select it at plugin settings 2/3!!! + ESPEASY_SERIAL_CONSOLE_PORT.write(0x02); // type=value + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // length hi + ESPEASY_SERIAL_CONSOLE_PORT.write(0x04); // length low + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? + ESPEASY_SERIAL_CONSOLE_PORT.write( dimvalue ); // dim value (0-255) + ESPEASY_SERIAL_CONSOLE_PORT.write( uint8_t(19 + Plugin_091_numrelay + dimvalue) ); // checksum:sum of all bytes in packet mod 256 + ESPEASY_SERIAL_CONSOLE_PORT.flush(); break; } case SER_SWITCH_WIFIDIMMER: { - Serial.write(0xFF); // Wifidimmer header FF55 - Serial.write(0x55); - Serial.write( dimvalue ); // dim value (0-255) - Serial.write(0x05); - Serial.write(0xDC); - Serial.write(0x0A); - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xFF); // Wifidimmer header FF55 + ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); + ESPEASY_SERIAL_CONSOLE_PORT.write( dimvalue ); // dim value (0-255) + ESPEASY_SERIAL_CONSOLE_PORT.write(0x05); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xDC); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x0A); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); Plugin_091_switchstate[1] = dimvalue; break; } diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 1ab83fad69..a99a9108a4 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -16,6 +16,7 @@ #include "src/ESPEasyCore/Controller.h" #include "src/ESPEasyCore/ESPEasy_Log.h" +#include "src/ESPEasyCore/Serial.h" #include "src/Globals/Cache.h" #include "src/Globals/Device.h" diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index 4fbe549881..01c3877508 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -90,13 +90,13 @@ void updateLogLevelCache() { const bool useSerial = Settings.UseSerial && !activeTaskUseSerial0(); if (log_to_serial_disabled) { if (useSerial) { - Serial.setDebugOutput(false); + ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(false); } } else { max_lvl = _max(max_lvl, Settings.SerialLogLevel); #ifndef BUILD_NO_DEBUG if (useSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) { - Serial.setDebugOutput(true); + ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); } #endif } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 2856dba467..c305301dcc 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -163,7 +163,7 @@ void ESPEasy_setup() checkRAM(F("setup")); #endif // ifndef BUILD_NO_RAM_TRACKER - Serial.begin(115200); + ESPEASY_SERIAL_CONSOLE_PORT.begin(115200); // serialPrint("\n\n\nBOOOTTT\n\n\n"); @@ -378,7 +378,7 @@ void ESPEasy_setup() # ifndef BUILD_NO_DEBUG if (Settings.UseSerial && (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)) { - Serial.setDebugOutput(true); + ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); } #endif diff --git a/src/src/ESPEasyCore/Serial.cpp b/src/src/ESPEasyCore/Serial.cpp index 78d2d81bc8..65fbc09682 100644 --- a/src/src/ESPEasyCore/Serial.cpp +++ b/src/src/ESPEasyCore/Serial.cpp @@ -25,15 +25,15 @@ void initSerial() } // make sure previous serial buffers are flushed before resetting baudrate - Serial.flush(); - Serial.begin(Settings.BaudRate); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.begin(Settings.BaudRate); - // Serial.setDebugOutput(true); + // ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); } void serial() { - if (Serial.available()) + if (ESPEASY_SERIAL_CONSOLE_PORT.available()) { String dummy; @@ -44,14 +44,14 @@ void serial() if (!Settings.UseSerial || activeTaskUseSerial0()) { return; } - while (Serial.available()) + while (ESPEASY_SERIAL_CONSOLE_PORT.available()) { delay(0); - SerialInByte = Serial.read(); + SerialInByte = ESPEASY_SERIAL_CONSOLE_PORT.read(); if (SerialInByte == 255) // binary data... { - Serial.flush(); + ESPEASY_SERIAL_CONSOLE_PORT.flush(); return; } @@ -68,7 +68,7 @@ void serial() break; } InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed - Serial.write('>'); + ESPEASY_SERIAL_CONSOLE_PORT.write('>'); serialPrintln(InputBuffer_Serial); ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SERIAL, InputBuffer_Serial); SerialInByteCounter = 0; @@ -134,7 +134,7 @@ void addNewlineToSerialBuffer() { void process_serialWriteBuffer() { if (serialWriteBuffer.size() == 0) { return; } - size_t snip = Serial.availableForWrite(); + size_t snip = ESPEASY_SERIAL_CONSOLE_PORT.availableForWrite(); if (snip > 0) { size_t bytes_to_write = serialWriteBuffer.size(); @@ -144,7 +144,7 @@ void process_serialWriteBuffer() { while (bytes_to_write > 0 && !serialWriteBuffer.empty()) { const char c = serialWriteBuffer.front(); if (Settings.UseSerial) { - Serial.write(c); + ESPEASY_SERIAL_CONSOLE_PORT.write(c); } serialWriteBuffer.pop_front(); --bytes_to_write; diff --git a/src/src/Helpers/Misc.cpp b/src/src/Helpers/Misc.cpp index 2ed67b7ca3..e06ed95941 100644 --- a/src/src/Helpers/Misc.cpp +++ b/src/src/Helpers/Misc.cpp @@ -234,13 +234,13 @@ String getTaskValueName(taskIndex_t TaskIndex, uint8_t TaskValueIndex) { void emergencyReset() { // Direct Serial is allowed here, since this is only an emergency task. - Serial.begin(115200); - Serial.write(0xAA); - Serial.write(0x55); + ESPEASY_SERIAL_CONSOLE_PORT.begin(115200); + ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); + ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); delay(1); - if (Serial.available() == 2) { - if ((Serial.read() == 0xAA) && (Serial.read() == 0x55)) + if (ESPEASY_SERIAL_CONSOLE_PORT.available() == 2) { + if ((ESPEASY_SERIAL_CONSOLE_PORT.read() == 0xAA) && (ESPEASY_SERIAL_CONSOLE_PORT.read() == 0x55)) { serialPrintln(F("\n\n\rSystem will reset to factory defaults in 10 seconds...")); delay(10000); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 3716d772f5..9c6f9edb03 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -9,6 +9,7 @@ #include "../ESPEasyCore/ESPEasy_backgroundtasks.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" +#include "../ESPEasyCore/Serial.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" @@ -901,7 +902,7 @@ bool hasIPaddr() { for (auto addr : addrList) { if ((configured = (!addr.isLocal() && (addr.ifnumber() == STATION_IF)))) { /* - Serial.printf("STA: IF='%s' hostname='%s' addr= %s\n", + ESPEASY_SERIAL_CONSOLE_PORT.printf("STA: IF='%s' hostname='%s' addr= %s\n", addr.ifname().c_str(), addr.ifhostname(), addr.toString().c_str()); @@ -1269,7 +1270,7 @@ String getDigestAuth(const String& authReq, F("\", response=\"") + response + '"'; - // Serial.println(authorization); + // ESPEASY_SERIAL_CONSOLE_PORT.println(authorization); return authorization; } diff --git a/src/src/Helpers/OTA.cpp b/src/src/Helpers/OTA.cpp index fba3e33352..fdf88d5586 100644 --- a/src/src/Helpers/OTA.cpp +++ b/src/src/Helpers/OTA.cpp @@ -84,7 +84,7 @@ void ArduinoOTAInit() }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { if (Settings.UseSerial) { - Serial.printf("OTA : Progress %u%%\r", (progress / (total / 100))); + ESPEASY_SERIAL_CONSOLE_PORT.printf("OTA : Progress %u%%\r", (progress / (total / 100))); } }); diff --git a/src/src/PluginStructs/P077_data_struct.cpp b/src/src/PluginStructs/P077_data_struct.cpp index a3ecc9b0b4..a00cec1c4c 100644 --- a/src/src/PluginStructs/P077_data_struct.cpp +++ b/src/src/PluginStructs/P077_data_struct.cpp @@ -106,8 +106,8 @@ bool P077_data_struct::processSerialData() { long t_start = millis(); bool found = false; - while (Serial.available() > 0 && !found) { - uint8_t serial_in_byte = Serial.read(); + while (ESPEASY_SERIAL_CONSOLE_PORT.available() > 0 && !found) { + uint8_t serial_in_byte = ESPEASY_SERIAL_CONSOLE_PORT.read(); count_bytes++; checksum -= serial_in_buffer[2]; // substract from checksum data to be removed memmove(serial_in_buffer, serial_in_buffer + 1, diff --git a/src/src/PluginStructs/P090_data_struct.cpp b/src/src/PluginStructs/P090_data_struct.cpp index 3b54909053..707b659908 100644 --- a/src/src/PluginStructs/P090_data_struct.cpp +++ b/src/src/PluginStructs/P090_data_struct.cpp @@ -229,7 +229,7 @@ CCS811Core::status CCS811::begin(void) delay(200); // returnError = setDriveMode(1); //Read every second - // Serial.println(); + // ESPEASY_SERIAL_CONSOLE_PORT.println(); return returnError; } // CCS811::begin @@ -346,11 +346,11 @@ CCS811Core::status CCS811::enableInterrupts(void) return returnError; } - // Serial.println(value, HEX); + // ESPEASY_SERIAL_CONSOLE_PORT.println(value, HEX); value |= (1 << 3); // Set INTERRUPT bit writeRegister(CSS811_MEAS_MODE, value); - // Serial.println(value, HEX); + // ESPEASY_SERIAL_CONSOLE_PORT.println(value, HEX); return returnError; } @@ -466,14 +466,14 @@ CCS811Core::status CCS811::readNTC(void) vrefCounts = (static_cast(data[CSS811_NTC + 0]) << 8) | data[CSS811_NTC + 1]; - // Serial.print("vrefCounts: "); - // Serial.println(vrefCounts); + // ESPEASY_SERIAL_CONSOLE_PORT.print("vrefCounts: "); + // ESPEASY_SERIAL_CONSOLE_PORT.println(vrefCounts); ntcCounts = (static_cast(data[CSS811_NTC + 2]) << 8) | data[CSS811_NTC + 3]; - // Serial.print("ntcCounts: "); - // Serial.println(ntcCounts); - // Serial.print("sum: "); - // Serial.println(ntcCounts + vrefCounts); + // ESPEASY_SERIAL_CONSOLE_PORT.print("ntcCounts: "); + // ESPEASY_SERIAL_CONSOLE_PORT.println(ntcCounts); + // ESPEASY_SERIAL_CONSOLE_PORT.print("sum: "); + // ESPEASY_SERIAL_CONSOLE_PORT.println(ntcCounts + vrefCounts); resistance = (static_cast(ntcCounts) * refResistance / static_cast(vrefCounts)); // Code from Milan Malesevic and Zoran Stupic, 2011, diff --git a/src/src/WebServer/Rules.cpp b/src/src/WebServer/Rules.cpp index 1e8370200f..004af02af1 100644 --- a/src/src/WebServer/Rules.cpp +++ b/src/src/WebServer/Rules.cpp @@ -13,6 +13,7 @@ #include "../WebServer/Markup_Forms.h" #include "../ESPEasyCore/ESPEasyRules.h" +#include "../ESPEasyCore/Serial.h" #include "../Globals/Settings.h" #include "../Helpers/ESPEasy_Storage.h" @@ -175,8 +176,8 @@ void handle_rules_new() { [/*&buffer,*/ &count, endIdx](fileInfo fi) { # ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("Start generation of: ")); - Serial.println(fi.Name); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Start generation of: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(fi.Name); # endif // ifdef WEBSERVER_RULES_DEBUG if (fi.isDirectory) @@ -227,8 +228,8 @@ void handle_rules_new() { } addHtml(F("")); # ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("End generation of: ")); - Serial.println(fi.Name); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("End generation of: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(fi.Name); # endif // ifdef WEBSERVER_RULES_DEBUG return count < endIdx; @@ -275,7 +276,7 @@ void handle_rules_backup() { } # ifdef WEBSERVER_NEW_RULES # ifdef WEBSERVER_RULES_DEBUG - Serial.println(F("handle rules backup")); + ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle rules backup")); # endif // ifdef WEBSERVER_RULES_DEBUG if (!isLoggedIn() || !Settings.UseRules) { return; } @@ -347,9 +348,9 @@ void handle_rules_delete() { fileName = fileName.substring(0, fileName.length() - 4); bool removed = false; # ifdef WEBSERVER_RULES_DEBUG - Serial.println(F("handle_rules_delete")); - Serial.print(F("File name: ")); - Serial.println(fileName); + ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle_rules_delete")); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("File name: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(fileName); # endif // ifdef WEBSERVER_RULES_DEBUG if (fileName.length() > 0) @@ -392,8 +393,8 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { bool handle = false; # ifdef WEBSERVER_RULES_DEBUG - Serial.println(originalUri); - Serial.println(F("handle_rules_edit")); + ESPEASY_SERIAL_CONSOLE_PORT.println(originalUri); + ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle_rules_edit")); # endif // ifdef WEBSERVER_RULES_DEBUG if (isAddNew || (originalUri.startsWith(F("/rules/")) @@ -431,8 +432,8 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { eventName = FileNameToEvent(fileName); } # ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("File name: ")); - Serial.println(fileName); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("File name: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(fileName); # endif // ifdef WEBSERVER_RULES_DEBUG bool isEdit = fileExists(fileName); @@ -501,16 +502,16 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { bool isReadOnly = !isOverwrite && ((isEdit && !isAddNew && !isNew) || (isAddNew && isNew)); # ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("Is Overwrite: ")); - Serial.println(isOverwrite); - Serial.print(F("Is edit: ")); - Serial.println(isEdit); - Serial.print(F("Is addnew: ")); - Serial.println(isAddNew); - Serial.print(F("Is New: ")); - Serial.println(isNew); - Serial.print(F("Is Read Only: ")); - Serial.println(isReadOnly); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is Overwrite: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(isOverwrite); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is edit: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(isEdit); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is addnew: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(isAddNew); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is New: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(isNew); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is Read Only: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(isReadOnly); # endif // ifdef WEBSERVER_RULES_DEBUG addFormTextBox(F("Event name") // Label @@ -571,8 +572,8 @@ void Rule_showRuleTextArea(const String& fileName) { bool Rule_Download(const String& path) { # ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("Rule_Download path: ")); - Serial.println(path); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Rule_Download path: ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(path); # endif // ifdef WEBSERVER_RULES_DEBUG fs::File dataFile = tryOpenFile(path, "r"); @@ -609,8 +610,8 @@ bool EnumerateFileAndDirectory(String & rootPath # ifdef ESP8266 fs::Dir dir = ESPEASY_FS.openDir(rootPath); - Serial.print(F("Enumerate files of ")); - Serial.println(rootPath); + ESPEASY_SERIAL_CONSOLE_PORT.print(F("Enumerate files of ")); + ESPEASY_SERIAL_CONSOLE_PORT.println(rootPath); while (next && dir.next()) { // Skip files From e433288ac48a60efddfe37a5e97a4f530c0c7d75 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 18:04:19 +0200 Subject: [PATCH 324/404] [Factory Default] Fix default settings for SSID2 --- src/Custom-sample.h | 1 + src/src/CustomBuild/ESPEasyDefaults.h | 3 +++ src/src/Helpers/ESPEasy_FactoryDefault.cpp | 3 +-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 1081dd2b50..cea29a4c8b 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -92,6 +92,7 @@ #define DEFAULT_USE_EXTD_CONTROLLER_CREDENTIALS false // true: Allow longer user credentials for controllers #define DEFAULT_PORT 8080 // Enter your Server port value +#define DEFAULT_CONTROLLER_TIMEOUT 100 // Default timeout in msec #define DEFAULT_PROTOCOL 0 // Protocol used for controller communications // 0 = Stand-alone (no controller set) diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index 7829ef9e87..f1064b64f5 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -140,6 +140,9 @@ #ifndef DEFAULT_CONTROLLER_PASS #define DEFAULT_CONTROLLER_PASS "" // Default controller Password #endif +#ifndef DEFAULT_CONTROLLER_TIMEOUT +#define DEFAULT_CONTROLLER_TIMEOUT 100 +#endif // using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol ! #ifndef DEFAULT_PUB diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 2695c43cb6..7fcb9583f8 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -173,8 +173,6 @@ void ResetFactory() strcpy_P(SecuritySettings.WifiSSID2, PSTR(DEFAULT_SSID2)); strcpy_P(SecuritySettings.WifiKey2, PSTR(DEFAULT_KEY2)); strcpy_P(SecuritySettings.WifiAPKey, PSTR(DEFAULT_AP_KEY)); - SecuritySettings.WifiSSID2[0] = 0; - SecuritySettings.WifiKey2[0] = 0; } strcpy_P(SecuritySettings.Password, PSTR(DEFAULT_ADMIN_PASS)); @@ -281,6 +279,7 @@ void ResetFactory() ControllerSettings.UseDNS = DEFAULT_SERVER_USEDNS; ControllerSettings.useExtendedCredentials(DEFAULT_USE_EXTD_CONTROLLER_CREDENTIALS); ControllerSettings.Port = DEFAULT_PORT; + ControllerSettings.ClientTimeout = DEFAULT_CONTROLLER_TIMEOUT; setControllerUser(0, ControllerSettings, F(DEFAULT_CONTROLLER_USER)); setControllerPass(0, ControllerSettings, F(DEFAULT_CONTROLLER_PASS)); From e4541513014eba80c1daf2a9bc779781fc05ec46 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 Oct 2022 11:33:33 +0200 Subject: [PATCH 325/404] [WiFi] Reduce time needed to connect to WiFi --- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 9 ++++++--- src/src/ESPEasyCore/ESPEasyWifi.cpp | 5 ++++- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 4 +++- src/src/ESPEasyCore/ESPEasy_setup.cpp | 1 + src/src/WebServer/SysInfoPage.cpp | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 7d49b205ab..c6c97a8820 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -359,7 +359,8 @@ void onDisconnect(const WiFiEventStationModeDisconnected& event) { if (WiFi.status() == WL_CONNECTED) { // See https://github.com/esp8266/Arduino/issues/5912 WiFi.persistent(false); - WiFi.disconnect(true); + WiFi.disconnect(false); + delay(0); } } @@ -423,8 +424,10 @@ void onWiFiScanDone(void *arg, STATUS status) { } WiFiMode_t mode = WiFi.getMode(); - //WiFi.mode(WIFI_OFF); - WiFi.mode(mode); + setWifiMode(WIFI_OFF); + delay(1); + setWifiMode(mode); + delay(1); } #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e4bb8af93e..a2c3326dd1 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -454,6 +454,7 @@ void AttemptWiFiConnect() { } else { WiFi.begin(candidate.ssid.c_str(), candidate.key.c_str()); } + delay(1); } else { WiFiEventData.wifiConnectInProgress = false; } @@ -631,7 +632,8 @@ void initWiFi() WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters // The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections, // those WiFi connections will take a long time to make or sometimes will not work at all. - WiFi.disconnect(true); + WiFi.disconnect(false); + delay(1); WifiScan(false); setWifiMode(WIFI_OFF); @@ -871,6 +873,7 @@ void WifiDisconnect() #endif #ifdef ESP32 WiFi.disconnect(); + delay(1); WiFi.removeEvent(wm_event_id); { const IPAddress ip; diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index f515ae15f2..d6509094cd 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -231,10 +231,12 @@ void handle_unprocessedNetworkEvents() if (!WiFi.getAutoConnect()) { WiFi.setAutoConnect(true); + delay(1); } } else { if (WiFi.getAutoConnect()) { WiFi.setAutoConnect(false); + delay(1); } } } @@ -667,7 +669,7 @@ void processScanDone() { } #endif - setSTA(false); +// setSTA(false); NetworkConnectRelaxed(); #ifdef USES_ESPEASY_NOW temp_disable_EspEasy_now_timer = millis() + 20000; diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index c305301dcc..5fd31459f4 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -333,6 +333,7 @@ void ESPEasy_setup() // It appears reconnecting from RTC may take just as long to be able to send first packet as performing a scan first and then connect. // Perhaps the WiFi radio needs some time to stabilize first? WifiScan(false); + setWifiMode(WIFI_OFF); } #ifndef BUILD_NO_RAM_TRACKER logMemUsageAfter(F("WifiScan()")); diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index f10435821a..2aad01366c 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -238,7 +238,7 @@ void handle_sysinfo() { addHtml(F("")); // Needed to get the copy button on the same header line. addCopyButton(F("copyText"), F("\\n"), F("Copy info to clipboard")); - TXBuffer += githublogo; + TXBuffer.addFlashString((PGM_P)FPSTR(githublogo)); serve_JS(JSfiles_e::GitHubClipboard); # else // ifdef WEBSERVER_GITHUB_COPY From 4db381e4ea027b0e8d4372652ba5f8ae24e35d02 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 9 Oct 2022 00:26:03 +0200 Subject: [PATCH 326/404] [WiFi Setup] Fix serving CSS on initial WiFi setup --- src/src/WebServer/ESPEasy_WebServer.cpp | 7 +++-- src/src/WebServer/LoadFromFS.cpp | 38 ++++++++++++++++++++----- src/src/WebServer/LoadFromFS.h | 1 + src/src/WebServer/SetupPage.cpp | 13 +++++---- src/src/WebServer/WebTemplateParser.cpp | 10 +++++-- src/src/WebServer/WebTemplateParser.h | 1 + 6 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index 595a73494b..ce8f4b21e8 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -382,10 +382,11 @@ void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser const bool addJS = true; const bool addMeta = true; +/* if (tmplName.equals(F("TmplAP"))) { - getWebPageTemplateDefaultHead(parser, !addMeta, !addJS); + getWebPageTemplateDefaultHead(parser, addMeta, !addJS); if (!parser.isTail()) { #ifndef WEBPAGE_TEMPLATE_AP_HEADER @@ -404,7 +405,9 @@ void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser getWebPageTemplateDefaultContentSection(parser); getWebPageTemplateDefaultFooter(parser); } - else if (tmplName.equals(F("TmplMsg"))) + else + */ + if (tmplName.equals(F("TmplMsg"))) { getWebPageTemplateDefaultHead(parser, !addMeta, !addJS); if (!parser.isTail()) { diff --git a/src/src/WebServer/LoadFromFS.cpp b/src/src/WebServer/LoadFromFS.cpp index 7780fdfd3d..601da2293d 100644 --- a/src/src/WebServer/LoadFromFS.cpp +++ b/src/src/WebServer/LoadFromFS.cpp @@ -74,23 +74,47 @@ bool fileIsEmbedded(const String& path) { return false; } -void serveEmbedded(const String& path, const String& contentType) { +void do_serveEmbedded(const __FlashStringHelper* contentType, PGM_P content, bool serve_inline) { + // Serve using our own Web_StreamingBuffer + // Serving via web_server.send_P may cause memory allocation issues when sending large flash strings. + if (!serve_inline) { + TXBuffer.startStream(contentType, F("*"), 200); + } + TXBuffer.addFlashString(content); + if (!serve_inline) { + TXBuffer.endStream(); + } +} + +void serveEmbedded(const String& path, const __FlashStringHelper* contentType, bool serve_inline) { #if defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS) if (matchFilename(path, F("esp.css"))) { - web_server.send_P(200, contentType.c_str(), (PGM_P)FPSTR(DATA_ESPEASY_DEFAULT_MIN_CSS)); + do_serveEmbedded(contentType, (PGM_P)FPSTR(DATA_ESPEASY_DEFAULT_MIN_CSS), serve_inline); return; } #endif // if defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS) #ifdef WEBSERVER_FAVICON if (matchFilename(path, F("favicon.ico"))) { - web_server.send_P(200, contentType.c_str(), favicon_8b_ico, favicon_8b_ico_len); + do_serveEmbedded(contentType, (PGM_P)FPSTR(favicon_8b_ico), false); return; } #endif // ifdef WEBSERVER_FAVICON } + +void serve_CSS_inline() { + const __FlashStringHelper* fname = F("esp.css"); + addHtml(F("")); +} + // ******************************************************************************** // Match static files and strip "static_xxx_" prefix // ******************************************************************************** @@ -214,7 +238,7 @@ bool loadFromFS(String path) { #endif // ifdef WEBSERVER_CUSTOM bool mustCheckCredentials = false; - const String contentType = get_ContentType(path, mustCheckCredentials); + const __FlashStringHelper* contentType = get_ContentType(path, mustCheckCredentials); const bool serve_304 = static_file && reply_304_not_modified(path); // Reply with a 304 Not Modified @@ -250,7 +274,7 @@ bool loadFromFS(String path) { } if (serve_304) { - web_server.send(304, contentType, EMPTY_STRING); + web_server.send(304, String(contentType), EMPTY_STRING); } else { if (fileExists(path)) { fs::File f = tryOpenFile(path.c_str(), "r"); @@ -258,14 +282,14 @@ bool loadFromFS(String path) { if (!f) { return false; } - web_server.streamFile(f, contentType); + web_server.streamFile(f, String(contentType)); f.close(); } if (!fileEmbedded) { return false; } - serveEmbedded(path, contentType); + serveEmbedded(path, contentType, false); } statusLED(true); diff --git a/src/src/WebServer/LoadFromFS.h b/src/src/WebServer/LoadFromFS.h index 88c702abdd..ac66631fcf 100644 --- a/src/src/WebServer/LoadFromFS.h +++ b/src/src/WebServer/LoadFromFS.h @@ -6,6 +6,7 @@ bool loadFromFS(String path); +void serve_CSS_inline(); // Send the content of a file directly to the webserver, like addHtml() // Return is nr bytes streamed. diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index 8061872d09..2d54870719 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -52,12 +52,13 @@ void handle_setup() { const bool connected = NetworkConnected(); - if (connected) { - navMenuIndex = MENU_INDEX_TOOLS; +// if (connected) { + navMenuIndex = MENU_INDEX_SETUP; sendHeadandTail_stdtemplate(_HEAD); - } else { +/* } else { sendHeadandTail(F("TmplAP")); } + */ const bool clearButtonPressed = hasArg(F("performclearcredentials")); const bool clearWiFiCredentials = @@ -216,12 +217,12 @@ void handle_setup() { html_end_form(); } - if (connected) { +// if (connected) { sendHeadandTail_stdtemplate(_TAIL); - } else { +/* } else { sendHeadandTail(F("TmplAP"), true); } - +*/ TXBuffer.endStream(); delay(10); if (clearWiFiCredentials) { diff --git a/src/src/WebServer/WebTemplateParser.cpp b/src/src/WebServer/WebTemplateParser.cpp index dceeddf2bd..80b9c0f0de 100644 --- a/src/src/WebServer/WebTemplateParser.cpp +++ b/src/src/WebServer/WebTemplateParser.cpp @@ -12,7 +12,7 @@ #include "../Static/WebStaticData.h" #include "../WebServer/HTML_wrappers.h" - +#include "../WebServer/LoadFromFS.h" #include "../../ESPEasy_common.h" @@ -301,7 +301,6 @@ void WebTemplateParser::getWebPageTemplateVar(const String& varName) #endif // if !FEATURE_NOTIFIER addHtml(F("'); @@ -325,7 +324,12 @@ void WebTemplateParser::getWebPageTemplateVar(const String& varName) else if (varName.equals(F("css"))) { serve_favicon(); - serve_CSS(CSSfiles_e::ESPEasy_default); + if (MENU_INDEX_SETUP == navMenuIndex) { + // Serve embedded CSS + serve_CSS_inline(); + } else { + serve_CSS(CSSfiles_e::ESPEasy_default); + } #if FEATURE_RULES_EASY_COLOR_CODE if (MENU_INDEX_RULES == navMenuIndex || MENU_INDEX_CUSTOM_PAGE == navMenuIndex) { diff --git a/src/src/WebServer/WebTemplateParser.h b/src/src/WebServer/WebTemplateParser.h index 52509efd24..e0becbe533 100644 --- a/src/src/WebServer/WebTemplateParser.h +++ b/src/src/WebServer/WebTemplateParser.h @@ -20,6 +20,7 @@ #define MENU_INDEX_RULES 5 #define MENU_INDEX_NOTIFICATIONS 6 #define MENU_INDEX_TOOLS 7 +#define MENU_INDEX_SETUP 254 #define MENU_INDEX_CUSTOM_PAGE 255 extern uint8_t navMenuIndex; From 096b18cfde60102e6dd193f475b22ac60c3895e2 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 10 Oct 2022 10:35:27 +0200 Subject: [PATCH 327/404] [Webserver] Fix strange crashes when serving flash strings --- src/src/DataStructs/Web_StreamingBuffer.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/src/DataStructs/Web_StreamingBuffer.cpp b/src/src/DataStructs/Web_StreamingBuffer.cpp index ea48845922..9a76872463 100644 --- a/src/src/DataStructs/Web_StreamingBuffer.cpp +++ b/src/src/DataStructs/Web_StreamingBuffer.cpp @@ -103,25 +103,18 @@ Web_StreamingBuffer& Web_StreamingBuffer::addFlashString(PGM_P str) { int flush_step = CHUNKED_BUFFER_SIZE - this->buf.length(); if (flush_step < 1) { flush_step = 0; } -/* + + /* // This part does act strange on 1 heap builds // See: https://github.com/letscontrolit/ESPEasy/pull/3680#issuecomment-1031716163 if (length < static_cast(flush_step)) { // Just use the faster String operator to copy flash strings. - this->buf += str; + // Very likely casting it to FPSTR first does fix the crashes, but it does not yield any noticable speed improvements + this->buf += FPSTR(str); return *this; } -*/ - // FIXME TD-er: Not sure what happens, but streaming large flash chunks does cause allocation issues. - const bool stream_P = ESP.getFreeHeap() > 4000 && - length > (CHUNKED_BUFFER_SIZE >> 2) && - length < (2 * CHUNKED_BUFFER_SIZE); - - if (stream_P && ((this->buf.length() + length) > CHUNKED_BUFFER_SIZE)) { - // Do not copy to the internal buffer, but stream immediately. - flush(); - web_server.sendContent_P(str); - } else { + */ + { // Copy to internal buffer and send in chunks unsigned int pos = 0; while (pos < length) { From a3658d6f75adad84708554f3ffe5245a7e9a574c Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 13:23:04 +0200 Subject: [PATCH 328/404] Revert "[Serial] Make Serial port for ESPEasy console/log configurable" This reverts commit 6a602a68f536692395f3b41f5b120bd491b20118. --- src/src/CustomBuild/define_plugin_sets.h | 3 --- src/src/DataStructs_templ/SettingsStruct.cpp | 4 ++-- src/src/ESPEasyCore/Serial.h | 6 ------ src/src/WebServer/AdvancedConfigPage.cpp | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 68bc72a59d..c706ce4eff 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2374,8 +2374,5 @@ To create/register a plugin, you have to : #endif #endif -#ifndef FEATURE_DEFINE_SERIAL_CONSOLE_PORT - #define FEATURE_DEFINE_SERIAL_CONSOLE_PORT 0 -#endif #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 6ff91e9cbc..9a2d6504f1 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -491,8 +491,8 @@ void SettingsStruct_tmpl::clearMisc() { deepSleep_wakeTime = 0; CustomCSS = false; WDI2CAddress = 0; - UseRules = DEFAULT_USE_RULES; - UseSerial = DEFAULT_USE_SERIAL; + UseRules = false; + UseSerial = true; UseSSDP = false; WireClockStretchLimit = 0; I2C_clockSpeed = 400000; diff --git a/src/src/ESPEasyCore/Serial.h b/src/src/ESPEasyCore/Serial.h index 7ce885cf76..4c219b80fb 100644 --- a/src/src/ESPEasyCore/Serial.h +++ b/src/src/ESPEasyCore/Serial.h @@ -43,11 +43,5 @@ void serialPrintln(); void serialPrintln(unsigned long value); */ -#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT - #define ESPEASY_SERIAL_CONSOLE_PORT -#else - // Using the standard Serial0 HW serial port. - #define ESPEASY_SERIAL_CONSOLE_PORT Serial -#endif #endif // ifndef ESPEASYCORE_SERIAL_H diff --git a/src/src/WebServer/AdvancedConfigPage.cpp b/src/src/WebServer/AdvancedConfigPage.cpp index d575f46c3c..f9b5212c86 100644 --- a/src/src/WebServer/AdvancedConfigPage.cpp +++ b/src/src/WebServer/AdvancedConfigPage.cpp @@ -207,7 +207,7 @@ void handle_advanced() { addFormSubHeader(F("Serial Settings")); - addFormCheckBox(F("Enable Serial Port Console"), F("useserial"), Settings.UseSerial); + addFormCheckBox(F("Enable Serial port"), F("useserial"), Settings.UseSerial); addFormNumericBox(F("Baud Rate"), F("baudrate"), Settings.BaudRate, 0, 1000000); From 396b2a30275265b7f95480aaff82f4ccd6007ad4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 7 Oct 2022 13:30:22 +0200 Subject: [PATCH 329/404] Revert "[Serial] Rename Serial. to ESPEASY_SERIAL_CONSOLE_PORT." This reverts commit a01f861ed2a703ae7d7347c184d8c77c6e3fb13c. --- src/ESPEasy.ino | 2 +- src/_P040_ID12.ino | 8 +- src/_P077_CSE7766.ino | 6 +- src/_P091_SerSwitch.ino | 148 ++++++++++----------- src/_Plugin_Helper.h | 1 - src/src/ESPEasyCore/ESPEasy_Log.cpp | 4 +- src/src/ESPEasyCore/ESPEasy_setup.cpp | 4 +- src/src/ESPEasyCore/Serial.cpp | 20 +-- src/src/Helpers/Misc.cpp | 10 +- src/src/Helpers/Networking.cpp | 5 +- src/src/Helpers/OTA.cpp | 2 +- src/src/PluginStructs/P077_data_struct.cpp | 4 +- src/src/PluginStructs/P090_data_struct.cpp | 18 +-- src/src/WebServer/Rules.cpp | 53 ++++---- 14 files changed, 141 insertions(+), 144 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index daf64129e1..d81f72b92b 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -127,7 +127,7 @@ void preinit(); void preinit() { system_phy_set_powerup_option(3); // Global WiFi constructors are not called yet - // (global class instances like WiFi, Serial.... are not yet initialized).. + // (global class instances like WiFi, Serial... are not yet initialized).. // No global object methods or C++ exceptions can be called in here! // The below is a static class method, which is similar to a function, so it's ok. #ifndef CORE_POST_3_0_0 diff --git a/src/_P040_ID12.ino b/src/_P040_ID12.ino index 5731bd2672..3e6b17db2f 100644 --- a/src/_P040_ID12.ino +++ b/src/_P040_ID12.ino @@ -50,7 +50,7 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_INIT: { Plugin_040_init = true; - ESPEASY_SERIAL_CONSOLE_PORT.begin(9600); + Serial.begin(9600); success = true; break; } @@ -77,12 +77,12 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string) uint8_t bytesread = 0; uint8_t tempbyte = 0; - if ((val = ESPEASY_SERIAL_CONSOLE_PORT.read()) == 2) + if ((val = Serial.read()) == 2) { // check for header bytesread = 0; while (bytesread < 12) { // read 10 digit code + 2 digit checksum - if ( ESPEASY_SERIAL_CONSOLE_PORT.available() > 0) { - val = ESPEASY_SERIAL_CONSOLE_PORT.read(); + if ( Serial.available() > 0) { + val = Serial.read(); if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { // if header or stop bytes before the 10 digit reading break; diff --git a/src/_P077_CSE7766.ino b/src/_P077_CSE7766.ino index 8752dfb044..da96da5d83 100644 --- a/src/_P077_CSE7766.ino +++ b/src/_P077_CSE7766.ino @@ -96,8 +96,8 @@ boolean Plugin_077(uint8_t function, struct EventStruct *event, String& string) disableSerialLog(); // disable logging on serial port (used for CSE7766 // communication) Settings.BaudRate = 4800; // set BaudRate for CSE7766 - ESPEASY_SERIAL_CONSOLE_PORT.flush(); - ESPEASY_SERIAL_CONSOLE_PORT.begin(Settings.BaudRate, SERIAL_8E1); + Serial.flush(); + Serial.begin(Settings.BaudRate, SERIAL_8E1); success = true; break; } @@ -214,7 +214,7 @@ boolean Plugin_077(uint8_t function, struct EventStruct *event, String& string) log += '/'; log += P077_data->count_max; log += '/'; - log += ESPEASY_SERIAL_CONSOLE_PORT.available(); + log += Serial.available(); addLogMove(LOG_LEVEL_DEBUG, log); log = F("CSE: nr "); log += P077_data->count_pkt; diff --git a/src/_P091_SerSwitch.ino b/src/_P091_SerSwitch.ino index 43c526ba45..7dd017d5e4 100644 --- a/src/_P091_SerSwitch.ino +++ b/src/_P091_SerSwitch.ino @@ -225,13 +225,13 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) Plugin_091_ownindex = event->TaskIndex; Settings.UseSerial = true; // make sure that serial enabled Settings.SerialLogLevel = 0; // and logging disabled - ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(false); // really, disable it! + Serial.setDebugOutput(false); // really, disable it! log = F("SerSW : Init "); if (PCONFIG(0) == SER_SWITCH_YEWE) { Plugin_091_numrelay = PCONFIG(1); - ESPEASY_SERIAL_CONSOLE_PORT.begin(9600, SERIAL_8N1); - ESPEASY_SERIAL_CONSOLE_PORT.setRxBufferSize(BUFFER_SIZE); // Arduino core for ESP8266 WiFi chip 2.4.0 + Serial.begin(9600, SERIAL_8N1); + Serial.setRxBufferSize(BUFFER_SIZE); // Arduino core for ESP8266 WiFi chip 2.4.0 delay(1); getmcustate(); // request status on startup log += F(" Yewe "); @@ -241,7 +241,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (PCONFIG(0) == SER_SWITCH_SONOFFDUAL) { Plugin_091_numrelay = 3; // 3rd button is the "wifi" button - ESPEASY_SERIAL_CONSOLE_PORT.begin(19230, SERIAL_8N1); + Serial.begin(19230, SERIAL_8N1); log += F(" Sonoff Dual"); } if (PCONFIG(0) == SER_SWITCH_LCTECH) @@ -280,7 +280,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) break; } } - ESPEASY_SERIAL_CONSOLE_PORT.begin(Plugin_091_speed, SERIAL_8N1); + Serial.begin(Plugin_091_speed, SERIAL_8N1); log += F(" LCTech "); log += Plugin_091_speed; log += F(" baud "); @@ -292,7 +292,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) Plugin_091_numrelay = 2; // 2nd button is the dimvalue Plugin_091_switchstate[1] = 255; Plugin_091_ostate[1] = 255; - ESPEASY_SERIAL_CONSOLE_PORT.begin(9600, SERIAL_8N1); + Serial.begin(9600, SERIAL_8N1); log += F(" Wifi Dimmer"); } @@ -329,10 +329,10 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) if (Plugin_091_init) { - while (ESPEASY_SERIAL_CONSOLE_PORT.available() > 0) { + while (Serial.available() > 0) { yield(); if (bytes_read < BUFFER_SIZE) { - serial_buf[bytes_read] = ESPEASY_SERIAL_CONSOLE_PORT.read(); + serial_buf[bytes_read] = Serial.read(); if (bytes_read == 0) { // packet start @@ -543,7 +543,7 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) bytes_read++; } } else - ESPEASY_SERIAL_CONSOLE_PORT.read(); // if buffer full, dump incoming + Serial.read(); // if buffer full, dump incoming } } // plugin initialized end success = true; @@ -826,14 +826,14 @@ boolean Plugin_091(uint8_t function, struct EventStruct *event, String& string) } void getmcustate() { - ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA - ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 - ESPEASY_SERIAL_CONSOLE_PORT.write(0x08); // Tuya command 08 - request status - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x07); - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0x55); // Tuya header 55AA + Serial.write(0xAA); + Serial.write(0x00); // version 00 + Serial.write(0x08); // Tuya command 08 - request status + Serial.write(0x00); + Serial.write(0x00); + Serial.write(0x07); + Serial.flush(); } void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum_mode) // btnnum=0,1,2, state=0/1 @@ -844,19 +844,19 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum { case SER_SWITCH_YEWE: { - ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA - ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 - ESPEASY_SERIAL_CONSOLE_PORT.write(0x06); // Tuya command 06 - send order - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x05); // following data length 0x05 - ESPEASY_SERIAL_CONSOLE_PORT.write( (btnnum + 1) ); // relay number 1,2,3 - ESPEASY_SERIAL_CONSOLE_PORT.write(0x01); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write(0x01); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write( state ); // status - ESPEASY_SERIAL_CONSOLE_PORT.write((13 + btnnum + state)); // checksum:sum of all bytes in packet mod 256 - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0x55); // Tuya header 55AA + Serial.write(0xAA); + Serial.write(0x00); // version 00 + Serial.write(0x06); // Tuya command 06 - send order + Serial.write(0x00); + Serial.write(0x05); // following data length 0x05 + Serial.write( (btnnum + 1) ); // relay number 1,2,3 + Serial.write(0x01); // ? + Serial.write(0x00); // ? + Serial.write(0x01); // ? + Serial.write( state ); // status + Serial.write((13 + btnnum + state)); // checksum:sum of all bytes in packet mod 256 + Serial.flush(); break; } case SER_SWITCH_SONOFFDUAL: @@ -872,11 +872,11 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum Plugin_091_switchstate[1] = state; } sstate = Plugin_091_switchstate[0] + (Plugin_091_switchstate[1] << 1) + (Plugin_091_switchstate[2] << 2); - ESPEASY_SERIAL_CONSOLE_PORT.write(0xA0); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x04); - ESPEASY_SERIAL_CONSOLE_PORT.write( sstate ); - ESPEASY_SERIAL_CONSOLE_PORT.write(0xA1); - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0xA0); + Serial.write(0x04); + Serial.write( sstate ); + Serial.write(0xA1); + Serial.flush(); break; } case SER_SWITCH_LCTECH: @@ -892,23 +892,23 @@ void sendmcucommand(uint8_t btnnum, uint8_t state, uint8_t swtype, uint8_t btnum delay(1); } if (Plugin_091_ipd) { - ESPEASY_SERIAL_CONSOLE_PORT.write(0x0D); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x0A); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x2B); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x49); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x50); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x44); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x2C); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x30); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x2C); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x34); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x3A); + Serial.write(0x0D); + Serial.write(0x0A); + Serial.write(0x2B); + Serial.write(0x49); + Serial.write(0x50); + Serial.write(0x44); + Serial.write(0x2C); + Serial.write(0x30); + Serial.write(0x2C); + Serial.write(0x34); + Serial.write(0x3A); } - ESPEASY_SERIAL_CONSOLE_PORT.write(0xA0); - ESPEASY_SERIAL_CONSOLE_PORT.write((0x01 + btnnum)); - ESPEASY_SERIAL_CONSOLE_PORT.write((0x00 + state)); - ESPEASY_SERIAL_CONSOLE_PORT.write((0xA1 + state + btnnum)); - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0xA0); + Serial.write((0x01 + btnnum)); + Serial.write((0x00 + state)); + Serial.write((0xA1 + state + btnnum)); + Serial.flush(); } break; @@ -952,33 +952,33 @@ void sendmcudim(uint8_t dimvalue, uint8_t swtype) { case SER_SWITCH_YEWE: { - ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); // Tuya header 55AA - ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // version 00 - ESPEASY_SERIAL_CONSOLE_PORT.write(0x06); // Tuya command 06 - send order - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x08); // following data length 0x08 - ESPEASY_SERIAL_CONSOLE_PORT.write(Plugin_091_numrelay); // dimmer order-id? select it at plugin settings 2/3!!! - ESPEASY_SERIAL_CONSOLE_PORT.write(0x02); // type=value - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // length hi - ESPEASY_SERIAL_CONSOLE_PORT.write(0x04); // length low - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write(0x00); // ? - ESPEASY_SERIAL_CONSOLE_PORT.write( dimvalue ); // dim value (0-255) - ESPEASY_SERIAL_CONSOLE_PORT.write( uint8_t(19 + Plugin_091_numrelay + dimvalue) ); // checksum:sum of all bytes in packet mod 256 - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0x55); // Tuya header 55AA + Serial.write(0xAA); + Serial.write(0x00); // version 00 + Serial.write(0x06); // Tuya command 06 - send order + Serial.write(0x00); + Serial.write(0x08); // following data length 0x08 + Serial.write(Plugin_091_numrelay); // dimmer order-id? select it at plugin settings 2/3!!! + Serial.write(0x02); // type=value + Serial.write(0x00); // length hi + Serial.write(0x04); // length low + Serial.write(0x00); // ? + Serial.write(0x00); // ? + Serial.write(0x00); // ? + Serial.write( dimvalue ); // dim value (0-255) + Serial.write( uint8_t(19 + Plugin_091_numrelay + dimvalue) ); // checksum:sum of all bytes in packet mod 256 + Serial.flush(); break; } case SER_SWITCH_WIFIDIMMER: { - ESPEASY_SERIAL_CONSOLE_PORT.write(0xFF); // Wifidimmer header FF55 - ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); - ESPEASY_SERIAL_CONSOLE_PORT.write( dimvalue ); // dim value (0-255) - ESPEASY_SERIAL_CONSOLE_PORT.write(0x05); - ESPEASY_SERIAL_CONSOLE_PORT.write(0xDC); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x0A); - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.write(0xFF); // Wifidimmer header FF55 + Serial.write(0x55); + Serial.write( dimvalue ); // dim value (0-255) + Serial.write(0x05); + Serial.write(0xDC); + Serial.write(0x0A); + Serial.flush(); Plugin_091_switchstate[1] = dimvalue; break; } diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index a99a9108a4..1ab83fad69 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -16,7 +16,6 @@ #include "src/ESPEasyCore/Controller.h" #include "src/ESPEasyCore/ESPEasy_Log.h" -#include "src/ESPEasyCore/Serial.h" #include "src/Globals/Cache.h" #include "src/Globals/Device.h" diff --git a/src/src/ESPEasyCore/ESPEasy_Log.cpp b/src/src/ESPEasyCore/ESPEasy_Log.cpp index 01c3877508..4fbe549881 100644 --- a/src/src/ESPEasyCore/ESPEasy_Log.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Log.cpp @@ -90,13 +90,13 @@ void updateLogLevelCache() { const bool useSerial = Settings.UseSerial && !activeTaskUseSerial0(); if (log_to_serial_disabled) { if (useSerial) { - ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(false); + Serial.setDebugOutput(false); } } else { max_lvl = _max(max_lvl, Settings.SerialLogLevel); #ifndef BUILD_NO_DEBUG if (useSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) { - ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); + Serial.setDebugOutput(true); } #endif } diff --git a/src/src/ESPEasyCore/ESPEasy_setup.cpp b/src/src/ESPEasyCore/ESPEasy_setup.cpp index 5fd31459f4..624f25ae60 100644 --- a/src/src/ESPEasyCore/ESPEasy_setup.cpp +++ b/src/src/ESPEasyCore/ESPEasy_setup.cpp @@ -163,7 +163,7 @@ void ESPEasy_setup() checkRAM(F("setup")); #endif // ifndef BUILD_NO_RAM_TRACKER - ESPEASY_SERIAL_CONSOLE_PORT.begin(115200); + Serial.begin(115200); // serialPrint("\n\n\nBOOOTTT\n\n\n"); @@ -379,7 +379,7 @@ void ESPEasy_setup() # ifndef BUILD_NO_DEBUG if (Settings.UseSerial && (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)) { - ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); + Serial.setDebugOutput(true); } #endif diff --git a/src/src/ESPEasyCore/Serial.cpp b/src/src/ESPEasyCore/Serial.cpp index 65fbc09682..78d2d81bc8 100644 --- a/src/src/ESPEasyCore/Serial.cpp +++ b/src/src/ESPEasyCore/Serial.cpp @@ -25,15 +25,15 @@ void initSerial() } // make sure previous serial buffers are flushed before resetting baudrate - ESPEASY_SERIAL_CONSOLE_PORT.flush(); - ESPEASY_SERIAL_CONSOLE_PORT.begin(Settings.BaudRate); + Serial.flush(); + Serial.begin(Settings.BaudRate); - // ESPEASY_SERIAL_CONSOLE_PORT.setDebugOutput(true); + // Serial.setDebugOutput(true); } void serial() { - if (ESPEASY_SERIAL_CONSOLE_PORT.available()) + if (Serial.available()) { String dummy; @@ -44,14 +44,14 @@ void serial() if (!Settings.UseSerial || activeTaskUseSerial0()) { return; } - while (ESPEASY_SERIAL_CONSOLE_PORT.available()) + while (Serial.available()) { delay(0); - SerialInByte = ESPEASY_SERIAL_CONSOLE_PORT.read(); + SerialInByte = Serial.read(); if (SerialInByte == 255) // binary data... { - ESPEASY_SERIAL_CONSOLE_PORT.flush(); + Serial.flush(); return; } @@ -68,7 +68,7 @@ void serial() break; } InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed - ESPEASY_SERIAL_CONSOLE_PORT.write('>'); + Serial.write('>'); serialPrintln(InputBuffer_Serial); ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_SERIAL, InputBuffer_Serial); SerialInByteCounter = 0; @@ -134,7 +134,7 @@ void addNewlineToSerialBuffer() { void process_serialWriteBuffer() { if (serialWriteBuffer.size() == 0) { return; } - size_t snip = ESPEASY_SERIAL_CONSOLE_PORT.availableForWrite(); + size_t snip = Serial.availableForWrite(); if (snip > 0) { size_t bytes_to_write = serialWriteBuffer.size(); @@ -144,7 +144,7 @@ void process_serialWriteBuffer() { while (bytes_to_write > 0 && !serialWriteBuffer.empty()) { const char c = serialWriteBuffer.front(); if (Settings.UseSerial) { - ESPEASY_SERIAL_CONSOLE_PORT.write(c); + Serial.write(c); } serialWriteBuffer.pop_front(); --bytes_to_write; diff --git a/src/src/Helpers/Misc.cpp b/src/src/Helpers/Misc.cpp index e06ed95941..2ed67b7ca3 100644 --- a/src/src/Helpers/Misc.cpp +++ b/src/src/Helpers/Misc.cpp @@ -234,13 +234,13 @@ String getTaskValueName(taskIndex_t TaskIndex, uint8_t TaskValueIndex) { void emergencyReset() { // Direct Serial is allowed here, since this is only an emergency task. - ESPEASY_SERIAL_CONSOLE_PORT.begin(115200); - ESPEASY_SERIAL_CONSOLE_PORT.write(0xAA); - ESPEASY_SERIAL_CONSOLE_PORT.write(0x55); + Serial.begin(115200); + Serial.write(0xAA); + Serial.write(0x55); delay(1); - if (ESPEASY_SERIAL_CONSOLE_PORT.available() == 2) { - if ((ESPEASY_SERIAL_CONSOLE_PORT.read() == 0xAA) && (ESPEASY_SERIAL_CONSOLE_PORT.read() == 0x55)) + if (Serial.available() == 2) { + if ((Serial.read() == 0xAA) && (Serial.read() == 0x55)) { serialPrintln(F("\n\n\rSystem will reset to factory defaults in 10 seconds...")); delay(10000); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 9c6f9edb03..3716d772f5 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -9,7 +9,6 @@ #include "../ESPEasyCore/ESPEasy_backgroundtasks.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" -#include "../ESPEasyCore/Serial.h" #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" @@ -902,7 +901,7 @@ bool hasIPaddr() { for (auto addr : addrList) { if ((configured = (!addr.isLocal() && (addr.ifnumber() == STATION_IF)))) { /* - ESPEASY_SERIAL_CONSOLE_PORT.printf("STA: IF='%s' hostname='%s' addr= %s\n", + Serial.printf("STA: IF='%s' hostname='%s' addr= %s\n", addr.ifname().c_str(), addr.ifhostname(), addr.toString().c_str()); @@ -1270,7 +1269,7 @@ String getDigestAuth(const String& authReq, F("\", response=\"") + response + '"'; - // ESPEASY_SERIAL_CONSOLE_PORT.println(authorization); + // Serial.println(authorization); return authorization; } diff --git a/src/src/Helpers/OTA.cpp b/src/src/Helpers/OTA.cpp index fdf88d5586..fba3e33352 100644 --- a/src/src/Helpers/OTA.cpp +++ b/src/src/Helpers/OTA.cpp @@ -84,7 +84,7 @@ void ArduinoOTAInit() }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { if (Settings.UseSerial) { - ESPEASY_SERIAL_CONSOLE_PORT.printf("OTA : Progress %u%%\r", (progress / (total / 100))); + Serial.printf("OTA : Progress %u%%\r", (progress / (total / 100))); } }); diff --git a/src/src/PluginStructs/P077_data_struct.cpp b/src/src/PluginStructs/P077_data_struct.cpp index a00cec1c4c..a3ecc9b0b4 100644 --- a/src/src/PluginStructs/P077_data_struct.cpp +++ b/src/src/PluginStructs/P077_data_struct.cpp @@ -106,8 +106,8 @@ bool P077_data_struct::processSerialData() { long t_start = millis(); bool found = false; - while (ESPEASY_SERIAL_CONSOLE_PORT.available() > 0 && !found) { - uint8_t serial_in_byte = ESPEASY_SERIAL_CONSOLE_PORT.read(); + while (Serial.available() > 0 && !found) { + uint8_t serial_in_byte = Serial.read(); count_bytes++; checksum -= serial_in_buffer[2]; // substract from checksum data to be removed memmove(serial_in_buffer, serial_in_buffer + 1, diff --git a/src/src/PluginStructs/P090_data_struct.cpp b/src/src/PluginStructs/P090_data_struct.cpp index 707b659908..3b54909053 100644 --- a/src/src/PluginStructs/P090_data_struct.cpp +++ b/src/src/PluginStructs/P090_data_struct.cpp @@ -229,7 +229,7 @@ CCS811Core::status CCS811::begin(void) delay(200); // returnError = setDriveMode(1); //Read every second - // ESPEASY_SERIAL_CONSOLE_PORT.println(); + // Serial.println(); return returnError; } // CCS811::begin @@ -346,11 +346,11 @@ CCS811Core::status CCS811::enableInterrupts(void) return returnError; } - // ESPEASY_SERIAL_CONSOLE_PORT.println(value, HEX); + // Serial.println(value, HEX); value |= (1 << 3); // Set INTERRUPT bit writeRegister(CSS811_MEAS_MODE, value); - // ESPEASY_SERIAL_CONSOLE_PORT.println(value, HEX); + // Serial.println(value, HEX); return returnError; } @@ -466,14 +466,14 @@ CCS811Core::status CCS811::readNTC(void) vrefCounts = (static_cast(data[CSS811_NTC + 0]) << 8) | data[CSS811_NTC + 1]; - // ESPEASY_SERIAL_CONSOLE_PORT.print("vrefCounts: "); - // ESPEASY_SERIAL_CONSOLE_PORT.println(vrefCounts); + // Serial.print("vrefCounts: "); + // Serial.println(vrefCounts); ntcCounts = (static_cast(data[CSS811_NTC + 2]) << 8) | data[CSS811_NTC + 3]; - // ESPEASY_SERIAL_CONSOLE_PORT.print("ntcCounts: "); - // ESPEASY_SERIAL_CONSOLE_PORT.println(ntcCounts); - // ESPEASY_SERIAL_CONSOLE_PORT.print("sum: "); - // ESPEASY_SERIAL_CONSOLE_PORT.println(ntcCounts + vrefCounts); + // Serial.print("ntcCounts: "); + // Serial.println(ntcCounts); + // Serial.print("sum: "); + // Serial.println(ntcCounts + vrefCounts); resistance = (static_cast(ntcCounts) * refResistance / static_cast(vrefCounts)); // Code from Milan Malesevic and Zoran Stupic, 2011, diff --git a/src/src/WebServer/Rules.cpp b/src/src/WebServer/Rules.cpp index 004af02af1..1e8370200f 100644 --- a/src/src/WebServer/Rules.cpp +++ b/src/src/WebServer/Rules.cpp @@ -13,7 +13,6 @@ #include "../WebServer/Markup_Forms.h" #include "../ESPEasyCore/ESPEasyRules.h" -#include "../ESPEasyCore/Serial.h" #include "../Globals/Settings.h" #include "../Helpers/ESPEasy_Storage.h" @@ -176,8 +175,8 @@ void handle_rules_new() { [/*&buffer,*/ &count, endIdx](fileInfo fi) { # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Start generation of: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(fi.Name); + Serial.print(F("Start generation of: ")); + Serial.println(fi.Name); # endif // ifdef WEBSERVER_RULES_DEBUG if (fi.isDirectory) @@ -228,8 +227,8 @@ void handle_rules_new() { } addHtml(F("")); # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.print(F("End generation of: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(fi.Name); + Serial.print(F("End generation of: ")); + Serial.println(fi.Name); # endif // ifdef WEBSERVER_RULES_DEBUG return count < endIdx; @@ -276,7 +275,7 @@ void handle_rules_backup() { } # ifdef WEBSERVER_NEW_RULES # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle rules backup")); + Serial.println(F("handle rules backup")); # endif // ifdef WEBSERVER_RULES_DEBUG if (!isLoggedIn() || !Settings.UseRules) { return; } @@ -348,9 +347,9 @@ void handle_rules_delete() { fileName = fileName.substring(0, fileName.length() - 4); bool removed = false; # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle_rules_delete")); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("File name: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(fileName); + Serial.println(F("handle_rules_delete")); + Serial.print(F("File name: ")); + Serial.println(fileName); # endif // ifdef WEBSERVER_RULES_DEBUG if (fileName.length() > 0) @@ -393,8 +392,8 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { bool handle = false; # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.println(originalUri); - ESPEASY_SERIAL_CONSOLE_PORT.println(F("handle_rules_edit")); + Serial.println(originalUri); + Serial.println(F("handle_rules_edit")); # endif // ifdef WEBSERVER_RULES_DEBUG if (isAddNew || (originalUri.startsWith(F("/rules/")) @@ -432,8 +431,8 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { eventName = FileNameToEvent(fileName); } # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.print(F("File name: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(fileName); + Serial.print(F("File name: ")); + Serial.println(fileName); # endif // ifdef WEBSERVER_RULES_DEBUG bool isEdit = fileExists(fileName); @@ -502,16 +501,16 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { bool isReadOnly = !isOverwrite && ((isEdit && !isAddNew && !isNew) || (isAddNew && isNew)); # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is Overwrite: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(isOverwrite); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is edit: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(isEdit); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is addnew: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(isAddNew); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is New: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(isNew); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Is Read Only: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(isReadOnly); + Serial.print(F("Is Overwrite: ")); + Serial.println(isOverwrite); + Serial.print(F("Is edit: ")); + Serial.println(isEdit); + Serial.print(F("Is addnew: ")); + Serial.println(isAddNew); + Serial.print(F("Is New: ")); + Serial.println(isNew); + Serial.print(F("Is Read Only: ")); + Serial.println(isReadOnly); # endif // ifdef WEBSERVER_RULES_DEBUG addFormTextBox(F("Event name") // Label @@ -572,8 +571,8 @@ void Rule_showRuleTextArea(const String& fileName) { bool Rule_Download(const String& path) { # ifdef WEBSERVER_RULES_DEBUG - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Rule_Download path: ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(path); + Serial.print(F("Rule_Download path: ")); + Serial.println(path); # endif // ifdef WEBSERVER_RULES_DEBUG fs::File dataFile = tryOpenFile(path, "r"); @@ -610,8 +609,8 @@ bool EnumerateFileAndDirectory(String & rootPath # ifdef ESP8266 fs::Dir dir = ESPEASY_FS.openDir(rootPath); - ESPEASY_SERIAL_CONSOLE_PORT.print(F("Enumerate files of ")); - ESPEASY_SERIAL_CONSOLE_PORT.println(rootPath); + Serial.print(F("Enumerate files of ")); + Serial.println(rootPath); while (next && dir.next()) { // Skip files From 219620f96c05d7a63d44f098e8a624ae4dceb5c4 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 16 Oct 2022 14:54:38 +0200 Subject: [PATCH 330/404] [Custom build] Add DEFAULT_CONTROLLER_FALLBACK_MESH for Custom.h --- src/Custom-sample.h | 1 + src/src/CustomBuild/ESPEasyDefaults.h | 5 ++++- src/src/Helpers/ESPEasy_FactoryDefault.cpp | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 672beaf65a..8d244aaa6b 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -93,6 +93,7 @@ #define DEFAULT_PORT 8080 // Enter your Server port value #define DEFAULT_CONTROLLER_TIMEOUT 100 // Default timeout in msec +#define DEFAULT_CONTROLLER_FALLBACK_MESH false // Let the (MQTT) controller use the mesh as a fallback route when there's no network connection #define DEFAULT_PROTOCOL 0 // Protocol used for controller communications // 0 = Stand-alone (no controller set) diff --git a/src/src/CustomBuild/ESPEasyDefaults.h b/src/src/CustomBuild/ESPEasyDefaults.h index f1064b64f5..d287a4b10d 100644 --- a/src/src/CustomBuild/ESPEasyDefaults.h +++ b/src/src/CustomBuild/ESPEasyDefaults.h @@ -141,7 +141,10 @@ #define DEFAULT_CONTROLLER_PASS "" // Default controller Password #endif #ifndef DEFAULT_CONTROLLER_TIMEOUT -#define DEFAULT_CONTROLLER_TIMEOUT 100 +#define DEFAULT_CONTROLLER_TIMEOUT 100 // Default timeout in msec +#endif +#ifndef DEFAULT_CONTROLLER_FALLBACK_MESH +#define DEFAULT_CONTROLLER_FALLBACK_MESH false // Let the (MQTT) controller use the mesh as a fallback route when there's no network connection #endif // using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol ! diff --git a/src/src/Helpers/ESPEasy_FactoryDefault.cpp b/src/src/Helpers/ESPEasy_FactoryDefault.cpp index 7fcb9583f8..060d977727 100644 --- a/src/src/Helpers/ESPEasy_FactoryDefault.cpp +++ b/src/src/Helpers/ESPEasy_FactoryDefault.cpp @@ -280,6 +280,7 @@ void ResetFactory() ControllerSettings.useExtendedCredentials(DEFAULT_USE_EXTD_CONTROLLER_CREDENTIALS); ControllerSettings.Port = DEFAULT_PORT; ControllerSettings.ClientTimeout = DEFAULT_CONTROLLER_TIMEOUT; + ControllerSettings.enableESPEasyNowFallback(DEFAULT_CONTROLLER_FALLBACK_MESH); setControllerUser(0, ControllerSettings, F(DEFAULT_CONTROLLER_USER)); setControllerPass(0, ControllerSettings, F(DEFAULT_CONTROLLER_PASS)); From 20c55df86d6b0d85e656bb9ef1c419b04c07d27e Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 16 Oct 2022 15:08:17 +0200 Subject: [PATCH 331/404] [p2p] Do not send uninitialized trailing node struct data --- src/src/Helpers/Networking.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index 3716d772f5..427210d03e 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -309,9 +309,14 @@ void checkUDP() break; } int copy_length = sizeof(NodeStruct); + // Older versions sent 80 bytes, regardless of the size of NodeStruct + // Make sure the extra data received is ignored as it was also not initialized + if (len == 80) { + copy_length = 56; + } - if (copy_length > len) { - copy_length = len; + if (copy_length > (len - 2)) { + copy_length = (len - 2); } NodeStruct received; memcpy(&received, &packetBuffer[2], copy_length); @@ -477,7 +482,8 @@ void sendSysInfoUDP(uint8_t repeats) } // Prepare UDP packet to send - uint8_t data[80]; + constexpr size_t data_size = sizeof(NodeStruct) + 2; + uint8_t data[data_size] = {0}; data[0] = 255; data[1] = 1; memcpy(&data[2], thisNode, sizeof(NodeStruct)); @@ -489,7 +495,7 @@ void sendSysInfoUDP(uint8_t repeats) IPAddress broadcastIP(255, 255, 255, 255); FeedSW_watchdog(); portUDP.beginPacket(broadcastIP, Settings.UDPPort); - portUDP.write(data, 80); + portUDP.write(data, data_size); portUDP.endPacket(); if (counter < (repeats - 1)) { From e3b4086396bdb8e4d8503bea61bd66e28907ce4b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 16 Oct 2022 15:26:06 +0200 Subject: [PATCH 332/404] [WiFi] Clear WiFi scan results when reset WiFi --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index a2c3326dd1..245d59197a 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -593,6 +593,7 @@ void resetWiFi() { } FeedSW_watchdog(); WiFiEventData.clearAll(); + WiFi_AP_Candidates.force_reload(); WifiDisconnect(); // Send this log only after WifiDisconnect() or else sending to syslog may cause issues From 4d502584502289fbd03f9813e4052d03f2b2e9a9 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 16 Oct 2022 15:49:57 +0200 Subject: [PATCH 333/404] [ESPEasy-NOW] Send event on p2p distance change "nodep2p#distance=N" --- src/src/DataStructs/NodesHandler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 205c921cc1..2ca6dffcf8 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -442,6 +442,11 @@ void NodesHandler::updateThisNode() { // Since we're the end node, claim highest success rate updateSuccessRate(thisNode.unit, 255); } + if (thisNode.distance != lastDistance) { + if (Settings.UseRules) { + eventQueue.addMove(std::move(concat(F("nodep2p#distance="), thisNode.distance))); + } + } #else addNode(thisNode); #endif From c6259e8f7ef1962f68e03399f4e28fc69c0f162a Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 17 Oct 2022 01:37:51 +0200 Subject: [PATCH 334/404] [ESPEasy-NOW] Fix missing include --- src/src/DataStructs/NodesHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 2ca6dffcf8..a274486846 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -8,6 +8,7 @@ #ifdef USES_ESPEASY_NOW #include "../Globals/ESPEasy_now_peermanager.h" #include "../Globals/ESPEasy_now_state.h" +#include "../Globals/EventQueue.h" #endif #include "../ESPEasyCore/ESPEasy_Log.h" From bab80d190cd8d4ba503be9bbcc285d7f4f4eba38 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 2 Nov 2022 13:24:21 +0100 Subject: [PATCH 335/404] [ESPEasy-NOW] Fix merge issues --- src/src/DataStructs/ESPEasy_Now_NTP_query.cpp | 58 +------------------ src/src/DataStructs/ESPEasy_Now_NTP_query.h | 3 - src/src/ESPEasyCore/ESPEasyWifi.cpp | 6 -- 3 files changed, 2 insertions(+), 65 deletions(-) diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp index 70605d67d1..f976dfdd73 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.cpp @@ -30,60 +30,6 @@ bool ESPEasy_Now_NTP_query::getMac(MAC_address& mac) const return true; } -// Only use peers if there is no external source available. -// A network without external synced source may drift as a whole -// All nodes in the network may be in sync with each other, but get out of sync with the rest of the world. -// Therefore use a strong bias for external synced nodes. -// But also must make sure the same NTP synced node will be held responsible for the entire network. -unsigned long ESPEasy_Now_NTP_query::computeExpectedWander(timeSource_t timeSource, - unsigned long timePassedSinceLastTimeSync) -{ - unsigned long expectedWander_ms = timePassedSinceLastTimeSync / TIME_WANDER_FACTOR; - - switch (timeSource) { - case timeSource_t::GPS_PPS_time_source: - { - expectedWander_ms += 1; - break; - } - case timeSource_t::GPS_time_source: - { - // Not sure about the wander here, as GPS does not have a drift. - // But the moment a message is received from a second's start may differ. - expectedWander_ms += 10; - break; - } - case timeSource_t::External_RTC_time_source: - case timeSource_t::NTP_time_source: - { - expectedWander_ms += 10; - break; - } - - case timeSource_t::ESP_now_peer: - { - expectedWander_ms += 100; - break; - } - - case timeSource_t::Restore_RTC_time_source: - { - expectedWander_ms += 2000; - break; - } - case timeSource_t::Manual_set: - { - expectedWander_ms += 10000; - break; - } - case timeSource_t::No_time_source: - { - // Cannot sync from it. - return 1 << 30; - } - } - return expectedWander_ms; -} void ESPEasy_Now_NTP_query::find_best_NTP(const MAC_address& mac, timeSource_t timeSource, @@ -163,7 +109,7 @@ void ESPEasy_Now_NTP_query::reset(bool success) bool ESPEasy_Now_NTP_query::hasLowerWander() const { - const long timePassed = timePassedSince(node_time.lastSyncTime); + const long timePassed = timePassedSince(node_time.lastSyncTime_ms); unsigned long currentExpectedWander_ms = computeExpectedWander(node_time.timeSource, timePassed); if (node_time.timeSource < _timeSource) { @@ -209,7 +155,7 @@ void ESPEasy_Now_NTP_query::createReply(unsigned long queryReceiveTimestamp) node_time.now(); _timeSource = node_time.timeSource; _unixTime_d = node_time.sysTime; - _expectedWander_ms = computeExpectedWander(node_time.timeSource, timePassedSince(node_time.lastSyncTime)); + _expectedWander_ms = computeExpectedWander(node_time.timeSource, timePassedSince(node_time.lastSyncTime_ms)); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; diff --git a/src/src/DataStructs/ESPEasy_Now_NTP_query.h b/src/src/DataStructs/ESPEasy_Now_NTP_query.h index 036dd5eae8..e54a26b059 100644 --- a/src/src/DataStructs/ESPEasy_Now_NTP_query.h +++ b/src/src/DataStructs/ESPEasy_Now_NTP_query.h @@ -28,9 +28,6 @@ class ESPEasy_Now_NTP_query { void reset(bool success); - static unsigned long computeExpectedWander(timeSource_t timeSource, - unsigned long timePassedSinceLastTimeSync); - bool hasLowerWander() const; bool isBroadcast() const; diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index b0bc101ec0..4843f7686b 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1093,12 +1093,6 @@ void WifiScan(bool async, uint8_t channel) { WiFiEventData.wifiConnectAttemptNeeded = needReconnect; } #endif - - const bool needReconnect = WiFiEventData.wifiConnectAttemptNeeded; - WifiDisconnect(); - WiFiEventData.wifiConnectAttemptNeeded = needReconnect; - } -#endif } // ******************************************************************************** From a9d1c4d86846648f3a975c9ee76f79df5c98bf0f Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 7 Nov 2022 00:38:09 +0100 Subject: [PATCH 336/404] [ESPEasy-NOW] Fix missing include --- src/src/DataStructs/NodesHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index e61b6c6e0e..d7f6ccd57c 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -24,6 +24,7 @@ #include "../Helpers/ESPEasy_time_calc.h" #include "../Helpers/Misc.h" #include "../Helpers/PeriodicalActions.h" +#include "../Helpers/StringConverter.h" #define ESPEASY_NOW_ALLOWED_AGE_NO_TRACEROUTE 35000 From 7a0ff8ac8d8eba5bc781f3b9f86769e03b2639dc Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 13 Dec 2022 17:25:48 +0100 Subject: [PATCH 337/404] [CUL reader] Add proper w-mBus decoding for various types --- src/src/DataStructs/mBusPacket.cpp | 258 +++++++++++++++++++++ src/src/DataStructs/mBusPacket.h | 47 ++++ src/src/PluginStructs/P094_data_struct.cpp | 75 +++--- 3 files changed, 353 insertions(+), 27 deletions(-) create mode 100644 src/src/DataStructs/mBusPacket.cpp create mode 100644 src/src/DataStructs/mBusPacket.h diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp new file mode 100644 index 0000000000..651e780168 --- /dev/null +++ b/src/src/DataStructs/mBusPacket.cpp @@ -0,0 +1,258 @@ +#include "../DataStructs/mBusPacket.h" + + +#include "../Helpers/StringConverter.h" + +#define FRAME_FORMAT_A_FIRST_BLOCK_LENGTH 10 +#define FRAME_FORMAT_A_OTHER_BLOCK_LENGTH 16 + +String mBusPacket_header_t::decodeManufacturerId(int id) +{ + String res; + int shift = 15; + + for (int i = 0; i < 3; ++i) { + shift -= 5; + res += static_cast(((id >> shift) & 0x1f) + 64); + } + return res; +} + +int mBusPacket_header_t::encodeManufacturerID(const String& id_str) +{ + int res = 0; + int nrChars = id_str.length(); + + if (nrChars > 3) { nrChars = 3; } + + for (int i = 0; i < nrChars; ++i) { + const char c = id_str[i]; + + if ((c >= 64) && (c < 96)) { + res += static_cast(c) - 64; + } + res <<= 5; + } + return res; +} + +String mBusPacket_header_t::getManufacturerId() const +{ + return decodeManufacturerId(_manufacturer); +} + +String mBusPacket_header_t::toString() const +{ + String res = decodeManufacturerId(_manufacturer); + + res += '.'; + res += formatToHex_no_prefix(_meterType, 2); + res += '.'; + res += formatToHex_no_prefix(_serialNr, 8); + return res; +} + +bool mBusPacket_header_t::isValid() const +{ + return _manufacturer != 0 && + _meterType != 0 && + _serialNr != 0 && + _length > 0; +} + +bool mBusPacket_t::parse(const String& payload) +{ + if (payload.startsWith(F("bY"))) { + return parseHeaders(removeChecksumsFrameB(payload)); + } + + if (payload.startsWith(F("b"))) { + return parseHeaders(removeChecksumsFrameA(payload)); + } + return false; +} + +bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) +{ + const size_t payloadSize = payloadWithoutChecksums.size(); + + + if (payloadSize < 10) { return false; } + int offset = 0; + + // 1st block is a static DataLinkLayer of 10 bytes + { + _deviceId1._manufacturer = makeWord(payloadWithoutChecksums[offset + 3], payloadWithoutChecksums[offset + 2]); + + // Type (offset + 9; convert to hex) + _deviceId1._meterType = payloadWithoutChecksums[offset + 9]; + + // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) + _deviceId1._serialNr = 0; + + for (int i = 0; i < 4; ++i) { + const uint32_t val = payloadWithoutChecksums[offset + 7 - i]; + _deviceId1._serialNr += val << (i * 8); + } + offset += 10; + _deviceId1._length = offset; + } + + // next blocks can be anything. we skip known blocks of no interest, parse known blocks if interest and stop on onknown blocks + while (offset < payloadSize) { + switch (payloadWithoutChecksums[offset]) { + case 0x8C: // ELL short + offset += 3; // fixed length + break; + case 0x90: // AFL + offset++; + offset += (payloadWithoutChecksums[offset] & 0xff); // dynamic length with length in 1st byte + offset++; // length byte + break; + case 0x72: // TPL_RESPONSE_MBUS_LONG_HEADER + _deviceId2 = _deviceId1; + + // note that serial/manufacturer are swapped !! + + _deviceId1._manufacturer = makeWord(payloadWithoutChecksums[offset + 6], payloadWithoutChecksums[offset + 5]); + + // Type (offset + 9; convert to hex) + _deviceId1._meterType = payloadWithoutChecksums[offset + 8]; + + // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) + _deviceId1._serialNr = 0; + + _deviceId1._length = payloadSize - _deviceId2._length; + + for (int i = 0; i < 4; ++i) { + const uint32_t val = payloadWithoutChecksums[offset + 4 - i]; + _deviceId1._serialNr += val << (i * 8); + } + + // We're done + offset = payloadSize; + break; + default: + // We're done + offset = payloadSize; + break; + } + } + + if (_deviceId1.isValid() && _deviceId2.isValid() && _deviceId1.toString().startsWith(F("ITW.30."))) { + // ITW does not follow the spec and puts the redio converter behind the actual meter. Need to swap both + std::swap(_deviceId1, _deviceId2); + } + + return _deviceId1.isValid(); +} + +uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) +{ + // Need to have at least 2 HEX nibbles + if ((index + 1) >= str.length()) { return 0; } + return hexToUL(str, index, 2); +} + +/** + * Format: + * [10 bytes message] + [2 bytes CRC] + * [16 bytes message] + [2 bytes CRC] + * [16 bytes message] + [2 bytes CRC] + * ... + * (last block can be < 16 bytes) + */ +mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) +{ + mBusPacket_data result; + const size_t payloadLength = payload.length(); + + if (payloadLength < 4) { return result; } + + int sourceIndex = 1; // Starts with "b" + int targetIndex = 0; + + // 1st byte contains length of data (excuding 1st byte and excluding CRC) + const int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; + if (payloadLength < (2* expectedMessageSize)) { + // Not an exact check, but close enough to fail early on packets which are seriously too short. + return result; + } + + result.reserve(expectedMessageSize); + + while (targetIndex < expectedMessageSize) { + // end index is start index + block size + 2 byte checksums + int blockSize = (sourceIndex == 0) ? FRAME_FORMAT_A_FIRST_BLOCK_LENGTH : FRAME_FORMAT_A_OTHER_BLOCK_LENGTH; + + if ((targetIndex + blockSize) > expectedMessageSize) { // last block + blockSize = expectedMessageSize - targetIndex; + } + + // FIXME: handle truncated source messages + for (int i = 0; i < blockSize; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars + targetIndex += blockSize; + } + return result; +} + +/** + * Format: + * [126 bytes message] + [2 bytes CRC] + * [125 bytes message] + [2 bytes CRC] + * (if message length <=126 bytes, only the 1st block exists) + * (last block can be < 125 bytes) + */ +mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) +{ + mBusPacket_data result; + const size_t payloadLength = payload.length(); + + if (payloadLength < 4) { return result; } + + int sourceIndex = 2; // Starts with "bY" + + // 1st byte contains length of data (excuding 1st byte BUT INCLUDING CRC) + int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; + if (payloadLength < (2* expectedMessageSize)) { + return result; + } + + expectedMessageSize -= 2; // CRC of 1st block + + if (expectedMessageSize > 128) { + expectedMessageSize -= 2; // CRC of 2nd block + } + + result.reserve(expectedMessageSize); + + // FIXME: handle truncated source messages + + const int block1Size = expectedMessageSize < 126 ? expectedMessageSize : 126; + + for (int i = 0; i < block1Size; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + + if (expectedMessageSize > 126) { + sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars + int block2Size = expectedMessageSize - 127; + + if (block2Size > 124) { block2Size = 124; } + + for (int i = 0; i < block2Size; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + } + + // remove the checksums and the 1st byte from the actual message length, so that the meaning of this byte is the same as in Frame A + result[0] = static_cast((expectedMessageSize - 1) & 0xff); + + return result; +} diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h new file mode 100644 index 0000000000..42f6272e41 --- /dev/null +++ b/src/src/DataStructs/mBusPacket.h @@ -0,0 +1,47 @@ +#ifndef DATASTRUCTS_MBUSPACKET_H +#define DATASTRUCTS_MBUSPACKET_H + +#include "../../ESPEasy_common.h" + +#include + +typedef std::vector mBusPacket_data; + +struct mBusPacket_header_t { + static String decodeManufacturerId(int id); + static int encodeManufacturerID(const String& id_str); + + String getManufacturerId() const; + + String toString() const; + + bool isValid() const; + + int _manufacturer = 0; + int _meterType = 0; + uint32_t _serialNr = 0; + int _length = 0; +}; + +struct mBusPacket_t { +public: + + bool parse(const String& payload); + +private: + + static uint8_t hexToByte(const String& str, + size_t index); + + static mBusPacket_data removeChecksumsFrameA(const String& payload); + static mBusPacket_data removeChecksumsFrameB(const String& payload); + + bool parseHeaders(const mBusPacket_data& payloadWithoutChecksums); + +public: + + mBusPacket_header_t _deviceId1; + mBusPacket_header_t _deviceId2; +}; + +#endif // ifndef DATASTRUCTS_MBUSPACKET_H diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 3d55f806e8..517253cae0 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -8,6 +8,8 @@ #include +#include "../DataStructs/mBusPacket.h" + #include "../Globals/ESPEasy_time.h" #include "../Helpers/StringConverter.h" @@ -276,36 +278,30 @@ bool P094_data_struct::parsePacket(const String& received) const { // Decoded packet - unsigned long packet_header[P094_FILTER_VALUE_Type_NR_ELEMENTS]; - packet_header[P094_packet_length] = hexToUL(received, 1, 2); - packet_header[P094_unknown1] = hexToUL(received, 3, 2); - packet_header[P094_manufacturer] = hexToUL(received, 5, 4); - packet_header[P094_serial_number] = hexToUL(received, 9, 8); - packet_header[P094_unknown2] = hexToUL(received, 17, 2); - packet_header[P094_meter_type] = hexToUL(received, 19, 2); - - // FIXME TD-er: Is this also correct? - packet_header[P094_rssi] = hexToUL(received, strlength - 4, 4); - - // FIXME TD-er: Is this correct? - // match_result = packet_length == (strlength - 21) / 2; + mBusPacket_t packet; + if (!packet.parse(received)) return false; + const uint32_t rssi = hexToUL(received, strlength - 4, 4); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(128)) { log = F("CUL Reader: "); - log += F(" length: "); - log += packet_header[P094_packet_length]; - log += F(" (header: "); - log += strlength - (packet_header[P094_packet_length] * 2); - log += F(") manu: "); - log += formatToHex_decimal(packet_header[P094_manufacturer]); - log += F(" serial: "); - log += formatToHex_decimal(packet_header[P094_serial_number]); - log += F(" mType: "); - log += formatToHex_decimal(packet_header[P094_meter_type]); + if (packet._deviceId1.isValid()) { + log += F(" deviceId1: "); + log += packet._deviceId1.toString(); + log += '('; + log += packet._deviceId1._length; + log += ')'; + } + if (packet._deviceId2.isValid()) { + log += F(" deviceId2: "); + log += packet._deviceId2.toString(); + log += '('; + log += packet._deviceId2._length; + log += ')'; + } log += F(" RSSI: "); - log += formatToHex_decimal(packet_header[P094_rssi]); + log += formatToHex_decimal(rssi); addLogMove(LOG_LEVEL_INFO, log); } } @@ -339,9 +335,34 @@ bool P094_data_struct::parsePacket(const String& received) const { match = inputString.equalsIgnoreCase(valueString); } } else { - unsigned long value = hexToUL(getFilter(f, filterValueType, optional, comparator)); - match = (value == packet_header[i]); - inputString = formatToHex_decimal(packet_header[i]); + const unsigned long value = hexToUL(getFilter(f, filterValueType, optional, comparator)); + uint32_t receivedValue = 0; + switch (static_cast(i)) { + case P094_packet_length: + receivedValue = packet._deviceId1._length; + match = value == receivedValue; + break; + case P094_manufacturer: + receivedValue = packet._deviceId1._manufacturer; + match = value == receivedValue; + break; + case P094_meter_type: + receivedValue = packet._deviceId1._meterType; + match = value == receivedValue; + break; + case P094_serial_number: + receivedValue = packet._deviceId1._serialNr; + match = value == receivedValue; + break; + case P094_rssi: + receivedValue = rssi; + match = value < rssi; + break; + default: + match = false; + break; + } + inputString = formatToHex_decimal(receivedValue); valueString = formatToHex_decimal(value); } From 610b9c0cfbf8fee063309205373b17a429cc6902 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 15 Dec 2022 09:51:31 +0100 Subject: [PATCH 338/404] [CUL reader] Allow set manufacturer in readable format --- src/src/DataStructs/mBusPacket.cpp | 6 +++--- src/src/DataStructs/mBusPacket.h | 2 +- src/src/PluginStructs/P094_data_struct.cpp | 19 +++++++++++++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 651e780168..12e01fe62f 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -6,7 +6,7 @@ #define FRAME_FORMAT_A_FIRST_BLOCK_LENGTH 10 #define FRAME_FORMAT_A_OTHER_BLOCK_LENGTH 16 -String mBusPacket_header_t::decodeManufacturerId(int id) +String mBusPacket_header_t::decodeManufacturerID(int id) { String res; int shift = 15; @@ -38,12 +38,12 @@ int mBusPacket_header_t::encodeManufacturerID(const String& id_str) String mBusPacket_header_t::getManufacturerId() const { - return decodeManufacturerId(_manufacturer); + return decodeManufacturerID(_manufacturer); } String mBusPacket_header_t::toString() const { - String res = decodeManufacturerId(_manufacturer); + String res = decodeManufacturerID(_manufacturer); res += '.'; res += formatToHex_no_prefix(_meterType, 2); diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h index 42f6272e41..284e0ef008 100644 --- a/src/src/DataStructs/mBusPacket.h +++ b/src/src/DataStructs/mBusPacket.h @@ -8,7 +8,7 @@ typedef std::vector mBusPacket_data; struct mBusPacket_header_t { - static String decodeManufacturerId(int id); + static String decodeManufacturerID(int id); static int encodeManufacturerID(const String& id_str); String getManufacturerId() const; diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 517253cae0..fedd06ff11 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -324,18 +324,26 @@ bool P094_data_struct::parsePacket(const String& received) const { P094_Filter_Comp comparator; bool match = false; String inputString; - String valueString; + String valueString = getFilter(f, filterValueType, optional, comparator); if (i == P094_Filter_Value_Type::P094_position) { - valueString = getFilter(f, filterValueType, optional, comparator); - if (received.length() >= (optional + valueString.length())) { // received string is long enough to fit the expression. inputString = received.substring(optional, optional + valueString.length()); match = inputString.equalsIgnoreCase(valueString); } + } else if (i == P094_Filter_Value_Type::P094_manufacturer) { + // Get vendor code + const unsigned long value = mBusPacket_header_t::encodeManufacturerID(valueString); + if (value == packet._deviceId1._manufacturer) { + match = true; + } else if (hexToUL(valueString) == packet._deviceId1._manufacturer) { + // Old 'compatible' mode, where the HEX notation was used instead of the manufacturer ID + match = true; + } + inputString = mBusPacket_header_t::decodeManufacturerID(packet._deviceId1._manufacturer); } else { - const unsigned long value = hexToUL(getFilter(f, filterValueType, optional, comparator)); + const unsigned long value = hexToUL(valueString); uint32_t receivedValue = 0; switch (static_cast(i)) { case P094_packet_length: @@ -343,8 +351,7 @@ bool P094_data_struct::parsePacket(const String& received) const { match = value == receivedValue; break; case P094_manufacturer: - receivedValue = packet._deviceId1._manufacturer; - match = value == receivedValue; + // Already handled break; case P094_meter_type: receivedValue = packet._deviceId1._meterType; From a0d743e38ae001db4dcb3cfa9b03fa7f747184f7 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 16 Dec 2022 17:16:29 +0100 Subject: [PATCH 339/404] [CUL reader] Add test CUL messages for debug --- src/_P094_CULReader.ino | 15 +- src/src/DataStructs/mBusPacket.cpp | 8 +- src/src/PluginStructs/P094_data_struct.cpp | 296 +++++++++++++++++++++ src/src/PluginStructs/P094_data_struct.h | 3 + 4 files changed, 315 insertions(+), 7 deletions(-) diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index fe8b24d3ae..15bb53604e 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -27,7 +27,11 @@ #define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) #define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) -#define P094_APPEND_RECEIVE_SYSTIME PCONFIG(0) +#define P094_GET_APPEND_RECEIVE_SYSTIME bitRead(PCONFIG(0),0) +#define P094_SET_APPEND_RECEIVE_SYSTIME(X) bitWrite(PCONFIG(0),0,X) + +#define P094_GET_GENERATE_DEBUG_CUL_DATA bitRead(PCONFIG(0),1) +#define P094_SET_GENERATE_DEBUG_CUL_DATA(X) bitWrite(PCONFIG(0),1,X) #define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. #define P094_NR_OUTPUT_OPTIONS 1 @@ -155,7 +159,8 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); - addFormCheckBox(F("Append system time"), F("systime"), P094_APPEND_RECEIVE_SYSTIME); + addFormCheckBox(F("Append system time"), F("systime"), P094_GET_APPEND_RECEIVE_SYSTIME); + addFormCheckBox(F("(debug) Generate CUL data"), F("debug_data"), P094_GET_GENERATE_DEBUG_CUL_DATA); success = true; break; @@ -178,7 +183,8 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) success = true; } - P094_APPEND_RECEIVE_SYSTIME = isFormItemChecked(F("systime")); + P094_SET_APPEND_RECEIVE_SYSTIME(isFormItemChecked(F("systime"))); + P094_SET_GENERATE_DEBUG_CUL_DATA(isFormItemChecked(F("debug_data"))); break; } @@ -198,6 +204,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) if (P094_data->init(port, serial_rx, serial_tx, P094_BAUDRATE)) { LoadCustomTaskSettings(event->TaskIndex, P094_data->_lines, P94_Nlines, 0); P094_data->post_init(); + P094_data->setGenerate_DebugCulData(P094_GET_GENERATE_DEBUG_CUL_DATA); success = true; serialHelper_log_GpioDescription(port, serial_rx, serial_tx); @@ -216,7 +223,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) // Scheduler.schedule_task_device_timer(event->TaskIndex, millis() + 10); delay(0); // Processing a full sentence may take a while, run some // background tasks. - P094_data->getSentence(event->String2, P094_APPEND_RECEIVE_SYSTIME); + P094_data->getSentence(event->String2, P094_GET_APPEND_RECEIVE_SYSTIME); if (event->String2.length() > 0) { if (Plugin_094_match_all(event->TaskIndex, event->String2)) { diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 12e01fe62f..1948868343 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -91,7 +91,7 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) _deviceId1._serialNr = 0; for (int i = 0; i < 4; ++i) { - const uint32_t val = payloadWithoutChecksums[offset + 7 - i]; + const uint32_t val = payloadWithoutChecksums[offset + 4 + i]; _deviceId1._serialNr += val << (i * 8); } offset += 10; @@ -103,11 +103,13 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) switch (payloadWithoutChecksums[offset]) { case 0x8C: // ELL short offset += 3; // fixed length + _deviceId1._length = payloadSize - offset; break; case 0x90: // AFL offset++; offset += (payloadWithoutChecksums[offset] & 0xff); // dynamic length with length in 1st byte offset++; // length byte + _deviceId1._length = payloadSize - offset; break; case 0x72: // TPL_RESPONSE_MBUS_LONG_HEADER _deviceId2 = _deviceId1; @@ -122,10 +124,10 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) _deviceId1._serialNr = 0; - _deviceId1._length = payloadSize - _deviceId2._length; + _deviceId1._length = payloadSize - offset; for (int i = 0; i < 4; ++i) { - const uint32_t val = payloadWithoutChecksums[offset + 4 - i]; + const uint32_t val = payloadWithoutChecksums[offset + 1 + i]; _deviceId1._serialNr += val << (i * 8); } diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index fedd06ff11..af9213500c 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -94,6 +94,290 @@ void P094_data_struct::sendString(const String& data) { } } +const __FlashStringHelper * getDebugSentences(int& count) { + switch (count) { + case 1: return F("b3C449344369291352337D55472593107009344230A920000200C0538ECE32625004C0527262500426CBF2CCC0805BDF032262500C2086CDF21326CFFFF046D26BB1103DA22B4E093E2"); break; //QDS.0A.00073159"); break; //QDS.37.35919236 + case 2: return F("b9644A732260729700A0AB8487A4E10002002747D00046D030AC1270CB02E0600000000446D3B17BF2C4C0600000083410084016D3B17DE268C010600000000CC190B0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22030402000F841001245C84E7"); break; //LUG.0A.70290726 + case 3: return F("bCE44A8153132000801022ADC7F6900C005098D2F2D70E24F3E43458739FD572B2DB7CB22EA563C57F3017308E093A4CBC662DF70F000A2E2B18215FC7098DBC7DC8A2ABAD8202F700C5A7D8B0FC89094823FC6B54565730369E73039146898536381B5DE8B8F3A5377A807EB30383ACC0176176C6C18265932082844F0B5A3F69B0A66FD0E35FAED9A53B825E073FC1E67193A727C97BC1025229C87421FA0381443A5F2F2897AE44D383FE125614F08BABEC6B46DF0FFCB910DAD1B3CD53B44AA83726492D845F840A2D20B738E9FB212D5C74FF91FD2796A22D669CBF0B0FEC1BAFA171A65FFB165B2E9"); break; //EMH.02.08003231 + case 4: return F("b5344E2306291001500030F388C30A7900F002C2583AE010032E1E493C32BEF51CDA37A430030071027A19EE14B0BBCAD656D0783516CCB7CFBC6AAFAECDCAD70020FE3DA54FCBC8EC2AED88DFD0972C55CF9336E1683574ABADBD046BB53623F8013"); break; //LGB.03.15009162 + case 5: return F("b5344A732806139690404B70A8C2063900F002C25923338000C8BC361CE2EE050FD3B7A6340300710DEC49523134391877289A80A53A505655A833F754F221E619D08FB4DB5AD773EAB16B545B306C69D1493CD851012BBF4624A5DDA556AF07E83E5"); break; //LUG.04.69396180 + case 6: return F("b9644A732460335700A043C1F7ACD0000200274DE02046D030D94250C804C0623000000446D3B177F2C4C060000005D610084016D3B179E248C010600000000CCB81D0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980F9"); break; //LUG.04.70350346 + case 7: return F("b13440000000000DA00DAA8CF7101FD0C3A02FD171101CB938032"); break; //@@@.DA.DA000000 + case 8: return F("b63445A146699750001026CE68C20D7900F002C25D7CE0C000B7C13179B38522166CE7AD700400710CDEF8D2A82F77DD15E367871F1E04261AAFAC430C2B55C1DED4A3148306D4C296CF10D72C9E79310A47DD73FDBFDF2CEA6490B6CA12A30EE5D64621A90B5E71F75D50D24C87B10E2ADDF802E"); break; //EBZ.02.00759966 + case 9: return F("b5E44496A3680003888049D2D7A1D0050053FBA7B54810C548AC112ECFC76CE753AF07A625248C05827C843371AB5DC6C6C8D5D457E845B4B67FB4CEFF06720EA7A9112BFD0A96BC7E97D49FB9BBD59155D109433F0C4823DEA7A13E5281C00E4945F5B05D7518CE085EC8BFE738122"); break; //ZRI.04.38008036 + case 10 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 11 : return F("b3E44B405399098502E0439DC7A0F70300530C7144B5962760A55DE8BA4E49C37676B0CD702698B5FBCE59E35E33D33F736AE13FB1C31DD43ADDC3FE7FF8E1EDC01D749974884BBF96580FE"); break; //AMT.04.50989039 + case 12 : return F("b5B4479169014216130377E5B8C2034900F002C256448000029E1A134984E32773DF97289000047791611023400302CBD0710FF4380B4AE49A140E94F319BE97049FDA8DDC96A8DC437F3BFB02ADC86082E9507934C7ED4FC6F4F678D613F25C09A1DDE927D817F5A824A8012"); break; //ESY.02.47000089"); break; //ESY.37.61211490 + case 13 : return F("b7B445A1415200000023724958C20A0900F002C25B4F60800C0E1D417100AD1BB6EDC72324371005A140102A00050F9B10710112A08DB9869998DE2C0D8614F76213F8682D10A8EF2951413C839461E8E3139EA62193E02B1584E6EC8EDB082AB70C6504F1ADF9E6ABD270E96FE8745AEB93C454FC3C9EAA2D5FCD6679E8A38A3E0818D4B6652993CEE5F8E514867801D"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 14 : return F("b49449344100549253508227F780DFF5F3500824600007E0007B06EFF2BE9FF000000007F2C000000009E24000000DAC000008000800080008000800080000000E9F10000000000000000002F046D010E8625249880E6"); break; //QDS.08.25490510 + case 15 : return F("b9644A732370335700A045D187A440000200274DD02046D071189260C33FD0638010000446D3B177F2C4C06000000DFDD0084016D3B179F258C010641000000CC0DBA0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980E0"); break; //LUG.04.70350337 + case 16 : return F("b4806AC1956030015020363917256030015AC190203D8000000466D00AC9200118625000D78113131363533303030619C3531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8057"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 17 : return F("b9E44A815242292070102881F7F4B0098050B0E989C939C3479F8904137236FE582B853DCACDD8DB48A717A6B42935CB977102079E6397B07AAD2A648E5B65E44D97F9A020B2BFAE433FA37FCB2A2C32711A5986B301D2F6E4A424C1144D808CE9D592C316B117C572689AC6C1322CC05E81F590CAAF457390F6B39DACC946FA314F8E8A34268157AC4338781C3EF5807F9221394DD1FAB5165E1261614B8B85758851295334DF52D9A4DCE2E1E17A555A21007D2DA802B"); break; //EMH.02.07922224 + case 18 : return F("b2E44B05C99010100021B65BE7AC30000002F2F0A6605020AFB1A33041AA002FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8008"); break; //WEP.1B.00010199 + case 19 : return F("b2E44B05C75000000041B8EF87A510000002F2F0A6661010AFB1A8905449802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F8"); break; //WEP.1B.00000075 + case 20 : return F("b1E44C418EA76010001034ECB7A820010A5597AB1CCF2014088590E64BCAB21DC1CC068DAA08035"); break; //FFD.03.000176EA + case 21 : return F("b4E442423245450514A07545F7AC6004005BDB5EDF3750DF41725EE867C3E39750E20B9F5FB092089B6A5DC7AA586101778BCD5EAD4995B102AC639F0FB4D12403EFE3554F72CAE4F5D348CC374F571CCE4A98634318027AAF3E7DD8600"); break; //HYD.07.51505424 + case 22 : return F("b4344A511031008667607CFF48C0031900F002C2531D311006D980E9CC8D28524C6417AE570210710CFF2DB65BFE77C51602690DAEB954A5455A2ABED621B74AC56A79D81390EBFCADC9D3D34F5928DDC"); break; //DME.07.66081003 + case 23 : return F("b4344A511031008667607CFF48C0031900F002C2532D31100BC55A548A0082663A6FC7AE670210710C7B178D748F610E2CB16DE82C823EF83334EF1A0C383FB42DF7BED1846323211FC25DCC1EBF085DE"); break; //DME.07.66081003 + case 24 : return F("b4344A511031008667607CFF48C0031900F002C2533D311004E0C2E86D68C08F425747AE77021071013F9284E0CB5896FFB27D33882716D09F7EC8175FD04516AAE9122E584095D6441E14E5B4ED189DD"); break; //DME.07.66081003 + case 25 : return F("b6E44A511825169584004B8737AB500600554B11A7F9F7DDCAC35695A3191EA83FD79D1876F378419D5AB37CA1BD857243492B6379B258A4831015F9F0D4B7098218D7E7C44421422FCABC0770F0E67C16EFA13ABEE798D58062CDB0F06AA312592C085F046D29B64F7031FE17CC7EC8B44D61FB5E2F37301ACA7AAC025666C802C"); break; //DME.04.58695182 + case 26 : return F("b4944C51402203571000451A77A090001202F2F046D2E299926040687ED7214000001FD17000413F6670400043B009378000000042B00000000025B1900025F1986B90002610A0003FD0C05000002FD0B3011F52BA393"); break; //EFE.04.71352002 + case 27 : return F("b2844C5146427807103073D877234626016C5140007D72000202F2F04DD1C6D2F3498260413B96E010001FD1700066080E7"); break; //EFE.07.16606234"); break; //EFE.07.71802764 + case 28 : return F("bA644C514960080900307DABF7296008090C5140007ED0000202F2F426E8D6C7E2944133C08000001FD1700840113039188130000C40113D611000084021324108D5A0000C40213A70F00008403132C0F00003550C403137B0E0000840413C0080000C404749913650800008405133C080000C40513AD831B07000084061380050000C406138401006999008407133A000000C407133A00000084286B081300000000046D332A8F260413A7137132000003FD0C02032102FD0B01114D8480FA"); break; //EFE.07.90800096"); break; //EFE.07.90800096 + case 29 : return F("b5E442515695800000C1A452E7A590050252502B45C2E823EF856FABFC4775E28D2904492FB74BA65A843BA7E63BC698D83279AE2BE04B957699517818F7B33F8E58001A7C9CE0E73C5769487247954D0A000E811754BAB1CED0E61567EB1FE504B091E0C7DCF4632E3FAC31618804D"); break; //EIE.1A.00005869 + case 30 : return F("b4806AC1956030015020363917256030015AC19020323000000466D0009780004872B000D7811313136353330303028633531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8030"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 31 : return F("bY5044972608062002001A7AC90340A517F5A8F83D78281AEFF06FDBDEDEF842336FA663F292D6EEACB0F54CA02FB47C8F587862B352ED30166FEE61753998230C38444F845C9FCC364D3C614095F92D14A28010"); break; //ITW.1A.02200608 + case 32 : return F("bY5E449726900634160004728499181897A60030BA0040A53FB81E378B33F9E23FEDF6A0B1B381F4972C2842041CC7EC8D74D675CE56222039CE82385073750F2B695CBEC9B0E8A48EC3F09B74C26E4194A06B7974203DDD0C7976874216E0D282DE"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 33 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 34 : return F("bY5044972625353893071A7A0B0040A5B12EC2E009C467CAD2AF0A38712684FE764C6181D2969A7F0F7B076CB9719FEB21C32E48161EEA5A1E6E92F354FED894994C368F17E6F68E2E6AA1D7C289E3FD7A908015"); break; //ITW.1A.93383525 + case 35 : return F("b2E449726606670194107A6AB8CB0D47ABF0000A00413E84B070004FD3442178001C00004933C00000000333B00000A2D00325A0000CD2E801C"); break; //ITW.07.19706660 + case 36 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 37 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 38 : return F("b494493447236379635083FD9780DFF5F350082030000F00007B06EFFC6F5FF310300007F2C070300009E24310300E13000008000800000000000001F007300A145C9006BFF64003D000C002F046D200E86255AA081DF"); break; //QDS.08.96373672 + case 39 : return F("b494493447153871216062D53780DFF5F350082DA00007F0007C113FF8331FF969799997F2C279899999F2596979988C999000000000000FFFF000000000000008B35000000FFFFFEFF00002F046D25068C2608D2803F"); break; //QDS.06.12875371 + case 40 : return F("b344493447153871216069A667A8000082004ED3926096C2701FD0C110157046D17138F2602FD3CC2010DFF5F0C005FC50861FF000006130701FFFC138B803F"); break; //QDS.06.12875371 + case 41 : return F("b3D44934417196746221AD6FF7AA210000081027C034955230182026CAC3BB62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B62102FDFE8FAC7E19004F33802D"); break; //QDS.1A.46671917 + case 42 : return F("b3744934417196746221A40247AA310002081027C034955230182026C5AE5B62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B621AD04802B"); break; //QDS.1A.46671917 + case 43 : return F("b39449344775149131706E1D57A680000200C13750000004C1300000010FC00426CFFFFCC081358000000C2086C9F61212502BB560000326CFFFF046D070B8A268D5880FA"); break; //QDS.06.13495177 + case 44 : return F("b4944934477514913170662C2780DFF5F3500827B0000810007C113FF5A69FF75000000FFFF000000009F255800004659000080008000800080008000800080009B248001000000000004002F046D1F0D8A266CB280FA"); break; //QDS.06.13495177 + case 45 : return F("b3744934484145047231AAE907A9600002081027C034955230082026CD1DAFFFF81037C034C41230082036CFFFF02DDAAFD170000326CFFFF046D0503AD21AB3580D9"); break; //QDS.1A.47501484 + case 46 : return F("b39449344843350131707BA4A7AF00000200C13000100004C13000000C11300426CFFFFCC081361000000C2086C9F6DF62502BB560000326CFFFF046D370A8A26486681E6"); break; //QDS.07.13503384 + case 47 : return F("b49449344843350131707395D780DFF5F350082000000EE0007C113FF4BC0FF00010000FFFF000000009F256100009FB5000080008000800080008000800080009B248001000000000005002F046D020D8A263BD880E7"); break; //QDS.07.13503384 + case 48 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 49 : return F("b2C449344098932353337D4E7728903252493443307C000082004ED39ACEB2C06702501FD0C10046D1C06902602FD705D3CC20189FB81DA"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 50 : return F("b5344934409893235333714F478077989032524934433070DFF5F3500D11E82CE0000100007C113FFFF362007007FCFC92C314304009F252620070020029102810C8E02730241023902940287023F0254029062770227012F046D14108D26710885D5"); break; //QDS.37.35328909 + case 51 : return F("b1F44685034025063591B28F57AE100000001FD17000265EF070F6A18DFC253E0F351D0900E8180F9"); break; //TCH.1B.63500234 + case 52 : return F("b294468501904601473F0AE14A0009F27EDA5B130CA280080770001045667006BA1007CB2008DC3009ED4000FE50096BA80EB"); break; //TCH.F0.14600419 + case 53 : return F("b294468508220285376F0F19BA0009F27A1280028A128000033000006BC4C006BA1007CB2008DC3009ED4000FE50096BA80DC"); break; //TCH.F0.53282082 + case 54 : return F("b50446850920420745937163972612600006850FE036B0000200415CC4CB0551F0084041552FC1C0082046C7C228D92D804951F1E72FE000000006F1BF114A212D1B377124C1EA62E83430E5006511443943F9B47F52901FD17002F1F2F800E"); break; //TCH.03.00002661"); break; //TCH.37.74200492 + case 55 : return F("b3644685005012040714351C0A004372900000060DA4E029B5FBAC4123A84170DBBFBF13D06000000000000000000AE3800000000000000000000000000FFFF94A6"); break; //TCH.43.40200105 + case 56 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 57 : return F("b8E44A81524229207010276807F680080056E68ED762185BEDAB68F79E2A8BF6562ED1C21105B74E82AA9D1B5E79311AB713DC2F86C785D18F6E470067B86284E8A9D1AF9F36330FE18968F826F8D1B21E99F1C08D45FB9CDBF04B37136E2FC1CED74FF3186482FA3058F6F1BD712BBE20098CCB0C72D51F6013CBB974678706CF2F4D6D0D07A793FE1EC8EAF701AD2BEE5922E69F72C356AC1B009A0E0646B0413DD45802B"); break; //EMH.02.07922224 + case 58 : return F("b374465B2118222001604DDD67A26140000046D1107152A01FD0C06326E796CFFFF0DFF5F0C00083D300001061308131C0BFFFC02FD1700140C7896145559D9FF8032"); break; //LSE.04.00228211 + case 59 : return F("b4BC465B251A16000F193DC2CA083110049244E01394465324604401311FC17067A4F0000000C13714800004C1310BC7A000000426C7F2C02BB560000326CFFFF420A046D2009912682046C9F258C04136643DF650000FFFF80DE"); break; //LSE.00.00000000 + case 60 : return F("b4BC465B251A18000F1950519A08311009E2423003944653252044013781E17067A500000000C13063401004C1310623C000000426C7F2C02BB560000326CFFFF420A046D330E912682046C9F258C04138720452E01000B2780DD"); break; //LSE.00.00000000 + case 61 : return F("b43C465B251A12001F0DDDD95A08310008A2460013144653221587296186735087A4F0000000B6E9102004B6E000041BB00426CFFFF326CFFFF046D2108912682BC3E046C9F258B046E9102000B2A80DD"); break; //LSE.00.00000000 + case 62 : return F("b25C465B251A0000AF1033454A2653205834710290E862400005F3573BB1B9A276422A2271D001D0004C9253580E4"); break; //LSE.00.00000000 + case 63 : return F("b4344A511031008667607CFF48C0031900F002C2531D311006D980E9CC8D28524C6417AE570210710CFF2DB65BFE77C51602690DAEB954A5455A2ABED621B74AC56A79D81390EBFCADC9D3D34F5928DDC"); break; //DME.07.66081003 + case 64 : return F("b4344A511031008667607CFF48C0031900F002C2532D31100BC55A548A0082663A6FC7AE670210710C7B178D748F610E2CB16DE82C823EF83334EF1A0C383FB42DF7BED1846323211FC25DCC1EBF085DE"); break; //DME.07.66081003 + case 65 : return F("b4344A511031008667607CFF48C0031900F002C2533D311004E0C2E86D68C08F425747AE77021071013F9284E0CB5896FFB27D33882716D09F7EC8175FD04516AAE9122E584095D6441E14E5B4ED189DD"); break; //DME.07.66081003 + case 66 : return F("b6E44A511825169584004B8737AB500600554B11A7F9F7DDCAC35695A3191EA83FD79D1876F378419D5AB37CA1BD857243492B6379B258A4831015F9F0D4B7098218D7E7C44421422FCABC0770F0E67C16EFA13ABEE798D58062CDB0F06AA312592C085F046D29B64F7031FE17CC7EC8B44D61FB5E2F37301ACA7AAC025666C802C"); break; //DME.04.58695182 + case 67 : return F("bYB04424341931031950067A800000002F2F0413F1570000046D092EC52504FD17004000000E780000000000004413184B0000426CBF2C840113F057000082016CDE24D3013B4E0400C4016D3128692C8104FD280182046CDE24840413F0570000C40413FD560000840513D1530000C40513CC4F0000840613184B0000C40678D313EA47000084071323430000C40713153F0000840813FD3B0000C4081393380000840913A3340000C4091311310000271081D7"); break; //MAD.06.19033119 + case 68 : return F("b4E44A5113748906370076F917A570040053A66831E6B6C8F06FB2C7CC1F60A673B63ACBF2F6A8D3347D34DE4BBDD4677E5DEC850D5CBBDF5B0AA7095B415EFCD93A124AC3B884FAF226845C439DBF3A2EB486CBE7D8D845383E3E480ED"); break; //DME.07.63904837 + case 69 : return F("b5344A511292535727507858F8C000E900F002C25823E090045AF7EFEDB43FBE691577A82003107105692A21A8C0C7531EEEAC3AA631D6BD790CA1B271C7E3C8860A189DA37AE30E89AB63AD316663EB4AD472596156E592602F8A016E51A5E0D8753"); break; //DME.07.72352529 + case 70 : return F("b5344A5117157367276075A048C00B0900F002C25218501000C373A89C912675F09407A2100310710DEF25F58D772CBD51AD6D2B487ED868B6B086976F51AE52E65D877F0310E9DCA942F4E7F94196DD2821329E662FD4E4C9F20A1A8829C54328EEC"); break; //DME.07.72365771 + case 71 : return F("b2E44A511880110827B0780AF7A4573200592F4DF44D5F258DF39AB376DD4A5BC338BBB2493257A98DC52C5E6299029DC79C01ED377C7F48028"); break; //DME.07.82100188 + case 72 : return F("b3644E61E95413900010E89957212517615E61E3C074230206593240B570397DF6230FBC015B276D63CD694FA79B17D1436E0E9FA1003C0763761BD8FBD67B73A8D"); break; //GWF.07.15765112"); break; //GWF.0E.00394195 + case 73 : return F("b9644FA12237704190007308E7AA8000020046D1E2B862B0413D1EA01F9CA0002FD17000001FD481D426C7F2C4413455C9E8A000084011370E50100C40113A0C200F70100840213EA9E0100C4021349870100735F8403130A700100C40313595301008404C386139F2B0100C4041345FA0000840513BABE2BCD0000C40513DEAA00008406139E8A00A1F700C40613D966000084071390400000C4F6040713E11C00008408136200000087F382DE"); break; //DWZ.07.19047723 + case 74 : return F("bA944FA1283211320020766737A6B009025ADD27B2058B2ADAAE5B5D2C8B11BD295CE460BD1ECA50B533A58FF19F7F9DEC291893DA502B763E7C80CEF440B899C92DE87D5548838FC2C9FF3873927441B0B17222FB14545D2E5A0CF81216074B3DF0911CB99BD20A558F2D873A9A649092F3C7B01BA2BEBCC26A58C0FD99ABC2E5E0E5AFC241A27B8C0863C571C3D586B7E2A06044B792CFE021C21BB1B71BCEE4D5D84E75C3FC0624DF07C8C8832C82140086903FD0C08000002FD0B011116A380EF"); break; //DWZ.07.20132183 + case 75 : return F("b3944934419504913170628617A660000200C13480900004C130000007BBF00426CFFFFCC081315020000C2086C9FC6D42A02BB560000326CFFFF046D1316952B82B084D3"); break; //QDS.06.13495019 + case 76 : return F("b2E446850915944496262C568A0009F276D03B017BC0000060A0A0809A71C0908090706070A0A09090A0B0B080708CB640A060A07071EA586E2"); break; //TCH.62.49445991 + case 77 : return F("b2E446850573060566562ADA6A0007E293200C0191400001400000000CC37000000000000000001010101010101023FB20101010001328686E1"); break; //TCH.62.56603057 + case 78 : return F("b2E4468505162250070628CD3A0009F277D00600A0B00000001010101002A010302010101020102010101010101018F6C0001010102AF7786F8"); break; //TCH.62.00256251 + case 79 : return F("b2F446850302976627462A01BA2064D280000600A240004000307070747EA0706060000000000000000000000000077A2000000000000FFFF80F6"); break; //TCH.62.62762930 + case 80 : return F("b2F446850370321809562C217A2069F270C00A00E0700000001000001B0E800000100010100000101000100000100B1AD000101010001328680F9"); break; //TCH.62.80210337 + case 81 : return F("b2D44653277993613170784017ABA0000000C13196100004C131100003AE500426C7F2C02BB560000326CFFFF046D2ACD2E068527CCD580DF"); break; //LSE.07.13369977 + case 82 : return F("bY24442D2C394864681D168D20AE91BF1622CC255857FE7B524DD67C4944CD428FBE5E0DFAB98021"); break; //KAM.16.68644839 + case 83 : return F("b2D446532490340131706417B7AB20000000C13814000004C13100000A12600426C7F2C02BB560000326CFFFF046D2ACD3B168327AC23800F"); break; //LSE.06.13400349 + case 84 : return F("b3644E61E08106100020E7F627236090021AE4C01071B0020A56EE84D172DF9648D9C4409131B88D3FD85BFD022BCB54971CACB714D617E5563719B95E9B2059A59"); break; //SEN.07.21000936"); break; //GWF.0E.00611008 + case 85 : return F("b3E44FA1287530019011691D07AC6002025D541F7DE1D910813127884F7DF4D80BF600A4323BD730B4639E4E0EA8B86129BDE9DD71D0F800C000109002487721866530201310101B10187CE"); break; //DWZ.16.19005387 + case 86 : return F("b9644FA1261281221000689447AB9000020046D302BAF2704136300009A0E0002FD17000001FD481C426C000044130E9B0000000084011300000000C4011300002A2D000084021300000000C402130000000098F984031300000000C40313000000008404B0D51300000000C404130000000084051300A00E000000C4051300000000840613000000B5CF00C406130000000084071300000000C4E74A071300000000840813000000009995812A"); break; //DWZ.06.21122861 + case 87 : return F("b3E44FA12336300190106617D7A81002025F1114AE0F19A04778065DD02E84809E9F7163157F05FB2506D26A3835904CED370FBCA9E0F800C00010900E10E03000A70207F3101013FFE80E3"); break; //DWZ.06.19006333 + case 88 : return F("b4C44B40968440303170787F77A3F0000000C1305000000046D1A2EAAA19F250F8F00010000000000000000000000D5BD00000000000000000000000000000000FFFF00000000000000000000000000000000FFFF000000FFFF80EE"); break; //BMT.07.03034468 + case 89 : return F("bY29442D2C394864681D168D20B3B0BF162236090AB83DFCC84216131495B5A2DF59242760EDECA043AF20801F"); break; //KAM.16.68644839 + case 90 : return F("b2844C51473278071030605C97237253816C5140006612000202F2F0464E66D243498260413070B010001FD1700146B80DD"); break; //EFE.06.16382537"); break; //EFE.06.71802773 + case 91 : return F("b39449344715387121606AE447AD40000200C13969799994C132798998CC999426C7F2CCC081396979999C2086C9F18DC2502BB560000326CFFFF046D2E0D8D261542803D"); break; //QDS.06.12875371 + case 92 : return F("b39449344724733131706336E7A270000200C13330600004C13100000218B00426C7F2CCC081382010000C2086C9FF2142A02BB560000326CFFFF046D1116952BF4D081DC"); break; //QDS.06.13334772 + case 93 : return F("b3944934451926513180637967A7D0000200C13110000004C13000000B0B100426CFFFFCC081311000000C2086C9F52D52A02BB560000326CFFFF046D3A0B862B28D08027"); break; //QDS.06.13659251 + case 94 : return F("bY5444A85C3281262703077AA90040254A1AED9189683FF741015BCF9C9FD17914758544A14121969793DAA718C7C091F9E26BF16197828BD514A4E66C5460849605A64ACFBD3D3167332F6AF040711E426CBF237DD6802A"); break; //WEH.07.27268132 + case 95 : return F("b394493444993671216075B197AD00000200C13850441004C13286138A3F900426CBF2CCC081345574000C2086CDF284D2302BB560000326CFFFF046D330BD62497B485F8"); break; //QDS.07.12679349 + case 96 : return F("b39449344782049131707F5A37A480000200C13121902004C13000000D42000426CFFFFCC081353750100C2086C9F077F2A02BB560000326CFFFF046D0716952B9ADF80EA"); break; //QDS.07.13492078 + case 97 : return F("b3944934462526513180768437A880000200C13060400004C13000000950300426CFFFFCC081398000000C2086C9F0D7D2A02BB560000326CFFFF046D320B862BCC358012"); break; //QDS.07.13655262 + case 98 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 99 : return F("b6644496A721102551437F5C77224831715496A000726005005827161FD1AB240AE86C2A6D7F691E4C8531E4530AE4FC8A294BE87862FDDDCE843D7679005C55E082A744BC18EA87FF12298AE4258EE9D89B1F9511318B8D7152464FB11007F5CEB827893513C954A6E9735185FE268124771D567A080E8"); break; //ZRI.07.15178324"); break; //ZRI.37.55021172 + case 100 : return F("bY50449726041331160007728499181897A60030E10030A59E74DF73596296EE08CF3F1BA88B47A3A264C30177EC921B750B03B99F992A0EEB064560EFAD6C5EC7CCA1009D72C63B0E79000000000000697E801E"); break; //ITW.07.16311304"); break; //ITW.30.18189984 + case 101 : return F("b2F44090773754205100794947ADD100000046D070DBB2404130F000029E0000259F0D834FD17010000000424132B5729820001FD7462313A802A"); break; //AXI.07.05427573 + case 102 : return F("bAE44EE4D449858203C07C8B87A0100A0257AB76440C2E16196857D0FAC3205AFB9D036CD7885C1F60C61095F2300D08DF56026E74FFB2F876BD89D27F65B3EA3729F53B26A48F2A5684EDD67A16177F8DD127C2CD8FE1C42CD5035E7EE110515C7369DB07AA59D5954E077C30AA29423D12429C77F6A7DEF679B3A90D7FD075AB7ED262466ECB4FDB66C609FC5DCBEA89FBCEB7BAA4EB8C312CF1A242B39A696A25E81CF0B5994B25CBDC06749D29F5B0F9E9F98476FFF9ED428840C0082459878C8FCEBA90EC380F7"); break; //SON.07.20589844 + case 103 : return F("b4344010648020780011656A78C001D900F002C2561675D61AD80F90FDEC404B8CAB47A80032007100A387268EF9F9CC8106E5D7FEE6E9D41D7E8780E2B18C2F71743F96AC442C6191D9B8E8E2AEE85F1"); break; //APA.16.80070248 + case 104 : return F("b2E44685017467703627254FFA0009F299A23A02C3A000008060605050B45060504020407060412140C0F0F100E111BFE070B0A0908C0EC81DC"); break; //TCH.72.03774617 + case 105 : return F("b2E446850812896626572C47AA0009F290D1620272200060001018DE4606A430F1101000701010302010403020403DC700002050302E7F581EE"); break; //TCH.72.62962881 + case 106 : return F("b2E44685007457014707281B0A0009F270400600A0100000000000001A1A60000000000010000000000000000010086A10000000000FFFF8007"); break; //TCH.72.14704507 + case 107 : return F("b2F4468509851603374725693A2069F27CE00600A600000000409090A8C140B090C0C0F0E070F0C0D0F0E0E0B0F0A640F09090D0E1009932C80FB"); break; //TCH.72.33605198 + case 108 : return F("b2F446850396450729572A1CAA2069F27FC09800D3E0200000238383EF87E353F3A3B3A2C2E1E2B3830111E2A181FA0AB2432273805208FCC86D2"); break; //TCH.72.72506439 + case 109 : return F("b76447916987435614037E4C2729646866079161102FC0060058CA7D7567090FFC84CBDE4FE2996BF8080E6A2C41D6DF46D8921894C814CC0BB36C550312F03A2734512ED7A69349DE3C349CFC079B62A3AD93BAA84A087C739785EFC9A415F6AF0662B05401FD0C4C9D4A676DA7FC1F6C592823EA6B6DFCAA3DDB2E4D5B6E87C5EA1B92E903D62"); break; //ESY.02.60864696"); break; //ESY.37.61357498 + case 110 : return F("bCE44A8154457060801022C397FDE00C005F4FEE3A225126DE3E8344CEACB8502C615B4F7EE9D9CA99F2E3AB5AEA9B3417ABD2B8DF835C0A8C31510DC184ACC8E261E24B717F51C01887D9B39D57965A4004CB68B65206E173F7374489CCBBAB63D4F4B33B488DE06DD33C93EB719BDD805E331238755D22C7E94ECD3636C1CCD965CF4E6DC37123EA8D95771BBCD12431AD12B646EBD21FCB77BD2D100C9CCCE7546268B3AF080DEC8F6B61BCC209013295A74A2730D9CB11E52056D0C0879EA29A2CE24210EAF58587855A790FF343CF82914E0164ED08C70FD54DB800BD9B1C0F2431883324E43A1D293"); break; //EMH.02.08065744 + case 111 : return F("bCE44A8153132000801022ADC7F9000C00546CF1AA7C3268079B9F3A0D8D2FA9AE941DDCDA1D0D8CFA6358FB9FDAD0AF38BB344D954ADD742E77428CA48DD918F361E23D5805BA6BB4CD2470016F66B92CF5D2AF69C7751F1FD2D887A10F26865E6AD95F58754980416935DA7A6C669823CDA9A3CF4D0EBE233D7F706DA6ECFD8209C8F140A7666B9AB2D9ED8C0D5AE04C3600B0899207B54AA98FABF9D14F773F41A53378E9A5678516B95EDEDED334821972EC196927F794E72725C78300FE65155E4E49B43A329EE44AD6FD90070548499CCFFD9FB71ACB4183B4B14DEF7D8B99BF02B754E651850960D80F6"); break; //EMH.02.08003231 + case 112 : return F("b7B445A1415200000023724958C2049900F002C259D7515009EC6163C4A7CB4E8935772324371005A140102490050646D0710FDE80DD548AA00BBCFEB3152BF11CDD91D4D31F1C73144BBB17696622104EB91D19A32FF7CA939126767495134EE598AF96AC9F0081A83B4D7EAF7A497981C15604C85E4E3B9FBA393BDAD8E0DED15EED4BA887D9970D17797849FE68045"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 113 : return F("b5B445A14152000000237E4CE8C2048900F002C259C751500003AD02FC41ACF50E92F72324371005A140102480030E8FC8710B2BC8D30DC227AD803ED24F3B6FCC6E5131442E65A7F5CC4589D51AE2FB2690E9457810BDAAAC81988A3E5E81E6CDA24BE256218D907511C8044"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 114 : return F("b1E44C418557901000102E4437ADB00108561D52810CD237CA87FB7C5A2F62A65C25C457BF78028"); break; //FFD.02.00017955 + case 115 : return F("bY4344471325798761013672193170604713010210000000000004788F419E030DFD110E39313133303730363030475A4431060200000000000006823C0000000000004E88"); break; //DZG.02.60703119"); break; //DZG.36.61877925 + case 116 : return F("b7B447916419806613037A83A8C204C900F002C25B4AA0000CC2128E94C8F3D946F737210552961791611024C00500ACF0710FCFB475BDA1FD49D52FF6FB45E833D5D97609373AB3EB562E01CE23D1389FFEC7EE41D4E7B20D35D8B80581C289834F4E3C542C09B0C37331332A321B79DAF7F60CDB028452AE3A26291EFD25C87DDC9EACF462C7B441510340F755C800B"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 117 : return F("b6B44791641980661303756A58C204B900F002C25B3AA0000ABEB03EC47E933C072B97210552961791611024B00400536871036D216BF2B74E11F1952539F406B7D4DB7721B1154E21C36F0F55BD4B5B5FF9977572BCD27D93A909347A0D84AE9E804C361E9E6D98F9BE296F76E3A5100357CDD3FA09AABE44103EB508044"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 118 : return F("b73447916856565601002F8DC8C0037900F012C25809A62002B5C02299AC829AD82267A370050471010A9AE87B893A51E226DD3203AD775D84E2B2E04D96F85DA0CD258EBC10912241ACAEB1406433A637F6C70811B7FC99565C388A0365A9B57F94E0380317F5CA1052D6FE55C7BE3118A4D1CD05AABC646F5D288B129D7934E68CF030A"); break; //ESY.02.60656585 + case 119 : return F("b7B447916419806613037A83A8C20EC900F002C259EB10000F76F8B1B2D9E402B9498721055296179161102EC00508B8E0710072DE1601CB75C3C9C30E9E037024B1D516151D3724CCF1654B2AC7707B5B41F2BBE3F2C19E9467A0740AB6A4F7F03F5E764FCCECC689EEA66BB4A9A6F25FDDCE8A60E9D998A43936B8A3B2EB57A8F667B476D1ED1CD2381D0ABF6118033"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 120 : return F("b6344FA30883161560002C10A8C2042900F002C2549030000BC2C8A72651D570AEB967AA7004007103CB056B91B8007B8882351411FD19256641A220725C724891287445B85FDFDA2DB638B542BB7FC7209833DE16EDCBB90FA686C10076EED63BD40AB0EE3EBCDFDF40032F5C0DCD66322BE804A"); break; //LGZ.02.56613188 + case 121 : return F("b6B445A14043300000237C1FB8C200E900F002C250E000000F96A649A04D7DC457E8972807759005A1401020E0040A6D20710A07B663F2ED91A0DEA4515C0C1D4A296569A7C4DC27AE724F38CF0E518949AFAA9C3AA8703638F5305E2A333941756C4F5BF4703A411B7FE92F58D7F2724E31E10DCDCBF2C7EE18CD4738043"); break; //EBZ.02.00597780"); break; //EBZ.37.00003304 + case 122 : return F("b5B445A14043300000237FF3F8C2001900F002C2501000000574262230ACE2FB2FB5072807759005A140102010030303C8710DD05806D5E2EFB0ACD9DA1964A191D7BADA8E1A508EE7CFA86336B14B1C756AA1E20FA5CE029D2CE99CC84BFA0CAFD723A5D0BC20E6FECC585FF"); break; //EBZ.02.00597780"); break; //EBZ.37.00003304 + case 123 : return F("b4E447916110000600702D8607A99004005860F4BADF0716289AEE56290239E4549E908B33CF4C280DEDD3382DF293865824ADFA25EBDDDF28DB046A59DA2A4C2DB62CF177F2E77EF3E62D6A67DEA6BBD01BEA1DFB9ED3DC8743E2E"); break; //ESY.02.60000011 + case 124 : return F("bD344A815394643100002D3DD8C2003900F002C25741E0000A17997475A31870EDCF27A0300B007101E6BCA68B34F4603824A04FC0B87A398438300B31366E3B94F45C0EEBFF210719F87A8382509BC329B59A4031ECAC4CA734374B06825329A3665EAA2C626DA096C8E50002E95443D540F92C90EE305931E8E066BB8A76AA2DDE94042B90B94E9D3174612DBF8755145BBA760A85B7C84DDF075950FFDE6EEB4EF76A664F4A474CE050E12021434806BB9C4CDDA5CA8F13DDE8010C5DB0EAD57FD5E6DF042A1C0AE83DA23EB2B8C3444A11D8A6F6274072E516F42DA449DC460D14C1D9E12F95CAE43112976493AD493F0"); break; //EMH.02.10434639 + case 125 : return F("b8E44A815262292070102C8F57FED00800592BC9808524F745DE09733D6B862F1FEF9AC816CCD59B730C0BC8D173E7B1B187735C505768A284780C3B7E53CCF252EC84F44DF2A8949DB12139FD80D000930321F57E73C8F22B44AB57C03F93C35B02B853E45A0960F0FCD326F4760CA76945EADF6F294356AC8308DE284EEBCECB57EDF9BB63BCC5D424A764348B2D40E86C812AEA58CA14B652DD3853BEF5BDF56A27F8031"); break; //EMH.02.07922226 + case 126 : return F("b5344A81594176710020267788C20D7900F002C256A000000E4D7497D043A0EE5B2A47AD7003007102F390C301AD7CB52A6B8633CA25AA26BDE4FDF94F3230E43CCBF66EEC0D4C0C7A6E66310DC6376768FE891C0CA84DD365D3FBF23690BB55E812B"); break; //EMH.02.10671794 + case 127 : return F("b2644AC482711000050378A347201271100AC4850021B0000002F2F0C01C103895936002F2F2F2F2F2F2F2F84F48029"); break; //REL.02.00112701"); break; //REL.37.00001127 + case 128 : return F("b7C44361C120001000002CA9C8C203F7A3F00000004050000000004FBCBA782750000000004FB82F53C000000000412B22A0000000004FB140000000004FB943C59F00000000004FDD9FC010000000004FDD954D8FC020000000004FDD9FC030000000004CF6EFDC8FC012909000004FDC8FC02F10400CDDC0004FDC8FC03F104000002FB2EF40101DC37FD1700DE8C80FE"); break; //GAV.02.00010012 + case 129 : return F("b3244361C373601000102603A8C20457A4500000004050900000004FBDA3482750800000004FB82F53C0000000004C3AE2A2415000001FD17001EB2801B"); break; //GAV.02.00013637 + case 130 : return F("bY394447135523636001027A830000000478232D9D030DFD110E35353332333630363030475A44310602ED8B0000000006823C00000000000004E4802B"); break; //DZG.02.60632355 + case 131 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 132 : return F("b494493447236379635083FD9780DFF5F350082030000F00007B06EFFC6F5FF310300007F2C070300009E24310300E13000008000800000000000001F007300A145C9006BFF64003D000C002F046D200E86255AA081DF"); break; //QDS.08.96373672 + case 133 : return F("b494493447153871216062D53780DFF5F350082DA00007F0007C113FF8331FF969799997F2C279899999F2596979988C999000000000000FFFF000000000000008B35000000FFFFFEFF00002F046D25068C2608D2803F"); break; //QDS.06.12875371 + case 134 : return F("b344493447153871216069A667A8000082004ED3926096C2701FD0C110157046D17138F2602FD3CC2010DFF5F0C005FC50861FF000006130701FFFC138B803F"); break; //QDS.06.12875371 + case 135 : return F("b3D44934417196746221AD6FF7AA210000081027C034955230182026CAC3BB62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B62102FDFE8FAC7E19004F33802D"); break; //QDS.1A.46671917 + case 136 : return F("b3744934417196746221A40247AA310002081027C034955230182026C5AE5B62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B621AD04802B"); break; //QDS.1A.46671917 + case 137 : return F("b39449344775149131706E1D57A680000200C13750000004C1300000010FC00426CFFFFCC081358000000C2086C9F61212502BB560000326CFFFF046D070B8A268D5880FA"); break; //QDS.06.13495177 + case 138 : return F("b4944934477514913170662C2780DFF5F3500827B0000810007C113FF5A69FF75000000FFFF000000009F255800004659000080008000800080008000800080009B248001000000000004002F046D1F0D8A266CB280FA"); break; //QDS.06.13495177 + case 139 : return F("b3744934484145047231AAE907A9600002081027C034955230082026CD1DAFFFF81037C034C41230082036CFFFF02DDAAFD170000326CFFFF046D0503AD21AB3580D9"); break; //QDS.1A.47501484 + case 140 : return F("b39449344843350131707BA4A7AF00000200C13000100004C13000000C11300426CFFFFCC081361000000C2086C9F6DF62502BB560000326CFFFF046D370A8A26486681E6"); break; //QDS.07.13503384 + case 141 : return F("b49449344843350131707395D780DFF5F350082000000EE0007C113FF4BC0FF00010000FFFF000000009F256100009FB5000080008000800080008000800080009B248001000000000005002F046D020D8A263BD880E7"); break; //QDS.07.13503384 + case 142 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 143 : return F("b2C449344098932353337D4E7728903252493443307C000082004ED39ACEB2C06702501FD0C10046D1C06902602FD705D3CC20189FB81DA"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 144 : return F("b5344934409893235333714F478077989032524934433070DFF5F3500D11E82CE0000100007C113FFFF362007007FCFC92C314304009F252620070020029102810C8E02730241023902940287023F0254029062770227012F046D14108D26710885D5"); break; //QDS.37.35328909 + case 145 : return F("b624468501509651494085A758C002A900F002C25DECE080028421E778E39B0665A707ADE0030071080A1255F4529D6628D1BD017B641EF0A8046B680C77DAB285B3C2A943522663000821E48556555C93D048F5DF327EFA4BECCA1914A1C0F9EFCE6532756F5E9BF68B0E01E8802D91270"); break; //TCH.08.14650915 + case 146 : return F("b31449344401892903408DFBB7A9B0000200B6E4800004B6E14010042A7D46CBF2CCB086E480000C2086CDF23326CB9BCFFFF046D0E0BD624CF16800B"); break; //QDS.08.90921840 + case 147 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 148 : return F("b3444EE4D774933221608D1BB7AF7000000046D280DBB24036EEB000059A9426CE1F7436E00000002FF2C000002598620C80B0265F10802FD66A000779E80EA"); break; //SON.08.22334977 + case 149 : return F("b2E44B00971280018540843227A0E0000202F2F036E0000000F1000016F1B8563822A0000E70A812A000000000000AF010000000000FFFF81DD"); break; //BMP.08.18002871 + case 150 : return F("b2E44B00971280018540843227A0E0000002F2F0F0000000000000000718D00000000000000000000000000000000FFFF0B2A00002FF97381DE"); break; //BMP.08.18002871 + case 151 : return F("b26446532392238253508D6A07AAF0000000B6E0000004B6E000000422F866C7F2C326CFFFF046D2D0A83279B6780E8"); break; //LSE.08.25382239 + case 152 : return F("b62446850189272149408C4E28C00CF900F002C2564B20800A81E8BCCCA14532696097A6400300710F61F531C03426B9317EAD69912E862AC2017148D8C179D50E133470B7A04CD063D00E6FB1C522DDDC80A3300335E26FE16F9D339A61C0F41BC1ACF4A0A8A29310674536C344CA64D7D"); break; //TCH.08.14729218 + case 153 : return F("b434468501892721494083F2A8C20CD900F002C255FB20800903D2653461ABE7080E57A5F002007103032214C1915B7A16175B00F90B8EB889A4C280207D9C74F5A4088C584D951BDB20851C3DF9E"); break; //TCH.08.14729218 + case 154 : return F("bY2F44C5145935816213087A080000202F2F046D0F2EBB24036E000000426C9F25436E000000317F00346D00200000F1458737"); break; //EFE.08.62813559 + case 155 : return F("b3E44F536861202000108F54A7A9B0020250A86DF3204D8B7DAFBD62C57159092FFCBB77F612E656C59AD065C96CC24B353B024A6930F800C00010900E10E03005DC1207F1B05074A5380F2"); break; //MWU.08.00021286 + case 156 : return F("b2E446850844616516180E459A0015C284604600A7200003900341D9A5C477E9ABC873D05000000000000000000019BB4000406456E897887DD"); break; //TCH.80.51164684 + case 157 : return F("b2E4468506974806164805122A001DE26EB02900D570200000000040D21820D4E301126353030334B44170B0A01004EE40000000000FFFF83D9"); break; //TCH.80.61807469 + case 158 : return F("b324468500441169269802F7CA0119F272F01600A3B00C8082F09000007730000000500000220140B1807030000007111000000000000000001C29A85D5"); break; //TCH.80.92164104 + case 159 : return F("b33446850710351129480ABE9A20F9F270000D00E03000128090B0900DA3600000000000000000000000100020000274800000000000000000000FFFF80E3"); break; //TCH.80.12510371 + case 160 : return F("b4944C51402203571000451A77A090001202F2F046D2E299926040687ED7214000001FD17000413F6670400043B009378000000042B00000000025B1900025F1986B90002610A0003FD0C05000002FD0B3011F52BA393"); break; //EFE.04.71352002 + case 161 : return F("b2844C5146427807103073D877234626016C5140007D72000202F2F04DD1C6D2F3498260413B96E010001FD1700066080E7"); break; //EFE.07.16606234"); break; //EFE.07.71802764 + case 162 : return F("bA644C514960080900307DABF7296008090C5140007ED0000202F2F426E8D6C7E2944133C08000001FD1700840113039188130000C40113D611000084021324108D5A0000C40213A70F00008403132C0F00003550C403137B0E0000840413C0080000C404749913650800008405133C080000C40513AD831B07000084061380050000C406138401006999008407133A000000C407133A00000084286B081300000000046D332A8F260413A7137132000003FD0C02032102FD0B01114D8480FA"); break; //EFE.07.90800096"); break; //EFE.07.90800096 + case 163 : return F("b4806AC1956030015020363917256030015AC19020323000000466D0009780004872B000D7811313136353330303028633531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8030"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 164 : return F("b3644A511621280223837CE5E7241022436931581038C002005A8F458578136DF07A14CE37F82BA702DF936647F231F18C961CF7A6CE31CFAACE57153A8888B"); break; //ELS.03.36240241"); break; //DME.37.22801262 + case 165 : return F("b1F44685034025063591B28F57AE100000001FD17000265EF070F6A18DFC253E0F351D0900E8180F9"); break; //TCH.1B.63500234 + case 166 : return F("b294468501904601473F0AE14A0009F27EDA5B130CA280080770001045667006BA1007CB2008DC3009ED4000FE50096BA80EB"); break; //TCH.F0.14600419 + case 167 : return F("b294468508220285376F0F19BA0009F27A1280028A128000033000006BC4C006BA1007CB2008DC3009ED4000FE50096BA80DC"); break; //TCH.F0.53282082 + case 168 : return F("b50446850920420745937163972612600006850FE036B0000200415CC4CB0551F0084041552FC1C0082046C7C228D92D804951F1E72FE000000006F1BF114A212D1B377124C1EA62E83430E5006511443943F9B47F52901FD17002F1F2F800E"); break; //TCH.03.00002661"); break; //TCH.37.74200492 + case 169 : return F("b3644685005012040714351C0A004372900000060DA4E029B5FBAC4123A84170DBBFBF13D06000000000000000000AE3800000000000000000000000000FFFF94A6"); break; //TCH.43.40200105 + case 170 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 171 : return F("b5E44496A973430000D1AFCF97AF7CB50057AB6BD92ED8A65D4DB8A19DDA1B6D3CD164A0F600C93485BCFC48263B255C4FC57033B6114A4DD1590F6E3B22855F7161BBFB100973B49CDB3593DEC5164ECF04F1CAB0311E89B873ECECCD7FBF0D60D125734B551865D12F7D012748025"); break; //ZRI.1A.00303497 + case 172 : return F("b4E449344492512971437674F72090328039344141A7510002081027CB4ED034955230F82026C8927C1027C0354466C2C230FC4026D2C0E892781037C034C412307BC3282036C892702FD171000326CFFFF048C536D2809BA22ECC883DC"); break; //QDS.1A.03280309"); break; //QDS.37.97122549 + case 173 : return F("b4E449344505427971537894372380266079344151A6203002081027C8B4A034955230282026CFFFFC1027C035446B3DE2302C4026D1107632681037C034C41234AE90082036CFFFF02FD170008326CFFFF0469C16D000BB822FEF28024"); break; //QDS.1A.07660238"); break; //QDS.37.97275450 + case 174 : return F("b3E44934435188745211A19F67801FD080D81027C034955230182026CF8CB932381037C034C41230082036CFFFF0359F5FD17300010326CFFFF046D060A8428027576FDAC7E5F0192628012"); break; //QDS.1A.45871835 + case 175 : return F("b3E44934455319745221A29607801FD088A81027C034955230F82026CB7439C2381037C034C41230082036CFFFF037174FD17500010326CFFFF046D260B862B02842AFDAC7E8200271080FB"); break; //QDS.1A.45973155 + case 176 : return F("b3E44934404155047231ABDD57801FD084C81027C034955230082026CCC02FFFF81037C034C41230082036CFFFF03E0CFFD17000000326CFFFF046D080DAC2102EA18FDAC7E11005C3E80E0"); break; //QDS.1A.47501504 + case 177 : return F("bY60442515485001000C1A7A23005025568AED71E43AF834900BEC738E08C4FA2637B8915FB401FD6296F19C3AEECEEBC3164B967CD5445E6AAFE90F416314191CB1839210B7CD2EFE168911FD465DAB56CCDA9C82862B90F29353AB57532B49E67E"); break; //EIE.1A.00015048 + case 178 : return F("bY75442515639716000C1A8C208A900F002C25A7000000DDCE55D203E089D07AA800500710760097C0A7F24E9681882D62EFF802EC33146C9B3828FD5B2026432F40E7098DA78C4538579DDE260B2DCCE933093DA312A2C499D4473F150422121279632724B2FCB44A2110D2A2DA87B8C084512CDD698F"); break; //EIE.1A.00169763 + case 179 : return F("b5E442515954400000C1AA17A7A74005025F6B841CED5F1892796E8217F31F08E864EF5C0BBBDFE640AE3711C34C4B5B8AE3B821F1F0F3FF81C8259CBDABD6D05A0A751305C3399E9450DE8E86BE0BDB2D7AFA79BB10179B7EB1F37983CB8C7F10746888DFA54B4CD95AB8C78018025"); break; //EIE.1A.00004495 + case 180 : return F("b5E442515695800000C1A452E7AF200502547F361FEDBED8040998A4AF106CE368D0D469CFE69DD1983E5D5A84078AB4F4F2AFD97FD57668A660038C14F4B79CC3CAB703C3C4ADB6B19AE027E25C4E157B23E9A4D5A7CF24F4962BD29591A73F3E3BD13C9F26D15826364C2DFB28051"); break; //EIE.1A.00005869 + case 181 : return F("b37449344981002451F1AF6837AC418002081027C034955230082026C7CB5FFFF81037C034C41230282036C6D2A027047FD178400326C962A046D080FA623CD2B8AD1"); break; //QDS.1A.45021098 + case 182 : return F("bY5844972642631092001A727299291897A60030B21340A5C84E203CFF62E039C2A1F61CF679A05B7DA7F31E4F0AAA0F30EFFECF4AC176AC9E173C426799C618D50A4B285CBB9074CDF78FA733C7AEC4F66C45D760FDFEE2327E8016"); break; //ITW.1A.92106342"); break; //ITW.30.18299972 + case 183 : return F("b3E449344981002451F1A2CED7801FD08FB81027C034955230082026C61FAFFFF81037C034C41230282036C6D2A034D22FD17840018326C962A046D0A0EA523028B4BFDAC7EF0002E078AD5"); break; //QDS.1A.45021098 + case 184 : return F("bY5044972694376092001A7A3E1340A553D753D0583A78B2BC306DF80BA1DBF6FC88DAFCD83AF7D955EC6196B643A571494B99AE831F8894A4726042E23EA5C474411A585EEEEE8E84A15F54562C31168159804D"); break; //ITW.1A.92603794 + case 185 : return F("bY5044972625353893071A7AE40040A517031B1A58F312C641E1E45D19F6DD3EA9B61FC929D70F39747F6A8A3BA53D7ED25B2A86C741728467DADC3652D54F40660B397E72F60CE3434006A1D843B3248D9C8016"); break; //ITW.1A.93383525 + case 186 : return F("b1744242349075722754982E471F202000001FD0C6202FD173000CFB38EF8"); break; //HYD.49.22570749 + case 187 : return F("b1744242349075722754982E471F602000001FD0C6202FD17300044308CEF"); break; //HYD.49.22570749 + case 188 : return F("b1744242349075722754982E471FC02000001FD0C6202FD173000B52092F0"); break; //HYD.49.22570749 + case 189 : return F("b1744242349075722754982E4711402000001FD0C6202FD17300084489CF0"); break; //HYD.49.22570749 + case 190 : return F("b63442D2C272951803504DCB48C2064900F002C251664000038AA5E8D66325C253B6B7A6400400710EDD4746D6402CF31496EE7AE09E634270E5701ED9E5D16E7A5A22EBC15B0CB6AC0EF980F73E5AD3BF6E658AFC24F614AFBF844AD1EC8CA21C0FCF8FC2E9E64C0B28542EE8C7EA37B444A8036"); break; //KAM.04.80512927 + case 191 : return F("b5E44A7329022226704041EDE7A7500502599F38B5BB9B53F705A6B158D76D3C33F390AE5F6E48A051680C3B866F317F4DBC781E920051DB2619F768DA54EB632DA8746E483A5569A9D8C0E16905ED61857D1B9A07C6EB6AE501B22E0D55A7DD4AF67DB88D6DDCCA5B78E5B88528014"); break; //LUG.04.67222290 + case 192 : return F("b60446850090510825937364F8C0039900F002C2584340D0063667A2334810387B25C72989280612423FE048500307DA907106591F67C43C0B36FCA410346B6A06E7CAADE06D06CF2911ED2775E3297F20105876C245C9309EC93EA0F68B3F9FA466371C73B4A39B80FEBAD1F9C40758028"); break; //HYD.04.61809298"); break; //TCH.37.82100509 + case 193 : return F("b62446850189272149408C4E28C00CF900F002C2564B20800A81E8BCCCA14532696097A6400300710F61F531C03426B9317EAD69912E862AC2017148D8C179D50E133470B7A04CD063D00E6FB1C522DDDC80A3300335E26FE16F9D339A61C0F41BC1ACF4A0A8A29310674536C344CA64D7D"); break; //TCH.08.14729218 + case 194 : return F("b434468501892721494083F2A8C20CD900F002C255FB20800903D2653461ABE7080E57A5F002007103032214C1915B7A16175B00F90B8EB889A4C280207D9C74F5A4088C584D951BDB20851C3DF9E"); break; //TCH.08.14729218 + case 195 : return F("b48442423240756341200933E7AA0303A31A074C27AB1B79A4BF71E2818DAA788D064B94612F5AED2C06E10F1A022615C7EA6E4E97D999D450C33C358340DCB3D948F7F9B58E2B922ED1A580BA905B4E34388A184D5"); break; //HYD.00.34560724 + case 196 : return F("bY5044972670314082001A7A120040A5AE9E0AFE53E0E5216516C41E94CCEA4220BC25A8A5CCF38635E315900BA6BEB0CB5E343BF419524FFED59CD28D106314AC875F9812782700A8267FFCDB4A24251099804A"); break; //ITW.1A.82403170 + case 197 : return F("bY5044972670314082000A7A7A0040A5CE2F908D1B6C7FAB19CF06F0EE140BB44A84C7FF54BDA05D33D6EE45686D054984A4467283EDA6514E8094E361082D9555BD043A64D3F593BAE29C577984921E3CBC92D7"); break; //ITW.0A.82403170 + case 198 : return F("b3B44931536000000013721968C30AA900F002C25BBD101005A558A6E08987D124F027212334938931581036C0010657B0710B23E83B33BD1C8F5A3AB0DAFCEFB35C1D44718C68011"); break; //ELS.03.38493312"); break; //ELS.37.00000036 + case 199 : return F("b2E44B05C95720000021B556C7A500020059C8692AAFADBDBCAA36875B54901F2E32655B735A59AB899223306CD8402A02D189C816E86BB8061"); break; //WEP.1B.00007295 + case 200 : return F("b3B449526564412004237BD198C20E7900F002C25641C00002B7452AB08B6F3843AA6725644120095264203E700108D660710B78BE5BE2867BD38DCE24619A59D0A6BB9384E3A80E2"); break; //ITU.03.00124456"); break; //ITU.37.00124456 + case 201 : return F("b2E44A5111863054230037FB57A30002105DE7DCE381F74E06136FEB49A5B3D45B688341DDCF387CC0D6344DF5BF60078C7A596B1A0D3BE8020"); break; //DME.03.42056318 + case 202 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 203 : return F("b2644AC488437000050379BF37201843700AC485003210000002F2F0CFB6E16038161002F2F2F2F2F2F2F2F2C138057"); break; //REL.03.00378401"); break; //REL.37.00003784 + case 204 : return F("b3644496A855900500537290F7285590000496A0103CC002025CF5138AEB21021CE8339724700D0AF89B3CDDAAE2BAD28479AC27ADBE1E3C3B849269E632772E54C"); break; //ZRI.03.00005985"); break; //ZRI.37.50005985 + case 205 : return F("b1B44A5110301808238379BA77241022436931581038F88000002A7183766D900E3278003"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 206 : return F("b3B449526404107004237CE7B8C2076900F002C25832C020029B8AE8C5A07F337A5EF72046318043041000375001016F10710C9B050BA32F8730DFCC9465A1C3385BA84D8190D801B"); break; //PIP.03.04186304"); break; //ITU.37.00074140 + case 207 : return F("b3B4493154809000001379A2E8C2028900F002C252907000090080FACAA513D7A7B7B729549120430413A03CB001054A107101672D7C39DD223F7A8D3C4FFF7E9CA294237B1AD83DE"); break; //PIP.03.04124995"); break; //ELS.37.00000948 + case 208 : return F("b1944C418637901000103C9CE7A690000A00414EE75620202FD08EAF2A1B38039"); break; //FFD.03.00017963 + case 209 : return F("b3B449526544412004237036C8C2065900F002C25943B00000CC9351967A937062362723991270492262203650810BBE30710483A983059AFE3C21836C683F23BA2B5A04EBAE38021"); break; //ITR.03.04279139"); break; //ITU.37.00124454 + case 210 : return F("b3B4493154909000001375BA68C20BD900F002C25BE0200004F4E34B29075C9986ACB722009210493150003B10010E2D407103C75563866FAC12EBCE6FC5829323547A3CC9A488057"); break; //ELS.03.04210920"); break; //ELS.37.00000949 + case 211 : return F("b3B44931558130000013727848C20DD900F002C25DE0C0000ADFB2D6B2E02C73267AF72011713419315250339001037AB0710A68555FAD7A29A1A875EE33FD26D13EAE33A7AF08035"); break; //ELS.03.41131701"); break; //ELS.37.00001358 + case 212 : return F("b3644A511870350133837198E7280409628931580038F002105F09DD43A485B949F2AB07122E6A6CB3E4BDF9055A351316D145C3EF8522BDF56D9D12495B281D5B0"); break; //ELS.03.28964080"); break; //DME.37.13500387 + case 213 : return F("b3644A511621280223837CE5E724102243693158103850020050075969BAC2F21DD6DEDFFDBDDCF9F0E9A7E066046DF920DF3BFE4DA1174DE1943F173A93C0E2A5B"); break; //ELS.03.36240241"); break; //DME.37.22801262 + case 214 : return F("b1B44A5110301808238379BA77241022436931581038F88000002A7183766D900E3278003"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 215 : return F("b2E44B05C10130000021B34137A490000002F2F0A6653020AFB1A5105E7D102FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8016"); break; //WEP.1B.00001310 + case 216 : return F("b2E44B05C77010000041B1E0B7AE60000002F2F0A6641020AFB1A8103251802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F9"); break; //WEP.1B.00000177 + case 217 : return F("b4E44333081400004032AF18B7A03004005E5AEF57BA739B9789BD9AAFAE16068AFF9FB85A70613B3800B85D28B409B5BDD9607BE2A1450EEE20137C663FB522F4E6B9E914E8E3795C577BFB32D6E0152C21EB0358C41DD6D9F76498020"); break; //LAS.2A.04004081 + case 218 : return F("b1E443330886102001E1B8E9A7A180000202F2F026584030778281E18ADDC240B0000AB01768017"); break; //LAS.1B.00026188 + case 219 : return F("b2E443330603903003C1B18AF7A77002025BB29E575E63C4AA6174A82CED44D5497FA0207F44D4518D8CFA53CD7024276A675D4E0621C0F80E5"); break; //LAS.1B.00033960 + case 220 : return F("b7044B40908794920101B6F8B7A320000000265490A42651F0A8201650BCEB9072265D70912655F0A62659905526576FB4F0A02FB1ABD0142FB1ABB018201FB1A36B6C60122FB1AB90112FB1ABC0162FB1AC24B1C0152FB1ACF01066D3B1D2EAA25000FFFBE95FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA00FFFFFFFFFFFFFF7B5382DE"); break; //BMT.1B.20497908 + case 221 : return F("b60449615347810630C1BE5957A8C0000202F2F026505094265F908822DF20165880822658C081265680A62655808B1785265680A02FB1A880142FB1A95018201130DFB1AE00122FB1A660112FB1A100262FB491D1A660152FB1A1F0202FD1B60030DFD0F817605302E302E340F6C04"); break; //ELV.1B.63107834 + case 222 : return F("bY2944961565181468201B7A140000202F2F0265E20842659A0802FD1B30030DFD0F05302E302E340F5E46"); break; //ELV.1B.68141865 + case 223 : return F("b1644AF4C40020041011B788C7A0A0000000266F3000266F10026FE800F"); break; //SEO.1B.41000240 + case 224 : return F("b5E442515695800000C1A452E7A590050252502B45C2E823EF856FABFC4775E28D2904492FB74BA65A843BA7E63BC698D83279AE2BE04B957699517818F7B33F8E58001A7C9CE0E73C5769487247954D0A000E811754BAB1CED0E61567EB1FE504B091E0C7DCF4632E3FAC31618804D"); break; //EIE.1A.00005869 + case 225 : return F("b5344E2306291001500030F388C30A7900F002C2583AE010032E1E493C32BEF51CDA37A430030071027A19EE14B0BBCAD656D0783516CCB7CFBC6AAFAECDCAD70020FE3DA54FCBC8EC2AED88DFD0972C55CF9336E1683574ABADBD046BB53623F8013"); break; //LGB.03.15009162 + case 226 : return F("b5344A732806139690404B70A8C2063900F002C25923338000C8BC361CE2EE050FD3B7A6340300710DEC49523134391877289A80A53A505655A833F754F221E619D08FB4DB5AD773EAB16B545B306C69D1493CD851012BBF4624A5DDA556AF07E83E5"); break; //LUG.04.69396180 + case 227 : return F("b9644A732460335700A043C1F7ACD0000200274DE02046D030D94250C804C0623000000446D3B177F2C4C060000005D610084016D3B179E248C010600000000CCB81D0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980F9"); break; //LUG.04.70350346 + case 228 : return F("b13440000000000DA00DAA8CF7101FD0C3A02FD171101CB938032"); break; //@@@.DA.DA000000 + case 229 : return F("b63445A146699750001026CE68C20D7900F002C25D7CE0C000B7C13179B38522166CE7AD700400710CDEF8D2A82F77DD15E367871F1E04261AAFAC430C2B55C1DED4A3148306D4C296CF10D72C9E79310A47DD73FDBFDF2CEA6490B6CA12A30EE5D64621A90B5E71F75D50D24C87B10E2ADDF802E"); break; //EBZ.02.00759966 + case 230 : return F("b5E44496A3680003888049D2D7A1D0050053FBA7B54810C548AC112ECFC76CE753AF07A625248C05827C843371AB5DC6C6C8D5D457E845B4B67FB4CEFF06720EA7A9112BFD0A96BC7E97D49FB9BBD59155D109433F0C4823DEA7A13E5281C00E4945F5B05D7518CE085EC8BFE738122"); break; //ZRI.04.38008036 + case 231 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 232 : return F("b3E44B405399098502E0439DC7A0F70300530C7144B5962760A55DE8BA4E49C37676B0CD702698B5FBCE59E35E33D33F736AE13FB1C31DD43ADDC3FE7FF8E1EDC01D749974884BBF96580FE"); break; //AMT.04.50989039 + case 233 : return F("b5B4479169014216130377E5B8C2034900F002C256448000029E1A134984E32773DF97289000047791611023400302CBD0710FF4380B4AE49A140E94F319BE97049FDA8DDC96A8DC437F3BFB02ADC86082E9507934C7ED4FC6F4F678D613F25C09A1DDE927D817F5A824A8012"); break; //ESY.02.47000089"); break; //ESY.37.61211490 + case 234 : return F("b7B445A1415200000023724958C20A0900F002C25B4F60800C0E1D417100AD1BB6EDC72324371005A140102A00050F9B10710112A08DB9869998DE2C0D8614F76213F8682D10A8EF2951413C839461E8E3139EA62193E02B1584E6EC8EDB082AB70C6504F1ADF9E6ABD270E96FE8745AEB93C454FC3C9EAA2D5FCD6679E8A38A3E0818D4B6652993CEE5F8E514867801D"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 235 : return F("b49449344100549253508227F780DFF5F3500824600007E0007B06EFF2BE9FF000000007F2C000000009E24000000DAC000008000800080008000800080000000E9F10000000000000000002F046D010E8625249880E6"); break; //QDS.08.25490510 + case 236 : return F("b9644A732370335700A045D187A440000200274DD02046D071189260C33FD0638010000446D3B177F2C4C06000000DFDD0084016D3B179F258C010641000000CC0DBA0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980E0"); break; //LUG.04.70350337 + case 237 : return F("b4806AC1956030015020363917256030015AC190203D8000000466D00AC9200118625000D78113131363533303030619C3531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8057"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 238 : return F("b9E44A815242292070102881F7F4B0098050B0E989C939C3479F8904137236FE582B853DCACDD8DB48A717A6B42935CB977102079E6397B07AAD2A648E5B65E44D97F9A020B2BFAE433FA37FCB2A2C32711A5986B301D2F6E4A424C1144D808CE9D592C316B117C572689AC6C1322CC05E81F590CAAF457390F6B39DACC946FA314F8E8A34268157AC4338781C3EF5807F9221394DD1FAB5165E1261614B8B85758851295334DF52D9A4DCE2E1E17A555A21007D2DA802B"); break; //EMH.02.07922224 + case 239 : return F("b2E44B05C99010100021B65BE7AC30000002F2F0A6605020AFB1A33041AA002FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8008"); break; //WEP.1B.00010199 + case 240 : return F("b2E44B05C75000000041B8EF87A510000002F2F0A6661010AFB1A8905449802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F8"); break; //WEP.1B.00000075 + case 241 : return F("b1E44C418EA76010001034ECB7A820010A5597AB1CCF2014088590E64BCAB21DC1CC068DAA08035"); break; //FFD.03.000176EA + case 242 : return F("b4E442423245450514A07545F7AC6004005BDB5EDF3750DF41725EE867C3E39750E20B9F5FB092089B6A5DC7AA586101778BCD5EAD4995B102AC639F0FB4D12403EFE3554F72CAE4F5D348CC374F571CCE4A98634318027AAF3E7DD8600"); break; //HYD.07.51505424 + case 243 : return F("b3C449344454392352337ABFC727972126793442304FF0000200C050321648206004C0530240500426CBF2CCC0805098875630600C2086CDF23326CFFFF046D177FEA11D3242E1F830C"); break; //QDS.04.67127279"); break; //QDS.37.35924345 + case 244 : return F("bY5E449726900634160004728499181897A60030D30040A5D20022C396367C6A868B05FE2E9F70B6878070839C62E69DDC79CB409EBCAD68E950A6958B9B92FE6D1B700065B8BD52CB3035B93653FFDA3C3EF3EF6BBB1B450C7976874216AD188011"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 245 : return F("b3444A73228188269040439327A370000202F2F0974040970080C06348AF03500000C14040301000B2D6207000B3BDD4A2322000A5A05090A5E0506F29780E8"); break; //LUG.04.69821828 + case 246 : return F("b9644A732170135700A0476A67A2F00002002747501046D3315952B0C3CF20637000000446D3B177F2C4C06000000F4640084016D3B179F2A8C010636000000CCB85A0106330000008C020633000000CC02067E6A330000008C030633000000CC030600009A1900008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22890200000F001000C94A80E8"); break; //LUG.04.70350117 + case 247 : return F("b5E44496A044550108804533A7A19005005B14A145C0EEC7C6FC18A85582753BE2BD08B6F0F9320809C5F28436A3388BB09145DF69DA51ED00DCCFE7BA2D6F86936D17E654489390BB7511CC4DA27A576A9612B1243151C634899A74D3EBDB2CA578CA4444F5740D74D3EC766628013"); break; //ZRI.04.10504504 + case 248 : return F("bD6440186669601001637060C7215067071010660047400C0251CE72725D9364386C4BF8A15AF4C722115F38B66DDE9F4B800D05A14F870E74492B8F57CB2282388B864D71416FDE0A74CA84735B59D1806BBBF8483B6B14AB580F0D5257E8CC06889EBA80AFB032BCEECD849E7E6A4639B5649B0BF5CBB57BF0993AE16EF7D88D784ADD9CE09284880D14D1502967798901C9E24ED6A04A3B26AE580B5D2AEC46804DEC1CBEDCB1E0B3FE1F84679620FD59E297FE8E67374EE9C34CA5A7F45B4B3709C6BD4E0B546F706DDC571C6469CFA90602C0E339A054CDE1D0A0E071651FD49FEBD485D8E561BB36AF7BED2741D35BBC88051"); break; //APA.04.71700615"); break; //APA.37.00019666 + case 249 : return F("bA944C514381355920004A5FC7A3D0090257403AC17355186FF933BAF0D0820041595970BD168489A746DF337AB01D1DBBA3EF7D486D74CCCEE777E57BD12A15D22B89AB4B4266D84B9C5C1DDBC437CD64807AF0B2B232E3A3C1B4DA568C9F8BA39FDF4565C170ACEF1918655B45D82E8BAAD769B88FA917E82542CAD596AB2145433599FFDDD3FCE889F657A8AC07FE5CED3F184244475B59710CFDCA44D7C3AE00CC021FA6EE3F49B77939529B49279FC526803FD0C05010002FD0B01111E248025"); break; //EFE.04.92551338 + case 250 : return F("b6E44A511485268614004B97F7A86006005B8D6D972C8E06EFB5AEC0FC750DB9DFFE62BB59DA183A5709DFC5029CEB2E44FEAF475DD2F3CF6D90544F29372A5C027DACA08536B2457CDEDEB76E36B281F4A0FD4A203FE9F7DFD337BDEA15D02F53A21CB281A3EF01E15D779B3018A99D0E3EF2FF946A63F419E56644BBDF8FB8010"); break; //DME.04.61685248 + case 251 : return F("b3E44A51159351969A004761E7A030030050F0020FC830AABCA7CEE4EC8E44524D98802ED5CA2EF3C89774FF800730951E02569BF91C156331EC9C29730FE2F437128D7E574D29C4E808047"); break; //DME.04.69193559 + case 252 : return F("b7144685009022004593720EB8C00EE900F002C252CA40100F5CDA57367A4436D244E72791670692423FE040600407D7C07108660CA27A4DD53871B12F96FFEF0F84E0CA88A2201BD794859D35CCD051F34327D04EAAE8772675F8E7F28DE2E515FBC9AF3A40E72C078304158D453511F2CF39DBF98DBE1EAD84F0F2CAD975EDDCC4F"); break; //HYD.04.69701679"); break; //TCH.37.04200209 + case 253 : return F("bA944C514381355920004A5FC7A670090251913406458376E6F9CEB817ABA85D9F26E5867EBA222FDFF496F2C8A312E593C80C0604576D7B5269B4A25BD15B314C0598FE3395611400AA7ADB705EE2120686208A449BDC5EE828FF048F669516585611337839C0A40A308F4DE619997F29D2438CE9EC263574FC60D42197CFA7B47528574792BFFF54AFF9193CA678242653A97DEBCB5E5333687846A875A69C4B7371C762C03A2DB5AB738D92623907896AEBF03FD0C05010002FD0B0111C6E48020"); break; //EFE.04.92551338 + case 254 : return F("b5E44C51475051512010425417A1C004025EEA5F744D756D853BB606F5DBB33DD7B26896D7370BD9C50990E605CE03F8F16DEE8AA36EF2C87E3902F933DDD87E1D383B7C647E8D2236E5FF5E1BE6742D65511FE1629B5CD3F6F0F800C000109002F680300035E2001020A0901C98008"); break; //EFE.04.12150575 + case 255 : return F("b5344A5115158536941043C9D8C00CC900F002C25986B0110B13D74311F4D1ACF88797A7E7031071066DEA0D815DFAC31E07763666D4C46C2DEA856FCEC34F2B5CCF3750F72BD8F924544E73C51D7DBC11A1AE31049E5D0E121CE0053AEB8E018805B"); break; //DME.04.69535851 + case 256 : return F("bA944C514381355920004A5FC7A79009025E37121BAC0ACF1A216281AE7A85DA20DF90613A83417418BD9BA7B0F09C192713A65DECD3ECB2DFC5299683A5B2669EE70851493FC9944D7579F7FCD44CCC839E432D498E40EFDF1614BD9B7E6F1B4AD96CC16939C9D061434790765D3883275B80DE0508393A0F00C1B1590A66F94D920BD5E80125C610F7C0B0346D8D0CFE8DD4E8A14370077D90A7BCFA59345DB13D7134E80D5F2F1D50B3B043075126DF42C2A03FD0C05010002FD0B0111ABC78028"); break; //EFE.04.92551338 + case 257 : return F("b4E44EE4D557648251B048F777ABE004025D84601014EEA5EDCC08B007BC8BB1EBB266BADDEC127897EDA4296EEB8EB05A57DFCA5190F54B41C05B1BF0F5EF82B719CD27EA6242263DFB94F589F38843A1146916B872141977275BD8035"); break; //SON.04.25487655 + case 258 : return F("b2644AC488137000050371BF47201813700AC485000D90000002F2F0C32C60E569405002F2F2F2F2F2F2F2FB90E8059"); break; //REL.00.00378101"); break; //REL.37.00003781 + case 259 : return F("b2644AC488137000050371BF47202813700AC48500CE20000002F2F0C068D16635640002F2F2F2F2F2F2F2F72188058"); break; //REL.0C.00378102"); break; //REL.37.00003781 + case 260 : return F("b36446850790133512243C21BA1009F29793C0088230200007E0E4FFD476370544E2D33280000000000000000000CC8A2608214298C81CD45160105964E203B372E"); break; //TCH.43.51330179 + case 261 : return F("b3744685029069372274351B5A2129F27995400305C1200000007400B69792D4C914447BB7D4A2AC86CB37BFAFD59EEC7971B1F070D00000000002C0040004FD085CC"); break; //TCH.43.72930629 + case 262 : return F("b37446850715221622843FE7BA2129F29F827008800000080800D0000DE060000E00739EF48B3861639BC2044115A10CB0C6283102F1830C0080AD861D24C1E8F80E1"); break; //TCH.43.62215271 + case 263 : return F("b374468508475676739430ECDA2109F27793500287F15000000D34D95907D550ADB32A24C9AAAA9922ED6A76075D51C1F7937DB8D4B95F20E4C63EDC5997041E280FA"); break; //TCH.43.67677584 + case 264 : return F("b36446850442620514543A443A1009F279E180038CC0400803680000286DB08F0C00727FCF0C82F92E8128D31165D722873C60C1568910103062C700107EF3F912E"); break; //TCH.43.51202644 + case 265 : return F("b3744685060478860574395F9A20D9F29820500A00000000100060000E34A00000000000000000000000000000000FFFF0000000000000000000000000000FFFF80D4"); break; //TCH.43.60884760 + case 266 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 267 : return F("b364468504200545145444FE0A1009F29CA6900B0F00D008023001A68BB4748D28D4F7685755095534E09E187ADE5A7B903D03027041000000100008002CF41D570"); break; //TCH.44.51540042 + case 268 : return F("b37446850341929625744B280A20D9F27C9350058395A00000169848B3EDF2ECEF8A17F008A875B80FCB947E0914351334E69E4A14D72A8E296375279E286AB9B8008"); break; //TCH.44.62291934 + case 269 : return F("b36446850060670527144C1AAA0009F29C41F0190DE0F0081A5A1BF2595D38ABA9F512E89A3471D67F8F0C6206308383B6288298BD0A3D68424A228A9907F8B34B2"); break; //TCH.44.52700606 + case 270 : return F("bY5044972608062002001A7AC90340A517F5A8F83D78281AEFF06FDBDEDEF842336FA663F292D6EEACB0F54CA02FB47C8F587862B352ED30166FEE61753998230C38444F845C9FCC364D3C614095F92D14A28010"); break; //ITW.1A.02200608 + case 271 : return F("bY5E449726900634160004728499181897A60030BA0040A53FB81E378B33F9E23FEDF6A0B1B381F4972C2842041CC7EC8D74D675CE56222039CE82385073750F2B695CBEC9B0E8A48EC3F09B74C26E4194A06B7974203DDD0C7976874216E0D282DE"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 272 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 273 : return F("bY5044972625353893071A7A0B0040A5B12EC2E009C467CAD2AF0A38712684FE764C6181D2969A7F0F7B076CB9719FEB21C32E48161EEA5A1E6E92F354FED894994C368F17E6F68E2E6AA1D7C289E3FD7A908015"); break; //ITW.1A.93383525 + case 274 : return F("b2E449726606670194107A6AB8CB0D47ABF0000A00413E84B070004FD3442178001C00004933C00000000333B00000A2D00325A0000CD2E801C"); break; //ITW.07.19706660 + case 275 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + + } + count = 0; + return F(""); +} + + bool P094_data_struct::loop() { if (!isInitialized()) { return false; @@ -155,10 +439,22 @@ bool P094_data_struct::loop() { if (fullSentenceReceived) { ++sentences_received; length_last_received = sentence_part.length(); + } else { + if (debug_generate_CUL_data && sentence_part.length() == 0) { + static uint32_t last_test_sentence = 0; + static int count = 0; + if (timePassedSince(last_test_sentence) > 1000) { + count++; + sentence_part = getDebugSentences(count); + fullSentenceReceived = true; + last_test_sentence = millis(); + } + } } return fullSentenceReceived; } + const String& P094_data_struct::peekSentence() const { return sentence_part; } diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 9fdcd9db2a..a9fad8fc69 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -121,6 +121,8 @@ struct P094_data_struct : public PluginTaskData_base { // Get (and increment) debug counter uint32_t getDebugCounter(); + void setGenerate_DebugCulData(bool value) { debug_generate_CUL_data = value; } + private: bool max_length_reached() const; @@ -134,6 +136,7 @@ struct P094_data_struct : public PluginTaskData_base { uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; uint32_t debug_counter = 0; + bool debug_generate_CUL_data = false; bool valueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = {0}; P094_Filter_Value_Type valueType_index[P094_NR_FILTERS]; From cd68530b40c4b02bafcb845a23a46a0db337cbbe Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 17 Dec 2022 13:58:29 +0100 Subject: [PATCH 340/404] [CUL reader] Fix filtering with not all filter lines set --- src/src/DataStructs/mBusPacket.cpp | 12 ++-- src/src/PluginStructs/P094_data_struct.cpp | 65 ++++++++++++---------- src/src/PluginStructs/P094_data_struct.h | 6 +- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 1948868343..6b8bc6a7e4 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -25,13 +25,15 @@ int mBusPacket_header_t::encodeManufacturerID(const String& id_str) if (nrChars > 3) { nrChars = 3; } - for (int i = 0; i < nrChars; ++i) { - const char c = id_str[i]; + int i = 0; + while (i < nrChars) { + res <<= 5; + const int c = static_cast(toUpperCase(id_str[i])) - 64; - if ((c >= 64) && (c < 96)) { - res += static_cast(c) - 64; + if (c >= 0) { + res += c & 0x1f; } - res <<= 5; + ++i; } return res; } diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index af9213500c..66e522411f 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -16,8 +16,8 @@ P094_data_struct::P094_data_struct() : easySerial(nullptr) { for (int i = 0; i < P094_NR_FILTERS; ++i) { - valueType_index[i] = P094_Filter_Value_Type::P094_not_used; - filter_comp[i] = P094_Filter_Comp::P094_Equal_OR; + filterLine_valueType[i] = P094_Filter_Value_Type::P094_not_used; + filterLine_compare[i] = P094_Filter_Comp::P094_Equal_OR; } } @@ -53,24 +53,24 @@ bool P094_data_struct::init(ESPEasySerialPort port, } void P094_data_struct::post_init() { - for (uint8_t i = 0; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { - valueType_used[i] = false; + for (uint8_t f = 0; f < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++f) { + filterValueType_used[f] = false; } - for (uint8_t i = 0; i < P094_NR_FILTERS; ++i) { - size_t lines_baseindex = P094_Get_filter_base_index(i); - int index = _lines[lines_baseindex].toInt(); - int tmp_filter_comp = _lines[lines_baseindex + 2].toInt(); + for (uint8_t filterLine = 0; filterLine < P094_NR_FILTERS; ++filterLine) { + const size_t lines_baseindex = P094_Get_filter_base_index(filterLine); + const int index = _lines[lines_baseindex].toInt(); + const int tmp_filter_comp = _lines[lines_baseindex + 2].toInt(); const bool filter_string_notempty = _lines[lines_baseindex + 3].length() > 0; - const bool valid_index = index >= 0 && index < P094_FILTER_VALUE_Type_NR_ELEMENTS; + const bool valid_index = index > 0 && index < P094_FILTER_VALUE_Type_NR_ELEMENTS; const bool valid_filter_comp = tmp_filter_comp >= 0 && tmp_filter_comp < P094_FILTER_COMP_NR_ELEMENTS; - valueType_index[i] = P094_not_used; + filterLine_valueType[filterLine] = P094_not_used; if (valid_index && valid_filter_comp && filter_string_notempty) { - valueType_used[index] = true; - valueType_index[i] = static_cast(index); - filter_comp[i] = static_cast(tmp_filter_comp); + filterValueType_used[index] = true; + filterLine_valueType[filterLine] = static_cast(index); + filterLine_compare[filterLine] = static_cast(tmp_filter_comp); } } } @@ -510,7 +510,7 @@ bool P094_data_struct::invertMatch() const { bool P094_data_struct::filterUsed(uint8_t lineNr) const { - if (valueType_index[lineNr] == P094_Filter_Value_Type::P094_not_used) { return false; } + if (filterLine_valueType[lineNr] == P094_Filter_Value_Type::P094_not_used) { return false; } uint8_t varNr = P094_Get_filter_base_index(lineNr); return _lines[varNr + 3].length() > 0; } @@ -524,8 +524,8 @@ String P094_data_struct::getFilter(uint8_t lineNr, P094_Filter_Value_Type& filte if ((varNr + 3) >= P94_Nlines) { return ""; } optional = _lines[varNr + 1].toInt(); - filterValueType = valueType_index[lineNr]; - comparator = filter_comp[lineNr]; + filterValueType = filterLine_valueType[lineNr]; + comparator = filterLine_compare[lineNr]; // filterValueType = static_cast(_lines[varNr].toInt()); // comparator = static_cast(_lines[varNr + 2].toInt()); @@ -610,9 +610,9 @@ bool P094_data_struct::parsePacket(const String& received) const { // Do not check for "not used" (0) for (unsigned int i = 1; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { - if (valueType_used[i]) { - for (unsigned int f = 0; f < P094_NR_FILTERS; ++f) { - if (valueType_index[f] == i) { + if (filterValueType_used[i]) { + for (unsigned int filterLine = 0; filterLine < P094_NR_FILTERS; ++filterLine) { + if (filterLine_valueType[filterLine] == i) { // Have a matching filter uint32_t optional; @@ -620,7 +620,7 @@ bool P094_data_struct::parsePacket(const String& received) const { P094_Filter_Comp comparator; bool match = false; String inputString; - String valueString = getFilter(f, filterValueType, optional, comparator); + String valueString = getFilter(filterLine, filterValueType, optional, comparator); if (i == P094_Filter_Value_Type::P094_position) { if (received.length() >= (optional + valueString.length())) { @@ -630,14 +630,19 @@ bool P094_data_struct::parsePacket(const String& received) const { } } else if (i == P094_Filter_Value_Type::P094_manufacturer) { // Get vendor code - const unsigned long value = mBusPacket_header_t::encodeManufacturerID(valueString); - if (value == packet._deviceId1._manufacturer) { + const int value = mBusPacket_header_t::encodeManufacturerID(valueString); + inputString = mBusPacket_header_t::decodeManufacturerID(packet._deviceId1._manufacturer); + + addLog(LOG_LEVEL_INFO, concat(F("Manufacturer ID filter: "), + mBusPacket_header_t::decodeManufacturerID(value)) + concat(F(" input: "), inputString)); + + if (value == packet._deviceId1._manufacturer + /*inputString.equalsIgnoreCase(valueString)*/) { match = true; } else if (hexToUL(valueString) == packet._deviceId1._manufacturer) { // Old 'compatible' mode, where the HEX notation was used instead of the manufacturer ID match = true; } - inputString = mBusPacket_header_t::decodeManufacturerID(packet._deviceId1._manufacturer); } else { const unsigned long value = hexToUL(valueString); uint32_t receivedValue = 0; @@ -674,7 +679,7 @@ bool P094_data_struct::parsePacket(const String& received) const { String log; if (log.reserve(64)) { log += F("CUL Reader: "); - log += P094_FilterValueType_toString(valueType_index[f]); + log += P094_FilterValueType_toString(filterLine_valueType[filterLine]); log += F(": in:"); log += inputString; log += ' '; @@ -701,11 +706,11 @@ bool P094_data_struct::parsePacket(const String& received) const { switch (comparator) { case P094_Filter_Comp::P094_Equal_OR: - if (match) { filter_matches[f] = true; } + if (match) { filter_matches[filterLine] = true; } break; case P094_Filter_Comp::P094_NotEqual_OR: - if (!match) { filter_matches[f] = true; } + if (!match) { filter_matches[filterLine] = true; } break; case P094_Filter_Comp::P094_Equal_MUST: @@ -727,8 +732,8 @@ bool P094_data_struct::parsePacket(const String& received) const { int nrMatches = 0; int nrNotUsed = 0; - for (unsigned int f = 0; !match_result && f < P094_NR_FILTERS; ++f) { - if (f % P094_AND_FILTER_BLOCK == 0) { + for (unsigned int filterLine = 0; !match_result && filterLine < P094_NR_FILTERS; ++filterLine) { + if (filterLine % P094_AND_FILTER_BLOCK == 0) { if ((nrMatches > 0) && ((nrMatches + nrNotUsed) == P094_AND_FILTER_BLOCK)) { match_result = true; } @@ -736,10 +741,10 @@ bool P094_data_struct::parsePacket(const String& received) const { nrNotUsed = 0; } - if (filter_matches[f]) { + if (filter_matches[filterLine]) { ++nrMatches; } else { - if (!filterUsed(f)) { + if (!filterUsed(filterLine)) { ++nrNotUsed; } } diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index a9fad8fc69..02ffa184d5 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -138,9 +138,9 @@ struct P094_data_struct : public PluginTaskData_base { uint32_t debug_counter = 0; bool debug_generate_CUL_data = false; - bool valueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = {0}; - P094_Filter_Value_Type valueType_index[P094_NR_FILTERS]; - P094_Filter_Comp filter_comp[P094_NR_FILTERS]; + bool filterValueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = {0}; + P094_Filter_Value_Type filterLine_valueType[P094_NR_FILTERS]; + P094_Filter_Comp filterLine_compare[P094_NR_FILTERS]; }; From 47c862a19c9f576eebfd9587b03e53473ebde34d Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 17 Dec 2022 14:01:33 +0100 Subject: [PATCH 341/404] [CUL reader] Uncrustify --- src/_P094_CULReader.ino | 82 ++++++++++++---------- src/src/PluginStructs/P094_data_struct.cpp | 81 ++++++++++++--------- src/src/PluginStructs/P094_data_struct.h | 53 +++++++------- 3 files changed, 119 insertions(+), 97 deletions(-) diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 15bb53604e..9d6bb57faf 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -10,36 +10,36 @@ // -#include "src/Helpers/ESPEasy_Storage.h" -#include "src/Helpers/StringConverter.h" -#include "src/PluginStructs/P094_data_struct.h" +# include "src/Helpers/ESPEasy_Storage.h" +# include "src/Helpers/StringConverter.h" +# include "src/PluginStructs/P094_data_struct.h" -#include +# include -#define PLUGIN_094 -#define PLUGIN_ID_094 94 -#define PLUGIN_NAME_094 "Communication - CUL Reader" +# define PLUGIN_094 +# define PLUGIN_ID_094 94 +# define PLUGIN_NAME_094 "Communication - CUL Reader" -#define P094_BAUDRATE PCONFIG_LONG(0) -#define P094_BAUDRATE_LABEL PCONFIG_LABEL(0) +# define P094_BAUDRATE PCONFIG_LONG(0) +# define P094_BAUDRATE_LABEL PCONFIG_LABEL(0) -#define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) -#define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) +# define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) +# define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) -#define P094_GET_APPEND_RECEIVE_SYSTIME bitRead(PCONFIG(0),0) -#define P094_SET_APPEND_RECEIVE_SYSTIME(X) bitWrite(PCONFIG(0),0,X) +# define P094_GET_APPEND_RECEIVE_SYSTIME bitRead(PCONFIG(0), 0) +# define P094_SET_APPEND_RECEIVE_SYSTIME(X) bitWrite(PCONFIG(0), 0, X) -#define P094_GET_GENERATE_DEBUG_CUL_DATA bitRead(PCONFIG(0),1) -#define P094_SET_GENERATE_DEBUG_CUL_DATA(X) bitWrite(PCONFIG(0),1,X) +# define P094_GET_GENERATE_DEBUG_CUL_DATA bitRead(PCONFIG(0), 1) +# define P094_SET_GENERATE_DEBUG_CUL_DATA(X) bitWrite(PCONFIG(0), 1, X) -#define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. -#define P094_NR_OUTPUT_OPTIONS 1 +# define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. +# define P094_NR_OUTPUT_OPTIONS 1 -#define P094_NR_OUTPUT_VALUES 1 -#define P094_QUERY1_CONFIG_POS 3 +# define P094_NR_OUTPUT_VALUES 1 +# define P094_QUERY1_CONFIG_POS 3 -#define P094_DEFAULT_BAUDRATE 38400 +# define P094_DEFAULT_BAUDRATE 38400 // Plugin settings: @@ -77,6 +77,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = false; Device[deviceCount].DuplicateDetection = true; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving Device[deviceCount].ExitTaskBeforeSave = false; break; @@ -128,7 +129,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_SET_DEFAULTS: { - P094_BAUDRATE = P094_DEFAULT_BAUDRATE; + P094_BAUDRATE = P094_DEFAULT_BAUDRATE; P094_DEBUG_SENTENCE_LENGTH = 0; success = true; @@ -149,7 +150,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) break; } - case PLUGIN_WEBFORM_LOAD: + case PLUGIN_WEBFORM_LOAD: { addFormSubHeader(F("Filtering")); P094_html_show_matchForms(event); @@ -159,7 +160,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); - addFormCheckBox(F("Append system time"), F("systime"), P094_GET_APPEND_RECEIVE_SYSTIME); + addFormCheckBox(F("Append system time"), F("systime"), P094_GET_APPEND_RECEIVE_SYSTIME); addFormCheckBox(F("(debug) Generate CUL data"), F("debug_data"), P094_GET_GENERATE_DEBUG_CUL_DATA); success = true; @@ -167,7 +168,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) } case PLUGIN_WEBFORM_SAVE: { - P094_BAUDRATE = getFormItemInt(P094_BAUDRATE_LABEL); + P094_BAUDRATE = getFormItemInt(P094_BAUDRATE_LABEL); P094_DEBUG_SENTENCE_LENGTH = getFormItemInt(P094_DEBUG_SENTENCE_LABEL); P094_data_struct *P094_data = @@ -190,8 +191,8 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) } case PLUGIN_INIT: { - const int16_t serial_rx = CONFIG_PIN1; - const int16_t serial_tx = CONFIG_PIN2; + const int16_t serial_rx = CONFIG_PIN1; + const int16_t serial_tx = CONFIG_PIN2; const ESPEasySerialPort port = static_cast(CONFIG_PORT); initPluginTaskData(event->TaskIndex, new (std::nothrow) P094_data_struct()); P094_data_struct *P094_data = @@ -229,9 +230,11 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) if (Plugin_094_match_all(event->TaskIndex, event->String2)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; + if (log.reserve(128)) { log = F("CUL Reader: Sending: "); const size_t messageLength = event->String2.length(); + if (messageLength < 100) { log += event->String2; } else { @@ -243,10 +246,12 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) addLogMove(LOG_LEVEL_INFO, log); } } + // Filter length options: - // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit sending meters, which normaly is a fault) + // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit + // sending meters, which normaly is a fault) // - 38 char, The exact message, because we have 2 uint8_t from the value payload - //sendData_checkDuplicates(event, event->String2.substring(0, 22)); + // sendData_checkDuplicates(event, event->String2.substring(0, 22)); sendData(event); } } @@ -267,16 +272,19 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) event->String2 += String(debug_count); event->String2 += '_'; const char c = '0' + debug_count % 10; + for (long i = event->String2.length(); i < P094_DEBUG_SENTENCE_LENGTH; ++i) { event->String2 += c; } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("CUL Reader: Sending: "); log += event->String2.substring(0, 20); log += F("..."); addLogMove(LOG_LEVEL_INFO, log); } -// sendData_checkDuplicates(event, event->String2.substring(0, 22)); + + // sendData_checkDuplicates(event, event->String2.substring(0, 22)); sendData(event); } } @@ -353,8 +361,8 @@ void P094_html_show_matchForms(struct EventStruct *event) { addFormNote(F("0 = Do not turn off filter after sending to the connected device.")); { - const __FlashStringHelper * options[P094_Match_Type_NR_ELEMENTS]; - int optionValues[P094_Match_Type_NR_ELEMENTS]; + const __FlashStringHelper *options[P094_Match_Type_NR_ELEMENTS]; + int optionValues[P094_Match_Type_NR_ELEMENTS]; for (int i = 0; i < P094_Match_Type_NR_ELEMENTS; ++i) { P094_Match_Type matchType = static_cast(i); @@ -372,7 +380,7 @@ void P094_html_show_matchForms(struct EventStruct *event) { } - uint8_t filterSet = 0; + uint8_t filterSet = 0; uint32_t optional = 0; P094_Filter_Value_Type capture = P094_Filter_Value_Type::P094_packet_length; P094_Filter_Comp comparator = P094_Filter_Comp::P094_Equal_OR; @@ -403,8 +411,8 @@ void P094_html_show_matchForms(struct EventStruct *event) { // Combo box with filter types { - const __FlashStringHelper * options[P094_FILTER_VALUE_Type_NR_ELEMENTS]; - int optionValues[P094_FILTER_VALUE_Type_NR_ELEMENTS]; + const __FlashStringHelper *options[P094_FILTER_VALUE_Type_NR_ELEMENTS]; + int optionValues[P094_FILTER_VALUE_Type_NR_ELEMENTS]; for (int i = 0; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { P094_Filter_Value_Type filterValueType = static_cast(i); @@ -425,8 +433,8 @@ void P094_html_show_matchForms(struct EventStruct *event) { case 2: { // Comparator - const __FlashStringHelper * options[P094_FILTER_COMP_NR_ELEMENTS]; - int optionValues[P094_FILTER_COMP_NR_ELEMENTS]; + const __FlashStringHelper *options[P094_FILTER_COMP_NR_ELEMENTS]; + int optionValues[P094_FILTER_COMP_NR_ELEMENTS]; for (int i = 0; i < P094_FILTER_COMP_NR_ELEMENTS; ++i) { P094_Filter_Comp enumValue = static_cast(i); @@ -472,4 +480,4 @@ void P094_html_show_stats(struct EventStruct *event) { } } -#endif // USES_P094 \ No newline at end of file +#endif // USES_P094 diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 66e522411f..5b05ccb0ce 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -2,22 +2,22 @@ #ifdef USES_P094 -// Needed also here for PlatformIO's library finder as the .h file +// Needed also here for PlatformIO's library finder as the .h file // is in a directory which is excluded in the src_filter -#include +# include -#include +# include -#include "../DataStructs/mBusPacket.h" +# include "../DataStructs/mBusPacket.h" -#include "../Globals/ESPEasy_time.h" -#include "../Helpers/StringConverter.h" +# include "../Globals/ESPEasy_time.h" +# include "../Helpers/StringConverter.h" P094_data_struct::P094_data_struct() : easySerial(nullptr) { for (int i = 0; i < P094_NR_FILTERS; ++i) { filterLine_valueType[i] = P094_Filter_Value_Type::P094_not_used; - filterLine_compare[i] = P094_Filter_Comp::P094_Equal_OR; + filterLine_compare[i] = P094_Filter_Comp::P094_Equal_OR; } } @@ -35,10 +35,10 @@ void P094_data_struct::reset() { } } -bool P094_data_struct::init(ESPEasySerialPort port, - const int16_t serial_rx, - const int16_t serial_tx, - unsigned long baudrate) { +bool P094_data_struct::init(ESPEasySerialPort port, + const int16_t serial_rx, + const int16_t serial_tx, + unsigned long baudrate) { if ((serial_rx < 0) && (serial_tx < 0)) { return false; } @@ -58,12 +58,12 @@ void P094_data_struct::post_init() { } for (uint8_t filterLine = 0; filterLine < P094_NR_FILTERS; ++filterLine) { - const size_t lines_baseindex = P094_Get_filter_base_index(filterLine); - const int index = _lines[lines_baseindex].toInt(); - const int tmp_filter_comp = _lines[lines_baseindex + 2].toInt(); - const bool filter_string_notempty = _lines[lines_baseindex + 3].length() > 0; - const bool valid_index = index > 0 && index < P094_FILTER_VALUE_Type_NR_ELEMENTS; - const bool valid_filter_comp = tmp_filter_comp >= 0 && tmp_filter_comp < P094_FILTER_COMP_NR_ELEMENTS; + const size_t lines_baseindex = P094_Get_filter_base_index(filterLine); + const int index = _lines[lines_baseindex].toInt(); + const int tmp_filter_comp = _lines[lines_baseindex + 2].toInt(); + const bool filter_string_notempty = _lines[lines_baseindex + 3].length() > 0; + const bool valid_index = index > 0 && index < P094_FILTER_VALUE_Type_NR_ELEMENTS; + const bool valid_filter_comp = tmp_filter_comp >= 0 && tmp_filter_comp < P094_FILTER_COMP_NR_ELEMENTS; filterLine_valueType[filterLine] = P094_not_used; @@ -414,6 +414,7 @@ bool P094_data_struct::loop() { valid = false; } } + if (valid) { fullSentenceReceived = true; } @@ -424,7 +425,8 @@ bool P094_data_struct::loop() { // Ignore LF break; default: - if (c >= 32 && c < 127) { + + if ((c >= 32) && (c < 127)) { sentence_part += c; } else { current_sentence_errored = true; @@ -440,28 +442,29 @@ bool P094_data_struct::loop() { ++sentences_received; length_last_received = sentence_part.length(); } else { - if (debug_generate_CUL_data && sentence_part.length() == 0) { + if (debug_generate_CUL_data && (sentence_part.length() == 0)) { static uint32_t last_test_sentence = 0; - static int count = 0; + static int count = 0; + if (timePassedSince(last_test_sentence) > 1000) { count++; - sentence_part = getDebugSentences(count); + sentence_part = getDebugSentences(count); fullSentenceReceived = true; - last_test_sentence = millis(); + last_test_sentence = millis(); } } } return fullSentenceReceived; } - const String& P094_data_struct::peekSentence() const { return sentence_part; } void P094_data_struct::getSentence(String& string, bool appendSysTime) { - string = std::move(sentence_part); + string = std::move(sentence_part); sentence_part = String(); // FIXME TD-er: Should not be needed as move already cleared it. + if (appendSysTime) { // Unix timestamp = 10 decimals + separator if (string.reserve(sentence_part.length() + 11)) { @@ -512,6 +515,7 @@ bool P094_data_struct::filterUsed(uint8_t lineNr) const { if (filterLine_valueType[lineNr] == P094_Filter_Value_Type::P094_not_used) { return false; } uint8_t varNr = P094_Get_filter_base_index(lineNr); + return _lines[varNr + 3].length() > 0; } @@ -575,13 +579,16 @@ bool P094_data_struct::parsePacket(const String& received) const { // Decoded packet mBusPacket_t packet; - if (!packet.parse(received)) return false; + + if (!packet.parse(received)) { return false; } const uint32_t rssi = hexToUL(received, strlength - 4, 4); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; + if (log.reserve(128)) { - log = F("CUL Reader: "); + log = F("CUL Reader: "); + if (packet._deviceId1.isValid()) { log += F(" deviceId1: "); log += packet._deviceId1.toString(); @@ -589,6 +596,7 @@ bool P094_data_struct::parsePacket(const String& received) const { log += packet._deviceId1._length; log += ')'; } + if (packet._deviceId2.isValid()) { log += F(" deviceId2: "); log += packet._deviceId2.toString(); @@ -626,17 +634,18 @@ bool P094_data_struct::parsePacket(const String& received) const { if (received.length() >= (optional + valueString.length())) { // received string is long enough to fit the expression. inputString = received.substring(optional, optional + valueString.length()); - match = inputString.equalsIgnoreCase(valueString); + match = inputString.equalsIgnoreCase(valueString); } } else if (i == P094_Filter_Value_Type::P094_manufacturer) { // Get vendor code const int value = mBusPacket_header_t::encodeManufacturerID(valueString); inputString = mBusPacket_header_t::decodeManufacturerID(packet._deviceId1._manufacturer); - addLog(LOG_LEVEL_INFO, concat(F("Manufacturer ID filter: "), - mBusPacket_header_t::decodeManufacturerID(value)) + concat(F(" input: "), inputString)); + addLog(LOG_LEVEL_INFO, concat(F("Manufacturer ID filter: "), + mBusPacket_header_t::decodeManufacturerID(value)) + concat(F(" input: "), inputString)); if (value == packet._deviceId1._manufacturer + /*inputString.equalsIgnoreCase(valueString)*/) { match = true; } else if (hexToUL(valueString) == packet._deviceId1._manufacturer) { @@ -645,26 +654,27 @@ bool P094_data_struct::parsePacket(const String& received) const { } } else { const unsigned long value = hexToUL(valueString); - uint32_t receivedValue = 0; + uint32_t receivedValue = 0; + switch (static_cast(i)) { case P094_packet_length: receivedValue = packet._deviceId1._length; - match = value == receivedValue; + match = value == receivedValue; break; case P094_manufacturer: // Already handled break; case P094_meter_type: receivedValue = packet._deviceId1._meterType; - match = value == receivedValue; + match = value == receivedValue; break; case P094_serial_number: receivedValue = packet._deviceId1._serialNr; - match = value == receivedValue; + match = value == receivedValue; break; case P094_rssi: receivedValue = rssi; - match = value < rssi; + match = value < rssi; break; default: match = false; @@ -677,6 +687,7 @@ bool P094_data_struct::parsePacket(const String& received) const { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; + if (log.reserve(64)) { log += F("CUL Reader: "); log += P094_FilterValueType_toString(filterLine_valueType[filterLine]); @@ -691,7 +702,7 @@ bool P094_data_struct::parsePacket(const String& received) const { case P094_Filter_Comp::P094_Equal_OR: case P094_Filter_Comp::P094_Equal_MUST: - if (match) { log += F(" expected MATCH"); } + if (match) { log += F(" expected MATCH"); } break; case P094_Filter_Comp::P094_NotEqual_OR: case P094_Filter_Comp::P094_NotEqual_MUST: diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 02ffa184d5..5a2f7e1626 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -4,8 +4,8 @@ #include "../../_Plugin_Helper.h" #ifdef USES_P094 -#include -#include +# include +# include # define P094_REGEX_POS 0 @@ -62,30 +62,31 @@ struct P094_data_struct : public PluginTaskData_base { void reset(); - bool init(ESPEasySerialPort port, - const int16_t serial_rx, - const int16_t serial_tx, - unsigned long baudrate); + bool init(ESPEasySerialPort port, + const int16_t serial_rx, + const int16_t serial_tx, + unsigned long baudrate); - void post_init(); + void post_init(); - bool isInitialized() const; + bool isInitialized() const; - void sendString(const String& data); + void sendString(const String& data); - bool loop(); + bool loop(); const String& peekSentence() const; - void getSentence(String& string, bool appendSysTime); + void getSentence(String& string, + bool appendSysTime); - void getSentencesReceived(uint32_t& succes, - uint32_t& error, - uint32_t& length_last) const; + void getSentencesReceived(uint32_t& succes, + uint32_t& error, + uint32_t& length_last) const; void setMaxLength(uint16_t maxlenght); - void setLine(uint8_t varNr, + void setLine(uint8_t varNr, const String& line); @@ -102,15 +103,15 @@ struct P094_data_struct : public PluginTaskData_base { uint32_t & optional, P094_Filter_Comp & comparator) const; - void setDisableFilterWindowTimer(); + void setDisableFilterWindowTimer(); - bool disableFilterWindowActive() const; + bool disableFilterWindowActive() const; - bool parsePacket(const String& received) const; + bool parsePacket(const String& received) const; - static const __FlashStringHelper * MatchType_toString(P094_Match_Type matchType); - static const __FlashStringHelper * P094_FilterValueType_toString(P094_Filter_Value_Type valueType); - static const __FlashStringHelper * P094_FilterComp_toString(P094_Filter_Comp comparator); + static const __FlashStringHelper* MatchType_toString(P094_Match_Type matchType); + static const __FlashStringHelper* P094_FilterValueType_toString(P094_Filter_Value_Type valueType); + static const __FlashStringHelper* P094_FilterComp_toString(P094_Filter_Comp comparator); // Made public so we don't have to copy the values when loading/saving. @@ -119,9 +120,11 @@ struct P094_data_struct : public PluginTaskData_base { static size_t P094_Get_filter_base_index(size_t filterLine); // Get (and increment) debug counter - uint32_t getDebugCounter(); + uint32_t getDebugCounter(); - void setGenerate_DebugCulData(bool value) { debug_generate_CUL_data = value; } + void setGenerate_DebugCulData(bool value) { + debug_generate_CUL_data = value; + } private: @@ -138,7 +141,7 @@ struct P094_data_struct : public PluginTaskData_base { uint32_t debug_counter = 0; bool debug_generate_CUL_data = false; - bool filterValueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = {0}; + bool filterValueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = { 0 }; P094_Filter_Value_Type filterLine_valueType[P094_NR_FILTERS]; P094_Filter_Comp filterLine_compare[P094_NR_FILTERS]; }; @@ -146,4 +149,4 @@ struct P094_data_struct : public PluginTaskData_base { #endif // USES_P094 -#endif // PLUGINSTRUCTS_P094_DATA_STRUCT_H \ No newline at end of file +#endif // PLUGINSTRUCTS_P094_DATA_STRUCT_H From 2584ebdf08c85b634dbd299c5e9045b951103405 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 17 Dec 2022 15:14:29 +0100 Subject: [PATCH 342/404] [CUL reader] By default leave out debug features --- src/_P094_CULReader.ino | 10 ++++++++++ src/src/DataStructs/mBusPacket.cpp | 6 +++--- src/src/PluginStructs/P094_data_struct.cpp | 10 ++++++++-- src/src/PluginStructs/P094_data_struct.h | 8 ++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 9d6bb57faf..b7d201ca3c 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -30,8 +30,10 @@ # define P094_GET_APPEND_RECEIVE_SYSTIME bitRead(PCONFIG(0), 0) # define P094_SET_APPEND_RECEIVE_SYSTIME(X) bitWrite(PCONFIG(0), 0, X) +#if P094_DEBUG_OPTIONS # define P094_GET_GENERATE_DEBUG_CUL_DATA bitRead(PCONFIG(0), 1) # define P094_SET_GENERATE_DEBUG_CUL_DATA(X) bitWrite(PCONFIG(0), 1, X) +#endif # define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. # define P094_NR_OUTPUT_OPTIONS 1 @@ -161,7 +163,9 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); addFormCheckBox(F("Append system time"), F("systime"), P094_GET_APPEND_RECEIVE_SYSTIME); +#if P094_DEBUG_OPTIONS addFormCheckBox(F("(debug) Generate CUL data"), F("debug_data"), P094_GET_GENERATE_DEBUG_CUL_DATA); +#endif success = true; break; @@ -185,7 +189,9 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) } P094_SET_APPEND_RECEIVE_SYSTIME(isFormItemChecked(F("systime"))); +#if P094_DEBUG_OPTIONS P094_SET_GENERATE_DEBUG_CUL_DATA(isFormItemChecked(F("debug_data"))); +#endif break; } @@ -205,7 +211,9 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) if (P094_data->init(port, serial_rx, serial_tx, P094_BAUDRATE)) { LoadCustomTaskSettings(event->TaskIndex, P094_data->_lines, P94_Nlines, 0); P094_data->post_init(); +#if P094_DEBUG_OPTIONS P094_data->setGenerate_DebugCulData(P094_GET_GENERATE_DEBUG_CUL_DATA); +#endif success = true; serialHelper_log_GpioDescription(port, serial_rx, serial_tx); @@ -267,6 +275,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) static_cast(getPluginTaskData(event->TaskIndex)); if ((nullptr != P094_data)) { + #if P094_DEBUG_OPTIONS const uint32_t debug_count = P094_data->getDebugCounter(); event->String2.reserve(P094_DEBUG_SENTENCE_LENGTH); event->String2 += String(debug_count); @@ -276,6 +285,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) for (long i = event->String2.length(); i < P094_DEBUG_SENTENCE_LENGTH; ++i) { event->String2 += c; } + #endif if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("CUL Reader: Sending: "); diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 6b8bc6a7e4..e3dbfb6aad 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -76,7 +76,7 @@ bool mBusPacket_t::parse(const String& payload) bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) { - const size_t payloadSize = payloadWithoutChecksums.size(); + const int payloadSize = payloadWithoutChecksums.size(); if (payloadSize < 10) { return false; } @@ -169,7 +169,7 @@ uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) { mBusPacket_data result; - const size_t payloadLength = payload.length(); + const int payloadLength = payload.length(); if (payloadLength < 4) { return result; } @@ -214,7 +214,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) { mBusPacket_data result; - const size_t payloadLength = payload.length(); + const int payloadLength = payload.length(); if (payloadLength < 4) { return result; } diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 5b05ccb0ce..815c02df96 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -94,6 +94,7 @@ void P094_data_struct::sendString(const String& data) { } } +#if P094_DEBUG_OPTIONS const __FlashStringHelper * getDebugSentences(int& count) { switch (count) { case 1: return F("b3C449344369291352337D55472593107009344230A920000200C0538ECE32625004C0527262500426CBF2CCC0805BDF032262500C2086CDF21326CFFFF046D26BB1103DA22B4E093E2"); break; //QDS.0A.00073159"); break; //QDS.37.35919236 @@ -376,7 +377,7 @@ const __FlashStringHelper * getDebugSentences(int& count) { count = 0; return F(""); } - +#endif bool P094_data_struct::loop() { if (!isInitialized()) { @@ -441,7 +442,9 @@ bool P094_data_struct::loop() { if (fullSentenceReceived) { ++sentences_received; length_last_received = sentence_part.length(); - } else { + } +#if P094_DEBUG_OPTIONS + else { if (debug_generate_CUL_data && (sentence_part.length() == 0)) { static uint32_t last_test_sentence = 0; static int count = 0; @@ -454,6 +457,7 @@ bool P094_data_struct::loop() { } } } +#endif return fullSentenceReceived; } @@ -825,8 +829,10 @@ size_t P094_data_struct::P094_Get_filter_base_index(size_t filterLine) { return filterLine * P094_ITEMS_PER_FILTER + P094_FIRST_FILTER_POS; } +#if P094_DEBUG_OPTIONS uint32_t P094_data_struct::getDebugCounter() { return debug_counter++; } +#endif #endif // USES_P094 diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 5a2f7e1626..8275ac4681 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -7,6 +7,10 @@ # include # include +# ifndef P094_DEBUG_OPTIONS +# define P094_DEBUG_OPTIONS 0 +# endif + # define P094_REGEX_POS 0 # define P094_NR_CHAR_USE_POS 1 @@ -119,12 +123,14 @@ struct P094_data_struct : public PluginTaskData_base { static size_t P094_Get_filter_base_index(size_t filterLine); +#if P094_DEBUG_OPTIONS // Get (and increment) debug counter uint32_t getDebugCounter(); void setGenerate_DebugCulData(bool value) { debug_generate_CUL_data = value; } +#endif private: @@ -138,8 +144,10 @@ struct P094_data_struct : public PluginTaskData_base { bool current_sentence_errored = false; uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; + #if P094_DEBUG_OPTIONS uint32_t debug_counter = 0; bool debug_generate_CUL_data = false; + #endif bool filterValueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = { 0 }; P094_Filter_Value_Type filterLine_valueType[P094_NR_FILTERS]; From 6b657af9398c32627587a37de306a4309a1ea866 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Dec 2022 00:58:20 +0100 Subject: [PATCH 343/404] [CUL Reader] Fix parsing 'type A' message headers & fix RSSI --- src/src/DataStructs/mBusPacket.cpp | 46 ++++++++++++++++------ src/src/DataStructs/mBusPacket.h | 8 +++- src/src/PluginStructs/P094_data_struct.cpp | 24 ++++++----- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index e3dbfb6aad..47b68c6bc3 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -26,6 +26,7 @@ int mBusPacket_header_t::encodeManufacturerID(const String& id_str) if (nrChars > 3) { nrChars = 3; } int i = 0; + while (i < nrChars) { res <<= 5; const int c = static_cast(toUpperCase(id_str[i])) - 64; @@ -62,8 +63,28 @@ bool mBusPacket_header_t::isValid() const _length > 0; } +void mBusPacket_header_t::clear() +{ + _manufacturer = 0; + _meterType = 0; + _serialNr = 0; + _length = 0; +} + bool mBusPacket_t::parse(const String& payload) { + if (payload.length() < 10) { return false; } + const uint16_t lqi_rssi = hexToUL(payload, payload.length() - 4, 4); + + _LQI = (lqi_rssi >> 8) & 0x7f; // Bit 7 = CRC OK Bit + _rssi = lqi_rssi & 0xFF; + + if (_rssi >= 128) { + _rssi -= 256; // 2-complement + } + _rssi = (_rssi / 2) - 74; + + if (payload.startsWith(F("bY"))) { return parseHeaders(removeChecksumsFrameB(payload)); } @@ -77,7 +98,8 @@ bool mBusPacket_t::parse(const String& payload) bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) { const int payloadSize = payloadWithoutChecksums.size(); - + _deviceId1.clear(); + _deviceId2.clear(); if (payloadSize < 10) { return false; } int offset = 0; @@ -96,15 +118,15 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) const uint32_t val = payloadWithoutChecksums[offset + 4 + i]; _deviceId1._serialNr += val << (i * 8); } - offset += 10; - _deviceId1._length = offset; + offset += 10; + _deviceId1._length = payloadWithoutChecksums[0]; } // next blocks can be anything. we skip known blocks of no interest, parse known blocks if interest and stop on onknown blocks while (offset < payloadSize) { - switch (payloadWithoutChecksums[offset]) { + switch (static_cast(payloadWithoutChecksums[offset])) { case 0x8C: // ELL short - offset += 3; // fixed length + offset += 3; // fixed length _deviceId1._length = payloadSize - offset; break; case 0x90: // AFL @@ -126,7 +148,6 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) _deviceId1._serialNr = 0; - _deviceId1._length = payloadSize - offset; for (int i = 0; i < 4; ++i) { const uint32_t val = payloadWithoutChecksums[offset + 1 + i]; @@ -138,6 +159,7 @@ bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) break; default: // We're done + addLog(LOG_LEVEL_ERROR, concat(F("CUL : offset "), offset) + F(" Data: ") + formatToHex(payloadWithoutChecksums[offset])); offset = payloadSize; break; } @@ -169,7 +191,7 @@ uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) { mBusPacket_data result; - const int payloadLength = payload.length(); + const int payloadLength = payload.length(); if (payloadLength < 4) { return result; } @@ -178,7 +200,8 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) // 1st byte contains length of data (excuding 1st byte and excluding CRC) const int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; - if (payloadLength < (2* expectedMessageSize)) { + + if (payloadLength < (2 * expectedMessageSize)) { // Not an exact check, but close enough to fail early on packets which are seriously too short. return result; } @@ -187,7 +210,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) while (targetIndex < expectedMessageSize) { // end index is start index + block size + 2 byte checksums - int blockSize = (sourceIndex == 0) ? FRAME_FORMAT_A_FIRST_BLOCK_LENGTH : FRAME_FORMAT_A_OTHER_BLOCK_LENGTH; + int blockSize = (sourceIndex == 1) ? FRAME_FORMAT_A_FIRST_BLOCK_LENGTH : FRAME_FORMAT_A_OTHER_BLOCK_LENGTH; if ((targetIndex + blockSize) > expectedMessageSize) { // last block blockSize = expectedMessageSize - targetIndex; @@ -214,7 +237,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) { mBusPacket_data result; - const int payloadLength = payload.length(); + const int payloadLength = payload.length(); if (payloadLength < 4) { return result; } @@ -222,7 +245,8 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) // 1st byte contains length of data (excuding 1st byte BUT INCLUDING CRC) int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; - if (payloadLength < (2* expectedMessageSize)) { + + if (payloadLength < (2 * expectedMessageSize)) { return result; } diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h index 284e0ef008..cea13fef57 100644 --- a/src/src/DataStructs/mBusPacket.h +++ b/src/src/DataStructs/mBusPacket.h @@ -13,9 +13,11 @@ struct mBusPacket_header_t { String getManufacturerId() const; - String toString() const; + String toString() const; - bool isValid() const; + bool isValid() const; + + void clear(); int _manufacturer = 0; int _meterType = 0; @@ -42,6 +44,8 @@ struct mBusPacket_t { mBusPacket_header_t _deviceId1; mBusPacket_header_t _deviceId2; + int _LQI = 0; + int _rssi = 0; }; #endif // ifndef DATASTRUCTS_MBUSPACKET_H diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 815c02df96..141483799c 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -442,8 +442,8 @@ bool P094_data_struct::loop() { if (fullSentenceReceived) { ++sentences_received; length_last_received = sentence_part.length(); - } -#if P094_DEBUG_OPTIONS + } +# if P094_DEBUG_OPTIONS else { if (debug_generate_CUL_data && (sentence_part.length() == 0)) { static uint32_t last_test_sentence = 0; @@ -451,13 +451,15 @@ bool P094_data_struct::loop() { if (timePassedSince(last_test_sentence) > 1000) { count++; - sentence_part = getDebugSentences(count); + +// sentence_part = F("b2644AC48585300005037FAB97201585300AC485003150000202F2F0C0AF314213993002F2F2F2F2F2F2F2FAFCA8046"); + sentence_part = getDebugSentences(count); fullSentenceReceived = true; last_test_sentence = millis(); } } } -#endif +# endif // if P094_DEBUG_OPTIONS return fullSentenceReceived; } @@ -585,7 +587,6 @@ bool P094_data_struct::parsePacket(const String& received) const { mBusPacket_t packet; if (!packet.parse(received)) { return false; } - const uint32_t rssi = hexToUL(received, strlength - 4, 4); if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; @@ -608,8 +609,10 @@ bool P094_data_struct::parsePacket(const String& received) const { log += packet._deviceId2._length; log += ')'; } + log += F(" LQI: "); + log += packet._LQI; log += F(" RSSI: "); - log += formatToHex_decimal(rssi); + log += packet._rssi; addLogMove(LOG_LEVEL_INFO, log); } } @@ -677,8 +680,8 @@ bool P094_data_struct::parsePacket(const String& received) const { match = value == receivedValue; break; case P094_rssi: - receivedValue = rssi; - match = value < rssi; + receivedValue = packet._rssi; + match = value > packet._rssi; break; default: match = false; @@ -829,10 +832,11 @@ size_t P094_data_struct::P094_Get_filter_base_index(size_t filterLine) { return filterLine * P094_ITEMS_PER_FILTER + P094_FIRST_FILTER_POS; } -#if P094_DEBUG_OPTIONS +# if P094_DEBUG_OPTIONS uint32_t P094_data_struct::getDebugCounter() { return debug_counter++; } -#endif + +# endif // if P094_DEBUG_OPTIONS #endif // USES_P094 From 1fc8fb2638b8fe00b93e4597a27f5655f928deb6 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Dec 2022 00:59:32 +0100 Subject: [PATCH 344/404] [CUL Reader] Compute checksum CUL messages for deduplication --- src/src/DataStructs/mBusPacket.cpp | 41 ++++++++++++++-------- src/src/DataStructs/mBusPacket.h | 7 ++-- src/src/PluginStructs/P094_data_struct.cpp | 2 ++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 47b68c6bc3..8ee124b01f 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -73,8 +73,21 @@ void mBusPacket_header_t::clear() bool mBusPacket_t::parse(const String& payload) { - if (payload.length() < 10) { return false; } - const uint16_t lqi_rssi = hexToUL(payload, payload.length() - 4, 4); + mBusPacket_data payloadWithoutChecksums; + + if (payload.startsWith(F("bY"))) { + payloadWithoutChecksums = removeChecksumsFrameB(payload, _checksum); + } else if (payload.startsWith(F("b"))) { + payloadWithoutChecksums = removeChecksumsFrameA(payload, _checksum); + } else { return false; } + + if (payloadWithoutChecksums.size() < 10) { return false; } + + int pos_semicolon = payload.indexOf(';'); + + if (pos_semicolon == -1) { pos_semicolon = payload.length(); } + + const uint16_t lqi_rssi = hexToUL(payload, pos_semicolon - 4, 4); _LQI = (lqi_rssi >> 8) & 0x7f; // Bit 7 = CRC OK Bit _rssi = lqi_rssi & 0xFF; @@ -83,21 +96,13 @@ bool mBusPacket_t::parse(const String& payload) _rssi -= 256; // 2-complement } _rssi = (_rssi / 2) - 74; - - - if (payload.startsWith(F("bY"))) { - return parseHeaders(removeChecksumsFrameB(payload)); - } - - if (payload.startsWith(F("b"))) { - return parseHeaders(removeChecksumsFrameA(payload)); - } - return false; + return parseHeaders(payloadWithoutChecksums); } bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) { const int payloadSize = payloadWithoutChecksums.size(); + _deviceId1.clear(); _deviceId2.clear(); @@ -188,7 +193,7 @@ uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) * ... * (last block can be < 16 bytes) */ -mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) +mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint16_t& checksum) { mBusPacket_data result; const int payloadLength = payload.length(); @@ -221,6 +226,8 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) result.push_back(hexToByte(payload, sourceIndex)); sourceIndex += 2; // 2 hex chars } + // [2 bytes CRC] + checksum ^= hexToUL(payload, sourceIndex, 4); sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars targetIndex += blockSize; } @@ -234,7 +241,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload) * (if message length <=126 bytes, only the 1st block exists) * (last block can be < 125 bytes) */ -mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) +mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint16_t& checksum) { mBusPacket_data result; const int payloadLength = payload.length(); @@ -266,9 +273,11 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) result.push_back(hexToByte(payload, sourceIndex)); sourceIndex += 2; // 2 hex chars } + // [2 bytes CRC] + checksum ^= hexToUL(payload, sourceIndex, 4); + sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars if (expectedMessageSize > 126) { - sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars int block2Size = expectedMessageSize - 127; if (block2Size > 124) { block2Size = 124; } @@ -277,6 +286,8 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload) result.push_back(hexToByte(payload, sourceIndex)); sourceIndex += 2; // 2 hex chars } + // [2 bytes CRC] + checksum ^= hexToUL(payload, sourceIndex, 4); } // remove the checksums and the 1st byte from the actual message length, so that the meaning of this byte is the same as in Frame A diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h index cea13fef57..74b462dbbd 100644 --- a/src/src/DataStructs/mBusPacket.h +++ b/src/src/DataStructs/mBusPacket.h @@ -35,8 +35,8 @@ struct mBusPacket_t { static uint8_t hexToByte(const String& str, size_t index); - static mBusPacket_data removeChecksumsFrameA(const String& payload); - static mBusPacket_data removeChecksumsFrameB(const String& payload); + static mBusPacket_data removeChecksumsFrameA(const String& payload, uint16_t& checksum); + static mBusPacket_data removeChecksumsFrameB(const String& payload, uint16_t& checksum); bool parseHeaders(const mBusPacket_data& payloadWithoutChecksums); @@ -46,6 +46,9 @@ struct mBusPacket_t { mBusPacket_header_t _deviceId2; int _LQI = 0; int _rssi = 0; + + // Checksum based on the XOR of all removed checksums from the message + uint16_t _checksum = 0; }; #endif // ifndef DATASTRUCTS_MBUSPACKET_H diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 141483799c..408aec7abc 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -609,6 +609,8 @@ bool P094_data_struct::parsePacket(const String& received) const { log += packet._deviceId2._length; log += ')'; } + log += F(" chksum: "); + log += formatToHex(packet._checksum, 4); log += F(" LQI: "); log += packet._LQI; log += F(" RSSI: "); From 40b8b2d34687219579095ccfeacfd8cd50ced33a Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 20 Dec 2022 12:00:26 +0100 Subject: [PATCH 345/404] [CUL reader] Improve mBus checksum uniqueness + reduce header membersize --- src/src/DataStructs/mBusPacket.cpp | 16 ++++++---- src/src/DataStructs/mBusPacket.h | 35 +++++++++++++++++----- src/src/PluginStructs/P094_data_struct.cpp | 16 ++++++---- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp index 8ee124b01f..c69adcf170 100644 --- a/src/src/DataStructs/mBusPacket.cpp +++ b/src/src/DataStructs/mBusPacket.cpp @@ -90,12 +90,13 @@ bool mBusPacket_t::parse(const String& payload) const uint16_t lqi_rssi = hexToUL(payload, pos_semicolon - 4, 4); _LQI = (lqi_rssi >> 8) & 0x7f; // Bit 7 = CRC OK Bit - _rssi = lqi_rssi & 0xFF; - if (_rssi >= 128) { - _rssi -= 256; // 2-complement + int rssi = lqi_rssi & 0xFF; + + if (rssi >= 128) { + rssi -= 256; // 2-complement } - _rssi = (_rssi / 2) - 74; + _rssi = (rssi / 2) - 74; return parseHeaders(payloadWithoutChecksums); } @@ -193,7 +194,7 @@ uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) * ... * (last block can be < 16 bytes) */ -mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint16_t& checksum) +mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint32_t& checksum) { mBusPacket_data result; const int payloadLength = payload.length(); @@ -227,6 +228,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint1 sourceIndex += 2; // 2 hex chars } // [2 bytes CRC] + checksum <<= 8; checksum ^= hexToUL(payload, sourceIndex, 4); sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars targetIndex += blockSize; @@ -241,7 +243,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint1 * (if message length <=126 bytes, only the 1st block exists) * (last block can be < 125 bytes) */ -mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint16_t& checksum) +mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint32_t& checksum) { mBusPacket_data result; const int payloadLength = payload.length(); @@ -274,6 +276,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint1 sourceIndex += 2; // 2 hex chars } // [2 bytes CRC] + checksum <<= 8; checksum ^= hexToUL(payload, sourceIndex, 4); sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars @@ -287,6 +290,7 @@ mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint1 sourceIndex += 2; // 2 hex chars } // [2 bytes CRC] + checksum <<= 8; checksum ^= hexToUL(payload, sourceIndex, 4); } diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h index 74b462dbbd..455663d9ee 100644 --- a/src/src/DataStructs/mBusPacket.h +++ b/src/src/DataStructs/mBusPacket.h @@ -19,10 +19,13 @@ struct mBusPacket_header_t { void clear(); - int _manufacturer = 0; - int _meterType = 0; + // Use for stats as key: uint32_t _serialNr = 0; - int _length = 0; + uint16_t _manufacturer = 0; + uint8_t _meterType = 0; + + // Use for filtering + uint8_t _length = 0; }; struct mBusPacket_t { @@ -35,8 +38,8 @@ struct mBusPacket_t { static uint8_t hexToByte(const String& str, size_t index); - static mBusPacket_data removeChecksumsFrameA(const String& payload, uint16_t& checksum); - static mBusPacket_data removeChecksumsFrameB(const String& payload, uint16_t& checksum); + static mBusPacket_data removeChecksumsFrameA(const String& payload, uint32_t& checksum); + static mBusPacket_data removeChecksumsFrameB(const String& payload, uint32_t& checksum); bool parseHeaders(const mBusPacket_data& payloadWithoutChecksums); @@ -44,11 +47,27 @@ struct mBusPacket_t { mBusPacket_header_t _deviceId1; mBusPacket_header_t _deviceId2; - int _LQI = 0; - int _rssi = 0; + int16_t _rssi = 0; + uint8_t _LQI = 0; + + +/* + // Statistics: + // Key: + deviceID1: + - manufacturer + - metertype + - serialnr + + // Value: + - message count + - rssi + - lqi??? +*/ + // Checksum based on the XOR of all removed checksums from the message - uint16_t _checksum = 0; + uint32_t _checksum = 0; }; #endif // ifndef DATASTRUCTS_MBUSPACKET_H diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 408aec7abc..04b3f5058e 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -452,8 +452,8 @@ bool P094_data_struct::loop() { if (timePassedSince(last_test_sentence) > 1000) { count++; -// sentence_part = F("b2644AC48585300005037FAB97201585300AC485003150000202F2F0C0AF314213993002F2F2F2F2F2F2F2FAFCA8046"); - sentence_part = getDebugSentences(count); + // sentence_part = F("b2644AC48585300005037FAB97201585300AC485003150000202F2F0C0AF314213993002F2F2F2F2F2F2F2FAFCA8046"); + sentence_part = getDebugSentences(count); fullSentenceReceived = true; last_test_sentence = millis(); } @@ -610,7 +610,7 @@ bool P094_data_struct::parsePacket(const String& received) const { log += ')'; } log += F(" chksum: "); - log += formatToHex(packet._checksum, 4); + log += formatToHex(packet._checksum, 8); log += F(" LQI: "); log += packet._LQI; log += F(" RSSI: "); @@ -682,9 +682,15 @@ bool P094_data_struct::parsePacket(const String& received) const { match = value == receivedValue; break; case P094_rssi: + { receivedValue = packet._rssi; - match = value > packet._rssi; + int int_value = 0; + + if (validIntFromString(valueString, int_value)) { + match = int_value > packet._rssi; + } break; + } default: match = false; break; @@ -841,4 +847,4 @@ uint32_t P094_data_struct::getDebugCounter() { # endif // if P094_DEBUG_OPTIONS -#endif // USES_P094 +#endif // USES_P094 From a4373be3ab0f80f89ccf97196c507abfbe792b24 Mon Sep 17 00:00:00 2001 From: TD-er Date: Wed, 18 Jan 2023 16:13:45 +0100 Subject: [PATCH 346/404] [Build] Exclude C019 from custom build. --- tools/pio/pre_custom_esp82xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 2c87bdf076..7133cba14c 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -58,7 +58,7 @@ # "-DUSES_C015", # Blynk # "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 - "-DUSES_C019", # ESPEasy-NOW +# "-DUSES_C019", # ESPEasy-NOW "-DUSES_ESPEASY_NOW", # "-DFEATURE_MDNS=1", From c7c8babc69fbf152b75036ed39fc8115d804cd20 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 19 Jan 2023 13:27:09 +0100 Subject: [PATCH 347/404] [ESPEasy_NOW] Fix merge issues forwarding MQTT packets --- .../ControllerDelayHandlerStruct.cpp | 40 ++++++++----------- .../ControllerDelayHandlerStruct.h | 4 +- src/src/ControllerQueue/Queue_element_base.h | 1 + src/src/ESPEasyCore/Controller.cpp | 6 --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 13 +++--- src/src/Helpers/PeriodicalActions.cpp | 4 ++ src/src/WebServer/AccessControl.cpp | 4 +- 7 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.cpp b/src/src/ControllerQueue/ControllerDelayHandlerStruct.cpp index 43c36da5fd..2dff65122b 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.cpp +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.cpp @@ -1,18 +1,6 @@ #include "../ControllerQueue/ControllerDelayHandlerStruct.h" -ControllerDelayHandlerStruct::ControllerDelayHandlerStruct() : - lastSend(0), - minTimeBetweenMessages(CONTROLLER_DELAY_QUEUE_DELAY_DFLT), - expire_timeout(0), - max_queue_depth(CONTROLLER_DELAY_QUEUE_DEPTH_DFLT), - attempt(0), - max_retries(CONTROLLER_DELAY_QUEUE_RETRY_DFLT), - delete_oldest(false), - must_check_reply(false), - deduplicate(false), - useLocalSystemTime(false) {} - bool ControllerDelayHandlerStruct::configureControllerSettings(controllerIndex_t ControllerIndex) { MakeControllerSettings(ControllerSettings); @@ -26,14 +14,16 @@ bool ControllerDelayHandlerStruct::configureControllerSettings(controllerIndex_t } void ControllerDelayHandlerStruct::configureControllerSettings(const ControllerSettingsStruct& settings) { - minTimeBetweenMessages = settings.MinimalTimeBetweenMessages; - max_queue_depth = settings.MaxQueueDepth; - max_retries = settings.MaxRetry; - delete_oldest = settings.DeleteOldest; - must_check_reply = settings.MustCheckReply; - deduplicate = settings.deduplicate(); - useLocalSystemTime = settings.useLocalSystemTime(); - + minTimeBetweenMessages = settings.MinimalTimeBetweenMessages; + max_queue_depth = settings.MaxQueueDepth; + max_retries = settings.MaxRetry; + delete_oldest = settings.DeleteOldest; + must_check_reply = settings.MustCheckReply; + deduplicate = settings.deduplicate(); + useLocalSystemTime = settings.useLocalSystemTime(); +#ifdef USES_ESPEASY_NOW + enableESPEasyNowFallback = settings.enableESPEasyNowFallback(); +#endif if (settings.allowExpire()) { expire_timeout = max_queue_depth * max_retries * (minTimeBetweenMessages + settings.ClientTimeout); @@ -62,14 +52,16 @@ bool ControllerDelayHandlerStruct::readyToProcess(const Queue_element_base& elem return false; } - if (Protocol[protocolIndex].needsNetwork) { + if (!enableESPEasyNowFallback && Protocol[protocolIndex].needsNetwork) { return NetworkConnected(10); } return true; } bool ControllerDelayHandlerStruct::queueFull(controllerIndex_t controller_idx) const { - if (sendQueue.size() >= max_queue_depth) { return true; } + if (sendQueue.size() >= max_queue_depth) { + return true; + } // Number of elements is not exceeding the limit, check memory int freeHeap = FreeMem(); @@ -93,7 +85,7 @@ bool ControllerDelayHandlerStruct::queueFull(controllerIndex_t controller_idx) c } #ifndef BUILD_NO_DEBUG - if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("Controller-"); log += controller_idx + 1; log += F(" : Memory used: "); @@ -264,7 +256,7 @@ void ControllerDelayHandlerStruct::process( if (element == nullptr) { return; } - if (readyToProcess(*element)) { + if (enableESPEasyNowFallback || readyToProcess(*element)) { MakeControllerSettings(ControllerSettings); if (AllocatedControllerSettings()) { diff --git a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h index 5ba75e754f..2c015e4f74 100644 --- a/src/src/ControllerQueue/ControllerDelayHandlerStruct.h +++ b/src/src/ControllerQueue/ControllerDelayHandlerStruct.h @@ -37,7 +37,7 @@ typedef bool (*do_process_function)(int, * ControllerDelayHandlerStruct \*********************************************************************************************/ struct ControllerDelayHandlerStruct { - ControllerDelayHandlerStruct(); + ControllerDelayHandlerStruct() = default; bool configureControllerSettings(controllerIndex_t ControllerIndex); void configureControllerSettings(const ControllerSettingsStruct& settings); @@ -89,7 +89,7 @@ struct ControllerDelayHandlerStruct { bool must_check_reply = false; bool deduplicate = false; bool useLocalSystemTime = false; - bool enableESPEasyNowFallback = false; + bool enableESPEasyNowFallback = false; }; diff --git a/src/src/ControllerQueue/Queue_element_base.h b/src/src/ControllerQueue/Queue_element_base.h index c9961b5909..7f529c1e34 100644 --- a/src/src/ControllerQueue/Queue_element_base.h +++ b/src/src/ControllerQueue/Queue_element_base.h @@ -34,6 +34,7 @@ class Queue_element_base { // Some formatting of values can be done when actually sending it. // This may require less RAM than keeping formatted strings in memory bool _processByController; + }; #endif // ifndef CONTROLLERQUEUE_QUEUE_ELEMENT_BASE_H diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 9a77937525..003878295a 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -631,9 +631,6 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const return false; } - if (MQTT_queueFull(controller_idx)) { - return false; - } const bool success = MQTTDelayHandler->addToQueue(std::unique_ptr(new MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained, callbackTask))); scheduleNextMQTTdelayQueue(); @@ -645,9 +642,6 @@ bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, Strin return false; } - if (MQTT_queueFull(controller_idx)) { - return false; - } const bool success = MQTTDelayHandler->addToQueue(std::unique_ptr(new MQTT_queue_element(controller_idx, taskIndex, std::move(topic), std::move(payload), retained, callbackTask))); scheduleNextMQTTdelayQueue(); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index ac88735ad3..42c51bf8ca 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1542,15 +1542,16 @@ void setConnectionSpeed() { } void setupStaticIPconfig() { + const IPAddress ip (Settings.IP); + const IPAddress gw (Settings.Gateway); + const IPAddress subnet (Settings.Subnet); + const IPAddress dns (Settings.DNS); + + WiFiEventData.dns0_cache = dns; + setUseStaticIP(WiFiUseStaticIP()); if (!WiFiUseStaticIP()) { return; } - const IPAddress ip = Settings.IP; - const IPAddress gw = Settings.Gateway; - const IPAddress subnet = Settings.Subnet; - const IPAddress dns = Settings.DNS; - - WiFiEventData.dns0_cache = Settings.DNS; WiFi.config(ip, gw, subnet, dns); diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index 8818424381..c98cbf36d4 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -300,10 +300,14 @@ void processMQTTdelayQueue() { return; } runPeriodicalMQTT(); // Update MQTT connected state. + #ifndef USES_ESPEASY_NOW + // When using ESPEasy_NOW we may still send MQTT messages even when we're not connected. + // For all other situations no need to continue. if (!MQTTclient_connected) { scheduleNextMQTTdelayQueue(); return; } + #endif START_TIMER; MQTT_queue_element *element(static_cast(MQTTDelayHandler->getNext())); diff --git a/src/src/WebServer/AccessControl.cpp b/src/src/WebServer/AccessControl.cpp index 24ba8c4aa6..103842adb9 100644 --- a/src/src/WebServer/AccessControl.cpp +++ b/src/src/WebServer/AccessControl.cpp @@ -58,8 +58,8 @@ bool getIPallowedRange(IPAddress& low, IPAddress& high) } return getSubnetRange(low, high); case ONLY_IP_RANGE_ALLOWED: - low = SecuritySettings.AllowedIPrangeLow; - high = SecuritySettings.AllowedIPrangeHigh; + low = IPAddress(SecuritySettings.AllowedIPrangeLow); + high = IPAddress(SecuritySettings.AllowedIPrangeHigh); break; default: low = IPAddress(0, 0, 0, 0); From fcdc022bb1111fc80514ea5578db9503f60b02bb Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 21 Jan 2023 14:34:53 +0100 Subject: [PATCH 348/404] [ESPEasy-NOW] Add new C019 ESPEasy-NOW controller --- src/_C019.cpp | 11 +++++-- src/src/ControllerQueue/C018_queue_element.h | 2 +- .../ControllerQueue/C019_queue_element.cpp | 31 ++++++------------- src/src/ControllerQueue/C019_queue_element.h | 21 +++++-------- tools/pio/pre_custom_esp32.py | 2 +- 5 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/_C019.cpp b/src/_C019.cpp index 76c384001e..e93abf00d8 100644 --- a/src/_C019.cpp +++ b/src/_C019.cpp @@ -10,6 +10,7 @@ #include "src/ControllerQueue/C019_queue_element.h" #include "src/Globals/ESPEasy_now_handler.h" #include "src/Helpers/C019_ESPEasyNow_helper.h" +#include "src/ControllerQueue/C019_queue_element.h" #define CPLUGIN_019 @@ -64,7 +65,9 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - success = C019_DelayHandler->addToQueue(C019_queue_element(event)); + std::unique_ptr element(new C019_queue_element(event)); + + success = C019_DelayHandler->addToQueue(std::move(element)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C019_DELAY_QUEUE, C019_DelayHandler->getNextScheduleTime()); break; @@ -99,7 +102,9 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& return success; } -bool do_process_c019_delay_queue(int controller_number, const C019_queue_element& element, ControllerSettingsStruct& ControllerSettings) { +bool do_process_c019_delay_queue(int controller_number, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { + const C019_queue_element& element = static_cast(element_base); + ESPEasy_Now_p2p_data data; const taskIndex_t taskIndex = element.event.TaskIndex; @@ -108,7 +113,7 @@ bool do_process_c019_delay_queue(int controller_number, const C019_queue_element data.sourceTaskIndex = taskIndex; data.plugin_id = getPluginID_from_TaskIndex(taskIndex); data.sourceUnit = Settings.Unit; - data.idx = Settings.TaskDeviceID[element.controller_idx][taskIndex]; + data.idx = Settings.TaskDeviceID[element._controller_idx][taskIndex]; data.sensorType = element.event.sensorType; data.valueCount = getValueCountForTask(taskIndex); diff --git a/src/src/ControllerQueue/C018_queue_element.h b/src/src/ControllerQueue/C018_queue_element.h index a1a682e173..5f9e11edb0 100644 --- a/src/src/ControllerQueue/C018_queue_element.h +++ b/src/src/ControllerQueue/C018_queue_element.h @@ -7,7 +7,7 @@ # include "../ControllerQueue/Queue_element_base.h" # include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/MessageRouteInfo.h" +# include "../DataStructs/MessageRouteInfo.h" # include "../Globals/CPlugins.h" diff --git a/src/src/ControllerQueue/C019_queue_element.cpp b/src/src/ControllerQueue/C019_queue_element.cpp index 9325a91dad..35272cab54 100644 --- a/src/src/ControllerQueue/C019_queue_element.cpp +++ b/src/src/ControllerQueue/C019_queue_element.cpp @@ -12,24 +12,11 @@ String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount); #endif -#ifdef USE_SECOND_HEAP -C019_queue_element::C019_queue_element(const C019_queue_element& other) : - packed(other.packed), - _timestamp(other._timestamp), - TaskIndex(other.TaskIndex), - controller_idx(other.controller_idx), - plugin_id(other.plugin_id) -#ifdef USES_ESPEASY_NOW - , MessageRouteInfo(other.MessageRouteInfo) -#endif +C019_queue_element::C019_queue_element(struct EventStruct *event_p) { - event.deep_copy(other.event); -} -#endif + _controller_idx = event_p->ControllerIndex; + _taskIndex = event_p->TaskIndex; -C019_queue_element::C019_queue_element(struct EventStruct *event_p) : - controller_idx(event_p->ControllerIndex) -{ event.deep_copy(event_p); #if FEATURE_PACKED_RAW_DATA packed = getPackedFromPlugin(event_p, 0); @@ -49,11 +36,13 @@ size_t C019_queue_element::getSize() const { return sizeof(*this) + packed.length(); } -bool C019_queue_element::isDuplicate(const C019_queue_element& other) const { - if ((other.controller_idx != controller_idx) || - (other.TaskIndex != TaskIndex) || - (other.plugin_id != plugin_id) || - (other.packed != packed)) { +bool C019_queue_element::isDuplicate(const Queue_element_base& other) const { + const C019_queue_element& oth = static_cast(other); + + if ((oth._controller_idx != _controller_idx) || + (oth._taskIndex != _taskIndex) || + (oth.plugin_id != plugin_id) || + (oth.packed != packed)) { return false; } diff --git a/src/src/ControllerQueue/C019_queue_element.h b/src/src/ControllerQueue/C019_queue_element.h index 3fd5b1bd15..e17999f1e6 100644 --- a/src/src/ControllerQueue/C019_queue_element.h +++ b/src/src/ControllerQueue/C019_queue_element.h @@ -5,27 +5,23 @@ #ifdef USES_C019 -#include "../CustomBuild/ESPEasyLimits.h" -#include "../DataStructs/ESPEasy_EventStruct.h" -#include "../DataStructs/MessageRouteInfo.h" -#include "../Globals/CPlugins.h" - +# include "../ControllerQueue/Queue_element_base.h" +# include "../CustomBuild/ESPEasyLimits.h" +# include "../DataStructs/ESPEasy_EventStruct.h" +# include "../DataStructs/MessageRouteInfo.h" +# include "../Globals/CPlugins.h" /*********************************************************************************************\ * C019_queue_element for queueing requests for C019: ESPEasy-NOW \*********************************************************************************************/ -class C019_queue_element { +class C019_queue_element : public Queue_element_base { public: C019_queue_element() = default; - #ifdef USE_SECOND_HEAP - C019_queue_element(const C019_queue_element& other); - #else C019_queue_element(const C019_queue_element& other) = delete; - #endif C019_queue_element(C019_queue_element&& other) = default; @@ -33,7 +29,7 @@ class C019_queue_element { size_t getSize() const; - bool isDuplicate(const C019_queue_element& other) const; + bool isDuplicate(const Queue_element_base& other) const; const MessageRouteInfo_t* getMessageRouteInfo() const { return nullptr; } @@ -42,9 +38,6 @@ class C019_queue_element { String packed; - unsigned long _timestamp = millis(); - taskIndex_t TaskIndex = INVALID_TASK_INDEX; - controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; pluginID_t plugin_id = INVALID_PLUGIN_ID; EventStruct event; }; diff --git a/tools/pio/pre_custom_esp32.py b/tools/pio/pre_custom_esp32.py index 3c54d9390a..b0a2bf18e0 100644 --- a/tools/pio/pre_custom_esp32.py +++ b/tools/pio/pre_custom_esp32.py @@ -61,7 +61,7 @@ # "-DUSES_C015", # Blynk "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 -# "-DUSES_C019", # ESPEasy-NOW + "-DUSES_C019", # ESPEasy-NOW "-DUSES_ESPEASY_NOW", "-DFEATURE_EXT_RTC=1", From 623ef8c3e1f447d32938608c27fd06ba9aaae4f2 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 23 Jan 2023 10:18:34 +0100 Subject: [PATCH 349/404] [LoRaTTN] Split up C018 source files All was in a single .cpp file. This was hard to read/maintain and probably resulted in code duplication in the binary as code would be compiled in-line by the compiler. --- src/_C018.cpp | 805 ++---------------- src/src/Controller_config/C018_config.cpp | 204 +++++ src/src/Controller_config/C018_config.h | 55 ++ .../Controller_struct/C018_data_struct.cpp | 397 +++++++++ src/src/Controller_struct/C018_data_struct.h | 124 +++ 5 files changed, 866 insertions(+), 719 deletions(-) create mode 100644 src/src/Controller_config/C018_config.cpp create mode 100644 src/src/Controller_config/C018_config.h create mode 100644 src/src/Controller_struct/C018_data_struct.cpp create mode 100644 src/src/Controller_struct/C018_data_struct.h diff --git a/src/_C018.cpp b/src/_C018.cpp index 5d9308d7a6..af736d6eb4 100644 --- a/src/_C018.cpp +++ b/src/_C018.cpp @@ -9,13 +9,14 @@ # define CPLUGIN_018 # define CPLUGIN_ID_018 18 # define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903" -# define C018_BAUDRATE_LABEL "baudrate" -# include + # include # include "src/ControllerQueue/C018_queue_element.h" +# include "src/Controller_config/C018_config.h" +# include "src/Controller_struct/C018_data_struct.h" # include "src/DataTypes/ESPEasy_plugin_functions.h" # include "src/Globals/CPlugins.h" # include "src/Globals/Protocol.h" @@ -31,499 +32,15 @@ # define C018_FORCE_SW_SERIAL false # endif // ifndef C018_FORCE_SW_SERIAL -struct C018_data_struct { -private: - void C018_logError(const __FlashStringHelper* command) const; - void updateCacheOnInit(); - -public: - - C018_data_struct() : C018_easySerial(nullptr), myLora(nullptr) {} - - ~C018_data_struct() { - reset(); - } - - void reset() { - if (myLora != nullptr) { - delete myLora; - myLora = nullptr; - } - - if (C018_easySerial != nullptr) { - delete C018_easySerial; - C018_easySerial = nullptr; - } - cacheDevAddr = String(); - cacheHWEUI = String(); - cacheSysVer = String(); - autobaud_success = false; - } - - bool init(const uint8_t port, const int8_t serial_rx, const int8_t serial_tx, unsigned long baudrate, - bool joinIsOTAA, taskIndex_t sampleSet_Initiator, int8_t reset_pin) { - if ((serial_rx < 0) || (serial_tx < 0)) { - // Both pins are needed, or else no serial possible - return false; - } - - // FIXME TD-er: Prevent unneeded OTAA joins. - // See: https://www.thethingsnetwork.org/forum/t/how-often-should-a-node-do-an-otaa-join-and-is-otaa-better-than-abp/11192/47?u=td-er - - - sampleSetInitiator = sampleSet_Initiator; - - if (isInitialized()) { - // Check to see if serial parameters have changed. - bool notChanged = true; - notChanged &= C018_easySerial->getRxPin() == serial_rx; - notChanged &= C018_easySerial->getTxPin() == serial_tx; - notChanged &= C018_easySerial->getBaudRate() == baudrate; - notChanged &= myLora->useOTAA() == joinIsOTAA; - - if (notChanged) { return true; } - } - reset(); - _resetPin = reset_pin; - _baudrate = baudrate; - - // FIXME TD-er: Make force SW serial a proper setting. - if (C018_easySerial != nullptr) { - delete C018_easySerial; - } - - C018_easySerial = new (std::nothrow) ESPeasySerial(static_cast(port), serial_rx, serial_tx, false, 64); - - if (C018_easySerial != nullptr) { - if (myLora != nullptr) { - delete myLora; - } - myLora = new (std::nothrow) rn2xx3(*C018_easySerial); - if (myLora == nullptr) { - delete C018_easySerial; - C018_easySerial = nullptr; - } else { - myLora->setAsyncMode(true); - myLora->setLastUsedJoinMode(joinIsOTAA); - triggerAutobaud(); - } - } - return isInitialized(); - } - - bool isInitialized() const; - - bool hasJoined() const { - if (!isInitialized()) { return false; } - return myLora->hasJoined(); - } - - bool useOTAA() const { - if (!isInitialized()) { return true; } - bool res = myLora->useOTAA(); - - C018_logError(F("useOTA()")); - return res; - } - - bool command_finished() const { - return myLora->command_finished(); - } - - bool txUncnfBytes(const uint8_t *data, uint8_t size, uint8_t port) { - bool res = myLora->txBytes(data, size, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; - - C018_logError(F("txUncnfBytes()")); - return res; - } - - bool txHexBytes(const String& data, uint8_t port) { - bool res = myLora->txHexBytes(data, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; - - C018_logError(F("txHexBytes()")); - return res; - } - - bool txUncnf(const String& data, uint8_t port) { - bool res = myLora->tx(data, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; - - C018_logError(F("txUncnf()")); - return res; - } - - bool setTTNstack(RN2xx3_datatypes::TTN_stack_version version) { - if (!isInitialized()) { return false; } - bool res = myLora->setTTNstack(version); - - C018_logError(F("setTTNstack")); - return res; - } - - bool setFrequencyPlan(RN2xx3_datatypes::Freq_plan plan, uint32_t rx2_freq) { - if (!isInitialized()) { return false; } - bool res = myLora->setFrequencyPlan(plan, rx2_freq); - - C018_logError(F("setFrequencyPlan()")); - return res; - } - - bool setSF(uint8_t sf) { - if (!isInitialized()) { return false; } - bool res = myLora->setSF(sf); - - C018_logError(F("setSF()")); - return res; - } - - bool setAdaptiveDataRate(bool enabled) { - if (!isInitialized()) { return false; } - bool res = myLora->setAdaptiveDataRate(enabled); - - C018_logError(F("setAdaptiveDataRate()")); - return res; - } - - - bool initOTAA(const String& AppEUI, const String& AppKey, const String& DevEUI) { - if (myLora == nullptr) { return false; } - bool success = myLora->initOTAA(AppEUI, AppKey, DevEUI); - cacheDevAddr = String(); - - C018_logError(F("initOTAA()")); - updateCacheOnInit(); - return success; - } - - bool initABP(const String& addr, const String& AppSKey, const String& NwkSKey) { - if (myLora == nullptr) { return false; } - bool success = myLora->initABP(addr, AppSKey, NwkSKey); - cacheDevAddr = addr; - - C018_logError(F("initABP()")); - updateCacheOnInit(); - return success; - } - - String sendRawCommand(const String& command) { - if (!isInitialized()) { return EMPTY_STRING; } - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("sendRawCommand: "); - log += command; - addLogMove(LOG_LEVEL_INFO, log); - } - String res = myLora->sendRawCommand(command); - - C018_logError(F("sendRawCommand()")); - return res; - } - - int getVbat() { - if (!isInitialized()) { return -1; } - return myLora->getVbat(); - } - - String peekLastError() { - if (!isInitialized()) { return EMPTY_STRING; } - return myLora->peekLastError(); - } - - String getLastError() { - if (!isInitialized()) { return EMPTY_STRING; } - return myLora->getLastError(); - } - - String getDataRate() { - if (!isInitialized()) { return EMPTY_STRING; } - String res = myLora->getDataRate(); - - C018_logError(F("getDataRate()")); - return res; - } - - int getRSSI() { - if (!isInitialized()) { return 0; } - return myLora->getRSSI(); - } - - uint32_t getRawStatus() { - if (!isInitialized()) { return 0; } - return myLora->getStatus().getRawStatus(); - } - - RN2xx3_status getStatus() const { - if (!isInitialized()) { return RN2xx3_status(); } - return myLora->getStatus(); - } - - bool getFrameCounters(uint32_t& dnctr, uint32_t& upctr) { - if (!isInitialized()) { return false; } - bool res = myLora->getFrameCounters(dnctr, upctr); - - C018_logError(F("getFrameCounters()")); - return res; - } - - bool setFrameCounters(uint32_t dnctr, uint32_t upctr) { - if (!isInitialized()) { return false; } - bool res = myLora->setFrameCounters(dnctr, upctr); - - C018_logError(F("setFrameCounters()")); - return res; - } - - // Cached data, only changing occasionally. - - String getDevaddr() { - if (cacheDevAddr.isEmpty()) - { - updateCacheOnInit(); - } - return cacheDevAddr; - } - - String hweui() { - if (cacheHWEUI.isEmpty()) { - if (isInitialized()) { - cacheHWEUI = myLora->hweui(); - } - } - return cacheHWEUI; - } - - String sysver() { - if (cacheSysVer.isEmpty()) { - if (isInitialized()) { - cacheSysVer = myLora->sysver(); - } - } - return cacheSysVer; - } - - uint8_t getSampleSetCount() const { - return sampleSetCounter; - } - - uint8_t getSampleSetCount(taskIndex_t taskIndex) { - if (sampleSetInitiator == taskIndex) - { - ++sampleSetCounter; - } - return sampleSetCounter; - } - - float getLoRaAirTime(uint8_t pl) const { - if (isInitialized()) { - return myLora->getLoRaAirTime(pl + 13); // We have a LoRaWAN header of 13 bytes. - } - return -1.0; - } - - void async_loop() { - if (isInitialized()) { - rn2xx3_handler::RN_state state = myLora->async_loop(); - - if (rn2xx3_handler::RN_state::must_perform_init == state) { - if (myLora->get_busy_count() > 10) { - if (validGpio(_resetPin)) { - pinMode(_resetPin, OUTPUT); - digitalWrite(_resetPin, LOW); - delay(50); - digitalWrite(_resetPin, HIGH); - delay(200); - } - autobaud_success = false; - - // triggerAutobaud(); - } - } - } - } - -private: - - void triggerAutobaud() { - if ((C018_easySerial == nullptr) || (myLora == nullptr)) { - return; - } - int retries = 2; - - while (retries > 0 && !autobaud_success) { - if (retries == 1) { - if (validGpio(_resetPin)) { - pinMode(_resetPin, OUTPUT); - digitalWrite(_resetPin, LOW); - delay(50); - digitalWrite(_resetPin, HIGH); - delay(200); - } - } - - // wakeUP_RN2483 and set data rate - // Delay must be longer than specified in the datasheet for firmware 1.0.3 - // See: https://www.thethingsnetwork.org/forum/t/rn2483a-problems-no-serial-communication/7866/36?u=td-er - - // First set the baud rate low enough to even trigger autobaud when 9600 baud is active - C018_easySerial->begin(600); - C018_easySerial->write(static_cast(0x00)); - - // Set to desired baud rate. - C018_easySerial->begin(_baudrate); - C018_easySerial->write(static_cast(0x55)); - C018_easySerial->println(); - delay(100); - - String response = myLora->sysver(); - - // we could use sendRawCommand(F("sys get ver")); here - // C018_easySerial->println(F("sys get ver")); - // String response = C018_easySerial->readStringUntil('\n'); - autobaud_success = response.length() > 10; - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("C018 AutoBaud: "); - log += response; - log += F(" status: "); - log += myLora->sendRawCommand(F("mac get status")); - addLogMove(LOG_LEVEL_INFO, log); - C018_logError(F("autobaud check")); - } - --retries; - } - } - - ESPeasySerial *C018_easySerial = nullptr; - rn2xx3 *myLora = nullptr; - String cacheDevAddr; - String cacheHWEUI; - String cacheSysVer; - unsigned long _baudrate = 57600; - uint8_t sampleSetCounter = 0; - taskIndex_t sampleSetInitiator = INVALID_TASK_INDEX; - int8_t _resetPin = -1; - bool autobaud_success = false; -}; - - - bool C018_data_struct::isInitialized() const { - if ((C018_easySerial != nullptr) && (myLora != nullptr)) { - if (autobaud_success) { - return true; - } - } - return false; - } - - void C018_data_struct::C018_logError(const __FlashStringHelper* command) const { - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String error = myLora->peekLastError(); - - // String error = myLora->getLastError(); - - if (error.length() > 0) { - String log = F("RN2483: "); - log += command; - log += F(": "); - log += error; - addLogMove(LOG_LEVEL_INFO, log); - } - } - } - - void C018_data_struct::updateCacheOnInit() { - if (isInitialized()) { - if (cacheDevAddr.isEmpty() && myLora->getStatus().Joined) - { - cacheDevAddr = myLora->sendRawCommand(F("mac get devaddr")); - - if (cacheDevAddr == F("00000000")) { - cacheDevAddr = String(); - } - } - } - } - +// FIXME TD-er: Must add a controller data struct vector, like with plugins. C018_data_struct *C018_data = nullptr; -# define C018_DEVICE_EUI_LEN 17 -# define C018_DEVICE_ADDR_LEN 33 -# define C018_NETWORK_SESSION_KEY_LEN 33 -# define C018_APP_SESSION_KEY_LEN 33 -# define C018_USE_OTAA 0 -# define C018_USE_ABP 1 -struct C018_ConfigStruct -{ - C018_ConfigStruct() { - reset(); - } - - void validate() { - ZERO_TERMINATE(DeviceEUI); - ZERO_TERMINATE(DeviceAddr); - ZERO_TERMINATE(NetworkSessionKey); - ZERO_TERMINATE(AppSessionKey); - - if ((baudrate < 2400) || (baudrate > 115200)) { - reset(); - } - if (stackVersion >= RN2xx3_datatypes::TTN_stack_version::TTN_NOT_SET) { - stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v3; - } - switch (frequencyplan) { - case RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU: - case RN2xx3_datatypes::Freq_plan::TTN_EU: - case RN2xx3_datatypes::Freq_plan::DEFAULT_EU: - if (rx2_freq < 867000000 || rx2_freq > 870000000) { - rx2_freq = 0; - } - break; - case RN2xx3_datatypes::Freq_plan::TTN_US: - // FIXME TD-er: Need to find the ranges for US (and other regions) - break; - default: - rx2_freq = 0; - break; - } - } - - void reset() { - ZERO_FILL(DeviceEUI); - ZERO_FILL(DeviceAddr); - ZERO_FILL(NetworkSessionKey); - ZERO_FILL(AppSessionKey); - baudrate = 57600; - rxpin = -1; - txpin = -1; - resetpin = -1; - sf = 7; - frequencyplan = RN2xx3_datatypes::Freq_plan::TTN_EU; - rx2_freq = 0; - stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v3; - joinmethod = C018_USE_OTAA; - } - - char DeviceEUI[C018_DEVICE_EUI_LEN] = { 0 }; - char DeviceAddr[C018_DEVICE_ADDR_LEN] = { 0 }; - char NetworkSessionKey[C018_NETWORK_SESSION_KEY_LEN] = { 0 }; - char AppSessionKey[C018_APP_SESSION_KEY_LEN] = { 0 }; - unsigned long baudrate = 57600; - int8_t rxpin = 12; - int8_t txpin = 14; - int8_t resetpin = -1; - uint8_t sf = 7; - uint8_t frequencyplan = RN2xx3_datatypes::Freq_plan::TTN_EU; - uint8_t joinmethod = C018_USE_OTAA; - uint8_t serialPort = 0; - uint8_t stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v2; - uint8_t adr = 0; - uint32_t rx2_freq = 0; -}; - // Forward declarations -bool C018_init(struct EventStruct *event); -String c018_add_joinChanged_script_element_line(const String& id, bool forOTAA); +bool C018_init(struct EventStruct *event); +String c018_add_joinChanged_script_element_line(const String& id, + bool forOTAA); bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& string) @@ -594,8 +111,12 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(event->ControllerIndex); html_add_script(false); addHtml(F("function joinChanged(elem){ var styleOTAA = elem.value == 0 ? '' : 'none'; var styleABP = elem.value == 1 ? '' : 'none';")); - addHtml(c018_add_joinChanged_script_element_line(getControllerParameterInternalName(ProtocolIndex, ControllerSettingsStruct::CONTROLLER_USER), true)); - addHtml(c018_add_joinChanged_script_element_line(getControllerParameterInternalName(ProtocolIndex, ControllerSettingsStruct::CONTROLLER_PASS), true)); + addHtml(c018_add_joinChanged_script_element_line(getControllerParameterInternalName(ProtocolIndex, + ControllerSettingsStruct::CONTROLLER_USER), + true)); + addHtml(c018_add_joinChanged_script_element_line(getControllerParameterInternalName(ProtocolIndex, + ControllerSettingsStruct::CONTROLLER_PASS), + true)); addHtml(c018_add_joinChanged_script_element_line(F("deveui"), true)); addHtml(c018_add_joinChanged_script_element_line(F("deveui_note"), true)); @@ -606,27 +127,15 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& html_add_script_end(); } - unsigned long baudrate; - uint32_t rx2_frequency; - int8_t rxpin; - int8_t txpin; - int8_t resetpin; - uint8_t sf; - uint8_t frequencyplan; - uint8_t joinmethod; - uint8_t stackVersion; - uint8_t adr; - - ESPEasySerialPort port = ESPEasySerialPort::not_set; - { // Keep this object in a small scope so we can destruct it as soon as possible again. std::shared_ptr customConfig; { // Try to allocate on 2nd heap - #ifdef USE_SECOND_HEAP -// HeapSelectIram ephemeral; - #endif + # ifdef USE_SECOND_HEAP + + // HeapSelectIram ephemeral; + # endif // ifdef USE_SECOND_HEAP std::shared_ptr tmp_shared(new (std::nothrow) C018_ConfigStruct); customConfig = std::move(tmp_shared); } @@ -635,139 +144,9 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& break; } LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C018_ConfigStruct)); - customConfig->validate(); - baudrate = customConfig->baudrate; - rxpin = customConfig->rxpin; - txpin = customConfig->txpin; - resetpin = customConfig->resetpin; - sf = customConfig->sf; - frequencyplan = customConfig->frequencyplan; - rx2_frequency = customConfig->rx2_freq; - joinmethod = customConfig->joinmethod; - stackVersion = customConfig->stackVersion; - adr = customConfig->adr; - port = static_cast(customConfig->serialPort); - - { - addFormTextBox(F("Device EUI"), F("deveui"), customConfig->DeviceEUI, C018_DEVICE_EUI_LEN - 1); - String deveui_note = F("Leave empty to use HW DevEUI: "); - - if (C018_data != nullptr) { - deveui_note += C018_data->hweui(); - } - addFormNote(deveui_note, F("deveui_note")); - } - - addFormTextBox(F("Device Addr"), F("devaddr"), customConfig->DeviceAddr, C018_DEVICE_ADDR_LEN - 1); - addFormTextBox(F("Network Session Key"), F("nskey"), customConfig->NetworkSessionKey, C018_NETWORK_SESSION_KEY_LEN - 1); - addFormTextBox(F("App Session Key"), F("appskey"), customConfig->AppSessionKey, C018_APP_SESSION_KEY_LEN - 1); + customConfig->webform_load(C018_data); } - { - const __FlashStringHelper * options[2] = { F("OTAA"), F("ABP") }; - const int values[2] = { C018_USE_OTAA, C018_USE_ABP }; - addFormSelector_script(F("Activation Method"), F("joinmethod"), 2, - options, values, nullptr, joinmethod, - F("joinChanged(this)")); // Script to toggle OTAA/ABP fields visibility when changing selection. - } - html_add_script(F("document.getElementById('joinmethod').onchange();"), false); - - addTableSeparator(F("Connection Configuration"), 2, 3); - { - const __FlashStringHelper * options[4] = { F("SINGLE_CHANNEL_EU"), F("TTN_EU"), F("TTN_US"), F("DEFAULT_EU") }; - int values[4] = - { - RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU, - RN2xx3_datatypes::Freq_plan::TTN_EU, - RN2xx3_datatypes::Freq_plan::TTN_US, - RN2xx3_datatypes::Freq_plan::DEFAULT_EU - }; - - addFormSelector(F("Frequency Plan"), F("frequencyplan"), 4, options, values, nullptr, frequencyplan, false); - addFormNumericBox(F("RX2 Frequency"), F("rx2freq"), rx2_frequency, 0); - addUnit(F("Hz")); - addFormNote(F("0 = default, or else override default")); - } - { - const __FlashStringHelper * options[2] = { F("TTN v2"), F("TTN v3") }; - int values[2] = { - RN2xx3_datatypes::TTN_stack_version::TTN_v2, - RN2xx3_datatypes::TTN_stack_version::TTN_v3 - }; - - addFormSelector(F("TTN Stack"), F("ttnstack"), 2, options, values, nullptr, stackVersion, false); - } - - addFormNumericBox(F("Spread Factor"), F("sf"), sf, 7, 12); - addFormCheckBox(F("Adaptive Data Rate (ADR)"), F("adr"), adr); - - - addTableSeparator(F("Serial Port Configuration"), 2, 3); - - serialHelper_webformLoad(port, rxpin, txpin, true); - - // Show serial port selection - addFormPinSelect(PinSelectPurpose::Generic_input, formatGpioName_RX(false), F("taskdevicepin1"), rxpin); - addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_TX(false), F("taskdevicepin2"), txpin); - - html_add_script(F("document.getElementById('serPort').onchange();"), false); - - addFormNumericBox(F("Baudrate"), F(C018_BAUDRATE_LABEL), baudrate, 2400, 115200); - addUnit(F("baud")); - addFormNote(F("Module default baudrate: 57600 bps")); - - // Optional reset pin RN2xx3 - addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output_optional(F("Reset")), F("taskdevicepin3"), resetpin); - - addTableSeparator(F("Device Status"), 2, 3); - - if (C018_data != nullptr) { - // Some information on detected device - addRowLabel(F("Hardware DevEUI")); - addHtml(C018_data->hweui()); - addRowLabel(F("Version Number")); - addHtml(C018_data->sysver()); - - addRowLabel(F("Voltage")); - addHtmlFloat(static_cast(C018_data->getVbat()) / 1000.0f, 3); - - addRowLabel(F("Device Addr")); - addHtml(C018_data->getDevaddr()); - - uint32_t dnctr, upctr; - - if (C018_data->getFrameCounters(dnctr, upctr)) { - addRowLabel(F("Frame Counters (down/up)")); - String values = String(dnctr); - values += '/'; - values += upctr; - addHtml(values); - } - - addRowLabel(F("Last Command Error")); - addHtml(C018_data->getLastError()); - - addRowLabel(F("Sample Set Counter")); - addHtmlInt(C018_data->getSampleSetCount()); - - addRowLabel(F("Data Rate")); - addHtml(C018_data->getDataRate()); - - { - RN2xx3_status status = C018_data->getStatus(); - - addRowLabel(F("Status RAW value")); - addHtmlInt(status.getRawStatus()); - - addRowLabel(F("Activation Status")); - addEnabled(status.Joined); - - addRowLabel(F("Silent Immediately")); - addHtmlInt(status.SilentImmediately ? 1 : 0); - } - } - - break; } case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: @@ -775,36 +154,18 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& std::shared_ptr customConfig; { // Try to allocate on 2nd heap - #ifdef USE_SECOND_HEAP -// HeapSelectIram ephemeral; - #endif + # ifdef USE_SECOND_HEAP + + // HeapSelectIram ephemeral; + # endif // ifdef USE_SECOND_HEAP std::shared_ptr tmp_shared(new (std::nothrow) C018_ConfigStruct); customConfig = std::move(tmp_shared); } if (customConfig) { - customConfig->reset(); - String deveui = webArg(F("deveui")); - String devaddr = webArg(F("devaddr")); - String nskey = webArg(F("nskey")); - String appskey = webArg(F("appskey")); - - strlcpy(customConfig->DeviceEUI, deveui.c_str(), sizeof(customConfig->DeviceEUI)); - strlcpy(customConfig->DeviceAddr, devaddr.c_str(), sizeof(customConfig->DeviceAddr)); - strlcpy(customConfig->NetworkSessionKey, nskey.c_str(), sizeof(customConfig->NetworkSessionKey)); - strlcpy(customConfig->AppSessionKey, appskey.c_str(), sizeof(customConfig->AppSessionKey)); - customConfig->baudrate = getFormItemInt(F(C018_BAUDRATE_LABEL), customConfig->baudrate); - customConfig->rxpin = getFormItemInt(F("taskdevicepin1"), customConfig->rxpin); - customConfig->txpin = getFormItemInt(F("taskdevicepin2"), customConfig->txpin); - customConfig->resetpin = getFormItemInt(F("taskdevicepin3"), customConfig->resetpin); - customConfig->sf = getFormItemInt(F("sf"), customConfig->sf); - customConfig->frequencyplan = getFormItemInt(F("frequencyplan"), customConfig->frequencyplan); - customConfig->rx2_freq = getFormItemInt(F("rx2freq"), customConfig->rx2_freq); - customConfig->joinmethod = getFormItemInt(F("joinmethod"), customConfig->joinmethod); - customConfig->stackVersion = getFormItemInt(F("ttnstack"), customConfig->stackVersion); - customConfig->adr = isFormItemChecked(F("adr")); - serialHelper_webformSave(customConfig->serialPort, customConfig->rxpin, customConfig->txpin); - SaveCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C018_ConfigStruct)); + customConfig->webform_save(); + SaveCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), + sizeof(C018_ConfigStruct)); } break; } @@ -838,6 +199,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& if (C018_DelayHandler == nullptr) { break; } + if (C018_DelayHandler->queueFull(event->ControllerIndex)) { break; } @@ -871,13 +233,15 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& if (C018_data != nullptr) { if (C018_data->isInitialized()) { - const String command = parseString(string, 1); + const String command = parseString(string, 1); + if (command.equals(F("lorawan"))) { const String subcommand = parseString(string, 2); + if (subcommand.equals(F("write"))) { const String loraWriteCommand = parseStringToEnd(string, 3); - const String res = C018_data->sendRawCommand(loraWriteCommand); - String logstr = F("LoRaWAN cmd: "); + const String res = C018_data->sendRawCommand(loraWriteCommand); + String logstr = F("LoRaWAN cmd: "); logstr += loraWriteCommand; logstr += F(" -> "); logstr += res; @@ -936,7 +300,7 @@ bool C018_init(struct EventStruct *event) { } { // Allocate ControllerSettings object in a scope, so we can destruct it as soon as possible. - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { return false; @@ -953,9 +317,10 @@ bool C018_init(struct EventStruct *event) { std::shared_ptr customConfig; { // Try to allocate on 2nd heap - #ifdef USE_SECOND_HEAP -// HeapSelectIram ephemeral; - #endif + # ifdef USE_SECOND_HEAP + + // HeapSelectIram ephemeral; + # endif // ifdef USE_SECOND_HEAP std::shared_ptr tmp_shared(new (std::nothrow) C018_ConfigStruct); customConfig = std::move(tmp_shared); } @@ -974,9 +339,11 @@ bool C018_init(struct EventStruct *event) { } C018_data->setFrequencyPlan(static_cast(customConfig->frequencyplan), customConfig->rx2_freq); + if (!C018_data->setSF(customConfig->sf)) { return false; } + if (!C018_data->setAdaptiveDataRate(customConfig->adr != 0)) { return false; } @@ -1019,65 +386,65 @@ bool C018_init(struct EventStruct *event) { bool do_process_c018_delay_queue(int controller_number, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { const C018_queue_element& element = static_cast(element_base); // *INDENT-ON* - uint8_t pl = (element.packed.length() / 2); - float airtime_ms = C018_data->getLoRaAirTime(pl); - bool mustSetDelay = false; - bool success = false; - - if (!C018_data->command_finished()) { - mustSetDelay = true; - } else { - success = C018_data->txHexBytes(element.packed, ControllerSettings.Port); - - if (success) { - if (airtime_ms > 0.0f) { - ADD_TIMER_STAT(C018_AIR_TIME, static_cast(airtime_ms * 1000)); - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("LoRaWAN : Payload Length: "); - log += pl + 13; // We have a LoRaWAN header of 13 bytes. - log += F(" Air Time: "); - log += toString(airtime_ms, 3); - log += F(" ms"); - addLogMove(LOG_LEVEL_INFO, log); - } +uint8_t pl = (element.packed.length() / 2); +float airtime_ms = C018_data->getLoRaAirTime(pl); +bool mustSetDelay = false; +bool success = false; + +if (!C018_data->command_finished()) { + mustSetDelay = true; +} else { + success = C018_data->txHexBytes(element.packed, ControllerSettings.Port); + + if (success) { + if (airtime_ms > 0.0f) { + ADD_TIMER_STAT(C018_AIR_TIME, static_cast(airtime_ms * 1000)); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("LoRaWAN : Payload Length: "); + log += pl + 13; // We have a LoRaWAN header of 13 bytes. + log += F(" Air Time: "); + log += toString(airtime_ms, 3); + log += F(" ms"); + addLogMove(LOG_LEVEL_INFO, log); } } } - String error = C018_data->getLastError(); // Clear the error string. +} +String error = C018_data->getLastError(); // Clear the error string. - if (error.indexOf(F("no_free_ch")) != -1) { - mustSetDelay = true; - } +if (error.indexOf(F("no_free_ch")) != -1) { + mustSetDelay = true; +} - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("C018 : Sent: "); - log += element.packed; - log += F(" length: "); - log += String(element.packed.length()); +if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("C018 : Sent: "); + log += element.packed; + log += F(" length: "); + log += String(element.packed.length()); - if (success) { - log += F(" (success) "); - } - log += error; - addLogMove(LOG_LEVEL_INFO, log); + if (success) { + log += F(" (success) "); } + log += error; + addLogMove(LOG_LEVEL_INFO, log); +} - if (mustSetDelay) { - // Module is still sending, delay for 10x expected air time, which is equivalent of 10% air time duty cycle. - // This can be retried a few times, so at most 10 retries like these are needed to get below 1% air time again. - // Very likely only 2 - 3 of these delays are needed, as we have 8 channels to send from and messages are likely sent in bursts. - C018_DelayHandler->setAdditionalDelay(10 * airtime_ms); +if (mustSetDelay) { + // Module is still sending, delay for 10x expected air time, which is equivalent of 10% air time duty cycle. + // This can be retried a few times, so at most 10 retries like these are needed to get below 1% air time again. + // Very likely only 2 - 3 of these delays are needed, as we have 8 channels to send from and messages are likely sent in bursts. + C018_DelayHandler->setAdditionalDelay(10 * airtime_ms); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("LoRaWAN : Unable to send. Delay for "); - log += 10 * airtime_ms; - log += F(" ms"); - addLogMove(LOG_LEVEL_INFO, log); - } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("LoRaWAN : Unable to send. Delay for "); + log += 10 * airtime_ms; + log += F(" ms"); + addLogMove(LOG_LEVEL_INFO, log); } +} - return success; +return success; } String c018_add_joinChanged_script_element_line(const String& id, bool forOTAA) { diff --git a/src/src/Controller_config/C018_config.cpp b/src/src/Controller_config/C018_config.cpp new file mode 100644 index 0000000000..24e83a0a81 --- /dev/null +++ b/src/src/Controller_config/C018_config.cpp @@ -0,0 +1,204 @@ +#include "../Controller_config/C018_config.h" + +#ifdef USES_C018 + +# include "../Controller_struct/C018_data_struct.h" + +# define C018_BAUDRATE_LABEL "baudrate" + +void C018_ConfigStruct::validate() { + ZERO_TERMINATE(DeviceEUI); + ZERO_TERMINATE(DeviceAddr); + ZERO_TERMINATE(NetworkSessionKey); + ZERO_TERMINATE(AppSessionKey); + + if ((baudrate < 2400) || (baudrate > 115200)) { + reset(); + } + + if (stackVersion >= RN2xx3_datatypes::TTN_stack_version::TTN_NOT_SET) { + stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v3; + } + + switch (frequencyplan) { + case RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU: + case RN2xx3_datatypes::Freq_plan::TTN_EU: + case RN2xx3_datatypes::Freq_plan::DEFAULT_EU: + + if ((rx2_freq < 867000000) || (rx2_freq > 870000000)) { + rx2_freq = 0; + } + break; + case RN2xx3_datatypes::Freq_plan::TTN_US: + // FIXME TD-er: Need to find the ranges for US (and other regions) + break; + default: + rx2_freq = 0; + break; + } +} + +void C018_ConfigStruct::reset() { + ZERO_FILL(DeviceEUI); + ZERO_FILL(DeviceAddr); + ZERO_FILL(NetworkSessionKey); + ZERO_FILL(AppSessionKey); + baudrate = 57600; + rxpin = -1; + txpin = -1; + resetpin = -1; + sf = 7; + frequencyplan = RN2xx3_datatypes::Freq_plan::TTN_EU; + rx2_freq = 0; + stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v3; + joinmethod = C018_USE_OTAA; +} + +void C018_ConfigStruct::webform_load(C018_data_struct *C018_data) { + validate(); + ESPEasySerialPort port = static_cast(serialPort); + + { + addFormTextBox(F("Device EUI"), F("deveui"), DeviceEUI, C018_DEVICE_EUI_LEN - 1); + String deveui_note = F("Leave empty to use HW DevEUI: "); + + if (C018_data != nullptr) { + deveui_note += C018_data->hweui(); + } + addFormNote(deveui_note, F("deveui_note")); + } + + addFormTextBox(F("Device Addr"), F("devaddr"), DeviceAddr, C018_DEVICE_ADDR_LEN - 1); + addFormTextBox(F("Network Session Key"), F("nskey"), NetworkSessionKey, C018_NETWORK_SESSION_KEY_LEN - 1); + addFormTextBox(F("App Session Key"), F("appskey"), AppSessionKey, C018_APP_SESSION_KEY_LEN - 1); + + { + const __FlashStringHelper *options[2] = { F("OTAA"), F("ABP") }; + const int values[2] = { C018_USE_OTAA, C018_USE_ABP }; + addFormSelector_script(F("Activation Method"), F("joinmethod"), 2, + options, values, nullptr, joinmethod, + F("joinChanged(this)")); // Script to toggle OTAA/ABP fields visibility when changing selection. + } + html_add_script(F("document.getElementById('joinmethod').onchange();"), false); + + addTableSeparator(F("Connection Configuration"), 2, 3); + { + const __FlashStringHelper *options[4] = { F("SINGLE_CHANNEL_EU"), F("TTN_EU"), F("TTN_US"), F("DEFAULT_EU") }; + int values[4] = + { + RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU, + RN2xx3_datatypes::Freq_plan::TTN_EU, + RN2xx3_datatypes::Freq_plan::TTN_US, + RN2xx3_datatypes::Freq_plan::DEFAULT_EU + }; + + addFormSelector(F("Frequency Plan"), F("frequencyplan"), 4, options, values, nullptr, frequencyplan, false); + addFormNumericBox(F("RX2 Frequency"), F("rx2freq"), rx2_freq, 0); + addUnit(F("Hz")); + addFormNote(F("0 = default, or else override default")); + } + { + const __FlashStringHelper *options[2] = { F("TTN v2"), F("TTN v3") }; + int values[2] = { + RN2xx3_datatypes::TTN_stack_version::TTN_v2, + RN2xx3_datatypes::TTN_stack_version::TTN_v3 + }; + + addFormSelector(F("TTN Stack"), F("ttnstack"), 2, options, values, nullptr, stackVersion, false); + } + + addFormNumericBox(F("Spread Factor"), F("sf"), sf, 7, 12); + addFormCheckBox(F("Adaptive Data Rate (ADR)"), F("adr"), adr); + + + addTableSeparator(F("Serial Port Configuration"), 2, 3); + + serialHelper_webformLoad(port, rxpin, txpin, true); + + // Show serial port selection + addFormPinSelect(PinSelectPurpose::Generic_input, formatGpioName_RX(false), F("taskdevicepin1"), rxpin); + addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_TX(false), F("taskdevicepin2"), txpin); + + html_add_script(F("document.getElementById('serPort').onchange();"), false); + + addFormNumericBox(F("Baudrate"), F(C018_BAUDRATE_LABEL), baudrate, 2400, 115200); + addUnit(F("baud")); + addFormNote(F("Module default baudrate: 57600 bps")); + + // Optional reset pin RN2xx3 + addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output_optional(F("Reset")), F("taskdevicepin3"), resetpin); + + addTableSeparator(F("Device Status"), 2, 3); + + if (C018_data != nullptr) { + // Some information on detected device + addRowLabel(F("Hardware DevEUI")); + addHtml(C018_data->hweui()); + addRowLabel(F("Version Number")); + addHtml(C018_data->sysver()); + + addRowLabel(F("Voltage")); + addHtmlFloat(static_cast(C018_data->getVbat()) / 1000.0f, 3); + + addRowLabel(F("Device Addr")); + addHtml(C018_data->getDevaddr()); + + uint32_t dnctr, upctr; + + if (C018_data->getFrameCounters(dnctr, upctr)) { + addRowLabel(F("Frame Counters (down/up)")); + String values = String(dnctr); + values += '/'; + values += upctr; + addHtml(values); + } + + addRowLabel(F("Last Command Error")); + addHtml(C018_data->getLastError()); + + addRowLabel(F("Sample Set Counter")); + addHtmlInt(C018_data->getSampleSetCount()); + + addRowLabel(F("Data Rate")); + addHtml(C018_data->getDataRate()); + + { + RN2xx3_status status = C018_data->getStatus(); + + addRowLabel(F("Status RAW value")); + addHtmlInt(status.getRawStatus()); + + addRowLabel(F("Activation Status")); + addEnabled(status.Joined); + + addRowLabel(F("Silent Immediately")); + addHtmlInt(status.SilentImmediately ? 1 : 0); + } + } +} + +void C018_ConfigStruct::webform_save() { + reset(); + String deveui = webArg(F("deveui")); + String devaddr = webArg(F("devaddr")); + String nskey = webArg(F("nskey")); + String appskey = webArg(F("appskey")); + + strlcpy(DeviceEUI, deveui.c_str(), sizeof(DeviceEUI)); + strlcpy(DeviceAddr, devaddr.c_str(), sizeof(DeviceAddr)); + strlcpy(NetworkSessionKey, nskey.c_str(), sizeof(NetworkSessionKey)); + strlcpy(AppSessionKey, appskey.c_str(), sizeof(AppSessionKey)); + baudrate = getFormItemInt(F(C018_BAUDRATE_LABEL), baudrate); + rxpin = getFormItemInt(F("taskdevicepin1"), rxpin); + txpin = getFormItemInt(F("taskdevicepin2"), txpin); + resetpin = getFormItemInt(F("taskdevicepin3"), resetpin); + sf = getFormItemInt(F("sf"), sf); + frequencyplan = getFormItemInt(F("frequencyplan"), frequencyplan); + rx2_freq = getFormItemInt(F("rx2freq"), rx2_freq); + joinmethod = getFormItemInt(F("joinmethod"), joinmethod); + stackVersion = getFormItemInt(F("ttnstack"), stackVersion); + adr = isFormItemChecked(F("adr")); + serialHelper_webformSave(serialPort, rxpin, txpin); +} + +#endif // ifdef USES_C018 diff --git a/src/src/Controller_config/C018_config.h b/src/src/Controller_config/C018_config.h new file mode 100644 index 0000000000..3d276d2dc5 --- /dev/null +++ b/src/src/Controller_config/C018_config.h @@ -0,0 +1,55 @@ +#ifndef CONTROLLER_CONFIG_C018_CONFIG_H +#define CONTROLLER_CONFIG_C018_CONFIG_H + +#include "src/Helpers/_CPlugin_Helper.h" + +#ifdef USES_C018 + +// Forward declaration +struct C018_data_struct; + +# include + + +# define C018_DEVICE_EUI_LEN 17 +# define C018_DEVICE_ADDR_LEN 33 +# define C018_NETWORK_SESSION_KEY_LEN 33 +# define C018_APP_SESSION_KEY_LEN 33 +# define C018_USE_OTAA 0 +# define C018_USE_ABP 1 + +struct C018_ConfigStruct +{ + C018_ConfigStruct() = default; + + void validate(); + + void reset(); + + // Send all to the web interface + void webform_load(C018_data_struct* C018_data); + + // Collect all data from the web interface + void webform_save(); + + char DeviceEUI[C018_DEVICE_EUI_LEN] = { 0 }; + char DeviceAddr[C018_DEVICE_ADDR_LEN] = { 0 }; + char NetworkSessionKey[C018_NETWORK_SESSION_KEY_LEN] = { 0 }; + char AppSessionKey[C018_APP_SESSION_KEY_LEN] = { 0 }; + unsigned long baudrate = 57600; + int8_t rxpin = -1; + int8_t txpin = -1; + int8_t resetpin = -1; + uint8_t sf = 7; + uint8_t frequencyplan = RN2xx3_datatypes::Freq_plan::TTN_EU; + uint8_t joinmethod = C018_USE_OTAA; + uint8_t serialPort = 0; + uint8_t stackVersion = RN2xx3_datatypes::TTN_stack_version::TTN_v2; + uint8_t adr = 0; + uint32_t rx2_freq = 0; +}; + + +#endif // ifdef USES_C018 + +#endif // ifndef CONTROLLER_CONFIG_C018_CONFIG_H diff --git a/src/src/Controller_struct/C018_data_struct.cpp b/src/src/Controller_struct/C018_data_struct.cpp new file mode 100644 index 0000000000..885462bb96 --- /dev/null +++ b/src/src/Controller_struct/C018_data_struct.cpp @@ -0,0 +1,397 @@ +#include "../Controller_struct/C018_data_struct.h" + +#ifdef USES_C018 + +C018_data_struct::C018_data_struct() : + C018_easySerial(nullptr), + myLora(nullptr) {} + +C018_data_struct::~C018_data_struct() { + reset(); +} + +void C018_data_struct::reset() { + if (myLora != nullptr) { + delete myLora; + myLora = nullptr; + } + + if (C018_easySerial != nullptr) { + delete C018_easySerial; + C018_easySerial = nullptr; + } + cacheDevAddr = String(); + cacheHWEUI = String(); + cacheSysVer = String(); + autobaud_success = false; +} + +bool C018_data_struct::init(const uint8_t port, const int8_t serial_rx, const int8_t serial_tx, unsigned long baudrate, + bool joinIsOTAA, taskIndex_t sampleSet_Initiator, int8_t reset_pin) { + if ((serial_rx < 0) || (serial_tx < 0)) { + // Both pins are needed, or else no serial possible + return false; + } + + // FIXME TD-er: Prevent unneeded OTAA joins. + // See: https://www.thethingsnetwork.org/forum/t/how-often-should-a-node-do-an-otaa-join-and-is-otaa-better-than-abp/11192/47?u=td-er + + + sampleSetInitiator = sampleSet_Initiator; + + if (isInitialized()) { + // Check to see if serial parameters have changed. + bool notChanged = true; + notChanged &= C018_easySerial->getRxPin() == serial_rx; + notChanged &= C018_easySerial->getTxPin() == serial_tx; + notChanged &= C018_easySerial->getBaudRate() == baudrate; + notChanged &= myLora->useOTAA() == joinIsOTAA; + + if (notChanged) { return true; } + } + reset(); + _resetPin = reset_pin; + _baudrate = baudrate; + + // FIXME TD-er: Make force SW serial a proper setting. + if (C018_easySerial != nullptr) { + delete C018_easySerial; + } + + C018_easySerial = new (std::nothrow) ESPeasySerial(static_cast(port), serial_rx, serial_tx, false, 64); + + if (C018_easySerial != nullptr) { + if (myLora != nullptr) { + delete myLora; + } + myLora = new (std::nothrow) rn2xx3(*C018_easySerial); + + if (myLora == nullptr) { + delete C018_easySerial; + C018_easySerial = nullptr; + } else { + myLora->setAsyncMode(true); + myLora->setLastUsedJoinMode(joinIsOTAA); + triggerAutobaud(); + } + } + return isInitialized(); +} + +bool C018_data_struct::isInitialized() const { + if ((C018_easySerial != nullptr) && (myLora != nullptr)) { + if (autobaud_success) { + return true; + } + } + return false; +} + +bool C018_data_struct::hasJoined() const { + if (!isInitialized()) { return false; } + return myLora->hasJoined(); +} + +bool C018_data_struct::useOTAA() const { + if (!isInitialized()) { return true; } + bool res = myLora->useOTAA(); + + C018_logError(F("useOTA()")); + return res; +} + +bool C018_data_struct::command_finished() const { + return myLora->command_finished(); +} + +bool C018_data_struct::txUncnfBytes(const uint8_t *data, uint8_t size, uint8_t port) { + bool res = myLora->txBytes(data, size, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; + + C018_logError(F("txUncnfBytes()")); + return res; +} + +bool C018_data_struct::txHexBytes(const String& data, uint8_t port) { + bool res = myLora->txHexBytes(data, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; + + C018_logError(F("txHexBytes()")); + return res; +} + +bool C018_data_struct::txUncnf(const String& data, uint8_t port) { + bool res = myLora->tx(data, port) != RN2xx3_datatypes::TX_return_type::TX_FAIL; + + C018_logError(F("txUncnf()")); + return res; +} + +bool C018_data_struct::setTTNstack(RN2xx3_datatypes::TTN_stack_version version) { + if (!isInitialized()) { return false; } + bool res = myLora->setTTNstack(version); + + C018_logError(F("setTTNstack")); + return res; +} + +bool C018_data_struct::setFrequencyPlan(RN2xx3_datatypes::Freq_plan plan, uint32_t rx2_freq) { + if (!isInitialized()) { return false; } + bool res = myLora->setFrequencyPlan(plan, rx2_freq); + + C018_logError(F("setFrequencyPlan()")); + return res; +} + +bool C018_data_struct::setSF(uint8_t sf) { + if (!isInitialized()) { return false; } + bool res = myLora->setSF(sf); + + C018_logError(F("setSF()")); + return res; +} + +bool C018_data_struct::setAdaptiveDataRate(bool enabled) { + if (!isInitialized()) { return false; } + bool res = myLora->setAdaptiveDataRate(enabled); + + C018_logError(F("setAdaptiveDataRate()")); + return res; +} + +bool C018_data_struct::initOTAA(const String& AppEUI, const String& AppKey, const String& DevEUI) { + if (myLora == nullptr) { return false; } + bool success = myLora->initOTAA(AppEUI, AppKey, DevEUI); + + cacheDevAddr = String(); + + C018_logError(F("initOTAA()")); + updateCacheOnInit(); + return success; +} + +bool C018_data_struct::initABP(const String& addr, const String& AppSKey, const String& NwkSKey) { + if (myLora == nullptr) { return false; } + bool success = myLora->initABP(addr, AppSKey, NwkSKey); + + cacheDevAddr = addr; + + C018_logError(F("initABP()")); + updateCacheOnInit(); + return success; +} + +String C018_data_struct::sendRawCommand(const String& command) { + if (!isInitialized()) { return EMPTY_STRING; } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("sendRawCommand: "); + log += command; + addLogMove(LOG_LEVEL_INFO, log); + } + String res = myLora->sendRawCommand(command); + + C018_logError(F("sendRawCommand()")); + return res; +} + +int C018_data_struct::getVbat() { + if (!isInitialized()) { return -1; } + return myLora->getVbat(); +} + +String C018_data_struct::peekLastError() { + if (!isInitialized()) { return EMPTY_STRING; } + return myLora->peekLastError(); +} + +String C018_data_struct::getLastError() { + if (!isInitialized()) { return EMPTY_STRING; } + return myLora->getLastError(); +} + +String C018_data_struct::getDataRate() { + if (!isInitialized()) { return EMPTY_STRING; } + String res = myLora->getDataRate(); + + C018_logError(F("getDataRate()")); + return res; +} + +int C018_data_struct::getRSSI() { + if (!isInitialized()) { return 0; } + return myLora->getRSSI(); +} + +uint32_t C018_data_struct::getRawStatus() { + if (!isInitialized()) { return 0; } + return myLora->getStatus().getRawStatus(); +} + +RN2xx3_status C018_data_struct::getStatus() const { + if (!isInitialized()) { return RN2xx3_status(); } + return myLora->getStatus(); +} + +bool C018_data_struct::getFrameCounters(uint32_t& dnctr, uint32_t& upctr) { + if (!isInitialized()) { return false; } + bool res = myLora->getFrameCounters(dnctr, upctr); + + C018_logError(F("getFrameCounters()")); + return res; +} + +bool C018_data_struct::setFrameCounters(uint32_t dnctr, uint32_t upctr) { + if (!isInitialized()) { return false; } + bool res = myLora->setFrameCounters(dnctr, upctr); + + C018_logError(F("setFrameCounters()")); + return res; +} + +// Cached data, only changing occasionally. + +String C018_data_struct::getDevaddr() { + if (cacheDevAddr.isEmpty()) + { + updateCacheOnInit(); + } + return cacheDevAddr; +} + +String C018_data_struct::hweui() { + if (cacheHWEUI.isEmpty()) { + if (isInitialized()) { + cacheHWEUI = myLora->hweui(); + } + } + return cacheHWEUI; +} + +String C018_data_struct::sysver() { + if (cacheSysVer.isEmpty()) { + if (isInitialized()) { + cacheSysVer = myLora->sysver(); + } + } + return cacheSysVer; +} + +uint8_t C018_data_struct::getSampleSetCount() const { + return sampleSetCounter; +} + +uint8_t C018_data_struct::getSampleSetCount(taskIndex_t taskIndex) { + if (sampleSetInitiator == taskIndex) + { + ++sampleSetCounter; + } + return sampleSetCounter; +} + +float C018_data_struct::getLoRaAirTime(uint8_t pl) const { + if (isInitialized()) { + return myLora->getLoRaAirTime(pl + 13); // We have a LoRaWAN header of 13 bytes. + } + return -1.0; +} + +void C018_data_struct::async_loop() { + if (isInitialized()) { + rn2xx3_handler::RN_state state = myLora->async_loop(); + + if (rn2xx3_handler::RN_state::must_perform_init == state) { + if (myLora->get_busy_count() > 10) { + if (validGpio(_resetPin)) { + pinMode(_resetPin, OUTPUT); + digitalWrite(_resetPin, LOW); + delay(50); + digitalWrite(_resetPin, HIGH); + delay(200); + } + autobaud_success = false; + + // triggerAutobaud(); + } + } + } +} + +void C018_data_struct::C018_logError(const __FlashStringHelper *command) const { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String error = myLora->peekLastError(); + + // String error = myLora->getLastError(); + + if (error.length() > 0) { + String log = F("RN2483: "); + log += command; + log += F(": "); + log += error; + addLogMove(LOG_LEVEL_INFO, log); + } + } +} + +void C018_data_struct::updateCacheOnInit() { + if (isInitialized()) { + if (cacheDevAddr.isEmpty() && myLora->getStatus().Joined) + { + cacheDevAddr = myLora->sendRawCommand(F("mac get devaddr")); + + if (cacheDevAddr == F("00000000")) { + cacheDevAddr = String(); + } + } + } +} + +void C018_data_struct::triggerAutobaud() { + if ((C018_easySerial == nullptr) || (myLora == nullptr)) { + return; + } + int retries = 2; + + while (retries > 0 && !autobaud_success) { + if (retries == 1) { + if (validGpio(_resetPin)) { + pinMode(_resetPin, OUTPUT); + digitalWrite(_resetPin, LOW); + delay(50); + digitalWrite(_resetPin, HIGH); + delay(200); + } + } + + // wakeUP_RN2483 and set data rate + // Delay must be longer than specified in the datasheet for firmware 1.0.3 + // See: https://www.thethingsnetwork.org/forum/t/rn2483a-problems-no-serial-communication/7866/36?u=td-er + + // First set the baud rate low enough to even trigger autobaud when 9600 baud is active + C018_easySerial->begin(600); + C018_easySerial->write(static_cast(0x00)); + + // Set to desired baud rate. + C018_easySerial->begin(_baudrate); + C018_easySerial->write(static_cast(0x55)); + C018_easySerial->println(); + delay(100); + + String response = myLora->sysver(); + + // we could use sendRawCommand(F("sys get ver")); here + // C018_easySerial->println(F("sys get ver")); + // String response = C018_easySerial->readStringUntil('\n'); + autobaud_success = response.length() > 10; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("C018 AutoBaud: "); + log += response; + log += F(" status: "); + log += myLora->sendRawCommand(F("mac get status")); + addLogMove(LOG_LEVEL_INFO, log); + C018_logError(F("autobaud check")); + } + --retries; + } +} + + #endif // ifdef USES_C018 diff --git a/src/src/Controller_struct/C018_data_struct.h b/src/src/Controller_struct/C018_data_struct.h new file mode 100644 index 0000000000..7661cfeb2f --- /dev/null +++ b/src/src/Controller_struct/C018_data_struct.h @@ -0,0 +1,124 @@ +#ifndef CONTROLLER_STRUCT_C018_DATA_STRUCT_H +#define CONTROLLER_STRUCT_C018_DATA_STRUCT_H + +#include "src/Helpers/_CPlugin_Helper.h" + +#ifdef USES_C018 + +# include + + +struct C018_data_struct { +private: + + void C018_logError(const __FlashStringHelper *command) const; + void updateCacheOnInit(); + +public: + + C018_data_struct(); + + ~C018_data_struct(); + + void reset(); + + bool init(const uint8_t port, + const int8_t serial_rx, + const int8_t serial_tx, + unsigned long baudrate, + bool joinIsOTAA, + taskIndex_t sampleSet_Initiator, + int8_t reset_pin); + + bool isInitialized() const; + + bool hasJoined() const; + + bool useOTAA() const; + + bool command_finished() const; + + bool txUncnfBytes(const uint8_t *data, + uint8_t size, + uint8_t port); + + bool txHexBytes(const String& data, + uint8_t port); + + bool txUncnf(const String& data, + uint8_t port); + + bool setTTNstack(RN2xx3_datatypes::TTN_stack_version version); + + bool setFrequencyPlan(RN2xx3_datatypes::Freq_plan plan, + uint32_t rx2_freq); + + bool setSF(uint8_t sf); + + bool setAdaptiveDataRate(bool enabled); + + bool initOTAA(const String& AppEUI, + const String& AppKey, + const String& DevEUI); + + bool initABP(const String& addr, + const String& AppSKey, + const String& NwkSKey); + + String sendRawCommand(const String& command); + + int getVbat(); + + String peekLastError(); + + String getLastError(); + + String getDataRate(); + + int getRSSI(); + + uint32_t getRawStatus(); + + RN2xx3_status getStatus() const; + + bool getFrameCounters(uint32_t& dnctr, + uint32_t& upctr); + + bool setFrameCounters(uint32_t dnctr, + uint32_t upctr); + + // Cached data, only changing occasionally. + + String getDevaddr(); + + String hweui(); + + String sysver(); + + uint8_t getSampleSetCount() const; + + uint8_t getSampleSetCount(taskIndex_t taskIndex); + + float getLoRaAirTime(uint8_t pl) const; + + void async_loop(); + +private: + + void triggerAutobaud(); + + ESPeasySerial *C018_easySerial = nullptr; + rn2xx3 *myLora = nullptr; + String cacheDevAddr; + String cacheHWEUI; + String cacheSysVer; + unsigned long _baudrate = 57600; + uint8_t sampleSetCounter = 0; + taskIndex_t sampleSetInitiator = INVALID_TASK_INDEX; + int8_t _resetPin = -1; + bool autobaud_success = false; +}; + +#endif // ifdef USES_C018 + +#endif // ifndef CONTROLLER_STRUCT_C018_DATA_STRUCT_H From c0a1fc81b292d628f179040c9c9aceaa5d048a8d Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 23 Jan 2023 10:19:17 +0100 Subject: [PATCH 350/404] [ESPEasy_NOW] Add mesh config to C019 controller + filtering --- src/_C018.cpp | 1 - src/_C019.cpp | 82 ++++++++-- src/_P094_CULReader.ino | 32 ++++ .../ControllerQueue/Queue_element_base.cpp | 1 + src/src/ControllerQueue/Queue_element_base.h | 4 + src/src/Controller_config/C018_config.cpp | 13 +- src/src/Controller_config/C018_config.h | 2 +- src/src/Controller_config/C019_config.cpp | 44 +++++ src/src/Controller_config/C019_config.h | 55 +++++++ .../Controller_struct/C019_data_struct.cpp | 1 + src/src/Controller_struct/C019_data_struct.h | 6 + src/src/CustomBuild/ESPEasyLimits.h | 2 +- src/src/CustomBuild/define_plugin_sets.h | 3 + src/src/DataStructs_templ/SettingsStruct.cpp | 19 +++ src/src/DataTypes/ESPEasy_plugin_functions.h | 1 + src/src/ESPEasyCore/Controller.cpp | 154 ++++++++++++------ src/src/ESPEasyCore/Controller.h | 2 +- src/src/Globals/CPlugins.cpp | 33 +--- src/src/Globals/CPlugins.h | 17 +- src/src/Helpers/ESPEasy_now_handler.cpp | 38 ++++- src/src/Helpers/ESPEasy_now_handler.h | 9 + src/src/Helpers/PeriodicalActions.cpp | 33 +++- src/src/Helpers/_CPlugin_init.cpp | 6 +- 23 files changed, 439 insertions(+), 119 deletions(-) create mode 100644 src/src/Controller_config/C019_config.cpp create mode 100644 src/src/Controller_config/C019_config.h create mode 100644 src/src/Controller_struct/C019_data_struct.cpp create mode 100644 src/src/Controller_struct/C019_data_struct.h diff --git a/src/_C018.cpp b/src/_C018.cpp index af736d6eb4..7d132db8fb 100644 --- a/src/_C018.cpp +++ b/src/_C018.cpp @@ -11,7 +11,6 @@ # define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903" - # include # include "src/ControllerQueue/C018_queue_element.h" diff --git a/src/_C019.cpp b/src/_C019.cpp index e93abf00d8..4fefd7cd4e 100644 --- a/src/_C019.cpp +++ b/src/_C019.cpp @@ -6,16 +6,18 @@ // ################### Controller Plugin 019: ESPEasy-NOW ################################################ // ####################################################################################################### -#include "ESPEasy_common.h" -#include "src/ControllerQueue/C019_queue_element.h" -#include "src/Globals/ESPEasy_now_handler.h" -#include "src/Helpers/C019_ESPEasyNow_helper.h" -#include "src/ControllerQueue/C019_queue_element.h" +# include "ESPEasy_common.h" +# include "src/ControllerQueue/C019_queue_element.h" +# include "src/Controller_config/C019_config.h" +# include "src/Globals/ESPEasy_now_handler.h" +# include "src/Globals/SendData_DuplicateChecker.h" +# include "src/Helpers/C019_ESPEasyNow_helper.h" +# include "src/ControllerQueue/C019_queue_element.h" -#define CPLUGIN_019 -#define CPLUGIN_ID_019 19 -#define CPLUGIN_NAME_019 ESPEASY_NOW_NAME +# define CPLUGIN_019 +# define CPLUGIN_ID_019 19 +# define CPLUGIN_NAME_019 ESPEASY_NOW_NAME bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -27,12 +29,12 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& { Protocol[++protocolCount].Number = CPLUGIN_ID_019; Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = false; + Protocol[protocolCount].usesTemplate = true; Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesPassword = false; Protocol[protocolCount].usesExtCreds = false; Protocol[protocolCount].defaultPort = 0; - Protocol[protocolCount].usesID = true; + Protocol[protocolCount].usesID = false; Protocol[protocolCount].Custom = false; Protocol[protocolCount].usesHost = false; Protocol[protocolCount].usesPort = false; @@ -52,14 +54,53 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_INIT: { - success = init_c019_delay_queue(event->ControllerIndex); + // success = init_c019_delay_queue(event->ControllerIndex); + if (use_EspEasy_now) { ESPEasy_now_handler.end(); } + + // Load settings into ESPEasy_now_handler + std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + + if (customConfig) { + LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); + ESPEasy_now_handler.setConfig(*customConfig); + ESPEasy_now_handler.do_begin(); + success = true; + } + + break; + } + + case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: + { + std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + + if (customConfig) { + LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); + customConfig->webform_load(); + } + + break; + } + + case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: + { + std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + + if (customConfig) { + LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); + customConfig->webform_save(); + } + break; } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: { - event->String1 = F("%sysname%/#"); - event->String2 = F("%sysname%/%tskname%/%valname%"); + std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + + if (customConfig) { + customConfig->webform_save(); + } break; } @@ -82,9 +123,13 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND: { - // C019_data.async_loop(); - - // FIXME TD-er: Handle reading error state or return values. + // FIXME: This must be removed from the run50TimesPerSecond() function + if (ESPEasy_now_handler.loop()) { + // FIXME TD-er: Must check if enabled, etc. + } + START_TIMER; + SendData_DuplicateChecker.loop(); + STOP_TIMER(ESPEASY_NOW_DEDUP_LOOP); break; } @@ -102,7 +147,8 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& return success; } -bool do_process_c019_delay_queue(int controller_number, const Queue_element_base& element_base, ControllerSettingsStruct& ControllerSettings) { +bool do_process_c019_delay_queue(int controller_number, const Queue_element_base& element_base, + ControllerSettingsStruct& ControllerSettings) { const C019_queue_element& element = static_cast(element_base); ESPEasy_Now_p2p_data data; diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index b7d201ca3c..d83e35351c 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -320,6 +320,38 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) } + break; + } + + case PLUGIN_FILTEROUT_CONTROLLER_DATA: + { + // event->String1 => topic; + // event->String2 => payload; + if (Settings.TaskDeviceEnabled[event->TaskIndex]) { + // FIXME TD-er: Need to add checking for stats too + if (Plugin_094_match_all(event->TaskIndex, event->String2)) { + success = true; + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log; + + if (log.reserve(128)) { + log = F("CUL Reader: Sending: "); + const size_t messageLength = event->String2.length(); + + if (messageLength < 100) { + log += event->String2; + } else { + // Split string so we get start and end + log += event->String2.substring(0, 40); + log += F("..."); + log += event->String2.substring(messageLength - 40); + } + addLogMove(LOG_LEVEL_INFO, log); + } + } + } + } + break; } } diff --git a/src/src/ControllerQueue/Queue_element_base.cpp b/src/src/ControllerQueue/Queue_element_base.cpp index 82ac938e60..fb94817204 100644 --- a/src/src/ControllerQueue/Queue_element_base.cpp +++ b/src/src/ControllerQueue/Queue_element_base.cpp @@ -4,6 +4,7 @@ Queue_element_base::Queue_element_base() : _controller_idx(INVALID_CONTROLLER_INDEX), _taskIndex(INVALID_TASK_INDEX), _call_PLUGIN_PROCESS_CONTROLLER_DATA(false), + _call_PLUGIN_FILTEROUT_CONTROLLER_DATA(false), _processByController(false) { _timestamp = millis(); diff --git a/src/src/ControllerQueue/Queue_element_base.h b/src/src/ControllerQueue/Queue_element_base.h index 7f529c1e34..b01cab7e69 100644 --- a/src/src/ControllerQueue/Queue_element_base.h +++ b/src/src/ControllerQueue/Queue_element_base.h @@ -31,6 +31,10 @@ class Queue_element_base { // Typical use case is dumping large data which would otherwise take up lot of RAM. bool _call_PLUGIN_PROCESS_CONTROLLER_DATA; + // Call PLUGIN_FILTEROUT_CONTROLLER_DATA which will determine whether the message should be further processed or not. + // Typical use case is forwarding MQTT messages via ESPEasy-NOW mesh. + bool _call_PLUGIN_FILTEROUT_CONTROLLER_DATA; + // Some formatting of values can be done when actually sending it. // This may require less RAM than keeping formatted strings in memory bool _processByController; diff --git a/src/src/Controller_config/C018_config.cpp b/src/src/Controller_config/C018_config.cpp index 24e83a0a81..f1e30a1d37 100644 --- a/src/src/Controller_config/C018_config.cpp +++ b/src/src/Controller_config/C018_config.cpp @@ -54,9 +54,8 @@ void C018_ConfigStruct::reset() { joinmethod = C018_USE_OTAA; } -void C018_ConfigStruct::webform_load(C018_data_struct *C018_data) { - validate(); - ESPEasySerialPort port = static_cast(serialPort); +void C018_ConfigStruct::webform_load(C018_data_struct *C018_data) const { + const ESPEasySerialPort port = static_cast(serialPort); { addFormTextBox(F("Device EUI"), F("deveui"), DeviceEUI, C018_DEVICE_EUI_LEN - 1); @@ -179,10 +178,10 @@ void C018_ConfigStruct::webform_load(C018_data_struct *C018_data) { void C018_ConfigStruct::webform_save() { reset(); - String deveui = webArg(F("deveui")); - String devaddr = webArg(F("devaddr")); - String nskey = webArg(F("nskey")); - String appskey = webArg(F("appskey")); + const String deveui = webArg(F("deveui")); + const String devaddr = webArg(F("devaddr")); + const String nskey = webArg(F("nskey")); + const String appskey = webArg(F("appskey")); strlcpy(DeviceEUI, deveui.c_str(), sizeof(DeviceEUI)); strlcpy(DeviceAddr, devaddr.c_str(), sizeof(DeviceAddr)); diff --git a/src/src/Controller_config/C018_config.h b/src/src/Controller_config/C018_config.h index 3d276d2dc5..922e077292 100644 --- a/src/src/Controller_config/C018_config.h +++ b/src/src/Controller_config/C018_config.h @@ -27,7 +27,7 @@ struct C018_ConfigStruct void reset(); // Send all to the web interface - void webform_load(C018_data_struct* C018_data); + void webform_load(C018_data_struct *C018_data) const; // Collect all data from the web interface void webform_save(); diff --git a/src/src/Controller_config/C019_config.cpp b/src/src/Controller_config/C019_config.cpp new file mode 100644 index 0000000000..ecbeae28bd --- /dev/null +++ b/src/src/Controller_config/C019_config.cpp @@ -0,0 +1,44 @@ +#include "../Controller_config/C019_config.h" + +#ifdef USES_C019 + + +void C019_ConfigStruct::validate() { + if (!validTaskIndex(filterTaskIndex)) { + filterTaskIndex = INVALID_TASK_INDEX; + } + + if (!validControllerIndex(forwardControllerIdx)) { + forwardControllerIdx = INVALID_CONTROLLER_INDEX; + } +} + +void C019_ConfigStruct::reset() { + filterTaskIndex = INVALID_TASK_INDEX; + forwardControllerIdx = INVALID_CONTROLLER_INDEX; +} + +void C019_ConfigStruct::webform_load() { + addFormCheckBox(F("Forward MQTT from " ESPEASY_NOW_NAME), F("fwd_mqtt"), forwardMQTT); + + addTableSeparator(F("MQTT Forward Filtering"), 2, 3); + addFormCheckBox(F("Filter Forward MQTT"), F("filter_fwd"), filterMQTT_forward); + addRowLabel(F("Filter Task")); + addTaskSelect(F("ftask"), filterTaskIndex); + + addFormTextBox(F("Filter Publish Prefix"), F("pub_pref"), filterPublishPrefix, C019_MQTT_TOPIC_LENGTH - 1); + addFormTextBox(F("Filter Subscribe"), F("sub"), filterSubscribe, C019_MQTT_TOPIC_LENGTH - 1); +} + +void C019_ConfigStruct::webform_save() { + reset(); + + forwardMQTT = isFormItemChecked(F("fwd_mqtt")); + filterMQTT_forward = isFormItemChecked(F("filter_fwd")); + filterTaskIndex = getFormItemInt(F("ftask")); + + strlcpy(filterPublishPrefix, webArg(F("pub_pref")).c_str(), sizeof(filterPublishPrefix)); + strlcpy(filterSubscribe, webArg(F("sub")).c_str(), sizeof(filterSubscribe)); +} + +#endif // ifdef USES_C019 diff --git a/src/src/Controller_config/C019_config.h b/src/src/Controller_config/C019_config.h new file mode 100644 index 0000000000..dd93df52eb --- /dev/null +++ b/src/src/Controller_config/C019_config.h @@ -0,0 +1,55 @@ +#ifndef CONTROLLER_CONFIG_C019_CONFIG_H +#define CONTROLLER_CONFIG_C019_CONFIG_H + +#include "src/Helpers/_CPlugin_Helper.h" + +#ifdef USES_C019 + +# define C019_MQTT_TOPIC_LENGTH 128 + +struct C019_ConfigStruct +{ + C019_ConfigStruct() = default; + + void validate(); + + void reset(); + + // Send all to the web interface + void webform_load(); + + // Collect all data from the web interface + void webform_save(); + + + uint8_t configVersion = 1; // Format version of the stored data + uint8_t dummy_not_used = 0; // For 32-bit alignment + uint8_t dummy_not_used1 = 0; // For 32-bit alignment + uint8_t dummy_not_used2 = 0; // For 32-bit alignment + + union { + struct { + uint32_t forwardMQTT : 1; + uint32_t filterMQTT_forward : 1; + + + uint32_t notUsed : 30; // All bits should add up to 32 + }; + + uint32_t variousBits = 0; + }; + int8_t wifiChannel = -1; + + // MQTT filter options + taskIndex_t filterTaskIndex = INVALID_TASK_INDEX; // Task index to use for filtering + controllerIndex_t forwardControllerIdx = INVALID_CONTROLLER_INDEX; // Controller index to forward filtered data to + int8_t filterTopic_startindex = -1; // + int8_t filterTopic_endindex = -1; + char filterPublishPrefix[C019_MQTT_TOPIC_LENGTH] = { 0 }; + char filterSubscribe[C019_MQTT_TOPIC_LENGTH] = { 0 }; +}; + + +#endif // ifdef USES_C019 + +#endif // ifndef CONTROLLER_CONFIG_C019_CONFIG_H diff --git a/src/src/Controller_struct/C019_data_struct.cpp b/src/src/Controller_struct/C019_data_struct.cpp new file mode 100644 index 0000000000..3f6bc0c7ad --- /dev/null +++ b/src/src/Controller_struct/C019_data_struct.cpp @@ -0,0 +1 @@ +#include "../Controller_struct/C019_data_struct.h" \ No newline at end of file diff --git a/src/src/Controller_struct/C019_data_struct.h b/src/src/Controller_struct/C019_data_struct.h new file mode 100644 index 0000000000..d898c6a2c5 --- /dev/null +++ b/src/src/Controller_struct/C019_data_struct.h @@ -0,0 +1,6 @@ +#ifndef CONTROLLER_STRUCT_C019_DATA_STRUCT_H +#define CONTROLLER_STRUCT_C019_DATA_STRUCT_H + + + +#endif \ No newline at end of file diff --git a/src/src/CustomBuild/ESPEasyLimits.h b/src/src/CustomBuild/ESPEasyLimits.h index 867352179b..a9b887d8c4 100644 --- a/src/src/CustomBuild/ESPEasyLimits.h +++ b/src/src/CustomBuild/ESPEasyLimits.h @@ -108,7 +108,7 @@ #define PLUGIN_MAX DEVICES_MAX #endif #ifndef CPLUGIN_MAX - #define CPLUGIN_MAX 20 + #define CPLUGIN_MAX 25 #endif #ifndef NPLUGIN_MAX #define NPLUGIN_MAX 4 diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 4e3a403274..10c9ccc701 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -2062,6 +2062,9 @@ To create/register a plugin, you have to : #ifndef USES_C018 #define USES_C018 // TTN RN2483 #endif + #ifndef USES_C019 + #define USES_C019 // ESPEasy-NOW + #endif // Notifiers diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 04c5a68b0a..aa0076fd03 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -133,6 +133,16 @@ void SettingsStruct_tmpl::SendToHttp_ack(bool value) { template bool SettingsStruct_tmpl::UseESPEasyNow() const { #ifdef USES_ESPEASY_NOW + // First check to see if we have the controller present and enabled + for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { + if (ControllerEnabled[x] && Protocol[x] == 19) { + if (supportedCPluginID(Protocol[x])) { + return ControllerEnabled[x]; + } + } + } + + // FIXME TD-er: Must either remove this bit, or make a settings transition. return bitRead(VariousBits1, 11); #else return false; @@ -142,6 +152,15 @@ bool SettingsStruct_tmpl::UseESPEasyNow() const { template void SettingsStruct_tmpl::UseESPEasyNow(bool value) { #ifdef USES_ESPEASY_NOW + // Update controller enabled state + for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { + if (ControllerEnabled[x] != value && Protocol[x] == 19) { + if (supportedCPluginID(Protocol[x])) { + ControllerEnabled[x] = value; + } + } + } + bitWrite(VariousBits1, 11, value); #endif } diff --git a/src/src/DataTypes/ESPEasy_plugin_functions.h b/src/src/DataTypes/ESPEasy_plugin_functions.h index 3d43d625c4..0ec545faaf 100644 --- a/src/src/DataTypes/ESPEasy_plugin_functions.h +++ b/src/src/DataTypes/ESPEasy_plugin_functions.h @@ -57,6 +57,7 @@ #define PLUGIN_READ_ERROR_OCCURED 45 // Function returns "true" when last measurement was an error, called when PLUGIN_READ returns false #define PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR 46 // Show the configuration for output type and what value to set to which taskvalue #define PLUGIN_PROCESS_CONTROLLER_DATA 47 // Can be called from the controller to signal the plugin to generate (or handle) sending the data. +#define PLUGIN_FILTEROUT_CONTROLLER_DATA 48 // Can be called from the controller to query a task whether the data should be processed further. diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 003878295a..a183cd38fa 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -21,9 +21,9 @@ #include "../Globals/ESPEasyWiFiEvent.h" #include "../Globals/ESPEasy_Scheduler.h" #ifdef USES_ESPEASY_NOW -#include "../Globals/ESPEasy_now_handler.h" -#include "../Globals/SendData_DuplicateChecker.h" -#endif +# include "../Globals/ESPEasy_now_handler.h" +# include "../Globals/SendData_DuplicateChecker.h" +#endif // ifdef USES_ESPEASY_NOW #include "../Globals/MQTT.h" #include "../Globals/Plugins.h" #include "../Globals/Protocol.h" @@ -47,7 +47,7 @@ void sendData(struct EventStruct *event) #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("sendData")); #endif // ifndef BUILD_NO_RAM_TRACKER -// LoadTaskSettings(event->TaskIndex); + // LoadTaskSettings(event->TaskIndex); if (Settings.UseRules) { createRuleEvents(event); @@ -57,7 +57,7 @@ void sendData(struct EventStruct *event) SendValueLogger(event->TaskIndex); } -// LoadTaskSettings(event->TaskIndex); // could have changed during background tasks. + // LoadTaskSettings(event->TaskIndex); // could have changed during background tasks. for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { @@ -95,7 +95,6 @@ void sendData(struct EventStruct *event) STOP_TIMER(SEND_DATA_STATS); } - // ******************************************************************************** // Send to controllers, via a duplicate check // Some plugins may receive the same data among nodes, so check first if @@ -107,25 +106,27 @@ void sendData_checkDuplicates(struct EventStruct *event, const String& compare_k { #ifdef USES_ESPEASY_NOW uint32_t key = SendData_DuplicateChecker.add(event, compare_key); + if (key != SendData_DuplicateChecker_struct::DUPLICATE_CHECKER_INVALID_KEY) { // Must send out request to other nodes to see if any other has already processed it. uint8_t broadcastMac[6]; ESPEasy_now_handler.sendSendData_DuplicateCheck( - key, - ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck, + key, + ESPEasy_Now_DuplicateCheck::message_t::KeyToCheck, broadcastMac); } -#else +#else // ifdef USES_ESPEASY_NOW sendData(event); -#endif +#endif // ifdef USES_ESPEASY_NOW } bool validUserVar(struct EventStruct *event) { - if (!validTaskIndex(event->TaskIndex)) return false; + if (!validTaskIndex(event->TaskIndex)) { return false; } const Sensor_VType vtype = event->getSensorType(); - if (vtype == Sensor_VType::SENSOR_TYPE_LONG || - vtype == Sensor_VType::SENSOR_TYPE_STRING // FIXME TD-er: Must look at length of event->String2 ? - ) return true; + + if ((vtype == Sensor_VType::SENSOR_TYPE_LONG) || + (vtype == Sensor_VType::SENSOR_TYPE_STRING) // FIXME TD-er: Must look at length of event->String2 ? + ) { return true; } const uint8_t valueCount = getValueCountForTask(event->TaskIndex); for (int i = 0; i < valueCount; ++i) { @@ -205,7 +206,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) MQTTclient_next_connect_attempt.setNow(); ++mqtt_reconnect_count; - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot connect, out of RAM")); @@ -220,7 +221,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) if (MQTTclient.connected()) { MQTTclient.disconnect(); } - + updateMQTTclient_connected(); // mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864 @@ -230,19 +231,20 @@ bool MQTTConnect(controllerIndex_t controller_idx) // For example because the server does not give an acknowledgement. // This way, we always need the set amount of timeout to handle the request. // Thus we should not make the timeout dynamic here if set to ignore ack. - const uint32_t timeout = ControllerSettings.MustCheckReply + const uint32_t timeout = ControllerSettings.MustCheckReply ? WiFiEventData.getSuggestedTimeout(Settings.Protocol[controller_idx], ControllerSettings.ClientTimeout) : ControllerSettings.ClientTimeout; - #ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + # ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + // See: https://github.com/espressif/arduino-esp32/pull/6676 mqtt.setTimeout((timeout + 500) / 1000); // in seconds!!!! Client *pClient = &mqtt; pClient->setTimeout(timeout); - #else - mqtt.setTimeout(timeout); // in msec as it should be! - #endif - + # else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + mqtt.setTimeout(timeout); // in msec as it should be! + # endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS + MQTTclient.setClient(mqtt); if (ControllerSettings.UseDNS) { @@ -255,12 +257,12 @@ bool MQTTConnect(controllerIndex_t controller_idx) // MQTT needs a unique clientname to subscribe to broker const String clientid = getMQTTclientID(ControllerSettings); - const String LWTTopic = getLWT_topic(ControllerSettings); - const String LWTMessageDisconnect = getLWT_messageDisconnect(ControllerSettings); - bool MQTTresult = false; - const uint8_t willQos = 0; - const bool willRetain = ControllerSettings.mqtt_willRetain() && ControllerSettings.mqtt_sendLWT(); - const bool cleanSession = ControllerSettings.mqtt_cleanSession(); // As suggested here: + const String LWTTopic = getLWT_topic(ControllerSettings); + const String LWTMessageDisconnect = getLWT_messageDisconnect(ControllerSettings); + bool MQTTresult = false; + const uint8_t willQos = 0; + const bool willRetain = ControllerSettings.mqtt_willRetain() && ControllerSettings.mqtt_sendLWT(); + const bool cleanSession = ControllerSettings.mqtt_cleanSession(); // As suggested here: if (MQTTclient_should_reconnect) { addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect")); @@ -299,6 +301,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) return false; } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; log += F("MQTT : Connected to broker with client ID: "); @@ -309,8 +312,9 @@ bool MQTTConnect(controllerIndex_t controller_idx) parseSystemVariables(subscribeTo, false); MQTTclient.subscribe(subscribeTo.c_str()); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("Subscribed to: "); + String log = F("Subscribed to: "); log += subscribeTo; addLogMove(LOG_LEVEL_INFO, log); } @@ -376,7 +380,7 @@ bool MQTTCheck(controllerIndex_t controller_idx) String LWTTopic, LWTMessageConnect; bool willRetain = false; { - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot check, out of RAM")); @@ -501,7 +505,7 @@ bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource) return false; } -void SendStatus(struct EventStruct *event, const __FlashStringHelper * status) +void SendStatus(struct EventStruct *event, const __FlashStringHelper *status) { SendStatus(event, String(status)); } @@ -537,6 +541,7 @@ void SendStatus(struct EventStruct *event, const String& status) controllerIndex_t firstEnabledMQTT_ControllerIndex() { for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i); + if (validProtocolIndex(ProtocolIndex)) { if (Protocol[ProtocolIndex].usesMQTT && Settings.ControllerEnabled[i]) { return i; @@ -559,11 +564,17 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { return false; } -#ifdef USES_ESPEASY_NOW +# ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& messageRouteInfo, bool retained, bool callbackTask) +bool MQTTpublish(controllerIndex_t controller_idx, + taskIndex_t taskIndex, + const ESPEasy_now_merger& message, + const MessageRouteInfo_t& messageRouteInfo, + bool retained, + bool callbackTask) { bool success = false; + if (!MQTT_queueFull(controller_idx)) { { @@ -571,18 +582,23 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes const size_t payloadSize = message.getPayloadSize(); MessageRouteInfo_t routeinfo = messageRouteInfo; String topic, payload; + if (message.getString(topic, pos) && message.getString(payload, pos)) { - success = true; const size_t bytesLeft = payloadSize - pos; + if (bytesLeft >= 4) { bool validMessageRouteInfo = false; + // There is some MessageRouteInfo left MessageRouteInfo_t::uint8_t_vector routeInfoData; routeInfoData.resize(bytesLeft); + // Use temp position as we don't yet know the true size of the message route info size_t tmp_pos = pos; + if (message.getBinaryData(&routeInfoData[0], bytesLeft, tmp_pos) == bytesLeft) { validMessageRouteInfo = routeinfo.deserialize(routeInfoData); + if (validMessageRouteInfo) { // Move pos for the actual number of bytes we read. pos += routeinfo.getSerializedSize(); @@ -595,26 +611,28 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes addLog(LOG_LEVEL_INFO, log); } } + if (!validMessageRouteInfo) { // Whatever may have been present, it could not be loaded, so clear just to be sure. routeinfo = messageRouteInfo; } + // Append our own unit number routeinfo.appendUnit(Settings.Unit); } - } - if (success) { - std::unique_ptr element = std::unique_ptr( - new MQTT_queue_element( - controller_idx, - INVALID_TASK_INDEX, - std::move(topic), - std::move(payload), - retained, - callbackTask)); + std::unique_ptr element = std::unique_ptr( + new MQTT_queue_element( + controller_idx, + taskIndex, + std::move(topic), + std::move(payload), + retained, + callbackTask)); + if (element) { + element->_call_PLUGIN_FILTEROUT_CONTROLLER_DATA = validTaskIndex(taskIndex); element->MessageRouteInfo = routeinfo; - success = MQTTDelayHandler->addToQueue(std::move(element)); + success = MQTTDelayHandler->addToQueue(std::move(element)); } } } @@ -623,26 +641,56 @@ bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& mes return success; } -#endif +# endif // ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained, bool callbackTask) +bool MQTTpublish(controllerIndex_t controller_idx, + taskIndex_t taskIndex, + const char *topic, + const char *payload, + bool retained, + bool callbackTask) { if (MQTTDelayHandler == nullptr) { return false; } - const bool success = MQTTDelayHandler->addToQueue(std::unique_ptr(new MQTT_queue_element(controller_idx, taskIndex, topic, payload, retained, callbackTask))); + std::unique_ptr element = + std::unique_ptr( + new MQTT_queue_element( + controller_idx, + taskIndex, + topic, + payload, + retained, + callbackTask)); + + if (!element) { return false; } + + const bool success = MQTTDelayHandler->addToQueue(std::move(element)); scheduleNextMQTTdelayQueue(); return success; } -bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, String&& topic, String&& payload, bool retained, bool callbackTask) { +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, String&& topic, String&& payload, bool retained, + bool callbackTask) { if (MQTTDelayHandler == nullptr) { return false; } - const bool success = MQTTDelayHandler->addToQueue(std::unique_ptr(new MQTT_queue_element(controller_idx, taskIndex, std::move(topic), std::move(payload), retained, callbackTask))); + std::unique_ptr element = + std::unique_ptr( + new MQTT_queue_element( + controller_idx, + taskIndex, + std::move(topic), + std::move(payload), + retained, + callbackTask)); + + if (!element) { return false; } + + const bool success = MQTTDelayHandler->addToQueue(std::move(element)); scheduleNextMQTTdelayQueue(); return success; @@ -666,7 +714,7 @@ void MQTTStatus(struct EventStruct *event, const String& status) bool mqtt_retainFlag; { // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot send status, out of RAM")); @@ -732,12 +780,15 @@ void SensorSendTask(taskIndex_t TaskIndex) const uint8_t valueCount = getValueCountForTask(TaskIndex); + // Store the previous value, in case %pvalue% is used in the formula String preValue[VARS_PER_TASK]; + if (Device[DeviceIndex].FormulaOption && Cache.hasFormula(TaskIndex)) { for (uint8_t varNr = 0; varNr < valueCount; varNr++) { const String formula = Cache.getTaskDeviceFormula(TaskIndex, varNr); + if (!formula.isEmpty()) { if (formula.indexOf(F("%pvalue%")) != -1) { @@ -762,6 +813,7 @@ void SensorSendTask(taskIndex_t TaskIndex) for (uint8_t varNr = 0; varNr < valueCount; varNr++) { String formula = Cache.getTaskDeviceFormula(TaskIndex, varNr); + if (!formula.isEmpty()) { START_TIMER; diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 0477c71b18..d9eb75476d 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -75,7 +75,7 @@ controllerIndex_t firstEnabledMQTT_ControllerIndex(); bool MQTT_queueFull(controllerIndex_t controller_idx); #ifdef USES_ESPEASY_NOW -bool MQTTpublish(controllerIndex_t controller_idx, const ESPEasy_now_merger& message, const MessageRouteInfo_t& messageRouteInfo, bool retained, bool callbackTask = false); +bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const ESPEasy_now_merger& message, const MessageRouteInfo_t& messageRouteInfo, bool retained, bool callbackTask = false); #endif bool MQTTpublish(controllerIndex_t controller_idx, taskIndex_t taskIndex, const char *topic, const char *payload, bool retained, bool callbackTask = false); diff --git a/src/src/Globals/CPlugins.cpp b/src/src/Globals/CPlugins.cpp index d8244024c1..af8ff6f4e1 100644 --- a/src/src/Globals/CPlugins.cpp +++ b/src/src/Globals/CPlugins.cpp @@ -11,7 +11,7 @@ // FIXME TD-er: Make these private and add functions to access its content. -std::map CPlugin_id_to_ProtocolIndex; +protocolIndex_t CPlugin_id_to_ProtocolIndex[CPLUGIN_MAX + 1]; cpluginID_t ProtocolIndex_to_CPlugin_id[CPLUGIN_MAX + 1]; bool (*CPlugin_ptr[CPLUGIN_MAX])(CPlugin::Function, @@ -178,6 +178,7 @@ bool CPluginCall(protocolIndex_t protocolIndex, CPlugin::Function Function, stru START_TIMER; bool ret = CPlugin_ptr[protocolIndex](Function, event, str); STOP_TIMER_CONTROLLER(protocolIndex, Function); + /* #ifndef BUILD_NO_DEBUG if (Function == CPlugin::Function::CPLUGIN_INIT) { if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { @@ -197,6 +198,7 @@ bool CPluginCall(protocolIndex_t protocolIndex, CPlugin::Function Function, stru } } #endif + */ return ret; } return false; @@ -238,11 +240,10 @@ bool validControllerIndex(controllerIndex_t index) bool validCPluginID(cpluginID_t cpluginID) { - if (cpluginID == INVALID_C_PLUGIN_ID) { - return false; + if (cpluginID != INVALID_C_PLUGIN_ID && cpluginID <= CPLUGIN_MAX) { + return validProtocolIndex(CPlugin_id_to_ProtocolIndex[cpluginID]); } - auto it = CPlugin_id_to_ProtocolIndex.find(cpluginID); - return it != CPlugin_id_to_ProtocolIndex.end(); + return false; } bool supportedCPluginID(cpluginID_t cpluginID) @@ -273,24 +274,8 @@ cpluginID_t getCPluginID_from_ControllerIndex(controllerIndex_t index) { protocolIndex_t getProtocolIndex(cpluginID_t cpluginID) { - if (cpluginID != INVALID_C_PLUGIN_ID) { - auto it = CPlugin_id_to_ProtocolIndex.find(cpluginID); - - if (it != CPlugin_id_to_ProtocolIndex.end()) - { - if (!validProtocolIndex(it->second)) { return INVALID_PROTOCOL_INDEX; } - #ifndef BUILD_NO_DEBUG - if (Protocol[it->second].Number != cpluginID) { - // FIXME TD-er: Just a check for now, can be removed later when it does not occur. - String log = F("getProtocolIndex error in Protocol Vector. CPluginID: "); - log += String(cpluginID); - log += F(" p_index: "); - log += String(it->second); - addLogMove(LOG_LEVEL_ERROR, log); - } - #endif - return it->second; - } + if (cpluginID != INVALID_C_PLUGIN_ID && cpluginID <= CPLUGIN_MAX) { + return CPlugin_id_to_ProtocolIndex[cpluginID]; } return INVALID_PROTOCOL_INDEX; } @@ -318,7 +303,7 @@ String getCPluginNameFromCPluginID(cpluginID_t cpluginID) { bool addCPlugin(cpluginID_t cpluginID, protocolIndex_t x) { - if (x < CPLUGIN_MAX) { + if (x < CPLUGIN_MAX && cpluginID <= CPLUGIN_MAX) { ProtocolIndex_to_CPlugin_id[x] = cpluginID; CPlugin_id_to_ProtocolIndex[cpluginID] = x; return true; diff --git a/src/src/Globals/CPlugins.h b/src/src/Globals/CPlugins.h index 665fc0abc7..d3648c72b8 100644 --- a/src/src/Globals/CPlugins.h +++ b/src/src/Globals/CPlugins.h @@ -10,9 +10,6 @@ #include "../DataTypes/ControllerIndex.h" #include "../DataTypes/ProtocolIndex.h" -#include -//#include - /********************************************************************************************\ Structures to address the Cplugins (controllers) and their configurations. @@ -26,11 +23,19 @@ - Controller -> A selected instance of a CPlugin (analog to "task" for plugins, shown in the Controllers tab in the web interface) - Protocol -> A CPlugin included in the build. + Addressing these: + - cpluginID_t -> Unique ID of a Cplugin, like '1' for _C001.ino. '0' is the invalid cpluginID_t + - protocolIndex_t -> Counter for the included CPlugins in the build. + Highest used protocolIndex_t will thus always be at most the highest CPluginID. + We have the following one-to-one relations: - - CPlugin_id_to_ProtocolIndex - Map from CPlugin ID to Protocol Index. + - CPlugin_id_to_ProtocolIndex - Vector from CPlugin ID to Protocol Index. - ProtocolIndex_to_CPlugin_id - Vector from ProtocolIndex to CPlugin ID. - CPlugin_ptr - Array of function pointers to call Cplugins. - Protocol - Vector of ProtocolStruct containing Cplugin specific information. + + Since we only have a limited nr of CPlugins, and most builds will include almost all of them, + thus: CPlugin_id_to_ProtocolIndex is a vector and not a std::map as with the Plugins. \*********************************************************************************************/ @@ -51,8 +56,8 @@ bool CPluginCall(protocolIndex_t protocolIndex, bool anyControllerEnabled(); controllerIndex_t findFirstEnabledControllerWithId(cpluginID_t cpluginid); -// Map to match a controller ID to a "ProtocolIndex" -extern std::map CPlugin_id_to_ProtocolIndex; +// Vector to match a controller ID to a "ProtocolIndex" +extern protocolIndex_t CPlugin_id_to_ProtocolIndex[CPLUGIN_MAX + 1]; // Vector to match a "ProtocolIndex" to a controller ID. // INVALID_CONTROLLER_INDEX may be used as index for this array. diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 696a1928ef..15ac4f5bfe 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -118,7 +118,28 @@ ESPEasy_now_handler_t::~ESPEasy_now_handler_t() } } +void ESPEasy_now_handler_t::setConfig(const C019_ConfigStruct& config) +{ + // FIXME TD-er: Must configure other settings too. + // Perhaps add C019_ConfigStruct as a member too? + _filterTaskCallback = config.filterMQTT_forward ? config.filterTaskIndex : INVALID_TASK_INDEX; +} + bool ESPEasy_now_handler_t::begin() +{ + if (!Settings.UseESPEasyNow()) { return false; } + // Check to see if we have an ESPEasy_NOW controller defined. + // Call CPLUGIN_INIT on it to load the settings. + const controllerIndex_t ESPEasy_NOW_controller_idx = get_ESPEasy_NOW_controller_index(); + if (validControllerIndex(ESPEasy_NOW_controller_idx) && Settings.ControllerEnabled[ESPEasy_NOW_controller_idx]) { + struct EventStruct tmpEvent; + tmpEvent.ControllerIndex = ESPEasy_NOW_controller_idx; + if (!CPluginCall(CPlugin::Function::CPLUGIN_INIT, &tmpEvent)) return false; + } + return do_begin(); +} + +bool ESPEasy_now_handler_t::do_begin() { if (!Settings.UseESPEasyNow()) { return false; } if (use_EspEasy_now) { return true; } @@ -271,6 +292,16 @@ bool ESPEasy_now_handler_t::loop() return somethingProcessed; } +controllerIndex_t ESPEasy_now_handler_t::get_ESPEasy_NOW_controller_index() +{ + for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) { + if (Settings.Protocol[x] == 19) { + return x; + } + } + return INVALID_CONTROLLER_INDEX; +} + void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() { const uint8_t ESPEasyNOW_channel = Nodes.getESPEasyNOW_channel(); @@ -1066,7 +1097,12 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge } } - success = MQTTpublish(controllerIndex, message, MessageRouteInfo, _mqtt_retainFlag); + success = MQTTpublish( + controllerIndex, + _filterTaskCallback, + message, + MessageRouteInfo, + _mqtt_retainFlag); if (!success) { mustKeep = false; return success; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 54c3493cd7..1023e66dce 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -5,6 +5,8 @@ #ifdef USES_ESPEASY_NOW +# include "../Controller_config/C019_config.h" + # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_NTP_query.h" # include "../DataStructs/ESPEasy_Now_p2p_data.h" @@ -24,14 +26,20 @@ class ESPEasy_now_handler_t { ~ESPEasy_now_handler_t(); + void setConfig(const C019_ConfigStruct& config); + bool begin(); + bool do_begin(); + void end(); bool loop(); private: + static controllerIndex_t get_ESPEasy_NOW_controller_index(); + void loop_check_ESPEasyNOW_run_state(); bool loop_process_ESPEasyNOW_in_queue(); @@ -133,6 +141,7 @@ class ESPEasy_now_handler_t { uint8_t _usedWiFiChannel = 0; uint8_t _lastScannedChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; + taskIndex_t _filterTaskCallback = INVALID_TASK_INDEX; bool _scanChannelsMode = true; bool _enableESPEasyNowFallback = false; bool _mqtt_retainFlag = false; diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index c98cbf36d4..e0bbfabab5 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -271,7 +271,16 @@ void runEach30Seconds() void scheduleNextMQTTdelayQueue() { if (MQTTDelayHandler != nullptr) { - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT_DELAY_QUEUE, MQTTDelayHandler->getNextScheduleTime()); + unsigned long nextScheduled(MQTTDelayHandler->getNextScheduleTime()); + #ifdef USES_ESPEASY_NOW + if (!MQTTclient_connected) { + // Sending via the mesh may be retried at shorter intervals + if (timePassedSince(nextScheduled) < -5) { + nextScheduled = millis() + 5; + } + } + #endif + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT_DELAY_QUEUE, nextScheduled); } } @@ -320,13 +329,25 @@ void processMQTTdelayQueue() { struct EventStruct TempEvent(element->_taskIndex); String dummy; - // FIXME TD-er: Do we need anything from the element in the event? -// TempEvent.String1 = element->_topic; -// TempEvent.String2 = element->_payload; if (PluginCall(PLUGIN_PROCESS_CONTROLLER_DATA, &TempEvent, dummy)) { processed = true; } - } else + } else if (element->_call_PLUGIN_FILTEROUT_CONTROLLER_DATA) { + struct EventStruct TempEvent(element->_taskIndex); + String dummy; + + // FIXME TD-er: Find a way to not having to copy these strings + TempEvent.String1 = element->_topic; + TempEvent.String2 = element->_payload; + + // Filter function to check if data should be forwarded or not. + // Since all plugins/tasks not supporting this function call will return false, + // the "true" result is about the non-standard action; to filter out the message. + if (PluginCall(PLUGIN_FILTEROUT_CONTROLLER_DATA, &TempEvent, dummy)) { + processed = true; + } + + } if (!processed) { #ifdef USES_ESPEASY_NOW MessageRouteInfo_t messageRouteInfo; @@ -368,7 +389,7 @@ void processMQTTdelayQueue() { } - Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible. + Scheduler.setIntervalTimerOverride(ESPEasy_Scheduler::IntervalTimer_e::TIMER_MQTT, 1); // Make sure the MQTT is being processed as soon as possible. scheduleNextMQTTdelayQueue(); STOP_TIMER(MQTT_DELAY_QUEUE); } diff --git a/src/src/Helpers/_CPlugin_init.cpp b/src/src/Helpers/_CPlugin_init.cpp index c799097fd8..1e02267507 100644 --- a/src/src/Helpers/_CPlugin_init.cpp +++ b/src/src/Helpers/_CPlugin_init.cpp @@ -27,15 +27,17 @@ void CPluginInit() #ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; #endif + // FIXME TD-er: Why would this ever be called at CPLUGIN_MAX index? ProtocolIndex_to_CPlugin_id[CPLUGIN_MAX] = INVALID_C_PLUGIN_ID; + CPlugin_id_to_ProtocolIndex[CPLUGIN_MAX] = INVALID_PROTOCOL_INDEX; uint8_t x; - // Clear pointer table for all plugins + // Clear pointer table for all Cplugins for (x = 0; x < CPLUGIN_MAX; x++) { CPlugin_ptr[x] = nullptr; ProtocolIndex_to_CPlugin_id[x] = INVALID_C_PLUGIN_ID; - // Do not initialize CPlugin_id_to_ProtocolIndex[x] to an invalid value. (it is map) + CPlugin_id_to_ProtocolIndex[x] = INVALID_PROTOCOL_INDEX; } x = 0; From 6c2ceff8684add368ad2e865719f865f976fcceb Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 9 Feb 2023 09:01:29 +0100 Subject: [PATCH 351/404] [WiFi] Allow WiFi scan per channel --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index e371db913d..a007b17210 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1085,7 +1085,7 @@ void WifiScan(bool async, uint8_t channel) { #ifdef ESP32 const bool passive = false; const uint32_t max_ms_per_chan = 300; - WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan /*, channel */); + WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan, channel); #endif if (!async) { FeedSW_watchdog(); From e6befd947d5fc80121314128b3b9ec9c7b8d1aea Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 17 Feb 2023 17:22:09 +0100 Subject: [PATCH 352/404] [ESPEasy_NOW] Fix sending announce packets + use forced WiFi channel --- src/src/DataStructs/NodesHandler.cpp | 9 ++-- src/src/ESPEasyCore/ESPEasyWifi.cpp | 4 +- src/src/Helpers/ESPEasy_now_handler.cpp | 63 ++++++++++++------------- src/src/Helpers/Networking.cpp | 4 +- tools/pio/pre_custom_esp82xx.py | 2 +- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index c16ac457d4..ee165d5f49 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -572,14 +572,16 @@ bool NodesHandler::isEndpoint() const #ifdef USES_ESPEASY_NOW uint8_t NodesHandler::getESPEasyNOW_channel() const { - if (active_network_medium == NetworkMedium_t::WIFI && NetworkConnected()) { - return WiFi.channel(); - } if (Settings.ForceESPEasyNOWchannel > 0) { return Settings.ForceESPEasyNOWchannel; } + if (active_network_medium == NetworkMedium_t::WIFI && NetworkConnected()) { + // FIXME TD-er: We can't be sure about the actual WiFi channel reported here. + return WiFi.channel(); + } if (isEndpoint()) { if (active_network_medium == NetworkMedium_t::WIFI) { + // FIXME TD-er: We can't be sure about the actual WiFi channel reported here. return WiFi.channel(); } } @@ -672,7 +674,6 @@ ESPEasy_Now_MQTT_QueueCheckState::Enum NodesHandler::getMQTTQueueState(uint8_t u return it->second.getMQTTQueueState(); } return ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset; - } void NodesHandler::setMQTTQueueState(uint8_t unit, ESPEasy_Now_MQTT_QueueCheckState::Enum state) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index a007b17210..db2b25d999 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -1101,7 +1101,9 @@ void WifiScan(bool async, uint8_t channel) { #endif #ifdef ESP32 - RTC.clearLastWiFi(); + if (!Settings.UseLastWiFiFromRTC()) { + RTC.clearLastWiFi(); + } if (WiFiConnected()) { # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Disconnect after scan")); diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 15ac4f5bfe..9e034d0002 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -208,9 +208,7 @@ bool ESPEasy_now_handler_t::do_begin() // WiFi.softAPdisconnect(false); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": begin on channel "); - log += _usedWiFiChannel; - addLog(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": begin on channel "), _usedWiFiChannel)); } if (!WifiEspNow.begin()) { @@ -237,9 +235,7 @@ bool ESPEasy_now_handler_t::do_begin() const MAC_address mac(it->bssid); sendDiscoveryAnnounce(mac, _usedWiFiChannel); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": Send discovery to "); - log += mac.toString(); - addLog(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": Send discovery to "), mac.toString())); } } } @@ -255,7 +251,9 @@ void ESPEasy_now_handler_t::end() _controllerIndex = INVALID_CONTROLLER_INDEX; _usedWiFiChannel = 0; use_EspEasy_now = false; - RTC.clearLastWiFi(); // Force a WiFi scan + if (!Settings.UseLastWiFiFromRTC()) { + RTC.clearLastWiFi(); // Force a WiFi scan + } if (_last_used != 0) { // Only call WifiEspNow.end() if it was started. WifiEspNow.end(); @@ -341,7 +339,7 @@ void ESPEasy_now_handler_t::loop_check_ESPEasyNOW_run_state() addLog(LOG_LEVEL_INFO, F(ESPEASY_NOW_NAME ": Inactive due to not receiving trace routes")); end(); temp_disable_EspEasy_now_timer = millis() + 10000; - WifiScan(true); + WifiScan(true, Nodes.getESPEasyNOW_channel()); return; } } @@ -619,11 +617,6 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo void ESPEasy_now_handler_t::sendDiscoveryAnnounce(int channel) { - MAC_address broadcast; - - for (int i = 0; i < 6; ++i) { - broadcast.mac[i] = 0xFF; - } sendDiscoveryAnnounce(ESPEasy_now_peermanager.getBroadcastMAC(), channel); } @@ -633,6 +626,7 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch if (thisNode == nullptr) { // Should not happen + addLog(LOG_LEVEL_ERROR, F("Cannot send DiscoveryAnnounce, No ThisNode")); return; } @@ -659,28 +653,37 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch return; } } + const unsigned long start = millis(); if (channel < 0) { // Send to all channels - - const unsigned long start = millis(); - // FIXME TD-er: Not sure whether we can send to channels > 11 in all countries. for (int ch = 1; ch < ESPEASY_NOW_MAX_CHANNEL; ++ch) { msg.send(mac, ch); delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": Sent discovery to all channels in "); - log += String(timePassedSince(start)); + String log = concat(F(ESPEASY_NOW_NAME ": Sent discovery to all channels in "), timePassedSince(start)); log += F(" ms"); - addLog(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, log); } } else { if (mac.all_one()) { +// size_t count = 0; + size_t sent_count = 0; for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { +// ++count; +// if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { + ++sent_count; msg.send(it->second.ESPEasy_Now_MAC(), channel); - } +// } + } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = concat(F(ESPEASY_NOW_NAME ": Sent discovery to "), sent_count); +// log += '/'; +// log += count; + log += concat(F(" Nodes in "), timePassedSince(start)); + log += F(" ms"); + addLogMove(LOG_LEVEL_INFO, log); } } @@ -823,8 +826,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& } } - MAC_address broadcast = ESPEasy_now_peermanager.getBroadcastMAC(); - sendTraceRoute(broadcast, traceRoute, channel); + sendTraceRoute(ESPEasy_now_peermanager.getBroadcastMAC(), traceRoute, Nodes.getESPEasyNOW_channel()); } @@ -855,19 +857,16 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy delay(0); } if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F(ESPEASY_NOW_NAME ": Sent Traceroute to all channels in "); - log += timePassedSince(start); + String log = concat(F(ESPEASY_NOW_NAME ": Sent Traceroute to all channels in "), timePassedSince(start)); log += F(" ms"); - addLog(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, log); } } else { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - log += F(ESPEASY_NOW_NAME ": sendTraceRoute "); - log += traceRoute.toString(); - log += F(" ch: "); - log += channel; - addLog(LOG_LEVEL_INFO, log); + String log = concat(F(ESPEASY_NOW_NAME ": sendTraceRoute "), traceRoute.toString()); + log += concat(F(" ch: "), channel); + log += concat(F(" to: "), mac.toString()); + addLogMove(LOG_LEVEL_INFO, log); } msg.send(mac, channel); diff --git a/src/src/Helpers/Networking.cpp b/src/src/Helpers/Networking.cpp index daf16972b0..16d05bcb9a 100644 --- a/src/src/Helpers/Networking.cpp +++ b/src/src/Helpers/Networking.cpp @@ -429,13 +429,11 @@ void refreshNodeList() Nodes.refreshNodeList(max_age_allowed, max_age); #ifdef USES_ESPEASY_NOW - #ifdef ESP8266 // FIXME TD-er: Do not perform regular scans on ESP32 as long as we cannot scan per channel if (!Nodes.isEndpoint()) { WifiScan(true, Nodes.getESPEasyNOW_channel()); } #endif - #endif if (max_age > (0.75 * max_age_allowed)) { Scheduler.sendGratuitousARP_now(); @@ -446,7 +444,7 @@ void refreshNodeList() // Send to all channels ESPEasy_now_handler.sendDiscoveryAnnounce(-1); } else { - ESPEasy_now_handler.sendDiscoveryAnnounce(); + ESPEasy_now_handler.sendDiscoveryAnnounce(Nodes.getESPEasyNOW_channel()); } ESPEasy_now_handler.sendNTPquery(); ESPEasy_now_handler.sendTraceRoute(); diff --git a/tools/pio/pre_custom_esp82xx.py b/tools/pio/pre_custom_esp82xx.py index 7133cba14c..2c87bdf076 100644 --- a/tools/pio/pre_custom_esp82xx.py +++ b/tools/pio/pre_custom_esp82xx.py @@ -58,7 +58,7 @@ # "-DUSES_C015", # Blynk # "-DUSES_C016", # Cache Controller "-DUSES_C018", # TTN/RN2483 -# "-DUSES_C019", # ESPEasy-NOW + "-DUSES_C019", # ESPEasy-NOW "-DUSES_ESPEASY_NOW", # "-DFEATURE_MDNS=1", From fdb4c520084429e9f2c737df2cac7f945100f6ae Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 17 Feb 2023 23:51:21 +0100 Subject: [PATCH 353/404] [ESPEasy_NOW] Detection of mesh nodes from scan --- src/src/DataStructs/NodesHandler.cpp | 12 +++++++----- src/src/DataStructs/NodesHandler.h | 6 +++--- src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp | 6 +++++- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 5 ++++- src/src/Helpers/ESPEasy_now_handler.cpp | 13 +++++++------ 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index ee165d5f49..99ecebb545 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -603,21 +603,23 @@ bool NodesHandler::recentlyBecameDistanceZero() { return true; } -void NodesHandler::setRSSI(const MAC_address& mac, int rssi) +bool NodesHandler::setRSSI(const MAC_address& mac, int rssi) { - setRSSI(getNodeByMac(mac), rssi); + return setRSSI(getNodeByMac(mac), rssi); } -void NodesHandler::setRSSI(uint8_t unit, int rssi) +bool NodesHandler::setRSSI(uint8_t unit, int rssi) { - setRSSI(getNode(unit), rssi); + return setRSSI(getNode(unit), rssi); } -void NodesHandler::setRSSI(NodeStruct * node, int rssi) +bool NodesHandler::setRSSI(NodeStruct * node, int rssi) { if (node != nullptr) { node->setRSSI(rssi); + return true; } + return false; } bool NodesHandler::lastTimeValidDistanceExpired() const diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index d1eff17518..e6b4a600f4 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -89,10 +89,10 @@ class NodesHandler { bool recentlyBecameDistanceZero(); - void setRSSI(const MAC_address& mac, + bool setRSSI(const MAC_address& mac, int rssi); - void setRSSI(uint8_t unit, + bool setRSSI(uint8_t unit, int rssi); #ifdef USES_ESPEASY_NOW @@ -122,7 +122,7 @@ class NodesHandler { private: - void setRSSI(NodeStruct *node, + bool setRSSI(NodeStruct *node, int rssi); unsigned long _lastTimeValidDistance = 0; diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index 770de752ea..45b9fc37fe 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -106,7 +106,11 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface - // TODO TD-er: Must implement like onProbeRequestAPmode for ESP8266 + #ifdef USES_ESPEASY_NOW + WiFiEventData.processedProbeRequestAPmode = false; + APModeProbeRequestReceived_list.push_back(info.wifi_ap_probereqrecved); + #endif + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("WiFi : Event AP got probed")); #endif diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 66996be81c..46a8dd0f12 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -511,7 +511,10 @@ void processProbeRequestAPmode() { // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { - ESPEasy_now_handler.sendDiscoveryAnnounce(mac, Nodes.getESPEasyNOW_channel()); + const NodeStruct * node = Nodes.getNodeByMac(mac); + ESPEasy_now_handler.sendDiscoveryAnnounce( + (node != nullptr && node->ESPEasyNowPeer) ? node->ESPEasy_Now_MAC() : mac, + Nodes.getESPEasyNOW_channel()); } #endif } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 9e034d0002..4a6b4257a6 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -668,19 +668,20 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch } } else { if (mac.all_one()) { -// size_t count = 0; + size_t count = 0; size_t sent_count = 0; for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { -// ++count; + ++count; // if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { - ++sent_count; - msg.send(it->second.ESPEasy_Now_MAC(), channel); + + if (msg.send(it->second.ESPEasy_Now_MAC(), channel)) + ++sent_count; // } } if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = concat(F(ESPEASY_NOW_NAME ": Sent discovery to "), sent_count); -// log += '/'; -// log += count; + log += '/'; + log += count; log += concat(F(" Nodes in "), timePassedSince(start)); log += F(" ms"); addLogMove(LOG_LEVEL_INFO, log); From 3445e64205245c0b6a3fae8b9796a841e69871f2 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 20 Feb 2023 11:59:29 +0100 Subject: [PATCH 354/404] [ESPEasy-NOW] Improve routing based on MQTT queue state --- src/src/DataStructs/NodesHandler.cpp | 31 +++++- src/src/DataStructs/NodesHandler.h | 10 +- .../ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 30 +++--- src/src/Helpers/ESPEasy_now_handler.cpp | 95 +++++++++++-------- 4 files changed, 107 insertions(+), 59 deletions(-) diff --git a/src/src/DataStructs/NodesHandler.cpp b/src/src/DataStructs/NodesHandler.cpp index 99ecebb545..0b2f84a1fc 100644 --- a/src/src/DataStructs/NodesHandler.cpp +++ b/src/src/DataStructs/NodesHandler.cpp @@ -213,7 +213,7 @@ const NodeStruct * NodesHandler::getPreferredNode() const { return getPreferredNode_notMatching(dummy); } -const NodeStruct* NodesHandler::getPreferredNode_notMatching(uint8_t unit_nr) const { +const NodeStruct* NodesHandler::getPreferredNode_notMatching(uint8_t unit_nr, bool checkMQTT_QueueState) const { MAC_address not_matching; if (unit_nr != 0 && unit_nr != 255) { const NodeStruct* node = getNode(unit_nr); @@ -221,10 +221,10 @@ const NodeStruct* NodesHandler::getPreferredNode_notMatching(uint8_t unit_nr) co not_matching = node->ESPEasy_Now_MAC(); } } - return getPreferredNode_notMatching(not_matching); + return getPreferredNode_notMatching(not_matching, checkMQTT_QueueState); } -const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching) const { +const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& not_matching, bool checkMQTT_QueueState) const { const NodeStruct *thisNodeSTA = getNodeByMac(WifiSTAmacAddress()); const NodeStruct *thisNodeAP = getNodeByMac(WifiSoftAPmacAddress()); const NodeStruct *reject = getNodeByMac(not_matching); @@ -278,6 +278,21 @@ const NodeStruct * NodesHandler::getPreferredNode_notMatching(const MAC_address& } #endif } + #ifdef USES_ESPEASY_NOW + if (checkMQTT_QueueState) + { + if (res != nullptr) { + const bool mqttState_res_empty = getMQTTQueueState(res->unit) == ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty; + const bool mqttState_new_empty = getMQTTQueueState(it->second.unit) == ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty; + if (!mqttState_res_empty && mqttState_new_empty) { + mustSet = true; + } else if (mqttState_res_empty && !mqttState_new_empty) { + mustSet = false; + } + } + } + #endif + if (mustSet) { #ifdef USES_ESPEASY_NOW if (it->second.ESPEasyNowPeer && it->second.distance < 255) { @@ -694,6 +709,16 @@ void NodesHandler::setMQTTQueueState(const MAC_address& mac, ESPEasy_Now_MQTT_Qu } } +void NodesHandler::updateMQTT_checkQueue() { + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { + if (it->second.ESPEasyNowPeer) { + if (getMQTTQueueState(it->second.unit) != ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty) { + ESPEasy_now_MQTT_check_queue.push_back(it->second.ESPEasy_Now_MAC()); + } + } + } +} + #endif #endif \ No newline at end of file diff --git a/src/src/DataStructs/NodesHandler.h b/src/src/DataStructs/NodesHandler.h index e6b4a600f4..682cedade3 100644 --- a/src/src/DataStructs/NodesHandler.h +++ b/src/src/DataStructs/NodesHandler.h @@ -57,8 +57,8 @@ class NodesHandler { const NodeStruct * getPreferredNode() const; - const NodeStruct * getPreferredNode_notMatching(uint8_t unit_nr) const; - const NodeStruct * getPreferredNode_notMatching(const MAC_address& not_matching) const; + const NodeStruct * getPreferredNode_notMatching(uint8_t unit_nr, bool checkMQTT_QueueState = false) const; + const NodeStruct * getPreferredNode_notMatching(const MAC_address& not_matching, bool checkMQTT_QueueState = false) const; #ifdef USES_ESPEASY_NOW const ESPEasy_now_traceroute_struct* getTraceRoute(uint8_t unit) const; @@ -120,6 +120,12 @@ class NodesHandler { } +#ifdef USES_ESPEASY_NOW + void updateMQTT_checkQueue(); + std::list ESPEasy_now_traceroute_queue; + std::list ESPEasy_now_MQTT_check_queue; +#endif + private: bool setRSSI(NodeStruct *node, diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 46a8dd0f12..f628c71c23 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -496,28 +496,28 @@ void processProbeRequestAPmode() { Nodes.setRSSI(mac, rssi); - static MAC_address last_probed_mac; - if (last_probed_mac != mac) { - last_probed_mac = mac; - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("AP Mode: Probe Request: "); - log += mac.toString(); - log += F(" ("); - log += rssi; - log += F(" dBm)"); - addLog(LOG_LEVEL_INFO, log); - } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("AP Mode: Probe Request: "); + log += mac.toString(); + log += F(" ("); + log += rssi; + log += F(" dBm)"); + addLog(LOG_LEVEL_INFO, log); + } + + +// static MAC_address last_probed_mac; +// if (last_probed_mac != mac) { +// last_probed_mac = mac; // FIXME TD-er: Must create an answer for ESPEasy-NOW node discovery #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { - const NodeStruct * node = Nodes.getNodeByMac(mac); ESPEasy_now_handler.sendDiscoveryAnnounce( - (node != nullptr && node->ESPEasyNowPeer) ? node->ESPEasy_Now_MAC() : mac, - Nodes.getESPEasyNOW_channel()); + mac, Nodes.getESPEasyNOW_channel()); } #endif - } +// } APModeProbeRequestReceived_list.pop_front(); WiFiEventData.processedProbeRequestAPmode = APModeProbeRequestReceived_list.size() == 0; diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 4a6b4257a6..214a9a67b1 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -70,8 +70,6 @@ static uint64_t ICACHE_FLASH_ATTR mac_to_key(const uint8_t *mac, ESPEasy_now_hdr ESPEasy_Mutex ESPEasy_now_in_queue_mutex; std::map ESPEasy_now_in_queue; -std::list ESPEasy_now_traceroute_queue; -std::list ESPEasy_now_MQTT_check_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; @@ -429,36 +427,39 @@ void ESPEasy_now_handler_t::loop_process_ESPEasyNOW_send_queue() // Only process one every 100 msec. static unsigned long last_queue_processed = 0; if (timePassedSince(last_queue_processed) > 100) { - if (!ESPEasy_now_traceroute_queue.empty()) { - ESPEasy_now_traceroute_queue.sort(); - const ESPEasy_now_traceroute_struct route = ESPEasy_now_traceroute_queue.front(); + if (!Nodes.ESPEasy_now_traceroute_queue.empty()) { + Nodes.ESPEasy_now_traceroute_queue.sort(); + const ESPEasy_now_traceroute_struct route = Nodes.ESPEasy_now_traceroute_queue.front(); sendTraceRoute(route); _last_traceroute_received = millis(); last_queue_processed = millis(); // Remove possible duplicate routes and keep the best 2 size_t nrRoutes = 0; - for (auto it = ESPEasy_now_traceroute_queue.begin(); it != ESPEasy_now_traceroute_queue.end();) { - if (route.sameRoute(*it) || nrRoutes >= 2) { - it = ESPEasy_now_traceroute_queue.erase(it); + for (auto it = Nodes.ESPEasy_now_traceroute_queue.begin(); it != Nodes.ESPEasy_now_traceroute_queue.end();) { + addLog(LOG_LEVEL_INFO, concat(F("TraceRoutes: "), it->toString())); + if (route.sameRoute(*it) || nrRoutes >= 5) { + it = Nodes.ESPEasy_now_traceroute_queue.erase(it); } else { ++nrRoutes; ++it; } } - } else if (!ESPEasy_now_MQTT_check_queue.empty()) { - const MAC_address mac = ESPEasy_now_MQTT_check_queue.front(); - const NodeStruct * node = Nodes.getNodeByMac(mac); - if (node != nullptr) { - const uint8_t channel = node->channel; - sendMQTTCheckControllerQueue(mac, channel); - last_queue_processed = millis(); - } - // Remove duplicate entries in the list. - for (auto it = ESPEasy_now_MQTT_check_queue.begin(); it != ESPEasy_now_MQTT_check_queue.end();) { - if (*it == mac) { - it = ESPEasy_now_MQTT_check_queue.erase(it); - } else { - ++it; + } else if (!Nodes.ESPEasy_now_MQTT_check_queue.empty()) { + while (!Nodes.ESPEasy_now_MQTT_check_queue.empty()) { + const MAC_address mac = Nodes.ESPEasy_now_MQTT_check_queue.front(); + const NodeStruct * node = Nodes.getNodeByMac(mac); + if (node != nullptr) { + const uint8_t channel = node->channel; + sendMQTTCheckControllerQueue(mac, channel); + last_queue_processed = millis(); + } + // Remove duplicate entries in the list. + for (auto it = Nodes.ESPEasy_now_MQTT_check_queue.begin(); it != Nodes.ESPEasy_now_MQTT_check_queue.end();) { + if (*it == mac) { + it = Nodes.ESPEasy_now_MQTT_check_queue.erase(it); + } else { + ++it; + } } } } @@ -688,6 +689,13 @@ void ESPEasy_now_handler_t::sendDiscoveryAnnounce(const MAC_address& mac, int ch } } + const NodeStruct* node = Nodes.getNodeByMac(mac); + if (node != nullptr) { + const MAC_address espeasynow_mac = node->ESPEasy_Now_MAC(); + if (espeasynow_mac != mac) { + msg.send(espeasynow_mac, channel); + } + } msg.send(mac, channel); } // WifiScan(true, channel); @@ -821,10 +829,10 @@ void ESPEasy_now_handler_t::sendTraceRoute() void ESPEasy_now_handler_t::sendTraceRoute(const ESPEasy_now_traceroute_struct& traceRoute, int channel) { for (auto it = Nodes.begin(); it != Nodes.end(); ++it) { - if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { +// if (it->second.getAge() > ESPEASY_NOW_SINCE_LAST_BROADCAST) { const int peer_channel = it->second.channel == 0 ? channel : it->second.channel; sendTraceRoute(it->second.ESPEasy_Now_MAC(), traceRoute, peer_channel); - } +// } } sendTraceRoute(ESPEasy_now_peermanager.getBroadcastMAC(), traceRoute, Nodes.getESPEasyNOW_channel()); @@ -847,6 +855,7 @@ void ESPEasy_now_handler_t::sendTraceRoute(const MAC_address& mac, const ESPEasy addLog(LOG_LEVEL_ERROR, F(ESPEASY_NOW_NAME ": sendTraceRoute error adding trace route"));; return; } + if (mac.all_zero()) return; if (channel < 0) { // Send to all channels @@ -884,19 +893,27 @@ bool ESPEasy_now_handler_t::handle_TraceRoute(const ESPEasy_now_merger& message, ESPEasy_now_traceroute_struct traceroute(traceroute_size); if (message.getBinaryData(traceroute.get(), traceroute_size, payload_pos) == traceroute_size) { if (traceroute.getDistance() < 255) { - const uint8_t thisunit = Settings.Unit; - if (!traceroute.unitInTraceRoute(thisunit)) { - MAC_address mac; - message.getMac(mac); - Nodes.setTraceRoute(mac, traceroute); - if (thisunit != 0 && thisunit != 255 && !Nodes.isEndpoint()) { - // Do not forward the trace route if we're an endpoint. - traceroute.addUnit(thisunit); - traceroute.setSuccessRate_last_node(thisunit, Nodes.getSuccessRate(thisunit)); - ESPEasy_now_traceroute_queue.push_back(traceroute); - // Send MQTT queue check to the node we received the traceroute from - // It may be a viable path to send MQTT to, so stay informed of its MQTT queue state - ESPEasy_now_MQTT_check_queue.push_back(mac); + if (Nodes.getDistance() == 0) { + Nodes.ESPEasy_now_traceroute_queue.clear(); + Nodes.ESPEasy_now_MQTT_check_queue.clear(); + } else { + const uint8_t thisunit = Settings.Unit; + if (!traceroute.unitInTraceRoute(thisunit)) { + MAC_address mac; + message.getMac(mac); + Nodes.setTraceRoute(mac, traceroute); + if (thisunit != 0 && thisunit != 255 && !Nodes.isEndpoint()) { + // Do not forward the trace route if we're an endpoint. + uint8_t successrate; + const uint8_t lastUnit = traceroute.getUnit(traceroute.getDistance(), successrate); + successrate = Nodes.getSuccessRate(lastUnit); + traceroute.addUnit(thisunit); + traceroute.setSuccessRate_last_node(thisunit, successrate); + Nodes.ESPEasy_now_traceroute_queue.push_back(traceroute); + // Send MQTT queue check to the node we received the traceroute from + // It may be a viable path to send MQTT to, so stay informed of its MQTT queue state + Nodes.ESPEasy_now_MQTT_check_queue.push_back(mac); + } } } } @@ -1016,7 +1033,7 @@ bool ESPEasy_now_handler_t::sendToMQTT( switch (Nodes.getMQTTQueueState(preferred->unit)) { case ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset: case ESPEasy_Now_MQTT_QueueCheckState::Enum::Full: - ESPEasy_now_MQTT_check_queue.push_back(mac); + Nodes.updateMQTT_checkQueue(); return false; case ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty: break; @@ -1063,7 +1080,7 @@ bool ESPEasy_now_handler_t::sendToMQTT( case WifiEspNowSendStatus::FAIL: { Nodes.setMQTTQueueState(preferred->unit, ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset); - ESPEasy_now_MQTT_check_queue.push_back(mac); + Nodes.ESPEasy_now_MQTT_check_queue.push_back(mac); ++_send_failed_count; break; } From 9c72bcab290e22b4b75a07f120d3cbd471125e23 Mon Sep 17 00:00:00 2001 From: TD-er Date: Mon, 20 Feb 2023 15:30:09 +0100 Subject: [PATCH 355/404] [ESPEasy_NOW] Fix ESP32 could only connect to AP after 20 mins --- src/src/ESPEasyCore/ESPEasyWifi.cpp | 5 ++++- src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index db2b25d999..d583f04b73 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -519,7 +519,10 @@ bool prepareWiFi() { WiFiEventData.warnedNoValidWiFiSettings = false; #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { - setWifiMode(WIFI_AP_STA); + temp_disable_EspEasy_now_timer = millis() + WIFI_RECONNECT_WAIT; + ESPEasy_now_handler.end(); + setSTA(true); +// setWifiMode(WIFI_AP_STA); } else { setSTA(true); } diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index f628c71c23..29c46cd5a6 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -638,7 +638,7 @@ void processScanDone() { #ifdef USES_ESPEASY_NOW if (Settings.UseESPEasyNow()) { ESPEasy_now_handler.addPeerFromWiFiScan(); - if (!NetworkConnected() && (temp_disable_EspEasy_now_timer == 0 || timeOutReached(temp_disable_EspEasy_now_timer))) { + if (!NetworkConnected()) { if (WiFi_AP_Candidates.addedKnownCandidate()) { WiFi_AP_Candidates.force_reload(); if (!WiFiEventData.wifiConnectInProgress) { diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index 214a9a67b1..d5b07e286a 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -1033,6 +1033,8 @@ bool ESPEasy_now_handler_t::sendToMQTT( switch (Nodes.getMQTTQueueState(preferred->unit)) { case ESPEasy_Now_MQTT_QueueCheckState::Enum::Unset: case ESPEasy_Now_MQTT_QueueCheckState::Enum::Full: + // We need this one now, so add as first + Nodes.ESPEasy_now_MQTT_check_queue.push_front(mac); Nodes.updateMQTT_checkQueue(); return false; case ESPEasy_Now_MQTT_QueueCheckState::Enum::Empty: From e292d1812d791b20afd00523a90747761797e941 Mon Sep 17 00:00:00 2001 From: TD-er Date: Tue, 21 Feb 2023 15:21:05 +0100 Subject: [PATCH 356/404] [ESPEasy_NOW] Add filter option to ESPEasy_NOW controller --- src/_C019.cpp | 29 ++-- .../ControllerQueue/Queue_element_base.cpp | 1 - src/src/ControllerQueue/Queue_element_base.h | 4 - src/src/Controller_config/C019_config.cpp | 120 ++++++++++++++--- src/src/Controller_config/C019_config.h | 48 ++++--- src/src/ESPEasyCore/Controller.cpp | 20 ++- src/src/Helpers/ESPEasy_Storage.cpp | 2 +- src/src/Helpers/ESPEasy_now_handler.cpp | 126 ++++++++++++------ src/src/Helpers/ESPEasy_now_handler.h | 4 +- src/src/Helpers/PeriodicalActions.cpp | 15 --- src/src/WebServer/ESPEasy_WebServer.cpp | 6 +- src/src/WebServer/ESPEasy_WebServer.h | 3 +- tools/pio/pre_custom_esp32.py | 3 +- 13 files changed, 258 insertions(+), 123 deletions(-) diff --git a/src/_C019.cpp b/src/_C019.cpp index 4fefd7cd4e..93615739e0 100644 --- a/src/_C019.cpp +++ b/src/_C019.cpp @@ -29,7 +29,7 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& { Protocol[++protocolCount].Number = CPLUGIN_ID_019; Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesTemplate = false; Protocol[protocolCount].usesAccount = false; Protocol[protocolCount].usesPassword = false; Protocol[protocolCount].usesExtCreds = false; @@ -57,26 +57,18 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& // success = init_c019_delay_queue(event->ControllerIndex); if (use_EspEasy_now) { ESPEasy_now_handler.end(); } - // Load settings into ESPEasy_now_handler - std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); - - if (customConfig) { - LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); - ESPEasy_now_handler.setConfig(*customConfig); - ESPEasy_now_handler.do_begin(); - success = true; - } - + ESPEasy_now_handler.loadConfig(event); + ESPEasy_now_handler.do_begin(); + success = true; break; } case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { - std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + C019_ConfigStruct_ptr customConfig(new (std::nothrow) C019_ConfigStruct); if (customConfig) { - LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); - customConfig->webform_load(); + customConfig->webform_load(event); } break; @@ -84,11 +76,10 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: { - std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + C019_ConfigStruct_ptr customConfig(new (std::nothrow) C019_ConfigStruct); if (customConfig) { - LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(customConfig.get()), sizeof(C019_ConfigStruct)); - customConfig->webform_save(); + customConfig->webform_save(event); } break; @@ -96,10 +87,10 @@ bool CPlugin_019(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: { - std::shared_ptr customConfig(new (std::nothrow) C019_ConfigStruct); + C019_ConfigStruct_ptr customConfig(new (std::nothrow) C019_ConfigStruct); if (customConfig) { - customConfig->webform_save(); + // customConfig->webform_save(event); } break; } diff --git a/src/src/ControllerQueue/Queue_element_base.cpp b/src/src/ControllerQueue/Queue_element_base.cpp index fb94817204..82ac938e60 100644 --- a/src/src/ControllerQueue/Queue_element_base.cpp +++ b/src/src/ControllerQueue/Queue_element_base.cpp @@ -4,7 +4,6 @@ Queue_element_base::Queue_element_base() : _controller_idx(INVALID_CONTROLLER_INDEX), _taskIndex(INVALID_TASK_INDEX), _call_PLUGIN_PROCESS_CONTROLLER_DATA(false), - _call_PLUGIN_FILTEROUT_CONTROLLER_DATA(false), _processByController(false) { _timestamp = millis(); diff --git a/src/src/ControllerQueue/Queue_element_base.h b/src/src/ControllerQueue/Queue_element_base.h index b01cab7e69..7f529c1e34 100644 --- a/src/src/ControllerQueue/Queue_element_base.h +++ b/src/src/ControllerQueue/Queue_element_base.h @@ -31,10 +31,6 @@ class Queue_element_base { // Typical use case is dumping large data which would otherwise take up lot of RAM. bool _call_PLUGIN_PROCESS_CONTROLLER_DATA; - // Call PLUGIN_FILTEROUT_CONTROLLER_DATA which will determine whether the message should be further processed or not. - // Typical use case is forwarding MQTT messages via ESPEasy-NOW mesh. - bool _call_PLUGIN_FILTEROUT_CONTROLLER_DATA; - // Some formatting of values can be done when actually sending it. // This may require less RAM than keeping formatted strings in memory bool _processByController; diff --git a/src/src/Controller_config/C019_config.cpp b/src/src/Controller_config/C019_config.cpp index ecbeae28bd..e12fc88c35 100644 --- a/src/src/Controller_config/C019_config.cpp +++ b/src/src/Controller_config/C019_config.cpp @@ -2,11 +2,28 @@ #ifdef USES_C019 +# include "../Globals/Settings.h" + +# define C019_FORWARDFILTERING_ELEMENTS 3 + +void C019_ForwardFiltering::fromStringArray(String strings[], uint8_t filterNr) +{ + const uint8_t index = C019_FORWARDFILTERING_ELEMENTS * filterNr; + + taskIndex = strings[index + 0].toInt(); + matchTopic = std::move(strings[index + 1]); +} + +void C019_ForwardFiltering::toStringArray(String strings[], uint8_t filterNr) const +{ + const uint8_t index = C019_FORWARDFILTERING_ELEMENTS * filterNr; + + strings[index + 0] = taskIndex; + strings[index + 1] = std::move(matchTopic); +} void C019_ConfigStruct::validate() { - if (!validTaskIndex(filterTaskIndex)) { - filterTaskIndex = INVALID_TASK_INDEX; - } + if (nrTaskFilters > TASKS_MAX) { nrTaskFilters = 0; } if (!validControllerIndex(forwardControllerIdx)) { forwardControllerIdx = INVALID_CONTROLLER_INDEX; @@ -14,31 +31,104 @@ void C019_ConfigStruct::validate() { } void C019_ConfigStruct::reset() { - filterTaskIndex = INVALID_TASK_INDEX; + nrTaskFilters = 0; + filters.clear(); forwardControllerIdx = INVALID_CONTROLLER_INDEX; } -void C019_ConfigStruct::webform_load() { - addFormCheckBox(F("Forward MQTT from " ESPEASY_NOW_NAME), F("fwd_mqtt"), forwardMQTT); +void C019_ConfigStruct::init(struct EventStruct *event) { + constexpr size_t filtersOffset = offsetof(C019_ConfigStruct, filters); + + LoadCustomControllerSettings(event->ControllerIndex, reinterpret_cast(this), filtersOffset); + filters.resize(nrTaskFilters); + { + const int nrStrings = nrTaskFilters * C019_FORWARDFILTERING_ELEMENTS; + String strings[nrStrings]; + LoadStringArray(SettingsType::Enum::CustomControllerSettings_Type, + event->ControllerIndex, + strings, + nrStrings, + 0, + filtersOffset); + + for (uint8_t i = 0; i < nrTaskFilters; ++i) { + filters[i].fromStringArray(strings, i); + } + } + + if (wifiChannel < 0) { + wifiChannel = Settings.ForceESPEasyNOWchannel; + } +} + +void C019_ConfigStruct::webform_load(struct EventStruct *event) { + init(event); + addFormNumericBox(LabelType::ESPEASY_NOW_FORCED_CHANNEL, Settings.ForceESPEasyNOWchannel, 0, 14); + addFormNote(F("Force channel to use for " + ESPEASY_NOW_NAME + "-only mode (0 = use any channel)")); + + addFormCheckBox(F("Forward MQTT from " ESPEASY_NOW_NAME), F("fwd_mqtt"), forwardMQTT); addTableSeparator(F("MQTT Forward Filtering"), 2, 3); - addFormCheckBox(F("Filter Forward MQTT"), F("filter_fwd"), filterMQTT_forward); - addRowLabel(F("Filter Task")); - addTaskSelect(F("ftask"), filterTaskIndex); + addFormCheckBox(F("Filter Forward MQTT"), F("filter_fwd"), filterMQTT_forward); + addFormNumericBox(F("Nr Filter Tasks"), F("nrfiltertasks"), nrTaskFilters, 0, TASKS_MAX); - addFormTextBox(F("Filter Publish Prefix"), F("pub_pref"), filterPublishPrefix, C019_MQTT_TOPIC_LENGTH - 1); - addFormTextBox(F("Filter Subscribe"), F("sub"), filterSubscribe, C019_MQTT_TOPIC_LENGTH - 1); + for (uint8_t i = 0; i < nrTaskFilters; ++i) { + addTableSeparator(concat(F("Filter "), i + 1), 2, 2); + addFormTextBox(F("Match Topic"), + concat(F("topic_match"), i), + filters[i].matchTopic, + C019_MQTT_TOPIC_LENGTH - 1); + addRowLabel(F("Task")); + addTaskSelect(concat(F("ftask"), i), filters[i].taskIndex, false); + } + addFormSeparator(2); } -void C019_ConfigStruct::webform_save() { +void C019_ConfigStruct::webform_save(struct EventStruct *event) { reset(); forwardMQTT = isFormItemChecked(F("fwd_mqtt")); filterMQTT_forward = isFormItemChecked(F("filter_fwd")); - filterTaskIndex = getFormItemInt(F("ftask")); + nrTaskFilters = getFormItemInt(F("nrfiltertasks")); + + // FIXME TD-er: For now have it as duplicate setting... + Settings.ForceESPEasyNOWchannel = getFormItemInt(getInternalLabel(LabelType::ESPEASY_NOW_FORCED_CHANNEL)); + wifiChannel = Settings.ForceESPEasyNOWchannel; + + + constexpr size_t filtersOffset = offsetof(C019_ConfigStruct, filters); + + SaveCustomControllerSettings(event->ControllerIndex, reinterpret_cast(this), filtersOffset); - strlcpy(filterPublishPrefix, webArg(F("pub_pref")).c_str(), sizeof(filterPublishPrefix)); - strlcpy(filterSubscribe, webArg(F("sub")).c_str(), sizeof(filterSubscribe)); + if (nrTaskFilters > 0) { + const int nrStrings = nrTaskFilters * C019_FORWARDFILTERING_ELEMENTS; + String strings[nrStrings]; + + for (uint8_t i = 0; i < nrTaskFilters; ++i) { + C019_ForwardFiltering filter; + + filter.taskIndex = getFormItemInt(concat(F("ftask"), i), INVALID_TASK_INDEX); + filter.matchTopic = webArg(concat(F("topic_match"), i)); + filter.toStringArray(strings, i); + } + SaveStringArray(SettingsType::Enum::CustomControllerSettings_Type, + event->ControllerIndex, + strings, + nrStrings, + 0, + filtersOffset); + } +} + +taskIndex_t C019_ConfigStruct::matchTopic(const String& topic) const +{ + for (auto it = filters.begin(); it != filters.end(); ++it) { + // FIXME TD-er: Must match MQTT topic wildcards + if (topic.indexOf(it->matchTopic) != -1) { return it->taskIndex; } + } + return INVALID_TASK_INDEX; } #endif // ifdef USES_C019 diff --git a/src/src/Controller_config/C019_config.h b/src/src/Controller_config/C019_config.h index dd93df52eb..f368e681b0 100644 --- a/src/src/Controller_config/C019_config.h +++ b/src/src/Controller_config/C019_config.h @@ -5,27 +5,44 @@ #ifdef USES_C019 +# include + # define C019_MQTT_TOPIC_LENGTH 128 +struct C019_ForwardFiltering +{ + void fromStringArray(String strings[], + uint8_t filterNr); + void toStringArray(String strings[], + uint8_t filterNr) const; + + taskIndex_t taskIndex = INVALID_TASK_INDEX; + String matchTopic; +}; + struct C019_ConfigStruct { C019_ConfigStruct() = default; - void validate(); + void validate(); - void reset(); + void reset(); + + void init(struct EventStruct *event); // Send all to the web interface - void webform_load(); + void webform_load(struct EventStruct *event); // Collect all data from the web interface - void webform_save(); + void webform_save(struct EventStruct *event); + + taskIndex_t matchTopic(const String& topic) const; - uint8_t configVersion = 1; // Format version of the stored data - uint8_t dummy_not_used = 0; // For 32-bit alignment - uint8_t dummy_not_used1 = 0; // For 32-bit alignment - uint8_t dummy_not_used2 = 0; // For 32-bit alignment + uint8_t configVersion = 1; // Format version of the stored data + uint8_t nrTaskFilters = 0; // Number of task/topics to configure for filtering + int8_t wifiChannel = -1; + controllerIndex_t forwardControllerIdx = INVALID_CONTROLLER_INDEX; // Controller index to forward filtered data to union { struct { @@ -38,18 +55,15 @@ struct C019_ConfigStruct uint32_t variousBits = 0; }; - int8_t wifiChannel = -1; - - // MQTT filter options - taskIndex_t filterTaskIndex = INVALID_TASK_INDEX; // Task index to use for filtering - controllerIndex_t forwardControllerIdx = INVALID_CONTROLLER_INDEX; // Controller index to forward filtered data to - int8_t filterTopic_startindex = -1; // - int8_t filterTopic_endindex = -1; - char filterPublishPrefix[C019_MQTT_TOPIC_LENGTH] = { 0 }; - char filterSubscribe[C019_MQTT_TOPIC_LENGTH] = { 0 }; + + uint32_t reserved = 0; // Need to have the start of 'filters' at the same position. + + std::vectorfilters; }; +typedef std::shared_ptr C019_ConfigStruct_ptr; + #endif // ifdef USES_C019 #endif // ifndef CONTROLLER_CONFIG_C019_CONFIG_H diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index c8114efd5a..0e30ea48cb 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -586,6 +586,23 @@ bool MQTTpublish(controllerIndex_t controller_idx, if (message.getString(topic, pos) && message.getString(payload, pos)) { const size_t bytesLeft = payloadSize - pos; + if (callbackTask && validTaskIndex(taskIndex)) { + struct EventStruct TempEvent(taskIndex); + String dummy; + TempEvent.String1 = std::move(topic); + TempEvent.String2 = std::move(payload); + + // Filter function to check if data should be forwarded or not. + // Since all plugins/tasks not supporting this function call will return false, + // the "true" result is about the non-standard action; to filter out the message. + if (PluginCall(PLUGIN_FILTEROUT_CONTROLLER_DATA, &TempEvent, dummy)) { + scheduleNextMQTTdelayQueue(); + return true; + } + topic = std::move(TempEvent.String1); + payload = std::move(TempEvent.String2); + } + if (bytesLeft >= 4) { bool validMessageRouteInfo = false; @@ -627,10 +644,9 @@ bool MQTTpublish(controllerIndex_t controller_idx, std::move(topic), std::move(payload), retained, - callbackTask)); + false)); if (element) { - element->_call_PLUGIN_FILTEROUT_CONTROLLER_DATA = validTaskIndex(taskIndex); element->MessageRouteInfo = routeinfo; success = MQTTDelayHandler->addToQueue(std::move(element)); } diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 9c91d63188..74675e5e30 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -808,7 +808,7 @@ String LoadStringArray(SettingsType::Enum settingsType, int index, String string #ifndef BUILD_NO_DEBUG return F("Invalid index for custom settings"); #else - return F("Save error"); + return F("Load error"); #endif } diff --git a/src/src/Helpers/ESPEasy_now_handler.cpp b/src/src/Helpers/ESPEasy_now_handler.cpp index d5b07e286a..b6668df604 100644 --- a/src/src/Helpers/ESPEasy_now_handler.cpp +++ b/src/src/Helpers/ESPEasy_now_handler.cpp @@ -5,7 +5,6 @@ # include "../Helpers/_CPlugin_Helper.h" - # include "../ControllerQueue/MQTT_queue_element.h" # include "../DataStructs/ESPEasy_Now_DuplicateCheck.h" # include "../DataStructs/ESPEasy_Now_MQTT_queue_check_packet.h" @@ -73,8 +72,9 @@ std::map ESPEasy_now_in_queue; void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t *buf, size_t count, void *cbarg) { START_TIMER; - const size_t payload_length = count - sizeof(ESPEasy_now_hdr); - if (count < sizeof(ESPEasy_now_hdr) || (payload_length > ESPEasy_Now_packet::getMaxPayloadSize())) { + const size_t payload_length = count - sizeof(ESPEasy_now_hdr); + + if ((count < sizeof(ESPEasy_now_hdr)) || (payload_length > ESPEasy_Now_packet::getMaxPayloadSize())) { STOP_TIMER(INVALID_ESPEASY_NOW_LOOP); return; // Too small } @@ -86,7 +86,7 @@ void ICACHE_FLASH_ATTR ESPEasy_now_onReceive(const uint8_t mac[6], const uint8_t return; } - const uint8_t *payload = buf + sizeof(ESPEasy_now_hdr); + const uint8_t *payload = buf + sizeof(ESPEasy_now_hdr); const uint16_t checksum = calc_CRC16(reinterpret_cast(payload), payload_length); if (header.checksum != checksum) { @@ -116,23 +116,28 @@ ESPEasy_now_handler_t::~ESPEasy_now_handler_t() } } -void ESPEasy_now_handler_t::setConfig(const C019_ConfigStruct& config) +void ESPEasy_now_handler_t::loadConfig(struct EventStruct *event) { - // FIXME TD-er: Must configure other settings too. - // Perhaps add C019_ConfigStruct as a member too? - _filterTaskCallback = config.filterMQTT_forward ? config.filterTaskIndex : INVALID_TASK_INDEX; + customConfig.reset(new (std::nothrow) C019_ConfigStruct); + + if (customConfig) { + customConfig->init(event); + } } bool ESPEasy_now_handler_t::begin() { if (!Settings.UseESPEasyNow()) { return false; } + // Check to see if we have an ESPEasy_NOW controller defined. // Call CPLUGIN_INIT on it to load the settings. const controllerIndex_t ESPEasy_NOW_controller_idx = get_ESPEasy_NOW_controller_index(); + if (validControllerIndex(ESPEasy_NOW_controller_idx) && Settings.ControllerEnabled[ESPEasy_NOW_controller_idx]) { struct EventStruct tmpEvent; tmpEvent.ControllerIndex = ESPEasy_NOW_controller_idx; - if (!CPluginCall(CPlugin::Function::CPLUGIN_INIT, &tmpEvent)) return false; + + if (!CPluginCall(CPlugin::Function::CPLUGIN_INIT, &tmpEvent)) { return false; } } return do_begin(); } @@ -140,11 +145,14 @@ bool ESPEasy_now_handler_t::begin() bool ESPEasy_now_handler_t::do_begin() { if (!Settings.UseESPEasyNow()) { return false; } + if (use_EspEasy_now) { return true; } - if (WiFi.scanComplete() == WIFI_SCAN_RUNNING || !WiFiEventData.processedScanDone) { return false;} + + if ((WiFi.scanComplete() == WIFI_SCAN_RUNNING) || !WiFiEventData.processedScanDone) { return false; } + if (WiFiEventData.wifiConnectInProgress) { /* - if (loglevelActiveFor(LOG_LEVEL_INFO)) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; if (log.reserve(64)) { log = F(ESPEASY_NOW_NAME); @@ -269,13 +277,15 @@ void ESPEasy_now_handler_t::end() bool ESPEasy_now_handler_t::loop() { loop_check_ESPEasyNOW_run_state(); - if (!use_EspEasy_now) return false; + + if (!use_EspEasy_now) { return false; } bool somethingProcessed = loop_process_ESPEasyNOW_in_queue(); loop_process_ESPEasyNOW_send_queue(); if (_send_failed_count > 30 /*|| !active()*/) { _send_failed_count = 0; + // FIXME TD-er: Must check/mark so this becomes true: isESPEasy_now_only() // Start scanning the next channel to see if we may end up with a new found node @@ -556,17 +566,20 @@ void ESPEasy_now_handler_t::addPeerFromWiFiScan(const WiFi_AP_Candidate& peer) bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bool& mustKeep) { - bool handled = false; + bool handled = false; bool considerActive = false; + mustKeep = false; { // Check if message is sent by this node MAC_address receivedMAC; message.getMac(receivedMAC.mac); - if (WifiSoftAPmacAddress() == receivedMAC || - WifiSTAmacAddress() == receivedMAC) return handled; + + if ((WifiSoftAPmacAddress() == receivedMAC) || + (WifiSTAmacAddress() == receivedMAC)) { return handled; } } + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, concat(F(ESPEASY_NOW_NAME ": received "), message.getLogString())); } @@ -585,22 +598,22 @@ bool ESPEasy_now_handler_t::processMessage(const ESPEasy_now_merger& message, bo handled = handle_NTPquery(message, mustKeep); break; case ESPEasy_now_hdr::message_t::MQTTControllerMessage: - handled = handle_MQTTControllerMessage(message, mustKeep); + handled = handle_MQTTControllerMessage(message, mustKeep); considerActive = true; break; case ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue: - handled = handle_MQTTCheckControllerQueue(message, mustKeep); + handled = handle_MQTTCheckControllerQueue(message, mustKeep); considerActive = true; break; case ESPEasy_now_hdr::message_t::SendData_DuplicateCheck: handled = handle_SendData_DuplicateCheck(message, mustKeep); break; case ESPEasy_now_hdr::message_t::P2P_data: - handled = handle_ESPEasyNow_p2p(message, mustKeep); + handled = handle_ESPEasyNow_p2p(message, mustKeep); considerActive = true; break; case ESPEasy_now_hdr::message_t::TraceRoute: - handled = handle_TraceRoute(message, mustKeep); + handled = handle_TraceRoute(message, mustKeep); considerActive = true; break; } @@ -997,10 +1010,10 @@ bool ESPEasy_now_handler_t::handle_NTPquery(const ESPEasy_now_merger& message, b // ************************************************************* bool ESPEasy_now_handler_t::sendToMQTT( - controllerIndex_t controllerIndex, - const String& topic, - const String& payload, - const MessageRouteInfo_t* messageRouteInfo) + controllerIndex_t controllerIndex, + const String & topic, + const String & payload, + const MessageRouteInfo_t *messageRouteInfo) { if (!use_EspEasy_now) { return false; } @@ -1063,11 +1076,13 @@ bool ESPEasy_now_handler_t::sendToMQTT( if (topic_length != msg.addString(topic)) { return false; } + if (payload_length != msg.addString(payload)) { return false; } - if (routeInfo_length != 0 && routeInfo_length != msg.addBinaryData(&(routeInfo[0]), routeInfo_length)) { -// return false; + + if ((routeInfo_length != 0) && (routeInfo_length != msg.addBinaryData(&(routeInfo[0]), routeInfo_length))) { + // return false; } WifiEspNowSendStatus sendStatus = msg.send(mac, _ClientTimeout, preferred->channel); @@ -1098,8 +1113,12 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge # if FEATURE_MQTT // FIXME TD-er: Quick hack to just echo all data to the first enabled MQTT controller + controllerIndex_t controllerIndex = get_ESPEasy_NOW_controller_index(); + if (!validControllerIndex(controllerIndex)) { + controllerIndex = firstEnabledMQTT_ControllerIndex(); + } + - controllerIndex_t controllerIndex = firstEnabledMQTT_ControllerIndex(); if (validControllerIndex(controllerIndex)) { load_ControllerSettingsCache(controllerIndex); @@ -1115,13 +1134,24 @@ bool ESPEasy_now_handler_t::handle_MQTTControllerMessage(const ESPEasy_now_merge MessageRouteInfo.unit = node->unit; } } + + taskIndex_t filterTaskCallback = INVALID_TASK_INDEX; + if (customConfig) { + if (customConfig->filterMQTT_forward) { + String topic; + size_t pos = 0; + message.getString(topic, pos); + filterTaskCallback = customConfig->matchTopic(topic); + } + } success = MQTTpublish( controllerIndex, - _filterTaskCallback, + filterTaskCallback, message, MessageRouteInfo, - _mqtt_retainFlag); + _mqtt_retainFlag, + validTaskIndex(filterTaskCallback)); if (!success) { mustKeep = false; return success; @@ -1163,20 +1193,21 @@ bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(controllerIndex_t contr } const NodeStruct *preferred = Nodes.getPreferredNode(); - if (preferred != nullptr && Nodes.getDistance() > preferred->distance) { + if ((preferred != nullptr) && (Nodes.getDistance() > preferred->distance)) { return sendMQTTCheckControllerQueue(preferred->ESPEasy_Now_MAC(), preferred->channel); } return false; } -bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address & mac, - int channel, +bool ESPEasy_now_handler_t::sendMQTTCheckControllerQueue(const MAC_address & mac, + int channel, ESPEasy_Now_MQTT_QueueCheckState::Enum state) { ESPEasy_Now_MQTT_queue_check_packet query; query.state = state; const size_t len = sizeof(ESPEasy_Now_MQTT_queue_check_packet); ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::MQTTCheckControllerQueue, len); + if (len != msg.addBinaryData(reinterpret_cast(&query), len)) { return false; } @@ -1330,37 +1361,42 @@ bool ESPEasy_now_handler_t::handle_SendData_DuplicateCheck(const ESPEasy_now_mer void ESPEasy_now_handler_t::load_ControllerSettingsCache(controllerIndex_t controllerIndex) { - if (validControllerIndex(controllerIndex) && controllerIndex != _controllerIndex) + if (validControllerIndex(controllerIndex) && (controllerIndex != _controllerIndex)) { // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. MakeControllerSettings(ControllerSettings); + if (AllocatedControllerSettings()) { LoadControllerSettings(controllerIndex, ControllerSettings); _enableESPEasyNowFallback = ControllerSettings.enableESPEasyNowFallback(); - _ClientTimeout = ControllerSettings.ClientTimeout; - _mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); - _controllerIndex = controllerIndex; + + if ((Settings.Protocol[controllerIndex] == 19) && customConfig) { + _enableESPEasyNowFallback = customConfig->forwardMQTT; + } + _ClientTimeout = ControllerSettings.ClientTimeout; + _mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); + _controllerIndex = controllerIndex; } } } - - // ************************************************************* -// * ESPEasyNow p2p +// * ESPEasyNow p2p // ************************************************************* bool ESPEasy_now_handler_t::sendESPEasyNow_p2p(controllerIndex_t controllerIndex, const MAC_address& mac, const ESPEasy_Now_p2p_data& data) { if (!use_EspEasy_now) { return false; } ESPEasy_now_splitter msg(ESPEasy_now_hdr::message_t::P2P_data, data.getTotalSize()); + // Add the first part of the data object, without the data array. if (data.dataOffset != msg.addBinaryData(reinterpret_cast(&data), data.dataOffset)) { return false; } - + // Fetch the data array information, will also update size. - size_t size = 0; - const uint8_t* data_ptr = data.getBinaryData(0, size); + size_t size = 0; + const uint8_t *data_ptr = data.getBinaryData(0, size); + if (size != msg.addBinaryData(data_ptr, size)) { return false; } @@ -1408,14 +1444,16 @@ bool ESPEasy_now_handler_t::handle_ESPEasyNow_p2p(const ESPEasy_now_merger& mess log += F(" payload_pos: "); log += data.dataOffset; addLog(LOG_LEVEL_ERROR, log); -// return false; + + // return false; } // Call C019 controller with event containing this data object as a pointer. EventStruct event; + event.ControllerIndex = controller_index; - event.Par1 = sizeof(ESPEasy_Now_p2p_data); - event.Data = reinterpret_cast(&data); + event.Par1 = sizeof(ESPEasy_Now_p2p_data); + event.Data = reinterpret_cast(&data); CPluginCall(CPlugin::Function::CPLUGIN_PROTOCOL_RECV, &event); return true; diff --git a/src/src/Helpers/ESPEasy_now_handler.h b/src/src/Helpers/ESPEasy_now_handler.h index 1023e66dce..903bd1f1b5 100644 --- a/src/src/Helpers/ESPEasy_now_handler.h +++ b/src/src/Helpers/ESPEasy_now_handler.h @@ -28,6 +28,8 @@ class ESPEasy_now_handler_t { void setConfig(const C019_ConfigStruct& config); + void loadConfig(struct EventStruct *event); + bool begin(); bool do_begin(); @@ -141,7 +143,7 @@ class ESPEasy_now_handler_t { uint8_t _usedWiFiChannel = 0; uint8_t _lastScannedChannel = 0; controllerIndex_t _controllerIndex = INVALID_CONTROLLER_INDEX; - taskIndex_t _filterTaskCallback = INVALID_TASK_INDEX; + C019_ConfigStruct_ptr customConfig; bool _scanChannelsMode = true; bool _enableESPEasyNowFallback = false; bool _mqtt_retainFlag = false; diff --git a/src/src/Helpers/PeriodicalActions.cpp b/src/src/Helpers/PeriodicalActions.cpp index e0bbfabab5..a3b3eb713f 100644 --- a/src/src/Helpers/PeriodicalActions.cpp +++ b/src/src/Helpers/PeriodicalActions.cpp @@ -332,21 +332,6 @@ void processMQTTdelayQueue() { if (PluginCall(PLUGIN_PROCESS_CONTROLLER_DATA, &TempEvent, dummy)) { processed = true; } - } else if (element->_call_PLUGIN_FILTEROUT_CONTROLLER_DATA) { - struct EventStruct TempEvent(element->_taskIndex); - String dummy; - - // FIXME TD-er: Find a way to not having to copy these strings - TempEvent.String1 = element->_topic; - TempEvent.String2 = element->_payload; - - // Filter function to check if data should be forwarded or not. - // Since all plugins/tasks not supporting this function call will return false, - // the "true" result is about the non-standard action; to filter out the message. - if (PluginCall(PLUGIN_FILTEROUT_CONTROLLER_DATA, &TempEvent, dummy)) { - processed = true; - } - } if (!processed) { #ifdef USES_ESPEASY_NOW diff --git a/src/src/WebServer/ESPEasy_WebServer.cpp b/src/src/WebServer/ESPEasy_WebServer.cpp index 817d8545c2..e5763db299 100644 --- a/src/src/WebServer/ESPEasy_WebServer.cpp +++ b/src/src/WebServer/ESPEasy_WebServer.cpp @@ -650,14 +650,16 @@ void json_prop(LabelType::Enum label) { // Add a task select dropdown list // This allows to select a task index based on the existing tasks. // ******************************************************************************** -void addTaskSelect(const String& name, taskIndex_t choice) +void addTaskSelect(const String& name, taskIndex_t choice, bool onChangeReload) { String deviceName; addHtml(F("