diff --git a/src/_C001.ino b/src/_C001.ino index f3c09be3d..52b5f61e9 100644 --- a/src/_C001.ino +++ b/src/_C001.ino @@ -1,16 +1,15 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C001 -#include "src/Helpers/_CPlugin_DomoticzHelper.h" +# include "src/Helpers/_CPlugin_DomoticzHelper.h" -//####################################################################################################### -//########################### Controller Plugin 001: Domoticz HTTP ###################################### -//####################################################################################################### - -#define CPLUGIN_001 -#define CPLUGIN_ID_001 1 -#define CPLUGIN_NAME_001 "Domoticz HTTP" +// ####################################################################################################### +// ########################### Controller Plugin 001: Domoticz HTTP ###################################### +// ####################################################################################################### +# define CPLUGIN_001 +# define CPLUGIN_ID_001 1 +# define CPLUGIN_NAME_001 "Domoticz HTTP" bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& string) @@ -20,113 +19,116 @@ bool CPlugin_001(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_001; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesAccount = true; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 8080; - Protocol[protocolCount].usesID = true; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_001; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesAccount = true; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 8080; + Protocol[protocolCount].usesID = true; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_001); - break; - } + { + string = F(CPLUGIN_NAME_001); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c001_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c001_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c001_delay_queue(); - break; - } + { + exit_c001_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C001_DelayHandler == nullptr) { - break; - } - if (event->idx != 0) - { - // We now create a URI for the request - String url; - url.reserve(128); - url = F("/json.htm?type=command¶m="); - - const Sensor_VType sensorType = event->getSensorType(); - - - switch (sensorType) - { - case Sensor_VType::SENSOR_TYPE_SWITCH: - case Sensor_VType::SENSOR_TYPE_DIMMER: - url += F("switchlight&idx="); - url += event->idx; - url += F("&switchcmd="); - if (UserVar[event->BaseVarIndex] == 0) { - url += F("Off"); - } else { - if (sensorType == Sensor_VType::SENSOR_TYPE_SWITCH) { - url += F("On"); - } else { - url += F("Set%20Level&level="); - url += UserVar[event->BaseVarIndex]; - } - } - break; - - case Sensor_VType::SENSOR_TYPE_SINGLE: - case Sensor_VType::SENSOR_TYPE_LONG: - case Sensor_VType::SENSOR_TYPE_DUAL: - case Sensor_VType::SENSOR_TYPE_TRIPLE: - case Sensor_VType::SENSOR_TYPE_QUAD: - case Sensor_VType::SENSOR_TYPE_TEMP_HUM: - case Sensor_VType::SENSOR_TYPE_TEMP_BARO: - case Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO: - case Sensor_VType::SENSOR_TYPE_TEMP_HUM_BARO: - case Sensor_VType::SENSOR_TYPE_WIND: - case Sensor_VType::SENSOR_TYPE_STRING: - default: - url += F("udevice&idx="); - url += event->idx; - url += F("&nvalue=0"); - url += F("&svalue="); - url += formatDomoticzSensorType(event); - break; - } - - // Add WiFi reception quality - url += F("&rssi="); - url += mapRSSItoDomoticz(); - #if FEATURE_ADC_VCC - url += F("&battery="); - url += mapVccToDomoticz(); - #endif - - success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, url)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C001_DELAY_QUEUE, C001_DelayHandler->getNextScheduleTime()); - } // if ixd !=0 - else - { - addLog(LOG_LEVEL_ERROR, F("HTTP : IDX cannot be zero!")); - } + { + if (C001_DelayHandler == nullptr) { break; } + if (event->idx != 0) + { + // We now create a URI for the request + String url; + url.reserve(128); + url = F("/json.htm?type=command¶m="); + + const Sensor_VType sensorType = event->getSensorType(); + + + switch (sensorType) + { + case Sensor_VType::SENSOR_TYPE_SWITCH: + case Sensor_VType::SENSOR_TYPE_DIMMER: + url += F("switchlight&idx="); + url += event->idx; + url += F("&switchcmd="); + + if (UserVar[event->BaseVarIndex] == 0) { + url += F("Off"); + } else { + if (sensorType == Sensor_VType::SENSOR_TYPE_SWITCH) { + url += F("On"); + } else { + url += F("Set%20Level&level="); + url += UserVar[event->BaseVarIndex]; + } + } + break; + + case Sensor_VType::SENSOR_TYPE_SINGLE: + case Sensor_VType::SENSOR_TYPE_LONG: + case Sensor_VType::SENSOR_TYPE_DUAL: + case Sensor_VType::SENSOR_TYPE_TRIPLE: + case Sensor_VType::SENSOR_TYPE_QUAD: + case Sensor_VType::SENSOR_TYPE_TEMP_HUM: + case Sensor_VType::SENSOR_TYPE_TEMP_BARO: + case Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO: + case Sensor_VType::SENSOR_TYPE_TEMP_HUM_BARO: + case Sensor_VType::SENSOR_TYPE_WIND: + case Sensor_VType::SENSOR_TYPE_STRING: + default: + url += F("udevice&idx="); + url += event->idx; + url += F("&nvalue=0"); + url += F("&svalue="); + url += formatDomoticzSensorType(event); + break; + } + + // Add WiFi reception quality + url += F("&rssi="); + url += mapRSSItoDomoticz(); + # if FEATURE_ADC_VCC + url += F("&battery="); + url += mapVccToDomoticz(); + # endif // if FEATURE_ADC_VCC + + success = C001_DelayHandler->addToQueue(C001_queue_element(event->ControllerIndex, url)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C001_DELAY_QUEUE, + C001_DelayHandler->getNextScheduleTime()); + } // if ixd !=0 + else + { + addLog(LOG_LEVEL_ERROR, F("HTTP : IDX cannot be zero!")); + } + break; + } + case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c001_delay_queue(); - delay(0); - break; - } + { + process_c001_delay_queue(); + delay(0); + break; + } default: break; @@ -141,16 +143,18 @@ bool do_process_c001_delay_queue(int controller_number, const C001_queue_element bool do_process_c001_delay_queue(int controller_number, const C001_queue_element& element, ControllerSettingsStruct& ControllerSettings) { WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) + + if (!try_connect_host(controller_number, client, ControllerSettings)) { return false; + } // This will send the request to the server String request = create_http_request_auth(controller_number, element.controller_idx, ControllerSettings, F("GET"), element.txt); -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, element.txt); -#endif +# endif // ifndef BUILD_NO_DEBUG return send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply); } -#endif +#endif // ifdef USES_C001 diff --git a/src/_C002.ino b/src/_C002.ino index 6a9d98501..240facd59 100644 --- a/src/_C002.ino +++ b/src/_C002.ino @@ -1,28 +1,28 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C002 -#include "src/Helpers/_CPlugin_DomoticzHelper.h" +# include "src/Helpers/_CPlugin_DomoticzHelper.h" // ####################################################################################################### // ########################### Controller Plugin 002: Domoticz MQTT ###################################### // ####################################################################################################### -#define CPLUGIN_002 -#define CPLUGIN_ID_002 2 -#define CPLUGIN_NAME_002 "Domoticz MQTT" +# define CPLUGIN_002 +# define CPLUGIN_ID_002 2 +# define CPLUGIN_NAME_002 "Domoticz MQTT" -#include "src/Commands/InternalCommands.h" -#include "src/Commands/GPIO.h" -#include "src/ESPEasyCore/ESPEasyGPIO.h" -#include "src/ESPEasyCore/ESPEasyRules.h" -#include "src/Globals/Settings.h" -#include "src/Helpers/PeriodicalActions.h" -#include "src/Helpers/StringParser.h" +# include "src/Commands/InternalCommands.h" +# include "src/Commands/GPIO.h" +# include "src/ESPEasyCore/ESPEasyGPIO.h" +# include "src/ESPEasyCore/ESPEasyRules.h" +# include "src/Globals/Settings.h" +# include "src/Helpers/PeriodicalActions.h" +# include "src/Helpers/StringParser.h" -#include +# include String CPlugin_002_pubname; -bool CPlugin_002_mqtt_retainFlag = false; +bool CPlugin_002_mqtt_retainFlag = false; bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -107,7 +107,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& if (Settings.TaskDeviceEnabled[x] && (Settings.TaskDeviceID[ControllerID][x] == idx)) // get idx for our controller index { String action; - bool mustSendEvent = false; + bool mustSendEvent = false; switch (Settings.TaskDeviceNumber[x]) { case 1: // temp solution, if input switch, update state @@ -129,19 +129,21 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& switch ((int)nvalue) { - case 0: // Off + case 0: // Off pwmValue = 0; UserVar[baseVar] = pwmValue; break; case 1: // On case 2: // Update dimmer value pwmValue = 0; + if (validIntFromString(svalue1, pwmValue)) { pwmValue *= 10; } UserVar[baseVar] = pwmValue; break; } + if (checkValidPortRange(PLUGIN_GPIO, Settings.TaskDevicePin1[x])) { action = F("pwm,"); action += Settings.TaskDevicePin1[x]; @@ -149,8 +151,9 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& action += pwmValue; } } else { - mustSendEvent = true; + mustSendEvent = true; UserVar[baseVar] = nvalue; + if (checkValidPortRange(PLUGIN_GPIO, Settings.TaskDevicePin1[x])) { action = F("gpio,"); action += Settings.TaskDevicePin1[x]; @@ -160,22 +163,24 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& } break; } -#if defined(USES_P088) || defined(USES_P115) - case 88: // Send heatpump IR (P088) if IDX matches - case 115: // Send heatpump IR (P115) if IDX matches +# if defined(USES_P088) || defined(USES_P115) + case 88: // Send heatpump IR (P088) if IDX matches + case 115: // Send heatpump IR (P115) if IDX matches { - action = F("heatpumpir,"); + action = F("heatpumpir,"); action += svalue1; // svalue1 is like 'gree,1,1,0,22,0,0' break; } -#endif // USES_P088 || USES_P115 +# endif // USES_P088 || USES_P115 default: break; } const bool validCommand = action.length() > 0; + if (validCommand) { mustSendEvent = true; + // Try plugin and internal ExecuteCommand(x, EventValueSource::Enum::VALUE_SOURCE_MQTT, action.c_str(), true, true, false); } @@ -205,9 +210,9 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& DynamicJsonDocument root(200); root[F("idx")] = event->idx; root[F("RSSI")] = mapRSSItoDomoticz(); - #if FEATURE_ADC_VCC + # if FEATURE_ADC_VCC root[F("Battery")] = mapVccToDomoticz(); - #endif // if FEATURE_ADC_VCC + # endif // if FEATURE_ADC_VCC const Sensor_VType sensorType = event->getSensorType(); @@ -253,11 +258,11 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& serializeJson(root, json); } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG String log = F("MQTT : "); log += json; addLog(LOG_LEVEL_DEBUG, log); -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG String pubname = CPlugin_002_pubname; parseControllerVariables(pubname, event, false); @@ -281,7 +286,6 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& default: break; - } return success; } diff --git a/src/_C003.ino b/src/_C003.ino index b591a2ca8..4ad5601a8 100644 --- a/src/_C003.ino +++ b/src/_C003.ino @@ -1,12 +1,13 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C003 -//####################################################################################################### -//########################### Controller Plugin 003: Nodo Telnet ####################################### -//####################################################################################################### -#define CPLUGIN_003 -#define CPLUGIN_ID_003 3 -#define CPLUGIN_NAME_003 "Nodo Telnet" +// ####################################################################################################### +// ########################### Controller Plugin 003: Nodo Telnet ####################################### +// ####################################################################################################### + +# define CPLUGIN_003 +# define CPLUGIN_ID_003 3 +# define CPLUGIN_NAME_003 "Nodo Telnet" bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -15,62 +16,61 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_003; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].defaultPort = 23; - Protocol[protocolCount].usesID = true; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_003; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].defaultPort = 23; + Protocol[protocolCount].usesID = true; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_003); - break; - } + { + string = F(CPLUGIN_NAME_003); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c003_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c003_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c003_delay_queue(); - break; - } + { + exit_c003_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C003_DelayHandler == nullptr) { - break; - } - - // We now create a URI for the request - String url = F("variableset "); - url += event->idx; - url += ","; - url += formatUserVarNoCheck(event, 0); - url += "\n"; - success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, url)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); - + { + if (C003_DelayHandler == nullptr) { break; } + // We now create a URI for the request + String url = F("variableset "); + url += event->idx; + url += ","; + url += formatUserVarNoCheck(event, 0); + url += "\n"; + success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, url)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime()); + + break; + } + case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c003_delay_queue(); - delay(0); - break; - } + { + process_c003_delay_queue(); + delay(0); + break; + } default: break; - } return success; } @@ -82,8 +82,10 @@ bool do_process_c003_delay_queue(int controller_number, const C003_queue_element bool do_process_c003_delay_queue(int controller_number, const C003_queue_element& element, ControllerSettingsStruct& ControllerSettings) { bool success = false; + // Use WiFiClient class to create TCP connections WiFiClient client; + if (!try_connect_host(controller_number, client, ControllerSettings, F("TELNT: "))) { return success; @@ -94,13 +96,15 @@ bool do_process_c003_delay_queue(int controller_number, const C003_queue_element client.print(" \n"); unsigned long timer = millis() + 200; - while (!client_available(client) && !timeOutReached(timer)) + + while (!client_available(client) && !timeOutReached(timer)) { delay(1); + } timer = millis() + 1000; + while (client_available(client) && !timeOutReached(timer) && !success) { - // String line = client.readStringUntil('\n'); String line; safeReadStringUntil(client, line, '\n'); @@ -116,18 +120,23 @@ bool do_process_c003_delay_queue(int controller_number, const C003_queue_element addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending pw")); client.println(getControllerPass(element.controller_idx, ControllerSettings)); delay(100); - while (client_available(client)) + + while (client_available(client)) { client.read(); + } addLog(LOG_LEVEL_DEBUG, F("TELNT: Sending cmd")); client.print(element.txt); delay(10); - while (client_available(client)) + + while (client_available(client)) { client.read(); + } addLog(LOG_LEVEL_DEBUG, F("TELNT: closing connection")); client.stop(); return success; } -#endif + +#endif // ifdef USES_C003 diff --git a/src/_C004.ino b/src/_C004.ino index 8dbd0f68e..138d5065b 100644 --- a/src/_C004.ino +++ b/src/_C004.ino @@ -1,12 +1,13 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C004 -//####################################################################################################### -//########################### Controller Plugin 004: ThingSpeak ######################################### -//####################################################################################################### -#define CPLUGIN_004 -#define CPLUGIN_ID_004 4 -#define CPLUGIN_NAME_004 "ThingSpeak" +// ####################################################################################################### +// ########################### Controller Plugin 004: ThingSpeak ######################################### +// ####################################################################################################### + +# define CPLUGIN_004 +# define CPLUGIN_ID_004 4 +# define CPLUGIN_NAME_004 "ThingSpeak" bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -15,72 +16,72 @@ bool CPlugin_004(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_004; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesAccount = true; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].defaultPort = 80; - Protocol[protocolCount].usesID = true; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_004; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesAccount = true; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].defaultPort = 80; + Protocol[protocolCount].usesID = true; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_004); - break; - } + { + string = F(CPLUGIN_NAME_004); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c004_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c004_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c004_delay_queue(); - break; - } + { + exit_c004_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_GET_PROTOCOL_DISPLAY_NAME: - { - success = true; - switch (event->idx) { - case ControllerSettingsStruct::CONTROLLER_USER: - string = F("ThingHTTP Name"); - break; - case ControllerSettingsStruct::CONTROLLER_PASS: - string = F("API Key"); - break; - default: - success = false; - break; - } - break; + { + success = true; + + switch (event->idx) { + case ControllerSettingsStruct::CONTROLLER_USER: + string = F("ThingHTTP Name"); + break; + case ControllerSettingsStruct::CONTROLLER_PASS: + string = F("API Key"); + break; + default: + success = false; + break; } + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C004_DelayHandler == nullptr) { - break; - } - success = C004_DelayHandler->addToQueue(C004_queue_element(event)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C004_DELAY_QUEUE, C004_DelayHandler->getNextScheduleTime()); - + { + if (C004_DelayHandler == nullptr) { break; } + success = C004_DelayHandler->addToQueue(C004_queue_element(event)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C004_DELAY_QUEUE, C004_DelayHandler->getNextScheduleTime()); + + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c004_delay_queue(); - delay(0); - break; - } + { + process_c004_delay_queue(); + delay(0); + break; + } default: break; - } return success; } @@ -92,16 +93,19 @@ bool do_process_c004_delay_queue(int controller_number, const C004_queue_element bool do_process_c004_delay_queue(int controller_number, const C004_queue_element& element, ControllerSettingsStruct& ControllerSettings) { WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) + + if (!try_connect_host(controller_number, client, ControllerSettings)) { return false; + } String postDataStr = F("api_key="); + postDataStr += getControllerPass(element.controller_idx, ControllerSettings); // used for API key if (element.sensorType == Sensor_VType::SENSOR_TYPE_STRING) { - postDataStr += F("&status="); - postDataStr += element.txt[0]; // FIXME TD-er: Is this correct? - // See: https://nl.mathworks.com/help/thingspeak/writedata.html + postDataStr += F("&status="); + postDataStr += element.txt[0]; // FIXME TD-er: Is this correct? + // See: https://nl.mathworks.com/help/thingspeak/writedata.html } else { for (byte x = 0; x < element.valueCount; x++) { @@ -112,8 +116,10 @@ bool do_process_c004_delay_queue(int controller_number, const C004_queue_element } } String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers. - if (ControllerSettings.UseDNS) + + if (ControllerSettings.UseDNS) { hostName = ControllerSettings.HostName; + } String postStr = do_create_http_request( hostName, F("POST"), @@ -121,8 +127,10 @@ bool do_process_c004_delay_queue(int controller_number, const C004_queue_element "", // auth_header F("Content-Type: application/x-www-form-urlencoded\r\n"), postDataStr.length()); + postStr += postDataStr; return send_via_http(controller_number, client, postStr, ControllerSettings.MustCheckReply); } -#endif + +#endif // ifdef USES_C004 diff --git a/src/_C005.ino b/src/_C005.ino index ec2350a76..633b70049 100644 --- a/src/_C005.ino +++ b/src/_C005.ino @@ -1,23 +1,23 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C005 -#include "src/Commands/InternalCommands.h" -#include "src/Globals/EventQueue.h" -#include "src/Globals/ExtraTaskSettings.h" -#include "src/Helpers/PeriodicalActions.h" -#include "src/Helpers/StringParser.h" -#include "_Plugin_Helper.h" +# include "src/Commands/InternalCommands.h" +# include "src/Globals/EventQueue.h" +# include "src/Globals/ExtraTaskSettings.h" +# include "src/Helpers/PeriodicalActions.h" +# include "src/Helpers/StringParser.h" +# include "_Plugin_Helper.h" -//####################################################################################################### -//################### Controller Plugin 005: Home Assistant (openHAB) MQTT ############################## -//####################################################################################################### +// ####################################################################################################### +// ################### Controller Plugin 005: Home Assistant (openHAB) MQTT ############################## +// ####################################################################################################### -#define CPLUGIN_005 -#define CPLUGIN_ID_005 5 -#define CPLUGIN_NAME_005 "Home Assistant (openHAB) MQTT" +# define CPLUGIN_005 +# define CPLUGIN_ID_005 5 +# define CPLUGIN_NAME_005 "Home Assistant (openHAB) MQTT" String CPlugin_005_pubname; -bool CPlugin_005_mqtt_retainFlag = false; +bool CPlugin_005_mqtt_retainFlag = false; bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& string) @@ -27,154 +27,163 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_005; - Protocol[protocolCount].usesMQTT = true; - Protocol[protocolCount].usesTemplate = true; - Protocol[protocolCount].usesAccount = true; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 1883; - Protocol[protocolCount].usesID = false; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_005; + Protocol[protocolCount].usesMQTT = true; + Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesAccount = true; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 1883; + Protocol[protocolCount].usesID = false; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_005); - break; - } + { + string = F(CPLUGIN_NAME_005); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_mqtt_delay_queue(event->ControllerIndex, CPlugin_005_pubname, CPlugin_005_mqtt_retainFlag); - break; - } + { + success = init_mqtt_delay_queue(event->ControllerIndex, CPlugin_005_pubname, CPlugin_005_mqtt_retainFlag); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_mqtt_delay_queue(); - break; - } + { + exit_mqtt_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: - { - event->String1 = F("%sysname%/#"); - event->String2 = F("%sysname%/%tskname%/%valname%"); - break; - } + { + event->String1 = F("%sysname%/#"); + event->String2 = F("%sysname%/%tskname%/%valname%"); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_RECV: - { - controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005); - if (!validControllerIndex(ControllerID)) { - // Controller is not enabled. - break; + { + controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005); + + if (!validControllerIndex(ControllerID)) { + // Controller is not enabled. + break; + } else { + // FIXME TD-er: Command is not parsed for template arguments. + + // Topic : event->String1 + // Message: event->String2 + String cmd; + bool validTopic = false; + const int lastindex = event->String1.lastIndexOf('/'); + const String lastPartTopic = event->String1.substring(lastindex + 1); + + if (lastPartTopic == F("cmd")) { + // Example: + // topic: ESP_Easy/Bathroom_pir_env/cmd + // data: gpio,14,0 + // Full command: gpio,14,0 + + cmd = event->String2; + + // SP_C005a: string= ;cmd=gpio,12,0 ;taskIndex=12 ;string1=ESPT12/cmd ;string2=gpio,12,0 + validTopic = true; } else { - // FIXME TD-er: Command is not parsed for template arguments. + // Example: + // topic: ESP_Easy/Bathroom_pir_env/GPIO/14 + // data: 0 or 1 + // Full command: gpio,14,0 + if (lastindex > 0) { + // Topic has at least one separator + int lastPartTopic_int; + float value_f; - // Topic : event->String1 - // Message: event->String2 - String cmd; - bool validTopic = false; - const int lastindex = event->String1.lastIndexOf('/'); - const String lastPartTopic = event->String1.substring(lastindex + 1); - if (lastPartTopic == F("cmd")) { - // Example: - // topic: ESP_Easy/Bathroom_pir_env/cmd - // data: gpio,14,0 - // Full command: gpio,14,0 - - cmd = event->String2; -//SP_C005a: string= ;cmd=gpio,12,0 ;taskIndex=12 ;string1=ESPT12/cmd ;string2=gpio,12,0 - validTopic = true; - } else { - // Example: - // topic: ESP_Easy/Bathroom_pir_env/GPIO/14 - // data: 0 or 1 - // Full command: gpio,14,0 - if (lastindex > 0) { - // Topic has at least one separator - int lastPartTopic_int; - float value_f; - if (validFloatFromString(event->String2, value_f) && - validIntFromString(lastPartTopic, lastPartTopic_int)) { - int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1); - cmd = event->String1.substring(prevLastindex + 1, lastindex); - cmd += ','; - cmd += lastPartTopic_int; - cmd += ','; - cmd += event->String2; // Just use the original format - validTopic = true; - } - } - } - if (validTopic) { - // in case of event, store to buffer and return... - String command = parseString(cmd, 1); - if (command == F("event") || command == F("asyncevent")) { - if (Settings.UseRules) { - eventQueue.add(parseStringToEnd(cmd, 2)); - } - } else { - ExecuteCommand(event->TaskIndex, EventValueSource::Enum::VALUE_SOURCE_MQTT, cmd.c_str(), true, true, true); + if (validFloatFromString(event->String2, value_f) && + validIntFromString(lastPartTopic, lastPartTopic_int)) { + int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1); + cmd = event->String1.substring(prevLastindex + 1, lastindex); + cmd += ','; + cmd += lastPartTopic_int; + cmd += ','; + cmd += event->String2; // Just use the original format + validTopic = true; } } } - break; + + if (validTopic) { + // in case of event, store to buffer and return... + String command = parseString(cmd, 1); + + if ((command == F("event")) || (command == F("asyncevent"))) { + if (Settings.UseRules) { + eventQueue.add(parseStringToEnd(cmd, 2)); + } + } else { + ExecuteCommand(event->TaskIndex, EventValueSource::Enum::VALUE_SOURCE_MQTT, cmd.c_str(), true, true, true); + } + } } + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: + { + String pubname = CPlugin_005_pubname; + bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; + + LoadTaskSettings(event->TaskIndex); + parseControllerVariables(pubname, event, false); + + byte valueCount = getValueCountForTask(event->TaskIndex); + + for (byte x = 0; x < valueCount; x++) { - String pubname = CPlugin_005_pubname; - bool mqtt_retainFlag = CPlugin_005_mqtt_retainFlag; - - LoadTaskSettings(event->TaskIndex); - parseControllerVariables(pubname, event, false); - - 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; - 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, 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 } - break; + 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, 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 // ifndef BUILD_NO_DEBUG } + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - processMQTTdelayQueue(); - delay(0); - break; - } + { + processMQTTdelayQueue(); + delay(0); + break; + } default: break; - } return success; } -#endif + +#endif // ifdef USES_C005 diff --git a/src/_C006.ino b/src/_C006.ino index 377255f58..a45f0b9a9 100644 --- a/src/_C006.ino +++ b/src/_C006.ino @@ -1,23 +1,24 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C006 -//####################################################################################################### -//########################### Controller Plugin 006: PiDome MQTT ######################################## -//####################################################################################################### -#include "src/Commands/InternalCommands.h" -#include "src/ESPEasyCore/Controller.h" -#include "src/Globals/ExtraTaskSettings.h" -#include "src/Globals/Settings.h" -#include "src/Helpers/Network.h" -#include "src/Helpers/PeriodicalActions.h" -#include "_Plugin_Helper.h" +// ####################################################################################################### +// ########################### Controller Plugin 006: PiDome MQTT ######################################## +// ####################################################################################################### -#define CPLUGIN_006 -#define CPLUGIN_ID_006 6 -#define CPLUGIN_NAME_006 "PiDome MQTT" +# include "src/Commands/InternalCommands.h" +# include "src/ESPEasyCore/Controller.h" +# include "src/Globals/ExtraTaskSettings.h" +# include "src/Globals/Settings.h" +# include "src/Helpers/Network.h" +# include "src/Helpers/PeriodicalActions.h" +# include "_Plugin_Helper.h" + +# define CPLUGIN_006 +# define CPLUGIN_ID_006 6 +# define CPLUGIN_NAME_006 "PiDome MQTT" String CPlugin_006_pubname; -bool CPlugin_006_mqtt_retainFlag = false; +bool CPlugin_006_mqtt_retainFlag = false; bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& string) @@ -27,121 +28,126 @@ bool CPlugin_006(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_006; - Protocol[protocolCount].usesMQTT = true; - Protocol[protocolCount].usesTemplate = true; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = false; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 1883; - Protocol[protocolCount].usesID = false; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_006; + Protocol[protocolCount].usesMQTT = true; + Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = false; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 1883; + Protocol[protocolCount].usesID = false; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_006); - break; - } + { + string = F(CPLUGIN_NAME_006); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_mqtt_delay_queue(event->ControllerIndex, CPlugin_006_pubname, CPlugin_006_mqtt_retainFlag); - break; - } + { + success = init_mqtt_delay_queue(event->ControllerIndex, CPlugin_006_pubname, CPlugin_006_mqtt_retainFlag); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_mqtt_delay_queue(); - break; - } + { + exit_mqtt_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: - { - event->String1 = F("/Home/#"); - event->String2 = F("/hooks/devices/%id%/SensorData/%valname%"); - break; - } + { + event->String1 = F("/Home/#"); + event->String2 = F("/hooks/devices/%id%/SensorData/%valname%"); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_RECV: - { - // topic structure /Home/Floor/Location/device//gpio/16 - // Split topic into array - String tmpTopic = event->String1.substring(1); - String topicSplit[10]; - int SlashIndex = tmpTopic.indexOf('/'); - byte count = 0; - while (SlashIndex > 0 && count < 10 - 1) - { - topicSplit[count] = tmpTopic.substring(0, SlashIndex); - tmpTopic = tmpTopic.substring(SlashIndex + 1); - SlashIndex = tmpTopic.indexOf('/'); - count++; - } - topicSplit[count] = tmpTopic; + { + // topic structure /Home/Floor/Location/device//gpio/16 + // Split topic into array + String tmpTopic = event->String1.substring(1); + String topicSplit[10]; + int SlashIndex = tmpTopic.indexOf('/'); + byte count = 0; - String name = topicSplit[4]; - if (name == Settings.Name) - { - String cmd = topicSplit[5]; - cmd += ','; - cmd += topicSplit[6].toInt(); // Par1 - cmd += ','; - if (event->String2 == F("false") || event->String2 == F("true")) - { - cmd += (event->String2 == F("true")) ? '1' : '0'; // Par2 - } - else - { - cmd += event->String2; // Par2 - } - ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_MQTT, cmd.c_str()); - } - break; + while (SlashIndex > 0 && count < 10 - 1) + { + topicSplit[count] = tmpTopic.substring(0, SlashIndex); + tmpTopic = tmpTopic.substring(SlashIndex + 1); + SlashIndex = tmpTopic.indexOf('/'); + count++; } + topicSplit[count] = tmpTopic; + + String name = topicSplit[4]; + + if (name == Settings.Name) + { + String cmd = topicSplit[5]; + cmd += ','; + cmd += topicSplit[6].toInt(); // Par1 + cmd += ','; + + if ((event->String2 == F("false")) || (event->String2 == F("true"))) + { + cmd += (event->String2 == F("true")) ? '1' : '0'; // Par2 + } + else + { + cmd += event->String2; // Par2 + } + ExecuteCommand_all(EventValueSource::Enum::VALUE_SOURCE_MQTT, cmd.c_str()); + } + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (!NetworkConnected(10)) { - success = false; - break; - } - String pubname = CPlugin_006_pubname; - bool mqtt_retainFlag = CPlugin_006_mqtt_retainFlag; - - statusLED(true); - - LoadTaskSettings(event->TaskIndex); - parseControllerVariables(pubname, event, false); - - byte valueCount = getValueCountForTask(event->TaskIndex); - for (byte x = 0; x < valueCount; x++) - { - String tmppubname = pubname; - parseSingleControllerVariable(tmppubname, event, x, false); - // 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); - } else { - String value = formatUserVarNoCheck(event, x); - MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); - } - } + { + if (!NetworkConnected(10)) { + success = false; break; } + String pubname = CPlugin_006_pubname; + bool mqtt_retainFlag = CPlugin_006_mqtt_retainFlag; + + statusLED(true); + + LoadTaskSettings(event->TaskIndex); + parseControllerVariables(pubname, event, false); + + byte valueCount = getValueCountForTask(event->TaskIndex); + + for (byte x = 0; x < valueCount; x++) + { + String tmppubname = pubname; + parseSingleControllerVariable(tmppubname, event, x, false); + + // 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); + } else { + String value = formatUserVarNoCheck(event, x); + MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), mqtt_retainFlag); + } + } + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - processMQTTdelayQueue(); - delay(0); - break; - } + { + processMQTTdelayQueue(); + delay(0); + break; + } default: break; - } return success; } -#endif + +#endif // ifdef USES_C006 diff --git a/src/_C007.ino b/src/_C007.ino index eb680347f..0f484b20f 100644 --- a/src/_C007.ino +++ b/src/_C007.ino @@ -1,7 +1,7 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C007 -#include "src/ESPEasyCore/Serial.h" +# include "src/ESPEasyCore/Serial.h" // ####################################################################################################### // ########################### Controller Plugin 007: Emoncms ############################################ diff --git a/src/_C008.ino b/src/_C008.ino index 6e7683e79..559b193c6 100644 --- a/src/_C008.ino +++ b/src/_C008.ino @@ -1,14 +1,15 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C008 -//####################################################################################################### -//########################### Controller Plugin 008: Generic HTTP ####################################### -//####################################################################################################### -#define CPLUGIN_008 -#define CPLUGIN_ID_008 8 -#define CPLUGIN_NAME_008 "Generic HTTP" -#include +// ####################################################################################################### +// ########################### Controller Plugin 008: Generic HTTP ####################################### +// ####################################################################################################### + +# define CPLUGIN_008 +# define CPLUGIN_ID_008 8 +# define CPLUGIN_NAME_008 "Generic HTTP" +# include bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -17,111 +18,113 @@ bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_008; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = true; - Protocol[protocolCount].usesAccount = true; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 80; - Protocol[protocolCount].usesID = true; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_008; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesAccount = true; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 80; + Protocol[protocolCount].usesID = true; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_008); - break; - } + { + string = F(CPLUGIN_NAME_008); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c008_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c008_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c008_delay_queue(); - break; - } + { + exit_c008_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: - { - event->String1 = ""; - event->String2 = F("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"); - break; - } + { + event->String1 = ""; + event->String2 = F("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: + { + if (C008_DelayHandler == nullptr) { + break; + } + + String pubname; { - if (C008_DelayHandler == nullptr) { + // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. + MakeControllerSettings(ControllerSettings); + + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("C008 : Generic HTTP - Cannot send, out of RAM")); break; } - - String pubname; - { - // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - addLog(LOG_LEVEL_ERROR, F("C008 : Generic HTTP - Cannot send, out of RAM")); - break; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - 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)); - if (success) { - // Element was added. - // Now we try to append to the existing element - // and thus preventing the need to create a long string only to copy it to a queue element. - C008_queue_element &element = C008_DelayHandler->sendQueue.back(); - - // Collect the values at the same run, to make sure all are from the same sample - LoadTaskSettings(event->TaskIndex); - parseControllerVariables(pubname, event, true); - - for (byte x = 0; x < valueCount; x++) - { - String tmppubname = pubname; - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - element.txt[x] = "/"; - element.txt[x] += tmppubname; - parseSingleControllerVariable(element.txt[x], event, x, true); - element.txt[x].replace(F("%value%"), formattedValue); -#ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); -#endif - } - } - } - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C008_DELAY_QUEUE, C008_DelayHandler->getNextScheduleTime()); - break; + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + 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)); + + if (success) { + // Element was added. + // Now we try to append to the existing element + // and thus preventing the need to create a long string only to copy it to a queue element. + C008_queue_element& element = C008_DelayHandler->sendQueue.back(); + + // Collect the values at the same run, to make sure all are from the same sample + LoadTaskSettings(event->TaskIndex); + parseControllerVariables(pubname, event, true); + + for (byte x = 0; x < valueCount; x++) + { + String tmppubname = pubname; + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + + if (isvalid) { + element.txt[x] = "/"; + element.txt[x] += tmppubname; + parseSingleControllerVariable(element.txt[x], event, x, true); + element.txt[x].replace(F("%value%"), formattedValue); +# ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); +# endif // ifndef BUILD_NO_DEBUG + } + } + } + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C008_DELAY_QUEUE, C008_DelayHandler->getNextScheduleTime()); + break; + } + case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c008_delay_queue(); - delay(0); - break; - } + { + process_c008_delay_queue(); + delay(0); + break; + } default: break; - } return success; } -//******************************************************************************** +// ******************************************************************************** // Generic HTTP get request -//******************************************************************************** +// ******************************************************************************** // Uncrustify may change this into multi line, which will result in failed builds // *INDENT-OFF* @@ -132,16 +135,21 @@ bool do_process_c008_delay_queue(int controller_number, const C008_queue_element while (element.txt[element.valuesSent] == "") { // A non valid value, which we are not going to send. // Increase sent counter until a valid value is found. - if (element.checkDone(true)) + if (element.checkDone(true)) { return true; + } } WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) - return false; - String request = create_http_request_auth(controller_number, element.controller_idx, ControllerSettings, F("GET"), element.txt[element.valuesSent]); + if (!try_connect_host(controller_number, client, ControllerSettings)) { + return false; + } + + String request = + create_http_request_auth(controller_number, element.controller_idx, ControllerSettings, F("GET"), element.txt[element.valuesSent]); + return element.checkDone(send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply)); } -#endif +#endif // ifdef USES_C008 diff --git a/src/_C009.ino b/src/_C009.ino index 66820bb4b..a1233c742 100644 --- a/src/_C009.ino +++ b/src/_C009.ino @@ -1,8 +1,9 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C009 -//####################################################################################################### -//########################### Controller Plugin 009: FHEM HTTP ########################################## -//####################################################################################################### + +// ####################################################################################################### +// ########################### Controller Plugin 009: FHEM HTTP ########################################## +// ####################################################################################################### /******************************************************************************* * Copyright 2016-2017 dev0 @@ -10,27 +11,27 @@ * https://github.com/ddtlabs/ * * Release notes: - - v1.0 - - changed switch and dimmer setreading cmds - - v1.01 - - added json content to http requests - - v1.02 - - some optimizations as requested by mvdbro - - fixed JSON TaskDeviceValueDecimals handling - - ArduinoJson Library v5.6.4 required (as used by stable R120) - - parse for HTTP errors 400, 401 - - moved on/off translation for Sensor_VType::SENSOR_TYPE_SWITCH/DIMMER to FHEM module - - v1.03 - - changed http request from GET to POST (RFC conform) - - removed obsolete http get url code - - v1.04 - - added build options and node_type_id to JSON/device + - v1.0 + - changed switch and dimmer setreading cmds + - v1.01 + - added json content to http requests + - v1.02 + - some optimizations as requested by mvdbro + - fixed JSON TaskDeviceValueDecimals handling + - ArduinoJson Library v5.6.4 required (as used by stable R120) + - parse for HTTP errors 400, 401 + - moved on/off translation for Sensor_VType::SENSOR_TYPE_SWITCH/DIMMER to FHEM module + - v1.03 + - changed http request from GET to POST (RFC conform) + - removed obsolete http get url code + - v1.04 + - added build options and node_type_id to JSON/device ******************************************************************************/ -#define CPLUGIN_009 -#define CPLUGIN_ID_009 9 -#define CPLUGIN_NAME_009 "FHEM HTTP" -#include +# define CPLUGIN_009 +# define CPLUGIN_ID_009 9 +# define CPLUGIN_NAME_009 "FHEM HTTP" +# include bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -39,64 +40,63 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_009; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = false; - Protocol[protocolCount].usesAccount = true; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].usesID = false; - Protocol[protocolCount].defaultPort = 8383; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_009; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesTemplate = false; + Protocol[protocolCount].usesAccount = true; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].usesID = false; + Protocol[protocolCount].defaultPort = 8383; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_009); - break; - } + { + string = F(CPLUGIN_NAME_009); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c009_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c009_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c009_delay_queue(); - break; - } + { + exit_c009_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C009_DelayHandler == nullptr) { - break; - } - - // FIXME TD-er must define a proper move operator - success = C009_DelayHandler->addToQueue(C009_queue_element(event)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime()); + { + if (C009_DelayHandler == nullptr) { break; } + // FIXME TD-er must define a proper move operator + success = C009_DelayHandler->addToQueue(C009_queue_element(event)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime()); + break; + } + case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c009_delay_queue(); - delay(0); - break; - } + { + process_c009_delay_queue(); + delay(0); + break; + } default: break; - } return success; } /*********************************************************************************************\ - * FHEM HTTP request +* FHEM HTTP request \*********************************************************************************************/ // Uncrustify may change this into multi line, which will result in failed builds @@ -106,28 +106,30 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element bool do_process_c009_delay_queue(int controller_number, const C009_queue_element& element, ControllerSettingsStruct& ControllerSettings) { WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) + + if (!try_connect_host(controller_number, client, ControllerSettings)) { return false; + } LoadTaskSettings(element.TaskIndex); String jsonString; { // Create json root object DynamicJsonDocument root(1024); - root[F("module")] = String(F("ESPEasy")); + root[F("module")] = String(F("ESPEasy")); root[F("version")] = String(F("1.04")); // Create nested objects JsonObject data = root.createNestedObject(String(F("data"))); - JsonObject ESP = data.createNestedObject(String(F("ESP"))); - ESP[F("name")] = Settings.Name; - ESP[F("unit")] = Settings.Unit; - ESP[F("version")] = Settings.Version; - ESP[F("build")] = Settings.Build; - ESP[F("build_notes")] = String(F(BUILD_NOTES)); - ESP[F("build_git")] = String(F(BUILD_GIT)); + JsonObject ESP = data.createNestedObject(String(F("ESP"))); + ESP[F("name")] = Settings.Name; + ESP[F("unit")] = Settings.Unit; + ESP[F("version")] = Settings.Version; + ESP[F("build")] = Settings.Build; + ESP[F("build_notes")] = String(F(BUILD_NOTES)); + ESP[F("build_git")] = String(F(BUILD_GIT)); ESP[F("node_type_id")] = NODE_TYPE_ID; - ESP[F("sleep")] = Settings.deepSleep_wakeTime; + ESP[F("sleep")] = Settings.deepSleep_wakeTime; // embed IP, important if there is NAT/PAT // char ipStr[20]; @@ -137,6 +139,7 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element // Create nested SENSOR json object JsonObject SENSOR = data.createNestedObject(String(F("SENSOR"))); + // char itemNames[valueCount][2]; for (byte x = 0; x < element.valueCount; x++) { @@ -155,10 +158,12 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element // We now create a URI for the request String request = create_http_request_auth( - controller_number, element.controller_idx, ControllerSettings, - F("POST"), F("/ESPEasy"), jsonString.length()); + controller_number, element.controller_idx, ControllerSettings, + F("POST"), F("/ESPEasy"), jsonString.length()); + request += jsonString; return send_via_http(controller_number, client, request, ControllerSettings.MustCheckReply); } -#endif + +#endif // ifdef USES_C009 diff --git a/src/_C010.ino b/src/_C010.ino index 08f537cbf..326dbc837 100644 --- a/src/_C010.ino +++ b/src/_C010.ino @@ -1,12 +1,13 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C010 -//####################################################################################################### -//########################### Controller Plugin 010: Generic UDP ######################################## -//####################################################################################################### -#define CPLUGIN_010 -#define CPLUGIN_ID_010 10 -#define CPLUGIN_NAME_010 "Generic UDP" +// ####################################################################################################### +// ########################### Controller Plugin 010: Generic UDP ######################################## +// ####################################################################################################### + +# define CPLUGIN_010 +# define CPLUGIN_ID_010 10 +# define CPLUGIN_NAME_010 "Generic UDP" bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -15,106 +16,107 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_010; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = true; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = false; - Protocol[protocolCount].defaultPort = 514; - Protocol[protocolCount].usesID = false; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_010; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = false; + Protocol[protocolCount].defaultPort = 514; + Protocol[protocolCount].usesID = false; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_010); - break; - } + { + string = F(CPLUGIN_NAME_010); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: - { - event->String1 = ""; - event->String2 = F("%sysname%_%tskname%_%valname%=%value%"); - break; - } + { + event->String1 = ""; + event->String2 = F("%sysname%_%tskname%_%valname%=%value%"); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c010_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c010_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c010_delay_queue(); - break; - } + { + exit_c010_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C010_DelayHandler == nullptr) { - break; - } - const byte valueCount = getValueCountForTask(event->TaskIndex); - if (valueCount == 0) { - break; - } - - LoadTaskSettings(event->TaskIndex); - C010_queue_element element(event, valueCount); - - { - String pubname; - { - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - break; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - pubname = ControllerSettings.Publish; - } - - parseControllerVariables(pubname, event, false); - - for (byte x = 0; x < valueCount; x++) - { - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - String tmppubname = pubname; - element.txt[x] = tmppubname; - parseSingleControllerVariable(element.txt[x], event, x, false); - element.txt[x].replace(F("%value%"), formattedValue); - addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); - } - } - } - // FIXME TD-er must define a proper move operator - success = C010_DelayHandler->addToQueue(C010_queue_element(element)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C010_DELAY_QUEUE, C010_DelayHandler->getNextScheduleTime()); + { + if (C010_DelayHandler == nullptr) { break; } + const byte valueCount = getValueCountForTask(event->TaskIndex); + + if (valueCount == 0) { + break; + } + + LoadTaskSettings(event->TaskIndex); + C010_queue_element element(event, valueCount); + + { + String pubname; + { + MakeControllerSettings(ControllerSettings); + + if (!AllocatedControllerSettings()) { + break; + } + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + pubname = ControllerSettings.Publish; + } + + parseControllerVariables(pubname, event, false); + + for (byte x = 0; x < valueCount; x++) + { + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + + if (isvalid) { + String tmppubname = pubname; + element.txt[x] = tmppubname; + parseSingleControllerVariable(element.txt[x], event, x, false); + element.txt[x].replace(F("%value%"), formattedValue); + addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); + } + } + } + + // FIXME TD-er must define a proper move operator + success = C010_DelayHandler->addToQueue(C010_queue_element(element)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C010_DELAY_QUEUE, C010_DelayHandler->getNextScheduleTime()); + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c010_delay_queue(); - delay(0); - break; - } + { + process_c010_delay_queue(); + delay(0); + break; + } default: break; - - } return success; } - -//******************************************************************************** +// ******************************************************************************** // Generic UDP message -//******************************************************************************** +// ******************************************************************************** // Uncrustify may change this into multi line, which will result in failed builds // *INDENT-OFF* @@ -125,21 +127,29 @@ bool do_process_c010_delay_queue(int controller_number, const C010_queue_element while (element.txt[element.valuesSent] == "") { // A non valid value, which we are not going to send. // Increase sent counter until a valid value is found. - if (element.checkDone(true)) + if (element.checkDone(true)) { return true; + } } WiFiUDP C010_portUDP; - if (!beginWiFiUDP_randomPort(C010_portUDP)) return false; - if (!try_connect_host(controller_number, C010_portUDP, ControllerSettings)) + + if (!beginWiFiUDP_randomPort(C010_portUDP)) { return false; } + + if (!try_connect_host(controller_number, C010_portUDP, ControllerSettings)) { return false; + } C010_portUDP.write( - (uint8_t*)element.txt[element.valuesSent].c_str(), - element.txt[element.valuesSent].length()); + (uint8_t *)element.txt[element.valuesSent].c_str(), + element.txt[element.valuesSent].length()); bool reply = C010_portUDP.endPacket(); + C010_portUDP.stop(); - if (ControllerSettings.MustCheckReply) + + if (ControllerSettings.MustCheckReply) { return element.checkDone(reply); + } return element.checkDone(true); } -#endif + +#endif // ifdef USES_C010 diff --git a/src/_C011.ino b/src/_C011.ino index c33b25483..a6fb8cdee 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -60,6 +60,7 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& { { MakeControllerSettings(ControllerSettings); + if (AllocatedControllerSettings()) { LoadControllerSettings(event->ControllerIndex, ControllerSettings); C011_sendBinary = ControllerSettings.sendBinary(); @@ -112,9 +113,9 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& } } { - // Place in scope to delete ControllerSettings as soon as it is no longer needed MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addHtmlError(F("Out of memory, cannot load page")); } else { @@ -258,7 +259,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) return false; } - ReplaceTokenByValue(element.uri, event, false); + ReplaceTokenByValue(element.uri, event, false); ReplaceTokenByValue(element.header, event, false); if (element.postStr.length() > 0) diff --git a/src/_C012.ino b/src/_C012.ino index ba4058341..d8afc7559 100644 --- a/src/_C012.ino +++ b/src/_C012.ino @@ -1,16 +1,17 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C012 -//####################################################################################################### -//########################### Controller Plugin 012: Blynk ############################################# -//####################################################################################################### + +// ####################################################################################################### +// ########################### Controller Plugin 012: Blynk ############################################# +// ####################################################################################################### // #ifdef PLUGIN_BUILD_TESTING -#include "src/Commands/Blynk.h" +# include "src/Commands/Blynk.h" -#define CPLUGIN_012 -#define CPLUGIN_ID_012 12 -#define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]" +# define CPLUGIN_012 +# define CPLUGIN_ID_012 12 +# define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]" bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -19,81 +20,82 @@ bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_012; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 80; - Protocol[protocolCount].usesID = true; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_012; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 80; + Protocol[protocolCount].usesID = true; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_012); - break; - } + { + string = F(CPLUGIN_NAME_012); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c012_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c012_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c012_delay_queue(); - break; - } + { + exit_c012_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C012_DelayHandler == nullptr) { - break; - } - LoadTaskSettings(event->TaskIndex); - - // Collect the values at the same run, to make sure all are from the same sample - byte valueCount = getValueCountForTask(event->TaskIndex); - C012_queue_element element(event, valueCount); - - for (byte x = 0; x < valueCount; x++) - { - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - element.txt[x] = F("update/V"); - element.txt[x] += event->idx + x; - element.txt[x] += F("?value="); - element.txt[x] += formattedValue; - addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); - } - } - // FIXME TD-er must define a proper move operator - success = C012_DelayHandler->addToQueue(C012_queue_element(element)); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C012_DELAY_QUEUE, C012_DelayHandler->getNextScheduleTime()); + { + if (C012_DelayHandler == nullptr) { break; } + LoadTaskSettings(event->TaskIndex); + + // Collect the values at the same run, to make sure all are from the same sample + byte valueCount = getValueCountForTask(event->TaskIndex); + C012_queue_element element(event, valueCount); + + for (byte x = 0; x < valueCount; x++) + { + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + + if (isvalid) { + element.txt[x] = F("update/V"); + element.txt[x] += event->idx + x; + element.txt[x] += F("?value="); + element.txt[x] += formattedValue; + addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); + } + } + + // FIXME TD-er must define a proper move operator + success = C012_DelayHandler->addToQueue(C012_queue_element(element)); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C012_DELAY_QUEUE, C012_DelayHandler->getNextScheduleTime()); + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c012_delay_queue(); - delay(0); - break; - } + { + process_c012_delay_queue(); + delay(0); + break; + } default: break; - } return success; } -//******************************************************************************** +// ******************************************************************************** // Process Queued Blynk request, with data set to NULL -//******************************************************************************** +// ******************************************************************************** // Uncrustify may change this into multi line, which will result in failed builds // *INDENT-OFF* @@ -104,14 +106,15 @@ bool do_process_c012_delay_queue(int controller_number, const C012_queue_element while (element.txt[element.valuesSent] == "") { // A non valid value, which we are not going to send. // Increase sent counter until a valid value is found. - if (element.checkDone(true)) + if (element.checkDone(true)) { return true; + } } + if (!NetworkConnected()) { return false; } return element.checkDone(Blynk_get(element.txt[element.valuesSent], element.controller_idx)); } - -#endif +#endif // ifdef USES_C012 diff --git a/src/_C013.ino b/src/_C013.ino index 76615e117..3a91ff8be 100644 --- a/src/_C013.ino +++ b/src/_C013.ino @@ -1,16 +1,16 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C013 -#include "src/Globals/Nodes.h" -#include "src/DataStructs/C013_p2p_dataStructs.h" +# include "src/Globals/Nodes.h" +# include "src/DataStructs/C013_p2p_dataStructs.h" // ####################################################################################################### // ########################### Controller Plugin 013: ESPEasy P2P network ################################ // ####################################################################################################### -#define CPLUGIN_013 -#define CPLUGIN_ID_013 13 -#define CPLUGIN_NAME_013 "ESPEasy P2P Networking" +# define CPLUGIN_013 +# define CPLUGIN_ID_013 13 +# define CPLUGIN_NAME_013 "ESPEasy P2P Networking" WiFiUDP C013_portUDP; @@ -71,18 +71,17 @@ bool CPlugin_013(CPlugin::Function function, struct EventStruct *event, String& break; } - /* - case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c013_delay_queue(event->ControllerIndex); - delay(0); - break; - } - */ + /* + case CPlugin::Function::CPLUGIN_FLUSH: + { + process_c013_delay_queue(event->ControllerIndex); + delay(0); + break; + } + */ default: break; - } return success; } @@ -106,6 +105,7 @@ void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskInde } struct C013_SensorInfoStruct infoReply; + infoReply.sourceUnit = Settings.Unit; infoReply.sourceTaskIndex = sourceTaskIndex; infoReply.destTaskIndex = destTaskIndex; @@ -140,7 +140,8 @@ void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskInde return; } struct C013_SensorDataStruct dataReply; - dataReply.sourceUnit = Settings.Unit; + + dataReply.sourceUnit = Settings.Unit; dataReply.sourceTaskIndex = sourceTaskIndex; dataReply.destTaskIndex = destTaskIndex; @@ -190,14 +191,14 @@ void C013_sendUDP(byte unit, byte *data, byte size) return; } } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { String log = F("C013 : Send UDP message to "); log += unit; addLog(LOG_LEVEL_DEBUG_MORE, log); } -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG statusLED(true); @@ -220,7 +221,7 @@ void C013_sendUDP(byte unit, byte *data, byte size) void C013_Receive(struct EventStruct *event) { if (event->Par2 < 6) { return; } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) { if ((event->Data[1] > 1) && (event->Data[1] < 6)) @@ -235,7 +236,7 @@ void C013_Receive(struct EventStruct *event) { addLog(LOG_LEVEL_DEBUG_MORE, log); } } -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG switch (event->Data[1]) { case 2: // sensor info pull request @@ -248,11 +249,12 @@ void C013_Receive(struct EventStruct *event) { { struct C013_SensorInfoStruct infoReply; int count = sizeof(C013_SensorInfoStruct); + if (event->Par2 < count) { count = event->Par2; } memcpy((byte *)&infoReply, (byte *)event->Data, count); - if (infoReply.isValid()) { + if (infoReply.isValid()) { // to prevent flash wear out (bugs in communication?) we can only write to an empty task // so it will write only once and has to be cleared manually through webgui // Also check the receiving end does support the plugin ID. @@ -267,6 +269,7 @@ void C013_Receive(struct EventStruct *event) { Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false; } safe_strncpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName, sizeof(infoReply.taskName)); + for (byte x = 0; x < VARS_PER_TASK; x++) { safe_strncpy(ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x], sizeof(infoReply.ValueNames[x])); } @@ -288,10 +291,11 @@ void C013_Receive(struct EventStruct *event) { { struct C013_SensorDataStruct dataReply; int count = sizeof(C013_SensorDataStruct); + if (event->Par2 < count) { count = event->Par2; } memcpy((byte *)&dataReply, (byte *)event->Data, count); - if (dataReply.isValid()) { + if (dataReply.isValid()) { // only if this task has a remote feed, update values const byte remoteFeed = Settings.TaskDeviceDataFeed[dataReply.destTaskIndex]; diff --git a/src/_C015.ino b/src/_C015.ino index 13e287530..32a1fce8e 100644 --- a/src/_C015.ino +++ b/src/_C015.ino @@ -1,13 +1,13 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C015 -#include "src/Globals/CPlugins.h" -#include "src/Commands/Common.h" +# include "src/Globals/CPlugins.h" +# include "src/Commands/Common.h" -//####################################################################################################### -//########################### Controller Plugin 015: Blynk ############################################# -//####################################################################################################### +// ####################################################################################################### +// ########################### Controller Plugin 015: Blynk ############################################# +// ####################################################################################################### // This plugin provides blynk native protocol. This makes possible receive callbacks from user // like button press, slider move etc. @@ -24,28 +24,28 @@ // Also it requires valid server thumbprint string to be entered in plugin settings. // #define CPLUGIN_015_SSL -#define CPLUGIN_015 -#define CPLUGIN_ID_015 15 -#define _BLYNK_USE_DEFAULT_FREE_RAM -#define BLYNK_TIMEOUT_MS 2000UL -#define BLYNK_HEARTBEAT 30 -#define CPLUGIN_015_RECONNECT_INTERVAL 60000 +# define CPLUGIN_015 +# define CPLUGIN_ID_015 15 +# define _BLYNK_USE_DEFAULT_FREE_RAM +# define BLYNK_TIMEOUT_MS 2000UL +# define BLYNK_HEARTBEAT 30 +# define CPLUGIN_015_RECONNECT_INTERVAL 60000 -#ifdef CPLUGIN_015_SSL - #include - #define CPLUGIN_NAME_015 "Blynk SSL [TESTING]" - // 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" - #define C015_LOG_PREFIX "BL (ssl): " -#else - #include - #define CPLUGIN_NAME_015 "Blynk [TESTING]" - #define C015_LOG_PREFIX "BL: " -#endif +# ifdef CPLUGIN_015_SSL + # include + # define CPLUGIN_NAME_015 "Blynk SSL [TESTING]" + +// 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" + # define C015_LOG_PREFIX "BL (ssl): " +# else // ifdef CPLUGIN_015_SSL + # include + # define CPLUGIN_NAME_015 "Blynk [TESTING]" + # define C015_LOG_PREFIX "BL: " +# endif // ifdef CPLUGIN_015_SSL - -static unsigned long _C015_LastConnectAttempt[CONTROLLER_MAX] = {0,0,0}; +static unsigned long _C015_LastConnectAttempt[CONTROLLER_MAX] = { 0, 0, 0 }; void CPlugin_015_handleInterrupt() { // This cplugin uses modified blynk library. @@ -54,14 +54,13 @@ void CPlugin_015_handleInterrupt() { backgroundtasks(); } - -void Blynk_Run_c015(){ - // user callbacks processing. Called from run10TimesPerSecond. - if (Blynk.connected()) - Blynk.run(); +void Blynk_Run_c015() { + // user callbacks processing. Called from run10TimesPerSecond. + if (Blynk.connected()) { + Blynk.run(); + } } - bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& string) { bool success = false; @@ -69,156 +68,167 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_015; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = true; - Protocol[protocolCount].usesExtCreds = true; - Protocol[protocolCount].defaultPort = 80; - Protocol[protocolCount].usesID = false; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_015; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = true; + Protocol[protocolCount].usesExtCreds = true; + Protocol[protocolCount].defaultPort = 80; + Protocol[protocolCount].usesID = false; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_015); - break; - } + { + string = F(CPLUGIN_NAME_015); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c015_delay_queue(event->ControllerIndex); + { + success = init_c015_delay_queue(event->ControllerIndex); - // when connected to another server and user has changed settings - if (success && Blynk.connected()){ - addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "disconnect from server")); - Blynk.disconnect(); - } - break; + // when connected to another server and user has changed settings + if (success && Blynk.connected()) { + addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "disconnect from server")); + Blynk.disconnect(); } + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c015_delay_queue(); - break; - } + { + exit_c015_delay_queue(); + break; + } - #ifdef CPLUGIN_015_SSL - case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: - { - char thumbprint[60]; - LoadCustomControllerSettings(event->ControllerIndex,(byte*)&thumbprint, sizeof(thumbprint)); - if (strlen(thumbprint) != 59) - strcpy(thumbprint, CPLUGIN_015_DEFAULT_THUMBPRINT); - addFormTextBox(F("Server thumbprint string"), F("c015_thumbprint"), thumbprint, 60); - success = true; - break; - } - #endif + # ifdef CPLUGIN_015_SSL + case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: + { + char thumbprint[60]; + LoadCustomControllerSettings(event->ControllerIndex, (byte *)&thumbprint, sizeof(thumbprint)); + + if (strlen(thumbprint) != 59) { + strcpy(thumbprint, CPLUGIN_015_DEFAULT_THUMBPRINT); + } + addFormTextBox(F("Server thumbprint string"), F("c015_thumbprint"), thumbprint, 60); + success = true; + break; + } + # endif // ifdef CPLUGIN_015_SSL case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: - { - success = true; - if (isFormItemChecked(F("controllerenabled"))){ - for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i); - if (validProtocolIndex(ProtocolIndex)) { - if (i != event->ControllerIndex && Protocol[ProtocolIndex].Number == 15 && Settings.ControllerEnabled[i]) { - success = false; - // FIXME: this will only show a warning message and not uncheck "enabled" in webform. - // Webserver object is not checking result of "success" var :( - addHtmlError(F("Only one enabled instance of blynk controller is supported")); - break; - } + { + success = true; + + if (isFormItemChecked(F("controllerenabled"))) { + for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { + protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i); + + if (validProtocolIndex(ProtocolIndex)) { + if ((i != event->ControllerIndex) && (Protocol[ProtocolIndex].Number == 15) && Settings.ControllerEnabled[i]) { + success = false; + + // FIXME: this will only show a warning message and not uncheck "enabled" in webform. + // Webserver object is not checking result of "success" var :( + addHtmlError(F("Only one enabled instance of blynk controller is supported")); + break; } } - // force to connect without delay when webform saved - _C015_LastConnectAttempt[event->ControllerIndex] = 0; - - #ifdef CPLUGIN_015_SSL - char thumbprint[60]; - String error = F("Specify server thumbprint with exactly 59 symbols string like " CPLUGIN_015_DEFAULT_THUMBPRINT); - if (!safe_strncpy(thumbprint, web_server.arg("c015_thumbprint"), 60) || strlen(thumbprint) != 59) { - addHtmlError(error); - } - SaveCustomControllerSettings(event->ControllerIndex,(byte*)&thumbprint, sizeof(thumbprint)); - #endif } + + // force to connect without delay when webform saved + _C015_LastConnectAttempt[event->ControllerIndex] = 0; + + # ifdef CPLUGIN_015_SSL + char thumbprint[60]; + String error = F("Specify server thumbprint with exactly 59 symbols string like " CPLUGIN_015_DEFAULT_THUMBPRINT); + + if (!safe_strncpy(thumbprint, web_server.arg("c015_thumbprint"), 60) || (strlen(thumbprint) != 59)) { + addHtmlError(error); + } + SaveCustomControllerSettings(event->ControllerIndex, (byte *)&thumbprint, sizeof(thumbprint)); + # endif // ifdef CPLUGIN_015_SSL + } + break; + } + + case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: + { + if (C015_DelayHandler == nullptr) { break; } - case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - if (C015_DelayHandler == nullptr) { - break; - } - - if (!Settings.ControllerEnabled[event->ControllerIndex]) - break; - - // 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)); - if (success) { - // Element was added. - // Now we try to append to the existing element - // and thus preventing the need to create a long string only to copy it to a queue element. - C015_queue_element &element = C015_DelayHandler->sendQueue.back(); - LoadTaskSettings(event->TaskIndex); - - for (byte x = 0; x < valueCount; x++) - { - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (!isvalid) - // send empty string to Blynk in case of error - formattedValue = F(""); - - String valueName = ExtraTaskSettings.TaskDeviceValueNames[x]; - String valueFullName = ExtraTaskSettings.TaskDeviceName; - valueFullName += F("."); - valueFullName += valueName; - String vPinNumberStr = valueName.substring(1, 4); - int vPinNumber = vPinNumberStr.toInt(); - String log = F(C015_LOG_PREFIX); - log += Blynk.connected()? F("(online): ") : F("(offline): "); - if (vPinNumber > 0 && vPinNumber < 256){ - log += F("send "); - log += valueFullName; - log += F(" = "); - log += formattedValue; - log += F(" to blynk pin v"); - log += vPinNumber; - } - else{ - vPinNumber = -1; - log += F("error got vPin number for "); - log += valueFullName; - log += F(", got not valid value: "); - log += vPinNumberStr; - } - addLog(LOG_LEVEL_INFO, log); - element.vPin[x] = vPinNumber; - element.txt[x] = formattedValue; - } - } - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C015_DELAY_QUEUE, C015_DelayHandler->getNextScheduleTime()); + if (!Settings.ControllerEnabled[event->ControllerIndex]) { break; } + // 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)); + + if (success) { + // Element was added. + // Now we try to append to the existing element + // and thus preventing the need to create a long string only to copy it to a queue element. + C015_queue_element& element = C015_DelayHandler->sendQueue.back(); + LoadTaskSettings(event->TaskIndex); + + for (byte x = 0; x < valueCount; x++) + { + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + + if (!isvalid) { + // send empty string to Blynk in case of error + formattedValue = F(""); + } + + String valueName = ExtraTaskSettings.TaskDeviceValueNames[x]; + String valueFullName = ExtraTaskSettings.TaskDeviceName; + valueFullName += F("."); + valueFullName += valueName; + String vPinNumberStr = valueName.substring(1, 4); + int vPinNumber = vPinNumberStr.toInt(); + String log = F(C015_LOG_PREFIX); + log += Blynk.connected() ? F("(online): ") : F("(offline): "); + + if ((vPinNumber > 0) && (vPinNumber < 256)) { + log += F("send "); + log += valueFullName; + log += F(" = "); + log += formattedValue; + log += F(" to blynk pin v"); + log += vPinNumber; + } + else { + vPinNumber = -1; + log += F("error got vPin number for "); + log += valueFullName; + log += F(", got not valid value: "); + log += vPinNumberStr; + } + addLog(LOG_LEVEL_INFO, log); + element.vPin[x] = vPinNumber; + element.txt[x] = formattedValue; + } + } + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C015_DELAY_QUEUE, C015_DelayHandler->getNextScheduleTime()); + break; + } + default: break; - } return success; } -//******************************************************************************** +// ******************************************************************************** // Process Queued Blynk request, with data set to NULL -//******************************************************************************** +// ******************************************************************************** // controller_plugin_number = 015 because of C015 // Uncrustify may change this into multi line, which will result in failed builds @@ -226,140 +236,148 @@ bool CPlugin_015(CPlugin::Function function, struct EventStruct *event, String& bool do_process_c015_delay_queue(int controller_plugin_number, const C015_queue_element& element, ControllerSettingsStruct& ControllerSettings); // *INDENT-ON* -bool do_process_c015_delay_queue(int controller_plugin_number, const C015_queue_element& element, ControllerSettingsStruct& ControllerSettings) { - if (!Settings.ControllerEnabled[element.controller_idx]) +bool do_process_c015_delay_queue(int controller_plugin_number, const C015_queue_element& element, + ControllerSettingsStruct& ControllerSettings) { + if (!Settings.ControllerEnabled[element.controller_idx]) { // controller has been disabled. Answer true to flush queue. return true; + } if (!NetworkConnected()) { return false; } - if (!Blynk_keep_connection_c015(element.controller_idx, ControllerSettings)) + if (!Blynk_keep_connection_c015(element.controller_idx, ControllerSettings)) { return false; + } while (element.vPin[element.valuesSent] == -1) { - // A non valid value, which we are not going to send. - // answer ok and skip real sending - if (element.checkDone(true)) + // A non valid value, which we are not going to send. + // answer ok and skip real sending + if (element.checkDone(true)) { return true; + } } bool sendSuccess = Blynk_send_c015( - element.txt[element.valuesSent], + element.txt[element.valuesSent], element.vPin[element.valuesSent], ControllerSettings.ClientTimeout); + return element.checkDone(sendSuccess); } - -boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct& ControllerSettings){ - if (!NetworkConnected()) +boolean Blynk_keep_connection_c015(int controllerIndex, ControllerSettingsStruct& ControllerSettings) { + if (!NetworkConnected()) { return false; + } - if (!Blynk.connected()){ - String auth = getControllerPass(controllerIndex, ControllerSettings); + if (!Blynk.connected()) { + String auth = getControllerPass(controllerIndex, ControllerSettings); boolean connectDefault = false; - if (timePassedSince(_C015_LastConnectAttempt[controllerIndex]) < CPLUGIN_015_RECONNECT_INTERVAL){ - //"skip connect to blynk server too often. Wait a little..."; + if (timePassedSince(_C015_LastConnectAttempt[controllerIndex]) < CPLUGIN_015_RECONNECT_INTERVAL) { + // "skip connect to blynk server too often. Wait a little..."; return false; } _C015_LastConnectAttempt[controllerIndex] = millis(); - #ifdef CPLUGIN_015_SSL - char thumbprint[60]; - LoadCustomControllerSettings(controllerIndex,(byte*)&thumbprint, sizeof(thumbprint)); - if (strlen(thumbprint) != 59){ - addLog(LOG_LEVEL_INFO, C015_LOG_PREFIX "Saved thumprint value is not correct:"); - addLog(LOG_LEVEL_INFO, thumbprint); - strcpy(thumbprint, CPLUGIN_015_DEFAULT_THUMBPRINT); - addLog(LOG_LEVEL_INFO, C015_LOG_PREFIX "using default one:"); - addLog(LOG_LEVEL_INFO, thumbprint); - } - #endif + # ifdef CPLUGIN_015_SSL + char thumbprint[60]; + LoadCustomControllerSettings(controllerIndex, (byte *)&thumbprint, sizeof(thumbprint)); + + if (strlen(thumbprint) != 59) { + addLog(LOG_LEVEL_INFO, C015_LOG_PREFIX "Saved thumprint value is not correct:"); + addLog(LOG_LEVEL_INFO, thumbprint); + strcpy(thumbprint, CPLUGIN_015_DEFAULT_THUMBPRINT); + addLog(LOG_LEVEL_INFO, C015_LOG_PREFIX "using default one:"); + addLog(LOG_LEVEL_INFO, thumbprint); + } + # endif // ifdef CPLUGIN_015_SSL String log = F(C015_LOG_PREFIX); - if (ControllerSettings.UseDNS){ + if (ControllerSettings.UseDNS) { String hostName = ControllerSettings.getHost(); - if (hostName.length() != 0){ + + if (hostName.length() != 0) { log += F("Connecting to custom blynk server "); log += ControllerSettings.getHostPortString(); Blynk.config(auth.c_str(), CPlugin_015_handleInterrupt, hostName.c_str(), ControllerSettings.Port - #ifdef CPLUGIN_015_SSL - ,thumbprint - #endif - ); + # ifdef CPLUGIN_015_SSL + , thumbprint + # endif // ifdef CPLUGIN_015_SSL + ); } - else{ - log += F("Custom blynk server name not specified. "); + else { + log += F("Custom blynk server name not specified. "); connectDefault = true; } } - else{ + else { IPAddress ip = ControllerSettings.getIP(); - if ((ip[0] + ip[1] + ip[2] + ip[3]) > 0){ + + if ((ip[0] + ip[1] + ip[2] + ip[3]) > 0) { log += F("Connecting to custom blynk server "); log += ControllerSettings.getHostPortString(); Blynk.config(auth.c_str(), CPlugin_015_handleInterrupt, ip, ControllerSettings.Port - #ifdef CPLUGIN_015_SSL - ,thumbprint - #endif - ); + # ifdef CPLUGIN_015_SSL + , thumbprint + # endif // ifdef CPLUGIN_015_SSL + ); } - else{ - log += F("Custom blynk server ip not specified. "); + else { + log += F("Custom blynk server ip not specified. "); connectDefault = true; } } addLog(LOG_LEVEL_INFO, log); - if (connectDefault){ + if (connectDefault) { addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "Connecting to default server")); Blynk.config(auth.c_str(), CPlugin_015_handleInterrupt, BLYNK_DEFAULT_DOMAIN - #ifdef CPLUGIN_015_SSL - ,BLYNK_DEFAULT_PORT_SSL - ,thumbprint - #else - ,BLYNK_DEFAULT_PORT - #endif - ); + # ifdef CPLUGIN_015_SSL + , BLYNK_DEFAULT_PORT_SSL + , thumbprint + # else // ifdef CPLUGIN_015_SSL + , BLYNK_DEFAULT_PORT + # endif // ifdef CPLUGIN_015_SSL + ); } - #ifdef CPLUGIN_015_SSL - if (!Blynk.connect()){ - if (!_blynkWifiClient.verify(thumbprint, BLYNK_DEFAULT_DOMAIN)){ - addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "thumbprint check FAILED! Check thumbprint in device settings and server thumbprint")); - addLog(LOG_LEVEL_INFO, thumbprint); - } + # ifdef CPLUGIN_015_SSL + + if (!Blynk.connect()) { + if (!_blynkWifiClient.verify(thumbprint, BLYNK_DEFAULT_DOMAIN)) { + addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "thumbprint check FAILED! Check thumbprint in device settings and server thumbprint")); + addLog(LOG_LEVEL_INFO, thumbprint); } - #else - Blynk.connect(); - #endif + } + # else // ifdef CPLUGIN_015_SSL + Blynk.connect(); + # endif // ifdef CPLUGIN_015_SSL } return Blynk.connected(); } - -String Command_Blynk_Set_c015(struct EventStruct *event, const char* Line){ - +String Command_Blynk_Set_c015(struct EventStruct *event, const char *Line) { // todo add multicontroller support and chek it is connected and enabled - if (!Blynk.connected()) - return F("Not connected to blynk server"); + if (!Blynk.connected()) { + return F("Not connected to blynk server"); + } int vPin = event->Par1; - if ((vPin < 0) || (vPin > 255)){ + if ((vPin < 0) || (vPin > 255)) { String err = F("Not correct blynk vPin number "); err += vPin; return err; @@ -367,13 +385,14 @@ String Command_Blynk_Set_c015(struct EventStruct *event, const char* Line){ String data = parseString(Line, 3); - if (data.length() == 0){ + if (data.length() == 0) { String err = F("Skip sending empty data to blynk vPin "); err += vPin; return err; } String log = F(C015_LOG_PREFIX "(online): send blynk pin v"); + log += vPin; log += F(" = "); log += data; @@ -383,21 +402,23 @@ String Command_Blynk_Set_c015(struct EventStruct *event, const char* Line){ return return_command_success(); } - boolean Blynk_send_c015(const String& value, int vPin, unsigned int clientTimeout) { Blynk.virtualWrite(vPin, value); - + unsigned long timer = millis() + clientTimeout; - while (!timeOutReached(timer)) - backgroundtasks(); + + while (!timeOutReached(timer)) { + backgroundtasks(); + } return true; } // This is called for all virtual pins, that don't have BLYNK_WRITE handler BLYNK_WRITE_DEFAULT() { - byte vPin = request.pin; + byte vPin = request.pin; float pinValue = param.asFloat(); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F(C015_LOG_PREFIX "server set v"); log += vPin; @@ -405,6 +426,7 @@ BLYNK_WRITE_DEFAULT() { log += pinValue; addLog(LOG_LEVEL_INFO, log); } + if (Settings.UseRules) { String eventCommand = F("blynkv"); eventCommand += vPin; @@ -422,6 +444,7 @@ BLYNK_CONNECTED() { String eventCommand = F("blynk_connected"); eventQueue.add(eventCommand); } + // addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "connected handler")); } @@ -431,6 +454,7 @@ BLYNK_APP_CONNECTED() { String eventCommand = F("blynk_app_connected"); eventQueue.add(eventCommand); } + // addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "app connected handler")); } @@ -440,7 +464,8 @@ BLYNK_APP_DISCONNECTED() { String eventCommand = F("blynk_app_disconnected"); eventQueue.add(eventCommand); } + // addLog(LOG_LEVEL_INFO, F(C015_LOG_PREFIX "app disconnected handler")); } -#endif +#endif // ifdef USES_C015 diff --git a/src/_C016.ino b/src/_C016.ino index d62e18fbf..e4b62dc94 100644 --- a/src/_C016.ino +++ b/src/_C016.ino @@ -1,37 +1,39 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C016 -//####################################################################################################### -//########################### Controller Plugin 016: Controller - Cache ################################# -//####################################################################################################### + +// ####################################################################################################### +// ########################### Controller Plugin 016: Controller - Cache ################################# +// ####################################################################################################### /* -This is a cache layer to collect data while not connected to a network. -The data will first be stored in RTC memory, which will survive a crash/reboot and even an OTA update. -If this RTC buffer is full, it will be flushed to whatever is set here as storage. + This is a cache layer to collect data while not connected to a network. + The data will first be stored in RTC memory, which will survive a crash/reboot and even an OTA update. + If this RTC buffer is full, it will be flushed to whatever is set here as storage. -Typical sample sets contain: -- UNIX timestamp -- task index delivering the data -- 4 float values + Typical sample sets contain: + - UNIX timestamp + - task index delivering the data + - 4 float values -These are the result of any plugin sending data to this controller. + These are the result of any plugin sending data to this controller. -The controller can save the samples from RTC memory to several places on the flash: -- Files on FS -- Part reserved for OTA update (TODO) -- Unused flash after the partitioned space (TODO) + The controller can save the samples from RTC memory to several places on the flash: + - Files on FS + - Part reserved for OTA update (TODO) + - Unused flash after the partitioned space (TODO) -The controller can deliver the data to: - -*/ + The controller can deliver the data to: + + */ -#include "src/Globals/C016_ControllerCache.h" -#include "src/Globals/ESPEasy_time.h" +# include "src/Globals/C016_ControllerCache.h" +# include "src/Globals/ESPEasy_time.h" -#define CPLUGIN_016 -#define CPLUGIN_ID_016 16 -#define CPLUGIN_NAME_016 "Cache Controller [Experimental]" -//#include +# define CPLUGIN_016 +# define CPLUGIN_ID_016 16 +# define CPLUGIN_NAME_016 "Cache Controller [Experimental]" + +// #include bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& string) { @@ -40,98 +42,94 @@ bool CPlugin_016(CPlugin::Function function, struct EventStruct *event, String& switch (function) { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: - { - Protocol[++protocolCount].Number = CPLUGIN_ID_016; - Protocol[protocolCount].usesMQTT = false; - Protocol[protocolCount].usesTemplate = true; - Protocol[protocolCount].usesAccount = false; - Protocol[protocolCount].usesPassword = false; - Protocol[protocolCount].defaultPort = 80; - Protocol[protocolCount].usesID = false; - Protocol[protocolCount].usesHost = false; - Protocol[protocolCount].usesPort = false; - Protocol[protocolCount].usesSampleSets = false; - Protocol[protocolCount].needsNetwork = false; - break; - } + { + Protocol[++protocolCount].Number = CPLUGIN_ID_016; + Protocol[protocolCount].usesMQTT = false; + Protocol[protocolCount].usesTemplate = true; + Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesPassword = false; + Protocol[protocolCount].defaultPort = 80; + Protocol[protocolCount].usesID = false; + Protocol[protocolCount].usesHost = false; + Protocol[protocolCount].usesPort = false; + Protocol[protocolCount].usesSampleSets = false; + Protocol[protocolCount].needsNetwork = false; + break; + } case CPlugin::Function::CPLUGIN_GET_DEVICENAME: - { - string = F(CPLUGIN_NAME_016); - break; - } + { + string = F(CPLUGIN_NAME_016); + break; + } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c016_delay_queue(event->ControllerIndex); - ControllerCache.init(); - break; - } + { + success = init_c016_delay_queue(event->ControllerIndex); + ControllerCache.init(); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c016_delay_queue(); - break; - } + { + exit_c016_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: - { - - break; - } + { + break; + } case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: - { - - break; - } + { + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE: - { - event->String1 = ""; - event->String2 = ""; - break; - } + { + event->String1 = ""; + event->String2 = ""; + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { - // Collect the values at the same run, to make sure all are from the same sample - byte valueCount = getValueCountForTask(event->TaskIndex); - C016_queue_element element(event, valueCount, node_time.getUnixTime()); - success = ControllerCache.write((uint8_t*)&element, sizeof(element)); + { + // Collect the values at the same run, to make sure all are from the same sample + byte valueCount = getValueCountForTask(event->TaskIndex); + C016_queue_element element(event, valueCount, node_time.getUnixTime()); + success = ControllerCache.write((uint8_t *)&element, sizeof(element)); -/* - if (C016_DelayHandler == nullptr) { - break; - } + /* + if (C016_DelayHandler == nullptr) { + break; + } - MakeControllerSettings(ControllerSettings); - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - success = C016_DelayHandler->addToQueue(element); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C016_DELAY_QUEUE, C016_DelayHandler->getNextScheduleTime()); -*/ - break; - } + MakeControllerSettings(ControllerSettings); + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + success = C016_DelayHandler->addToQueue(element); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C016_DELAY_QUEUE, + C016_DelayHandler->getNextScheduleTime()); + */ + break; + } case CPlugin::Function::CPLUGIN_FLUSH: - { - process_c016_delay_queue(); - delay(0); - break; - } + { + process_c016_delay_queue(); + delay(0); + break; + } default: break; - } return success; } - - -//******************************************************************************** +// ******************************************************************************** // Process the data from the cache -//******************************************************************************** +// ******************************************************************************** // Uncrustify may change this into multi line, which will result in failed builds // *INDENT-OFF* bool do_process_c016_delay_queue(int controller_number, const C016_queue_element& element, ControllerSettingsStruct& ControllerSettings); @@ -139,6 +137,7 @@ bool do_process_c016_delay_queue(int controller_number, const C016_queue_element bool do_process_c016_delay_queue(int controller_number, const C016_queue_element& element, ControllerSettingsStruct& ControllerSettings) { return true; + // FIXME TD-er: Hand over data to wherever it needs to be. // Ideas: // - Upload bin files to some server (HTTP post?) @@ -148,5 +147,4 @@ bool do_process_c016_delay_queue(int controller_number, const C016_queue_element // - Feed it to some plugin (e.g. a display to show a chart) } - -#endif +#endif // ifdef USES_C016 diff --git a/src/_C017.ino b/src/_C017.ino index 1e60054c5..a1ef7097f 100644 --- a/src/_C017.ino +++ b/src/_C017.ino @@ -1,8 +1,9 @@ #include "src/Helpers/_CPlugin_Helper.h" #ifdef USES_C017 -//####################################################################################################### -//########################### Controller Plugin 017: ZABBIX ########################################## -//####################################################################################################### + +// ####################################################################################################### +// ########################### Controller Plugin 017: ZABBIX ########################################## +// ####################################################################################################### // Based on https://www.zabbix.com/documentation/current/manual/appendix/items/trapper // and https://www.zabbix.com/documentation/4.2/manual/appendix/protocols/header_datalen @@ -16,12 +17,12 @@ // Aslo make sure that you enable send to controller (under Data Acquisition in tasks) // and set an interval because you need to actively send the data to Zabbix -#define CPLUGIN_017 -#define CPLUGIN_ID_017 17 -#define CPLUGIN_NAME_017 "Zabbix" -#include +# define CPLUGIN_017 +# define CPLUGIN_ID_017 17 +# define CPLUGIN_NAME_017 "Zabbix" +# include -bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String &string) +bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String& string) { bool success = false; @@ -29,13 +30,13 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & { case CPlugin::Function::CPLUGIN_PROTOCOL_ADD: { - Protocol[++protocolCount].Number = CPLUGIN_ID_017; - Protocol[protocolCount].usesMQTT = false; + Protocol[++protocolCount].Number = CPLUGIN_ID_017; + Protocol[protocolCount].usesMQTT = false; Protocol[protocolCount].usesTemplate = false; - Protocol[protocolCount].usesAccount = false; + Protocol[protocolCount].usesAccount = false; Protocol[protocolCount].usesPassword = false; - Protocol[protocolCount].usesID = false; - Protocol[protocolCount].defaultPort = 10051; + Protocol[protocolCount].usesID = false; + Protocol[protocolCount].defaultPort = 10051; break; } @@ -46,22 +47,23 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c017_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c017_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c017_delay_queue(); - break; - } + { + exit_c017_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: - { + { if (C017_DelayHandler == nullptr) { break; } + // FIXME TD-er must define a proper move operator success = C017_DelayHandler->addToQueue(C017_queue_element(event)); Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C017_DELAY_QUEUE, C017_DelayHandler->getNextScheduleTime()); @@ -77,7 +79,6 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & default: break; - } return success; } @@ -87,10 +88,11 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & bool do_process_c017_delay_queue(int controller_number, const C017_queue_element &element, ControllerSettingsStruct &ControllerSettings); // *INDENT-ON* -bool do_process_c017_delay_queue(int controller_number, const C017_queue_element &element, ControllerSettingsStruct &ControllerSettings) +bool do_process_c017_delay_queue(int controller_number, const C017_queue_element& element, ControllerSettingsStruct& ControllerSettings) { - if (element.valueCount == 0) - return true; //exit if we don't have anything to send. + if (element.valueCount == 0) { + return true; // exit if we don't have anything to send. + } if (!NetworkConnected(10)) { @@ -98,7 +100,8 @@ bool do_process_c017_delay_queue(int controller_number, const C017_queue_element } WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings, F("ZBX : "))) + + if (!try_connect_host(controller_number, client, ControllerSettings, F("ZBX : "))) { return false; } @@ -114,17 +117,19 @@ bool do_process_c017_delay_queue(int controller_number, const C017_queue_element // Create the schafolding root[F("request")] = F("sender data"); JsonArray data = root.createNestedArray(F("data")); + // Populate JSON with the data for (uint8_t i = 0; i < element.valueCount; i++) { - if (ExtraTaskSettings.TaskDeviceValueNames[i][0] == 0) - continue; //Zabbix will ignore an empty key anyway + if (ExtraTaskSettings.TaskDeviceValueNames[i][0] == 0) { + continue; // Zabbix will ignore an empty key anyway + } JsonObject block = data.createNestedObject(); - block[F("host")] = Settings.Name; // Zabbix hostname, Unit Name for the ESP easy - block[F("key")] = ExtraTaskSettings.TaskDeviceValueNames[i]; // Zabbix item key // Value Name for the ESP easy + block[F("host")] = Settings.Name; // Zabbix hostname, Unit Name for the ESP easy + block[F("key")] = ExtraTaskSettings.TaskDeviceValueNames[i]; // Zabbix item key // Value Name for the ESP easy float value = 0.0f; validFloatFromString(element.txt[i], value); - block[F("value")] = value; // ESPeasy supports only floats + block[F("value")] = value; // ESPeasy supports only floats } serializeJson(root, JSON_packet_content); } @@ -133,14 +138,15 @@ bool do_process_c017_delay_queue(int controller_number, const C017_queue_element char packet_header[] = "ZBXD\1"; uint64_t payload_len = JSON_packet_content.length(); - + // addLog(LOG_LEVEL_INFO, String(F("ZBX: ")) + JSON_packet_content); // Send the packet - client.write(packet_header, sizeof(packet_header) - 1); - client.write((char *)&payload_len, sizeof(payload_len)); + client.write(packet_header, sizeof(packet_header) - 1); + client.write((char *)&payload_len, sizeof(payload_len)); client.write(JSON_packet_content.c_str(), payload_len); client.stop(); return true; } -#endif + +#endif // ifdef USES_C017 diff --git a/src/_C018.ino b/src/_C018.ino index 9c585a189..561835ad8 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -337,9 +337,7 @@ private: } void triggerAutobaud() { - if ((C018_easySerial == nullptr) || (myLora == nullptr)) { - return; - } + if ((C018_easySerial == nullptr) || (myLora == nullptr)) {} int retries = 2; while (retries > 0 && !autobaud_success) { @@ -482,7 +480,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_SHOW_HOST_CONFIG: { - if (C018_data != nullptr && C018_data->isInitialized()) { + if ((C018_data != nullptr) && C018_data->isInitialized()) { string = F("Dev addr: "); string += C018_data->getDevaddr(); string += C018_data->useOTAA() ? F(" (OTAA)") : F(" (ABP)"); @@ -560,8 +558,10 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& { 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) + + if (C018_data != nullptr) { deveui_note += C018_data->hweui(); + } addFormNote(deveui_note, F("deveui_note")); } @@ -716,10 +716,12 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& if (C018_DelayHandler == nullptr) { break; } + if (C018_data != nullptr) { success = C018_DelayHandler->addToQueue( C018_queue_element(event, C018_data->getSampleSetCount(event->TaskIndex))); - Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C018_DELAY_QUEUE, C018_DelayHandler->getNextScheduleTime()); + Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C018_DELAY_QUEUE, + C018_DelayHandler->getNextScheduleTime()); if (!C018_data->isInitialized()) { // Sometimes the module does need some time after power on to respond. @@ -741,8 +743,9 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_FIFTY_PER_SECOND: { - if (C018_data != nullptr) + if (C018_data != nullptr) { C018_data->async_loop(); + } // FIXME TD-er: Handle reading error state or return values. break; @@ -766,8 +769,10 @@ bool C018_init(struct EventStruct *event) { String AppKey; taskIndex_t SampleSetInitiator = INVALID_TASK_INDEX; unsigned int Port = 0; + if (C018_data == nullptr) { C018_data = new (std::nothrow) C018_data_struct; + if (C018_data == nullptr) { return false; } @@ -797,8 +802,8 @@ bool C018_init(struct EventStruct *event) { customConfig->validate(); if (!C018_data->init(customConfig->serialPort, customConfig->rxpin, customConfig->txpin, customConfig->baudrate, - (customConfig->joinmethod == C018_USE_OTAA), - SampleSetInitiator, customConfig->resetpin)) + (customConfig->joinmethod == C018_USE_OTAA), + SampleSetInitiator, customConfig->resetpin)) { return false; } diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 776b85bc8..f6cb8dace 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -38,11 +38,11 @@ void clearPluginTaskData(taskIndex_t taskIndex) { } void initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { - if (!validTaskIndex(taskIndex)) { + if (!validTaskIndex(taskIndex)) { if (data != nullptr) { delete data; } - return; + return; } clearPluginTaskData(taskIndex); @@ -101,11 +101,13 @@ void pluginWebformShowValue(const String& valName, const String& value, bool add void pluginWebformShowValue(const String& valName, const String& valName_id, const String& value, const String& value_id, bool addBR) { String valName_tmp(valName); + if (!valName_tmp.endsWith(F(":"))) { valName_tmp += ':'; } addHtmlDiv(F("div_l"), valName_tmp, valName_id); - addHtmlDiv(F("div_r"), value, value_id); + addHtmlDiv(F("div_r"), value, value_id); + if (addBR) { addHtmlDiv(F("div_br")); } @@ -124,21 +126,23 @@ bool pluginOptionalTaskIndexArgumentMatch(taskIndex_t taskIndex, const String& s return found_taskIndex == taskIndex; } -int getValueCountForTask(taskIndex_t taskIndex) { +int getValueCountForTask(taskIndex_t taskIndex) { struct EventStruct TempEvent(taskIndex); String dummy; + PluginCall(PLUGIN_GET_DEVICEVALUECOUNT, &TempEvent, dummy); return TempEvent.Par1; } -int checkDeviceVTypeForTask(struct EventStruct* event) { +int checkDeviceVTypeForTask(struct EventStruct *event) { if (event->sensorType == Sensor_VType::SENSOR_TYPE_NOT_SET) { if (validTaskIndex(event->TaskIndex)) { String dummy; + if (PluginCall(PLUGIN_GET_DEVICEVTYPE, event, dummy)) { return event->idx; // pconfig_index } } } return -1; -} \ No newline at end of file +} diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 37b787d62..97cc2ad74 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -107,13 +107,19 @@ String getPluginCustomArgName(int varNr); // The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed // Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK) void pluginWebformShowValue(taskIndex_t taskIndex, - byte varNr, - const String& label, - const String& value, - bool addTrailingBreak = false); + byte varNr, + const String& label, + const String& value, + bool addTrailingBreak = false); -void pluginWebformShowValue(const String& valName, const String& value, bool addBR = true); -void pluginWebformShowValue(const String& valName, const String& valName_id, const String& value, const String& value_id, bool addBR = true); +void pluginWebformShowValue(const String& valName, + const String& value, + bool addBR = true); +void pluginWebformShowValue(const String& valName, + const String& valName_id, + const String& value, + const String& value_id, + bool addBR = true); // Check if given parameter nr matches with given taskIndex. // paramNr == 0 -> command, paramNr == 1 -> 1st parameter @@ -124,10 +130,10 @@ bool pluginOptionalTaskIndexArgumentMatch(taskIndex_t taskIndex, const String& string, byte paramNr); -int getValueCountForTask(taskIndex_t taskIndex); +int getValueCountForTask(taskIndex_t taskIndex); // Check if the DeviceVType is set and update if it isn't. // Return pconfig_index -int checkDeviceVTypeForTask(struct EventStruct* event); +int checkDeviceVTypeForTask(struct EventStruct *event); #endif // PLUGIN_HELPER_H diff --git a/src/src/Commands/Rules.cpp b/src/src/Commands/Rules.cpp index 8c6e627f9..b94d40c99 100644 --- a/src/src/Commands/Rules.cpp +++ b/src/src/Commands/Rules.cpp @@ -41,6 +41,7 @@ String Command_Rules_UseRules(struct EventStruct *event, const char *Line) String Command_Rules_Async_Events(struct EventStruct *event, const char *Line) { String eventName = parseStringToEndKeepCase(Line, 2); + eventName.replace('$', '#'); if (Settings.UseRules) { @@ -49,18 +50,19 @@ String Command_Rules_Async_Events(struct EventStruct *event, const char *Line) return return_command_success(); } - String Command_Rules_Events(struct EventStruct *event, const char *Line) { String eventName = parseStringToEndKeepCase(Line, 2); + eventName.replace('$', '#'); if (Settings.UseRules) { - const bool executeImmediately = - SourceNeedsStatusUpdate(event->Source) || - event->Source == EventValueSource::Enum::VALUE_SOURCE_RULES; + const bool executeImmediately = + SourceNeedsStatusUpdate(event->Source) || + event->Source == EventValueSource::Enum::VALUE_SOURCE_RULES; + if (executeImmediately) { - rulesProcessing(eventName); // TD-er: Process right now + rulesProcessing(eventName); // TD-er: Process right now } else { eventQueue.add(eventName); } @@ -75,6 +77,7 @@ String Command_Rules_Let(struct EventStruct *event, const char *Line) if (GetArgv(Line, TmpStr1, 3)) { if (event->Par1 >= 0) { double result = 0.0; + if (!isError(Calculate(TmpStr1, result))) { setCustomFloatVar(event->Par1, result); return return_command_success(); diff --git a/src/src/Commands/Tasks.cpp b/src/src/Commands/Tasks.cpp index 1b5dd59fe..9a8fc4401 100644 --- a/src/src/Commands/Tasks.cpp +++ b/src/src/Commands/Tasks.cpp @@ -1,7 +1,6 @@ #include "../Commands/Tasks.h" - #include "../../ESPEasy_common.h" @@ -21,9 +20,11 @@ bool validTaskVars(struct EventStruct *event, taskIndex_t& taskIndex, unsigned int& varNr) { if (event == nullptr) { return false; } + if (event->Par1 <= 0) { return false; } taskIndex_t tmp_taskIndex = static_cast(event->Par1 - 1); - varNr = 0; + + varNr = 0; if (event->Par2 > 0) { varNr = event->Par2 - 1; @@ -38,7 +39,7 @@ bool validTaskVars(struct EventStruct *event, taskIndex_t& taskIndex, unsigned i return true; } -bool taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& taskIndex) +bool taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& taskIndex) { String TmpStr1; unsigned int varNr; @@ -49,6 +50,7 @@ bool taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& task if (GetArgv(Line, TmpStr1, 4)) { // Perform calculation with float result. double result = 0; + if (isError(Calculate(TmpStr1, result))) { return false; } @@ -88,6 +90,7 @@ String Command_Task_EnableDisable(struct EventStruct *event, bool enable) if (validTaskVars(event, taskIndex, varNr)) { // This is a command so no guarantee the taskIndex is correct in the event event->setTaskIndex(taskIndex); + if (setTaskEnableStatus(event, enable)) { return return_command_success(); } @@ -107,8 +110,9 @@ String Command_Task_Enable(struct EventStruct *event, const char *Line) String Command_Task_ValueSet(struct EventStruct *event, const char *Line) { - taskIndex_t taskIndex; - if (taskValueSet(event, Line, taskIndex)) return return_command_success(); + taskIndex_t taskIndex; + + if (taskValueSet(event, Line, taskIndex)) { return return_command_success(); } return return_command_failed(); } @@ -130,6 +134,7 @@ String Command_Task_ValueToggle(struct EventStruct *event, const char *Line) String Command_Task_ValueSetAndRun(struct EventStruct *event, const char *Line) { taskIndex_t taskIndex; + if (taskValueSet(event, Line, taskIndex)) { SensorSendTask(taskIndex); diff --git a/src/src/DataStructs/Caches.cpp b/src/src/DataStructs/Caches.cpp index d31ec5533..d1093db91 100644 --- a/src/src/DataStructs/Caches.cpp +++ b/src/src/DataStructs/Caches.cpp @@ -6,7 +6,6 @@ #include - void Caches::clearAllCaches() { fileExistsMap.clear(); @@ -21,22 +20,24 @@ void Caches::updateTaskCaches() { void Caches::updateActiveTaskUseSerial0() { activeTaskUseSerial0 = false; + // Check to see if a task is enabled and using the pins we also use for receiving commands. // We're now receiving only from Serial0, so check if an enabled task is also using it. for (taskIndex_t task = 0; validTaskIndex(task); ++task) { const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(task); + if (Settings.TaskDeviceEnabled[task] && validDeviceIndex(DeviceIndex)) { - if (Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL || - Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL_PLUS1) { + if ((Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL) || + (Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL_PLUS1)) { switch (ESPeasySerialType::getSerialType( - ESPEasySerialPort::not_set, - Settings.TaskDevicePin1[task], - Settings.TaskDevicePin2[task])) + ESPEasySerialPort::not_set, + Settings.TaskDevicePin1[task], + Settings.TaskDevicePin2[task])) { case ESPEasySerialPort::serial0_swap: case ESPEasySerialPort::serial0: - activeTaskUseSerial0 = true;; + activeTaskUseSerial0 = true; default: break; } diff --git a/src/src/DataStructs/Caches.h b/src/src/DataStructs/Caches.h index 798dc2c44..f75d18153 100644 --- a/src/src/DataStructs/Caches.h +++ b/src/src/DataStructs/Caches.h @@ -10,7 +10,6 @@ typedef std::map TaskIndexValueNameMap; typedef std::map FilePresenceMap; struct Caches { - void clearAllCaches(); void updateTaskCaches(); diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index e51739875..6a49f4004 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -41,14 +41,14 @@ void sendData(struct EventStruct *event) START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("sendData")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER LoadTaskSettings(event->TaskIndex); if (Settings.UseRules) { createRuleEvents(event); } - if (Settings.UseValueLogger && Settings.InitSPI>0 && (Settings.Pin_sd_cs >= 0)) { + if (Settings.UseValueLogger && (Settings.InitSPI > 0) && (Settings.Pin_sd_cs >= 0)) { SendValueLogger(event->TaskIndex); } @@ -108,6 +108,7 @@ bool validUserVar(struct EventStruct *event) { } #ifdef USES_MQTT + /*********************************************************************************************\ * Handle incoming MQTT messages \*********************************************************************************************/ @@ -130,24 +131,26 @@ void incoming_mqtt_callback(char *c_topic, byte *b_payload, unsigned int length) // TD-er: This one cannot set the TaskIndex, but that may seem to work out.... hopefully. protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(enabledMqttController); + Scheduler.schedule_mqtt_controller_event_timer( - ProtocolIndex, + ProtocolIndex, CPlugin::Function::CPLUGIN_PROTOCOL_RECV, c_topic, b_payload, length); deviceIndex_t DeviceIndex = getDeviceIndex(PLUGIN_ID_MQTT_IMPORT); // Check if P037_MQTTimport is present in the build + if (validDeviceIndex(DeviceIndex)) { // Here we loop over all tasks and call each 037 plugin with function PLUGIN_MQTT_IMPORT for (taskIndex_t taskIndex = 0; taskIndex < TASKS_MAX; taskIndex++) { - if (Settings.TaskDeviceEnabled[taskIndex] && Settings.TaskDeviceNumber[taskIndex] == PLUGIN_ID_MQTT_IMPORT) + if (Settings.TaskDeviceEnabled[taskIndex] && (Settings.TaskDeviceNumber[taskIndex] == PLUGIN_ID_MQTT_IMPORT)) { Scheduler.schedule_mqtt_plugin_import_event_timer( - DeviceIndex, taskIndex, PLUGIN_MQTT_IMPORT, + DeviceIndex, taskIndex, PLUGIN_MQTT_IMPORT, c_topic, b_payload, length); } } - } + } } /*********************************************************************************************\ @@ -169,6 +172,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) { ++mqtt_reconnect_count; MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot connect, out of RAM")); return false; @@ -183,7 +187,8 @@ bool MQTTConnect(controllerIndex_t controller_idx) MQTTclient.disconnect(); } updateMQTTclient_connected(); -// mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864 + + // mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864 yield(); mqtt.setTimeout(ControllerSettings.ClientTimeout); MQTTclient.setClient(mqtt); @@ -204,7 +209,8 @@ bool MQTTConnect(controllerIndex_t controller_idx) uint8_t willQos = 0; bool willRetain = ControllerSettings.mqtt_willRetain() && ControllerSettings.mqtt_sendLWT(); bool cleanSession = ControllerSettings.mqtt_cleanSession(); // As suggested here: - // https://github.com/knolleary/pubsubclient/issues/458#issuecomment-493875150 + + // https://github.com/knolleary/pubsubclient/issues/458#issuecomment-493875150 if (hasControllerCredentialsSet(controller_idx, ControllerSettings)) { MQTTresult = @@ -230,6 +236,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) byte controller_number = Settings.Protocol[controller_idx]; + count_connection_results(MQTTresult, F("MQTT : Broker "), controller_number); if (!MQTTresult) { @@ -238,9 +245,11 @@ bool MQTTConnect(controllerIndex_t controller_idx) return false; } String log = F("MQTT : Connected to broker with client ID: "); + log += clientid; addLog(LOG_LEVEL_INFO, log); String subscribeTo = ControllerSettings.Subscribe; + parseSystemVariables(subscribeTo, false); MQTTclient.subscribe(subscribeTo.c_str()); log = F("Subscribed to: "); @@ -304,11 +313,12 @@ bool MQTTCheck(controllerIndex_t controller_idx) if (Protocol[ProtocolIndex].usesMQTT) { - bool mqtt_sendLWT = false; + bool mqtt_sendLWT = false; String LWTTopic, LWTMessageConnect; - bool willRetain = false; + bool willRetain = false; { MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot check, out of RAM")); return false; @@ -317,27 +327,29 @@ bool MQTTCheck(controllerIndex_t controller_idx) LoadControllerSettings(controller_idx, ControllerSettings); // FIXME TD-er: Is this still needed? + /* - #ifdef USES_ESPEASY_NOW - if (!MQTTclient.connected()) { - if (ControllerSettings.enableESPEasyNowFallback()) { + #ifdef USES_ESPEASY_NOW + if (!MQTTclient.connected()) { + if (ControllerSettings.enableESPEasyNowFallback()) { return true; - } - } - #endif - */ + } + } + #endif + */ if (!ControllerSettings.isSet()) { return true; } if (ControllerSettings.mqtt_sendLWT()) { - mqtt_sendLWT = true; + mqtt_sendLWT = true; LWTTopic = getLWT_topic(ControllerSettings); LWTMessageConnect = getLWT_messageConnect(ControllerSettings); willRetain = ControllerSettings.mqtt_willRetain(); } } + if (MQTTclient_should_reconnect || !MQTTclient.connected()) { if (MQTTclient_should_reconnect) { @@ -361,7 +373,6 @@ bool MQTTCheck(controllerIndex_t controller_idx) return true; } - String getLWT_topic(const ControllerSettingsStruct& ControllerSettings) { String LWTTopic; @@ -415,7 +426,7 @@ String getLWT_messageDisconnect(const ControllerSettingsStruct& ControllerSettin void SendStatusOnlyIfNeeded(struct EventStruct *event, bool param1, uint32_t key, const String& param2, int16_t param3) { if (SourceNeedsStatusUpdate(event->Source)) { SendStatus(event, getPinStateJSON(param1, key, param2, param3)); - printToWeb=false; //SP: 2020-06-12: to avoid to add more info to a JSON structure + printToWeb = false; // SP: 2020-06-12: to avoid to add more info to a JSON structure } } @@ -428,7 +439,7 @@ bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource) case EventValueSource::Enum::VALUE_SOURCE_WEB_FRONTEND: return true; - default: + default: break; } return false; @@ -436,7 +447,8 @@ bool SourceNeedsStatusUpdate(EventValueSource::Enum eventSource) void SendStatus(struct EventStruct *event, const String& status) { - if (status.length() == 0) return; + if (status.length() == 0) { return; } + switch (event->Source) { case EventValueSource::Enum::VALUE_SOURCE_HTTP: @@ -450,7 +462,7 @@ void SendStatus(struct EventStruct *event, const String& status) case EventValueSource::Enum::VALUE_SOURCE_MQTT: MQTTStatus(event, status); break; -#endif //USES_MQTT +#endif // USES_MQTT case EventValueSource::Enum::VALUE_SOURCE_SERIAL: serialPrintln(status); break; @@ -466,7 +478,9 @@ bool MQTT_queueFull(controllerIndex_t controller_idx) { return true; } MQTT_queue_element dummy_element; + dummy_element.controller_idx = controller_idx; + if (MQTTDelayHandler->queueFull(dummy_element)) { // The queue is full, try to make some room first. processMQTTdelayQueue(); @@ -480,15 +494,16 @@ bool MQTTpublish(controllerIndex_t controller_idx, const char *topic, const char if (MQTTDelayHandler == nullptr) { return false; } + if (MQTT_queueFull(controller_idx)) { return false; } const bool success = MQTTDelayHandler->addToQueue(MQTT_queue_element(controller_idx, topic, payload, retained)); + scheduleNextMQTTdelayQueue(); return success; } - /*********************************************************************************************\ * Send status info back to channel where request came from \*********************************************************************************************/ @@ -498,22 +513,24 @@ void MQTTStatus(struct EventStruct *event, const String& status) if (validControllerIndex(enabledMqttController)) { controllerIndex_t DomoticzMQTT_controllerIndex = findFirstEnabledControllerWithId(2); + if (DomoticzMQTT_controllerIndex == enabledMqttController) { // Do not send MQTT status updates to Domoticz return; } String pubname; - bool mqtt_retainFlag; + bool mqtt_retainFlag; { // Place the ControllerSettings in a scope to free the memory as soon as we got all relevant information. MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot send status, out of RAM")); return; } LoadControllerSettings(enabledMqttController, ControllerSettings); - pubname = ControllerSettings.Publish; + pubname = ControllerSettings.Publish; mqtt_retainFlag = ControllerSettings.mqtt_retainFlag(); } @@ -532,13 +549,14 @@ void MQTTStatus(struct EventStruct *event, const String& status) MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(), mqtt_retainFlag); } } -#endif //USES_MQTT +#endif // USES_MQTT /*********************************************************************************************\ - * send all sensordata +* send all sensordata \*********************************************************************************************/ + // void SensorSendAll() // { // for (taskIndex_t x = 0; x < TASKS_MAX; x++) @@ -549,52 +567,61 @@ void MQTTStatus(struct EventStruct *event, const String& status) /*********************************************************************************************\ - * send specific sensor task data, effectively calling PluginCall(PLUGIN_READ...) +* send specific sensor task data, effectively calling PluginCall(PLUGIN_READ...) \*********************************************************************************************/ void SensorSendTask(taskIndex_t TaskIndex) { - if (!validTaskIndex(TaskIndex)) return; + if (!validTaskIndex(TaskIndex)) { return; } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SensorSendTask")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER + if (Settings.TaskDeviceEnabled[TaskIndex]) { - bool success = false; + bool success = false; const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(TaskIndex); - if (!validDeviceIndex(DeviceIndex)) return; + + if (!validDeviceIndex(DeviceIndex)) { return; } LoadTaskSettings(TaskIndex); struct EventStruct TempEvent(TaskIndex); checkDeviceVTypeForTask(&TempEvent); + // TempEvent.idx = Settings.TaskDeviceID[TaskIndex]; todo check float preValue[VARS_PER_TASK]; // store values before change, in case we need it in the formula - for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) - preValue[varNr] = UserVar[TempEvent.BaseVarIndex + varNr]; - if(Settings.TaskDeviceDataFeed[TaskIndex] == 0) // only read local connected sensorsfeeds + for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) { + preValue[varNr] = UserVar[TempEvent.BaseVarIndex + varNr]; + } + + if (Settings.TaskDeviceDataFeed[TaskIndex] == 0) // only read local connected sensorsfeeds { String dummy; success = PluginCall(PLUGIN_READ, &TempEvent, dummy); } - else + else { success = true; + } if (success) { if (Device[DeviceIndex].FormulaOption) { START_TIMER; + for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) { if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0) { String formula = ExtraTaskSettings.TaskDeviceFormula[varNr]; formula.replace(F("%pvalue%"), String(preValue[varNr])); - formula.replace(F("%value%"), String(UserVar[TempEvent.BaseVarIndex + varNr])); + formula.replace(F("%value%"), String(UserVar[TempEvent.BaseVarIndex + varNr])); double result = 0; - if (!isError(Calculate(formula, result))) + + if (!isError(Calculate(formula, result))) { UserVar[TempEvent.BaseVarIndex + varNr] = result; + } } } STOP_TIMER(COMPUTE_FORMULA_STATS); diff --git a/src/src/ESPEasyCore/ESPEasyRules.cpp b/src/src/ESPEasyCore/ESPEasyRules.cpp index 16cd7abaa..aba57c98f 100644 --- a/src/src/ESPEasyCore/ESPEasyRules.cpp +++ b/src/src/ESPEasyCore/ESPEasyRules.cpp @@ -92,17 +92,18 @@ bool processNextEvent() { if (Settings.UseRules) { String nextEvent; + if (eventQueue.getNext(nextEvent)) { rulesProcessing(nextEvent); return true; } } + // Just make sure any (accidentally) added or remaining events are not kept. eventQueue.clear(); return false; } - /********************************************************************************************\ Rules processing \*********************************************************************************************/ @@ -113,7 +114,7 @@ void rulesProcessing(String& event) { START_TIMER #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("rulesProcessing")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER #ifndef BUILD_NO_DEBUG unsigned long timer = millis(); #endif // ifndef BUILD_NO_DEBUG @@ -147,13 +148,13 @@ void rulesProcessing(String& event) { if (fileExists(fileName)) { rulesProcessingFile(fileName, event); } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG else { addLog(LOG_LEVEL_DEBUG, String(F("EVENT: ")) + event + String(F(" is ingnored. File ")) + fileName + String(F(" not found."))); } -#endif // ifndef BUILD_NO_DEBUG +# endif // ifndef BUILD_NO_DEBUG #endif // WEBSERVER_NEW_RULES } @@ -181,7 +182,7 @@ String rulesProcessingFile(const String& fileName, String& event) { } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("rulesProcessingFile")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER #ifndef BUILD_NO_DEBUG if (Settings.SerialLogLevel == LOG_LEVEL_DEBUG_DEV) { @@ -308,18 +309,17 @@ String rulesProcessingFile(const String& fileName, String& event) { nestingLevel--; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("rulesProcessingFile2")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return ""; } - /********************************************************************************************\ Strip comment from the line. Return true when comment was stripped. \*********************************************************************************************/ bool rules_strip_trailing_comments(String& line) { - // Strip trailing comments + // Strip trailing comments int comment = line.indexOf(F("//")); if (comment >= 0) { @@ -327,7 +327,7 @@ bool rules_strip_trailing_comments(String& line) line.trim(); return true; } - return false; + return false; } /********************************************************************************************\ @@ -339,10 +339,11 @@ bool rules_replace_common_mistakes(const String& from, const String& to, String& if (line.indexOf(from) == -1) { return false; // Nothing replaced } + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log; log.reserve(32 + from.length() + to.length() + line.length()); - log = F("Rules (Syntax Error, auto-corrected): '"); + log = F("Rules (Syntax Error, auto-corrected): '"); log += from; log += F("' => '"); log += to; @@ -362,9 +363,11 @@ bool rules_replace_common_mistakes(const String& from, const String& to, String& bool check_rules_line_user_errors(String& line) { bool res = true; + if (rules_replace_common_mistakes(F("if["), F("if ["), line)) { res = false; } + if (rules_replace_common_mistakes(F("if%"), F("if %"), line)) { res = false; } @@ -372,15 +375,13 @@ bool check_rules_line_user_errors(String& line) return res; } - - /********************************************************************************************\ Parse string commands \*********************************************************************************************/ - bool get_next_inner_bracket(const String& line, int& startIndex, int& closingIndex, char closingBracket) { char openingBracket = closingIndex; + switch (closingBracket) { case ']': openingBracket = '['; break; case '}': openingBracket = '{'; break; @@ -390,8 +391,9 @@ bool get_next_inner_bracket(const String& line, int& startIndex, int& closingInd return false; } closingIndex = line.indexOf(closingBracket); - if (closingIndex == -1) return false; - + + if (closingIndex == -1) { return false; } + for (int i = closingIndex; i >= 0; --i) { if (line[i] == openingBracket) { startIndex = i; @@ -407,16 +409,20 @@ bool get_next_argument(const String& fullCommand, int& index, String& argument, return false; } int newIndex = fullCommand.indexOf(separator, index); + if (newIndex == -1) { argument = fullCommand.substring(index); } else { argument = fullCommand.substring(index, newIndex); } + if (argument.startsWith(String(separator))) { argument = argument.substring(1); } -// addLog(LOG_LEVEL_INFO, String("get_next_argument: ") + String(index) + " " + fullCommand + " " + argument); + + // addLog(LOG_LEVEL_INFO, String("get_next_argument: ") + String(index) + " " + fullCommand + " " + argument); index = newIndex; + if (index != -1) { ++index; } @@ -424,17 +430,17 @@ bool get_next_argument(const String& fullCommand, int& index, String& argument, } /* TD-er: Disabled for now, have to try and make the notation more intuitive. -bool parse_trigonometric_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, double& result) { - #ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES - if (cmd_s_lower.length() < 3) { + bool parse_trigonometric_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, double& result) { + #ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES + if (cmd_s_lower.length() < 3) { return false; - } - float farg1; - if (!validFloatFromString(arg1, farg1)) { + } + float farg1; + if (!validFloatFromString(arg1, farg1)) { return false; - } - const bool angle_in_deg = cmd_s_lower.endsWith(F("_d")); - if (cmd_s_lower[0] == 'a') { + } + const bool angle_in_deg = cmd_s_lower.endsWith(F("_d")); + if (cmd_s_lower[0] == 'a') { // acos, asin, atan, atan2 if (cmd_s_lower.startsWith(F("acos"))) { result = acos(farg1); @@ -458,59 +464,62 @@ bool parse_trigonometric_functions(const String& cmd_s_lower, const String& arg1 if (angle_in_deg) { farg1 = degrees(farg1); } - return true; - } - // cos, sin, tan - // These functions have the angle as input, so convert the argument to radians first (if needed) - if (angle_in_deg) { + return true; + } + // cos, sin, tan + // These functions have the angle as input, so convert the argument to radians first (if needed) + if (angle_in_deg) { farg1 = radians(farg1); - } - if (cmd_s_lower.startsWith(F("cos"))) { + } + if (cmd_s_lower.startsWith(F("cos"))) { result = cos(farg1); - } else if (cmd_s_lower.startsWith(F("sin"))) { + } else if (cmd_s_lower.startsWith(F("sin"))) { result = sin(farg1); - } else if (cmd_s_lower.startsWith(F("tan"))) { + } else if (cmd_s_lower.startsWith(F("tan"))) { result = tan(farg1); - } else { + } else { return false; - } - return true; - #else - return false; - #endif -} -*/ - - + } + return true; + #else + return false; + #endif + } + */ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, const String& arg3, int64_t& result) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("Bitwise: {"); log += wrapIfContains(cmd_s_lower, ':', '\"'); log += ':'; - log += wrapIfContains(arg1, ':', '\"');; + log += wrapIfContains(arg1, ':', '\"'); + if (arg2.length() > 0) { log += ':'; - log += wrapIfContains(arg2, ':', '\"');; + log += wrapIfContains(arg2, ':', '\"'); + if (arg3.length() > 0) { log += ':'; - log += wrapIfContains(arg3, ':', '\"');; + log += wrapIfContains(arg3, ':', '\"'); } } log += '}'; addLog(LOG_LEVEL_INFO, log); } + if (cmd_s_lower.length() < 2) { return false; } + if (cmd_s_lower.startsWith(F("bit"))) { uint32_t bitnr = 0; uint64_t iarg2 = 0; + if (!validUIntFromString(arg1, bitnr) || !validUInt64FromString(arg2, iarg2)) { - return false; + return false; } if (cmd_s_lower.equals(F("bitread"))) { - // Syntax like {bitread:0:123} to get a single decimal '1' + // Syntax like {bitread:0:123} to get a single decimal '1' result = bitRead(iarg2, bitnr); } 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' @@ -522,6 +531,7 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons bitClear(result, bitnr); } else if (cmd_s_lower.equals(F("bitwrite"))) { uint32_t iarg3 = 0; + // Syntax like {bitwrite:0:122:1} to set least significant bit of the given nr '122' to '1' => '123' if (validUIntFromString(arg3, iarg3)) { const int bitvalue = (iarg3 & 1); // Only use the last bit of the given parameter @@ -535,11 +545,13 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons // Starts with "bit", but no matching function found return false; } + // all functions starting with "bit" are checked return true; } uint64_t iarg1, iarg2 = 0; + if (!validUInt64FromString(arg1, iarg1) || !validUInt64FromString(arg2, iarg2)) { return false; } @@ -561,11 +573,13 @@ bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, cons } bool parse_math_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, const String& arg3, double& result) { - double farg1; - float farg2, farg3 = 0.0f; + double farg1; + float farg2, farg3 = 0.0f; + if (!validDoubleFromString(arg1, farg1)) { return false; } + if (cmd_s_lower.equals(F("constrain"))) { // Contrain a value X to be within range of A to B // Syntax like {constrain:x:a:b} to constrain x in range a...b @@ -586,25 +600,27 @@ bool parse_math_functions(const String& cmd_s_lower, const String& arg1, const S return true; } -void parse_string_commands(String &line) { +void parse_string_commands(String& line) { int startIndex, closingIndex; while (get_next_inner_bracket(line, startIndex, closingIndex, '}')) { // Command without opening and closing brackets. String fullCommand = line.substring(startIndex + 1, closingIndex); String cmd_s_lower = parseString(fullCommand, 1, ':'); - String arg1 = parseStringKeepCase(fullCommand, 2, ':'); - String arg2 = parseStringKeepCase(fullCommand, 3, ':'); - String arg3 = parseStringKeepCase(fullCommand, 4, ':'); + String arg1 = parseStringKeepCase(fullCommand, 2, ':'); + String arg2 = parseStringKeepCase(fullCommand, 3, ':'); + String arg3 = parseStringKeepCase(fullCommand, 4, ':'); + if (cmd_s_lower.length() > 0) { String replacement; // maybe just replace with empty to avoid looping? -// addLog(LOG_LEVEL_INFO, String(F("parse_string_commands cmd: ")) + cmd_s_lower + " " + arg1 + " " + arg2 + " " + arg3); + // addLog(LOG_LEVEL_INFO, String(F("parse_string_commands cmd: ")) + cmd_s_lower + " " + arg1 + " " + arg2 + " " + arg3); uint64_t iarg1, iarg2 = 0; - double fresult = 0.0; - int64_t iresult = 0; - if (/*parse_trigonometric_functions(cmd_s_lower, arg1, arg2, fresult) ||*/ - parse_math_functions(cmd_s_lower, arg1, arg2, arg3, fresult)) { + double fresult = 0.0; + int64_t iresult = 0; + + if ( /*parse_trigonometric_functions(cmd_s_lower, arg1, arg2, fresult) ||*/ + parse_math_functions(cmd_s_lower, arg1, arg2, arg3, fresult)) { const bool trimTrailingZeros = true; replacement = doubleToString(fresult, maxNrDecimals_double(fresult), trimTrailingZeros); } else if (parse_bitwise_functions(cmd_s_lower, arg1, arg2, arg3, iresult)) { @@ -613,6 +629,7 @@ void parse_string_commands(String &line) { // substring arduino style (first char included, last char excluded) // Syntax like 12345{substring:8:12:ANOTHER HELLO WORLD}67890 int startpos, endpos = -1; + if (validIntFromString(arg1, startpos) && validIntFromString(arg2, endpos)) { replacement = arg3.substring(startpos, endpos); @@ -624,23 +641,25 @@ void parse_string_commands(String &line) { && validUInt64FromString(arg2, iarg2)) { replacement = String(strtoul(arg2.c_str(), NULL, iarg1)); } + // FIXME TD-er: removed for now as it is too specific. // Maybe introduce one using 2 or 3 parameters ({div:100:255:3} for *100/255 3 decimals) + /* - } else if (cmd_s_lower.equals(F("div100ths"))) { - // division and giving the 100ths as integer - // 5 / 100 would yield 5 - // useful for fractions that use a full byte gaining a - // precision/granularity of 1/256 instead of only 1/100 - // Syntax like XXX{div100ths:24:256}XXX - if (validUInt64FromString(arg1, iarg1) + } else if (cmd_s_lower.equals(F("div100ths"))) { + // division and giving the 100ths as integer + // 5 / 100 would yield 5 + // useful for fractions that use a full byte gaining a + // precision/granularity of 1/256 instead of only 1/100 + // Syntax like XXX{div100ths:24:256}XXX + if (validUInt64FromString(arg1, iarg1) && validUInt64FromString(arg2, iarg2)) { - float val = (100.0 * iarg1) / (1.0 * iarg2); - char sval[10]; - sprintf_P(sval, PSTR("%02d"), (int)val); - replacement = String(sval); - } - */ + float val = (100.0 * iarg1) / (1.0 * iarg2); + char sval[10]; + sprintf_P(sval, PSTR("%02d"), (int)val); + replacement = String(sval); + } + */ } else if (cmd_s_lower.equals(F("tobin"))) { // Convert to binary string // Syntax like 1234{tobin:15}7890 @@ -653,7 +672,7 @@ void parse_string_commands(String &line) { if (validUInt64FromString(arg1, iarg1)) { replacement = ull2String(iarg1, HEX); } - } else if (cmd_s_lower.equals(F("ord"))) { + } else if (cmd_s_lower.equals(F("ord"))) { // Give the ordinal/integer value of the first character of a string // Syntax like let 1,{ord:B} uint8_t uval = arg1.c_str()[0]; @@ -669,23 +688,24 @@ void parse_string_commands(String &line) { replacement.replace('{', static_cast(0x02)); replacement.replace('}', static_cast(0x03)); } + // Replace the full command including opening and closing brackets. line.replace(line.substring(startIndex, closingIndex + 1), replacement); /* - if (replacement.length() > 0) { - addLog(LOG_LEVEL_INFO, String(F("parse_string_commands cmd: ")) + fullCommand + String(F(" -> ")) + replacement); - } - */ + if (replacement.length() > 0) { + addLog(LOG_LEVEL_INFO, String(F("parse_string_commands cmd: ")) + fullCommand + String(F(" -> ")) + replacement); + } + */ } } + // We now have to check if we did mask some parts and unmask them. // Let's hope we don't mess up any Unicode here. line.replace(static_cast(0x02), '{'); line.replace(static_cast(0x03), '}'); } - void replace_EventValueN_Argv(String& line, const String& argString, unsigned int argc) { String eventvalue; @@ -708,10 +728,11 @@ void replace_EventValueN_Argv(String& line, const String& argString, unsigned in } } - void substitute_eventvalue(String& line, const String& event) { - if (substitute_eventvalue_CallBack_ptr != nullptr) + if (substitute_eventvalue_CallBack_ptr != nullptr) { substitute_eventvalue_CallBack_ptr(line, event); + } + if (line.indexOf(F("%eventvalue")) != -1) { if (event.charAt(0) == '!') { line.replace(F("%eventvalue%"), event); // substitute %eventvalue% with @@ -771,9 +792,11 @@ void parseCompleteNonCommentLine(String& line, String& event, String& log, String lineOrg = line; // store original line for future use + line.toLowerCase(); // convert all to lower case to make checks easier String eventTrigger; + action = ""; if (!codeBlock) // do not check "on" rules if a block of actions is to be @@ -886,7 +909,7 @@ void processMatchedRule(String& action, String& event, } } } else { - // check for optional "if" condition + // check for optional "if" condition split = lcAction.indexOf(F("if ")); if (split != -1) { @@ -977,7 +1000,7 @@ void processMatchedRule(String& action, String& event, bool ruleMatch(const String& event, const String& rule) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("ruleMatch")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER String tmpEvent = event; String tmpRule = rule; @@ -1013,7 +1036,7 @@ bool ruleMatch(const String& event, const String& rule) { } // clock events need different handling... - if (event.substring(0, 10).equalsIgnoreCase(F("Clock#Time"))) + if (event.substring(0, 10).equalsIgnoreCase(F("Clock#Time"))) { int pos1 = event.indexOf('='); int pos2 = rule.indexOf('='); @@ -1055,7 +1078,7 @@ bool ruleMatch(const String& event, const String& rule) { } const bool stringMatch = tmpEvent.equalsIgnoreCase(rule.substring(0, posStart)); - double ruleValue = 0; + double ruleValue = 0; if (!validDoubleFromString(rule.substring(posEnd), ruleValue)) { return false; @@ -1070,7 +1093,7 @@ bool ruleMatch(const String& event, const String& rule) { } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("ruleMatch2")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return match; } @@ -1078,19 +1101,22 @@ bool ruleMatch(const String& event, const String& rule) { Check expression \*********************************************************************************************/ bool conditionMatchExtended(String& check) { - int condAnd = -1; - int condOr = -1; - bool rightcond = false; - bool leftcond = conditionMatch(check); // initial check + int condAnd = -1; + int condOr = -1; + bool rightcond = false; + bool leftcond = conditionMatch(check); // initial check + #ifndef BUILD_NO_DEBUG String debugstr; + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { debugstr += boolToString(leftcond); } - #endif + #endif // ifndef BUILD_NO_DEBUG do { #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("conditionMatchExtended: "); log += debugstr; @@ -1098,7 +1124,7 @@ bool conditionMatchExtended(String& check) { log += check; addLog(LOG_LEVEL_DEBUG, log); } - #endif + #endif // ifndef BUILD_NO_DEBUG condAnd = check.indexOf(F(" and ")); condOr = check.indexOf(F(" or ")); @@ -1110,35 +1136,39 @@ bool conditionMatchExtended(String& check) { leftcond = (leftcond && rightcond); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { debugstr += F(" && "); } - #endif + #endif // ifndef BUILD_NO_DEBUG } else { // OR is first check = check.substring(condOr + 4); rightcond = conditionMatch(check); leftcond = (leftcond || rightcond); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { debugstr += F(" || "); } - #endif + #endif // ifndef BUILD_NO_DEBUG } - + #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { debugstr += boolToString(rightcond); } - #endif + #endif // ifndef BUILD_NO_DEBUG } } while (condAnd > 0 || condOr > 0); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { check = debugstr; } - #endif + #endif // ifndef BUILD_NO_DEBUG return leftcond; } @@ -1149,56 +1179,56 @@ bool findCompareCondition(const String& check, char& compare, int& posStart, int { posStart = check.length(); posEnd = posStart; - int comparePos = 0; - bool found = false; + int comparePos = 0; + bool found = false; if (((comparePos = check.indexOf("!=")) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 2; compare = '<' + '>'; - found = true; + found = true; } if (((comparePos = check.indexOf("<>")) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 2; compare = '<' + '>'; - found = true; + found = true; } if (((comparePos = check.indexOf(">=")) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 2; compare = '>' + '='; - found = true; + found = true; } if (((comparePos = check.indexOf("<=")) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 2; compare = '<' + '='; - found = true; + found = true; } if (((comparePos = check.indexOf('<')) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 1; compare = '<'; - found = true; + found = true; } if (((comparePos = check.indexOf('>')) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 1; compare = '>'; - found = true; + found = true; } if (((comparePos = check.indexOf('=')) > 0) && (comparePos < posStart)) { posStart = comparePos; posEnd = posStart + 1; compare = '='; - found = true; + found = true; } return found; } @@ -1209,8 +1239,8 @@ bool compareIntValues(char compare, const int& Value1, const int& Value2) case '>' + '=': return Value1 >= Value2; case '<' + '=': return Value1 <= Value2; case '<' + '>': return Value1 != Value2; - case '>': return Value1 > Value2; - case '<': return Value1 < Value2; + case '>': return Value1 > Value2; + case '<': return Value1 < Value2; case '=': return Value1 == Value2; } return false; @@ -1229,7 +1259,6 @@ bool compareDoubleValues(char compare, const double& Value1, const double& Value return false; } - void logtimeStringToSeconds(const String& tBuf, int hours, int minutes, int seconds) { #ifndef BUILD_NO_DEBUG @@ -1254,40 +1283,44 @@ void logtimeStringToSeconds(const String& tBuf, int hours, int minutes, int seco // return whether it should be considered a time string. bool timeStringToSeconds(const String& tBuf, int& time_seconds) { time_seconds = -1; - int hours = 0; - int minutes = 0; - int seconds = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; int tmpIndex = 0; String hours_str, minutes_str, seconds_str; - bool validTime = false; + bool validTime = false; + if (get_next_argument(tBuf, tmpIndex, hours_str, ':')) { if (validIntFromString(hours_str, hours)) { validTime = true; - if (hours < 0 || hours > 24) { + + if ((hours < 0) || (hours > 24)) { validTime = false; } else { time_seconds = hours * 60 * 60; } + if (validTime && get_next_argument(tBuf, tmpIndex, minutes_str, ':')) { if (validIntFromString(minutes_str, minutes)) { - if ((minutes < 0) || (minutes > 59)) { - validTime = false; + if ((minutes < 0) || (minutes > 59)) { + validTime = false; } else { time_seconds += minutes * 60; } + if (validTime && get_next_argument(tBuf, tmpIndex, seconds_str, ':')) { // New format, only HH:MM:SS if (validIntFromString(seconds_str, seconds)) { if ((seconds < 0) || (seconds > 59)) { - validTime = false; + validTime = false; } else { time_seconds += seconds; } } } else { // Old format, only HH:MM - } + } } } else { // It is a valid time string, but could also be just a numerical. @@ -1310,16 +1343,17 @@ bool conditionMatch(const String& check) { String tmpCheck1 = check.substring(0, posStart); String tmpCheck2 = check.substring(posEnd); + tmpCheck1.trim(); tmpCheck2.trim(); - double Value1 = 0; - double Value2 = 0; + double Value1 = 0; + double Value2 = 0; int timeInSec1 = 0; int timeInSec2 = 0; bool validTime1 = timeStringToSeconds(tmpCheck1, timeInSec1); bool validTime2 = timeStringToSeconds(tmpCheck2, timeInSec2); - bool result = false; + bool result = false; bool compareTimes = false; @@ -1328,7 +1362,7 @@ bool conditionMatch(const String& check) { // At least one is a time containing ':' separator // AND both can be considered a time, so use it as a time and compare seconds. compareTimes = true; - result = compareIntValues(compare, timeInSec1, timeInSec2); + result = compareIntValues(compare, timeInSec1, timeInSec2); } else { if (!validDoubleFromString(tmpCheck1, Value1) || !validDoubleFromString(tmpCheck2, Value2)) @@ -1339,23 +1373,26 @@ bool conditionMatch(const String& check) { } #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("conditionMatch: _"); log += check; log += F("_ val1: "); - if (compareTimes) { - log += timeInSec1; + + if (compareTimes) { + log += timeInSec1; } else { log += Value1; } log += F(" \""); log += tmpCheck1; log += F("\" val2: "); - if (compareTimes) { - log += timeInSec2; + + if (compareTimes) { + log += timeInSec2; } else { log += Value2; - } + } log += F(" \""); log += tmpCheck2; log += F("\" "); @@ -1363,9 +1400,9 @@ bool conditionMatch(const String& check) { log += boolToString(result); addLog(LOG_LEVEL_DEBUG, log); } - #else + #else // ifndef BUILD_NO_DEBUG (void)compareTimes; // To avoid compiler warning - #endif + #endif // ifndef BUILD_NO_DEBUG return result; } @@ -1389,6 +1426,7 @@ void createRuleEvents(struct EventStruct *event) { eventString.reserve(128); // Enough for most use cases, prevent lots of memory allocations. eventString = getTaskDeviceName(event->TaskIndex); eventString += F("#All="); + for (byte varNr = 0; varNr < valueCount; varNr++) { if (varNr != 0) { eventString += ','; @@ -1406,6 +1444,6 @@ void createRuleEvents(struct EventStruct *event) { eventString += F("="); eventString += formatUserVarNoCheck(event, varNr); eventQueue.add(eventString); - } + } } } diff --git a/src/src/ESPEasyCore/ESPEasyRules.h b/src/src/ESPEasyCore/ESPEasyRules.h index 7fcd8335f..e9bcc5645 100644 --- a/src/src/ESPEasyCore/ESPEasyRules.h +++ b/src/src/ESPEasyCore/ESPEasyRules.h @@ -16,23 +16,24 @@ String EventToFileName(const String& eventName); String FileNameToEvent(const String& fileName); -void checkRuleSets(); +void checkRuleSets(); /********************************************************************************************\ Process next event from event queue \*********************************************************************************************/ -bool processNextEvent(); +bool processNextEvent(); /********************************************************************************************\ Rules processing \*********************************************************************************************/ -void rulesProcessing(String& event); +void rulesProcessing(String& event); /********************************************************************************************\ Rules processing \*********************************************************************************************/ -String rulesProcessingFile(const String& fileName, String& event); +String rulesProcessingFile(const String& fileName, + String & event); /********************************************************************************************\ @@ -45,7 +46,9 @@ bool rules_strip_trailing_comments(String& line); Test for common mistake Return true if mistake was found (and corrected) \*********************************************************************************************/ -bool rules_replace_common_mistakes(const String& from, const String& to, String& line); +bool rules_replace_common_mistakes(const String& from, + const String& to, + String & line); /********************************************************************************************\ Check for common mistakes @@ -54,41 +57,70 @@ bool rules_replace_common_mistakes(const String& from, const String& to, String& bool check_rules_line_user_errors(String& line); - /********************************************************************************************\ Parse string commands \*********************************************************************************************/ -bool get_next_inner_bracket(const String& line, int& startIndex, int& closingIndex, char closingBracket); +bool get_next_inner_bracket(const String& line, + int & startIndex, + int & closingIndex, + char closingBracket); -bool get_next_argument(const String& fullCommand, int& index, String& argument, char separator); +bool get_next_argument(const String& fullCommand, + int & index, + String & argument, + char separator); -//bool parse_trigonometric_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, double& result); -bool parse_bitwise_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, const String& arg3, uint32_t& result); -bool parse_math_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, const String& arg3, double& result); +// bool parse_trigonometric_functions(const String& cmd_s_lower, const String& arg1, const String& arg2, double& result); +bool parse_bitwise_functions(const String& cmd_s_lower, + const String& arg1, + const String& arg2, + const String& arg3, + uint32_t & result); +bool parse_math_functions(const String& cmd_s_lower, + const String& arg1, + const String& arg2, + const String& arg3, + double & result); -void parse_string_commands(String &line); +void parse_string_commands(String& line); -void replace_EventValueN_Argv(String& line, const String& argString, unsigned int argc); +void replace_EventValueN_Argv(String & line, + const String& argString, + unsigned int argc); -void substitute_eventvalue(String& line, const String& event); +void substitute_eventvalue(String & line, + const String& event); -void parseCompleteNonCommentLine(String& line, String& event, String& log, - String& action, bool& match, - bool& codeBlock, bool& isCommand, - bool condition[], bool ifBranche[], - byte& ifBlock, byte& fakeIfBlock); +void parseCompleteNonCommentLine(String& line, + String& event, + String& log, + String& action, + bool & match, + bool & codeBlock, + bool & isCommand, + bool condition[], + bool ifBranche[], + byte & ifBlock, + byte & fakeIfBlock); -void processMatchedRule(String& action, String& event, - String& log, bool& match, bool& codeBlock, - bool& isCommand, bool condition[], bool ifBranche[], - byte& ifBlock, byte& fakeIfBlock); +void processMatchedRule(String& action, + String& event, + String& log, + bool & match, + bool & codeBlock, + bool & isCommand, + bool condition[], + bool ifBranche[], + byte & ifBlock, + byte & fakeIfBlock); /********************************************************************************************\ Check if an event matches to a given rule \*********************************************************************************************/ -bool ruleMatch(const String& event, const String& rule); +bool ruleMatch(const String& event, + const String& rule); /********************************************************************************************\ Check expression @@ -98,10 +130,17 @@ bool conditionMatchExtended(String& check); // Find the compare condition. // @param posStart = first position of the compare condition in the string // @param posEnd = first position rest of the string, right after the compare condition. -bool findCompareCondition(const String& check, char& compare, int& posStart, int& posEnd); +bool findCompareCondition(const String& check, + char & compare, + int & posStart, + int & posEnd); -bool compareIntValues(char compare, const int& Value1, const int& Value2); -bool compareDoubleValues(char compare, const double& Value1, const double& Value2); +bool compareIntValues(char compare, + const int& Value1, + const int& Value2); +bool compareDoubleValues(char compare, + const double& Value1, + const double& Value2); bool conditionMatch(const String& check); @@ -126,5 +165,4 @@ bool timeStringToSeconds(const String& tBuf, void createRuleEvents(struct EventStruct *event); - -#endif \ No newline at end of file +#endif // ifndef ESPEASYCORE_ESPEASYRULES_H diff --git a/src/src/ESPEasyCore/Serial.cpp b/src/src/ESPEasyCore/Serial.cpp index 2662c9abb..bd78cc9d0 100644 --- a/src/src/ESPEasyCore/Serial.cpp +++ b/src/src/ESPEasyCore/Serial.cpp @@ -10,7 +10,6 @@ #include "../Helpers/Memory.h" - /********************************************************************************************\ * Get data from Serial Interface \*********************************************************************************************/ @@ -24,9 +23,11 @@ void initSerial() if (log_to_serial_disabled || !Settings.UseSerial || activeTaskUseSerial0()) { return; } - //make sure previous serial buffers are flushed before resetting baudrate + + // make sure previous serial buffers are flushed before resetting baudrate Serial.flush(); Serial.begin(Settings.BaudRate); + // Serial.setDebugOutput(true); } @@ -35,12 +36,13 @@ void serial() if (Serial.available()) { String dummy; + if (PluginCall(PLUGIN_SERIAL_IN, 0, dummy)) { return; } } - if (!Settings.UseSerial || activeTaskUseSerial0()) return; + if (!Settings.UseSerial || activeTaskUseSerial0()) { return; } while (Serial.available()) { @@ -87,10 +89,12 @@ void addToSerialBuffer(const char *line) { roomLeft -= 4000; // leave some free for normal use. } - const char* c = line; + const char *c = line; + while (roomLeft > 0) { // Must use PROGMEM aware functions here. char ch = pgm_read_byte(c++); + if (ch == '\0') { return; } else { diff --git a/src/src/ESPEasyCore/Serial.h b/src/src/ESPEasyCore/Serial.h index 22e08d96e..3933a67b2 100644 --- a/src/src/ESPEasyCore/Serial.h +++ b/src/src/ESPEasyCore/Serial.h @@ -41,4 +41,4 @@ void serialPrintln(); */ -#endif \ No newline at end of file +#endif // ifndef ESPEASYCORE_SERIAL_H diff --git a/src/src/Globals/Cache.cpp b/src/src/Globals/Cache.cpp index 50c9fdd40..c38e30866 100644 --- a/src/src/Globals/Cache.cpp +++ b/src/src/Globals/Cache.cpp @@ -22,4 +22,4 @@ bool activeTaskUseSerial0() return Cache.activeTaskUseSerial0; } -Caches Cache; \ No newline at end of file +Caches Cache; diff --git a/src/src/Globals/Cache.h b/src/src/Globals/Cache.h index 66e67e85a..a8f9c16a8 100644 --- a/src/src/Globals/Cache.h +++ b/src/src/Globals/Cache.h @@ -13,4 +13,4 @@ bool activeTaskUseSerial0(); extern Caches Cache; -#endif // GLOBALS_CACHE_H \ No newline at end of file +#endif // GLOBALS_CACHE_H diff --git a/src/src/Globals/RuntimeData.cpp b/src/src/Globals/RuntimeData.cpp index 58c9496b7..39aa5eb4d 100644 --- a/src/src/Globals/RuntimeData.cpp +++ b/src/src/Globals/RuntimeData.cpp @@ -21,10 +21,12 @@ void setCustomFloatVar(uint32_t index, const double& value) { bool getNextCustomFloatVar(uint32_t& index, double& value) { auto it = customFloatVar.find(index); - if (it == customFloatVar.end()) return false; + + if (it == customFloatVar.end()) { return false; } ++it; - if (it == customFloatVar.end()) return false; + + if (it == customFloatVar.end()) { return false; } index = it->first; value = it->second; return true; -} \ No newline at end of file +} diff --git a/src/src/Helpers/ESPEasy_math.cpp b/src/src/Helpers/ESPEasy_math.cpp index 4500aefca..9665644f8 100644 --- a/src/src/Helpers/ESPEasy_math.cpp +++ b/src/src/Helpers/ESPEasy_math.cpp @@ -4,58 +4,52 @@ int maxNrDecimals_double(const double& value) { - int res = ESPEASY_DOUBLE_NR_DECIMALS; - double factor = 1; - while ((value / factor) > 10 && res > 2) { - factor *= 10.0; - --res; - } - return res; + int res = ESPEASY_DOUBLE_NR_DECIMALS; + double factor = 1; + + while ((value / factor) > 10 && res > 2) { + factor *= 10.0; + --res; + } + return res; } bool approximatelyEqual(const double& a, const double& b, double epsilon) { - return std::abs(a - b) <= ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return std::abs(a - b) <= ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } bool approximatelyEqual(const float& a, const float& b, float epsilon) { - return std::abs(a - b) <= ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return std::abs(a - b) <= ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } - bool definitelyGreaterThan(const double& a, const double& b, double epsilon) { - return (a - b) > ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return (a - b) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } bool definitelyGreaterThan(const float& a, const float& b, float epsilon) { - return (a - b) > ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return (a - b) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } - bool definitelyLessThan(const double& a, const double& b, double epsilon) { - return (b - a) > ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return (b - a) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } bool definitelyLessThan(const float& a, const float& b, float epsilon) { - return (b - a) > ( (std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return (b - a) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } - bool essentiallyEqual(const double& a, const double& b, double epsilon) { - return std::abs(a - b) <= ( (std::abs(a) > std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return std::abs(a - b) <= ((std::abs(a) > std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } bool essentiallyEqual(const float& a, const float& b, float epsilon) { - return std::abs(a - b) <= ( (std::abs(a) > std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); + return std::abs(a - b) <= ((std::abs(a) > std::abs(b) ? std::abs(b) : std::abs(a)) * epsilon); } - - - - diff --git a/src/src/Helpers/Numerical.cpp b/src/src/Helpers/Numerical.cpp index dd3250c84..997fe015f 100644 --- a/src/src/Helpers/Numerical.cpp +++ b/src/src/Helpers/Numerical.cpp @@ -1,26 +1,30 @@ #include "Numerical.h" /********************************************************************************************\ - Check if string is valid float - \*********************************************************************************************/ - + Check if string is valid float + \*********************************************************************************************/ bool isValidFloat(float f) { - if (isnan(f)) return false; //("isnan"); - if (isinf(f)) return false; //("isinf"); + if (isnan(f)) { return false; // ("isnan"); + } + + if (isinf(f)) { return false; // ("isinf"); + } return true; } bool validIntFromString(const String& tBuf, int& result) { NumericalType detectedType; - const String numerical = getNumerical(tBuf, NumericalType::Integer, detectedType); - if (detectedType == NumericalType::BinaryUint || - detectedType == NumericalType::HexadecimalUInt) { + const String numerical = getNumerical(tBuf, NumericalType::Integer, detectedType); + + if ((detectedType == NumericalType::BinaryUint) || + (detectedType == NumericalType::HexadecimalUInt)) { unsigned int tmp; bool isvalid = validUIntFromString(numerical, tmp); result = static_cast(tmp); return isvalid; } const bool isvalid = numerical.length() > 0; + if (isvalid) { result = numerical.toInt(); } @@ -29,16 +33,18 @@ bool validIntFromString(const String& tBuf, int& result) { bool validInt64FromString(const String& tBuf, int64_t& result) { NumericalType detectedType; - const String numerical = getNumerical(tBuf, NumericalType::Integer, detectedType); - if (detectedType == NumericalType::BinaryUint || - detectedType == NumericalType::HexadecimalUInt) { + const String numerical = getNumerical(tBuf, NumericalType::Integer, detectedType); + + if ((detectedType == NumericalType::BinaryUint) || + (detectedType == NumericalType::HexadecimalUInt)) { uint64_t tmp; - bool isvalid = validUInt64FromString(numerical, tmp); + bool isvalid = validUInt64FromString(numerical, tmp); result = static_cast(tmp); return isvalid; } const bool isvalid = numerical.length() > 0; + if (isvalid) { result = atoll(numerical.c_str()); } @@ -47,16 +53,18 @@ bool validInt64FromString(const String& tBuf, int64_t& result) { bool validUIntFromString(const String& tBuf, unsigned int& result) { NumericalType detectedType; - String numerical = getNumerical(tBuf, NumericalType::HexadecimalUInt, detectedType); + String numerical = getNumerical(tBuf, NumericalType::HexadecimalUInt, detectedType); const bool isvalid = numerical.length() > 0; + if (isvalid) { int base = DEC; + if (detectedType == NumericalType::HexadecimalUInt) { numerical = numerical.substring(2); - base = HEX; + base = HEX; } else if (detectedType == NumericalType::BinaryUint) { numerical = numerical.substring(2); - base = BIN; + base = BIN; } result = strtoul(numerical.c_str(), NULL, base); } @@ -65,16 +73,18 @@ bool validUIntFromString(const String& tBuf, unsigned int& result) { bool validUInt64FromString(const String& tBuf, uint64_t& result) { NumericalType detectedType; - String numerical = getNumerical(tBuf, NumericalType::HexadecimalUInt, detectedType); + String numerical = getNumerical(tBuf, NumericalType::HexadecimalUInt, detectedType); const bool isvalid = numerical.length() > 0; + if (isvalid) { int base = DEC; + if (detectedType == NumericalType::HexadecimalUInt) { numerical = numerical.substring(2); - base = HEX; + base = HEX; } else if (detectedType == NumericalType::BinaryUint) { numerical = numerical.substring(2); - base = BIN; + base = BIN; } result = strtoull(numerical.c_str(), NULL, base); } @@ -83,12 +93,13 @@ bool validUInt64FromString(const String& tBuf, uint64_t& result) { bool validFloatFromString(const String& tBuf, float& result) { // DO not call validDoubleFromString and then cast to float. - // Working with double values is quite CPU intensive as it must be done in software + // Working with double values is quite CPU intensive as it must be done in software // since the ESP does not have large enough registers for handling double values in hardware. NumericalType detectedType; - const String numerical = getNumerical(tBuf, NumericalType::FloatingPoint, detectedType); - if (detectedType == NumericalType::BinaryUint || - detectedType == NumericalType::HexadecimalUInt) { + const String numerical = getNumerical(tBuf, NumericalType::FloatingPoint, detectedType); + + if ((detectedType == NumericalType::BinaryUint) || + (detectedType == NumericalType::HexadecimalUInt)) { unsigned int tmp; bool isvalid = validUIntFromString(tBuf, tmp); result = static_cast(tmp); @@ -96,6 +107,7 @@ bool validFloatFromString(const String& tBuf, float& result) { } const bool isvalid = numerical.length() > 0; + if (isvalid) { result = numerical.toFloat(); } @@ -104,28 +116,31 @@ bool validFloatFromString(const String& tBuf, float& result) { bool validDoubleFromString(const String& tBuf, double& result) { #ifdef CORE_POST_2_5_0 + // String.toDouble() is introduced in core 2.5.0 NumericalType detectedType; - const String numerical = getNumerical(tBuf, NumericalType::FloatingPoint, detectedType); - if (detectedType == NumericalType::BinaryUint || - detectedType == NumericalType::HexadecimalUInt) { + const String numerical = getNumerical(tBuf, NumericalType::FloatingPoint, detectedType); + + if ((detectedType == NumericalType::BinaryUint) || + (detectedType == NumericalType::HexadecimalUInt)) { uint64_t tmp; - bool isvalid = validUInt64FromString(tBuf, tmp); + bool isvalid = validUInt64FromString(tBuf, tmp); result = static_cast(tmp); return isvalid; } const bool isvalid = numerical.length() > 0; + if (isvalid) { result = numerical.toDouble(); } return isvalid; - #else + #else // ifdef CORE_POST_2_5_0 float tmp = static_cast(result); - bool res = validFloatFromString(tBuf, tmp); + bool res = validFloatFromString(tBuf, tmp); result = static_cast(tmp); return res; - #endif + #endif // ifdef CORE_POST_2_5_0 } bool mustConsiderAsString(NumericalType detectedType) { @@ -135,7 +150,7 @@ bool mustConsiderAsString(NumericalType detectedType) { break; case NumericalType::HexadecimalUInt: case NumericalType::BinaryUint: - return true; // Has '0x' or '0b' as prefix + return true; // Has '0x' or '0b' as prefix } return false; } @@ -143,17 +158,21 @@ bool mustConsiderAsString(NumericalType detectedType) { String getNumerical(const String& tBuf, NumericalType requestedType, NumericalType& detectedType) { String result; const unsigned int bufLength = tBuf.length(); - unsigned int firstDec = 0; + unsigned int firstDec = 0; + while (firstDec < bufLength && tBuf.charAt(firstDec) == ' ') { ++firstDec; } - if (firstDec >= bufLength) return result; + + if (firstDec >= bufLength) { return result; } bool decPt = false; + detectedType = NumericalType::Integer; char c = tBuf.charAt(firstDec); - if (c == '+' || c == '-') { - if (requestedType != NumericalType::HexadecimalUInt && - requestedType != NumericalType::BinaryUint) { + + if ((c == '+') || (c == '-')) { + if ((requestedType != NumericalType::HexadecimalUInt) && + (requestedType != NumericalType::BinaryUint)) { if (c == '-') { result += c; } @@ -162,49 +181,56 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy } else if (c == '0') { ++firstDec; result += c; + if (firstDec < bufLength) { c = tBuf.charAt(firstDec); - if (c == 'x' || c == 'X') { + + if ((c == 'x') || (c == 'X')) { ++firstDec; - result += c; + result += c; detectedType = NumericalType::HexadecimalUInt; - } else if (c == 'b' || c == 'B') { + } else if ((c == 'b') || (c == 'B')) { ++firstDec; - result += c; + result += c; detectedType = NumericalType::BinaryUint; } else if (NumericalType::FloatingPoint != requestedType) { - // Only floating point numbers should start with '0.' + // Only floating point numbers should start with '0.' // All other combinations are not valid. return result; } } } - for(unsigned int x=firstDec; x < bufLength; ++x) { + for (unsigned int x = firstDec; x < bufLength; ++x) { c = tBuf.charAt(x); - if(c == '.') { - if (NumericalType::FloatingPoint != requestedType) return result; + + if (c == '.') { + if (NumericalType::FloatingPoint != requestedType) { return result; } + // Only one decimal point allowed - if(decPt) return result; + if (decPt) { return result; } else { - decPt = true; + decPt = true; detectedType = NumericalType::FloatingPoint; } } else { switch (detectedType) { case NumericalType::FloatingPoint: case NumericalType::Integer: + if (!isdigit(c)) { return result; } break; case NumericalType::HexadecimalUInt: + if (!isxdigit(c)) { return result; } break; case NumericalType::BinaryUint: - if (c != '0' && c != '1') { + + if ((c != '0') && (c != '1')) { return result; } break; @@ -217,8 +243,7 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy bool isNumerical(const String& tBuf, NumericalType& detectedType) { NumericalType requestedType = NumericalType::FloatingPoint; - const String result = getNumerical(tBuf, requestedType, detectedType); + const String result = getNumerical(tBuf, requestedType, detectedType); + return result.length() > 0; } - - diff --git a/src/src/Helpers/Rules_calculate.cpp b/src/src/Helpers/Rules_calculate.cpp index 700e2e7fd..99e588607 100644 --- a/src/src/Helpers/Rules_calculate.cpp +++ b/src/src/Helpers/Rules_calculate.cpp @@ -576,6 +576,7 @@ String RulesCalculate_t::preProces(const String& input) preProcessReplace(preprocessed, UnaryOperator::Sq); preProcessReplace(preprocessed, UnaryOperator::Round); #ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES + // Try the "arc" functions first, or else "sin" is already replaced when "asin" is tried. if (preprocessed.indexOf(F("sin")) != -1) { preProcessReplace(preprocessed, UnaryOperator::ArcSin); @@ -583,19 +584,21 @@ String RulesCalculate_t::preProces(const String& input) preProcessReplace(preprocessed, UnaryOperator::Sin); preProcessReplace(preprocessed, UnaryOperator::Sin_d); } + if (preprocessed.indexOf(F("cos")) != -1) { preProcessReplace(preprocessed, UnaryOperator::ArcCos); preProcessReplace(preprocessed, UnaryOperator::ArcCos_d); preProcessReplace(preprocessed, UnaryOperator::Cos); preProcessReplace(preprocessed, UnaryOperator::Cos_d); } + if (preprocessed.indexOf(F("tan")) != -1) { preProcessReplace(preprocessed, UnaryOperator::ArcTan); preProcessReplace(preprocessed, UnaryOperator::ArcTan_d); preProcessReplace(preprocessed, UnaryOperator::Tan); preProcessReplace(preprocessed, UnaryOperator::Tan_d); } -#endif +#endif // ifdef USE_TRIGONOMETRIC_FUNCTIONS_RULES return preprocessed; } @@ -617,6 +620,7 @@ int CalculateParam(const String& TmpStr) { if (!isError(returnCode)) { #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { String log = F("CALCULATE PARAM: "); log += TmpStr; diff --git a/src/src/Helpers/Rules_calculate.h b/src/src/Helpers/Rules_calculate.h index 22119fb32..44029bb4e 100644 --- a/src/src/Helpers/Rules_calculate.h +++ b/src/src/Helpers/Rules_calculate.h @@ -29,24 +29,24 @@ bool isError(CalculateReturnCode returnCode); enum class UnaryOperator { Not = '!', Log = 192, // Start at some ASCII code we don't expect in the rules. - Ln, // Natural logarithm - Abs, // Absolute value - Exp, // exponential value, e^x - Sqrt, // Square Root - Sq, // Square, x^2 - Round, // Rounds to the nearest integer, but rounds halfway cases away from zero (instead of to the nearest even integer). - Sin, // Sine (radian) - Sin_d, // Sine (degree) - Cos, // Cosine (radian) - Cos_d, // Cosine (degree) - Tan, // Tangent (radian) - Tan_d, // Tangent (degree) - ArcSin, // Arc Sine (radian) - ArcSin_d, // Arc Sine (degree) - ArcCos, // Arc Cosine (radian) - ArcCos_d, // Arc Cosine (degree) - ArcTan, // Arc Tangent (radian) - ArcTan_d // Arc Tangent (degree) + Ln, // Natural logarithm + Abs, // Absolute value + Exp, // exponential value, e^x + Sqrt, // Square Root + Sq, // Square, x^2 + Round, // Rounds to the nearest integer, but rounds halfway cases away from zero (instead of to the nearest even integer). + Sin, // Sine (radian) + Sin_d, // Sine (degree) + Cos, // Cosine (radian) + Cos_d, // Cosine (degree) + Tan, // Tangent (radian) + Tan_d, // Tangent (degree) + ArcSin, // Arc Sine (radian) + ArcSin_d, // Arc Sine (degree) + ArcCos, // Arc Cosine (radian) + ArcCos_d, // Arc Cosine (degree) + ArcTan, // Arc Tangent (radian) + ArcTan_d // Arc Tangent (degree) }; void preProcessReplace(String & input, diff --git a/src/src/Helpers/StringConverter.cpp b/src/src/Helpers/StringConverter.cpp index e8aaa4acf..0d4ad5cfe 100644 --- a/src/src/Helpers/StringConverter.cpp +++ b/src/src/Helpers/StringConverter.cpp @@ -35,6 +35,7 @@ unsigned long str2int(const char *string) { unsigned int temp = 0; + validUIntFromString(string, temp); return static_cast(temp); @@ -42,21 +43,24 @@ unsigned long str2int(const char *string) String ull2String(uint64_t value, uint8_t base) { String res; + if (value == 0) { res = '0'; return res; } + while (value > 0) { - res += String(static_cast(value % base), base); + res += String(static_cast(value % base), base); value /= base; } - int endpos = res.length() - 1; + int endpos = res.length() - 1; int beginpos = 0; + while (endpos > beginpos) { const char c = res[beginpos]; res[beginpos] = res[endpos]; - res[endpos] = c; + res[endpos] = c; ++beginpos; --endpos; } @@ -64,7 +68,6 @@ String ull2String(uint64_t value, uint8_t base) { return res; } - /********************************************************************************************\ Check if valid float and convert string to float. \*********************************************************************************************/ @@ -131,6 +134,7 @@ unsigned long hexToUL(const String& input_c, size_t nrHexDecimals) { nr_decimals = inputLength; } String tmp = input_c.substring(0, nr_decimals); + return strtoul(tmp.c_str(), 0, 16); } @@ -207,7 +211,6 @@ String formatToHex_decimal(unsigned long value, unsigned long factor) { return result; } - String boolToString(bool value) { return value ? F("true") : F("false"); } @@ -238,13 +241,14 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck return "0"; } - const byte valueCount = getValueCountForTask(event->TaskIndex); + const byte valueCount = getValueCountForTask(event->TaskIndex); Sensor_VType sensorType = event->getSensorType(); if (valueCount <= rel_index) { isvalid = false; #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("No sensor value for TaskIndex: "); log += event->TaskIndex + 1; @@ -254,7 +258,7 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck log += getSensorTypeLabel(sensorType); addLog(LOG_LEVEL_ERROR, log); } - #endif + #endif // ifndef BUILD_NO_DEBUG return ""; } @@ -285,8 +289,9 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck f = 0; } LoadTaskSettings(event->TaskIndex); - + byte nrDecimals = ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]; + if (!Device[DeviceIndex].configurableDecimals()) { nrDecimals = 0; } @@ -301,12 +306,14 @@ String formatUserVarNoCheck(taskIndex_t TaskIndex, byte rel_index) { // FIXME TD-er: calls to this function cannot handle Sensor_VType::SENSOR_TYPE_STRING struct EventStruct TempEvent(TaskIndex); + return doFormatUserVar(&TempEvent, rel_index, false, isvalid); } String formatUserVar(taskIndex_t TaskIndex, byte rel_index, bool& isvalid) { // FIXME TD-er: calls to this function cannot handle Sensor_VType::SENSOR_TYPE_STRING struct EventStruct TempEvent(TaskIndex); + return doFormatUserVar(&TempEvent, rel_index, true, isvalid); } @@ -335,7 +342,6 @@ String get_formatted_Controller_number(cpluginID_t cpluginID) { return result; } - /*********************************************************************************************\ Wrap a string with given pre- and postfix string. \*********************************************************************************************/ @@ -355,7 +361,6 @@ String wrapIfContains(const String& value, char contains, char wrap) { return value; } - /*********************************************************************************************\ Format an object value pair for use in JSON. \*********************************************************************************************/ @@ -444,6 +449,7 @@ bool safe_strncpy(char *dest, const char *source, size_t max_size) { if (source == NULL) { return false; } bool result = true; + memset(dest, 0, max_size); size_t str_length = strlen(source); @@ -521,6 +527,7 @@ String parseStringToEndKeepCase(const String& string, byte indexFind, char separ return ""; } String result = string.substring(pos_begin, pos_end); + result.trim(); return stripQuotes(result); } @@ -708,7 +715,8 @@ void parseSpecialCharacters(String& s, boolean useURLencode) repl(F("÷"), divide, s, useURLencode); } } -#endif + +#endif // ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER /********************************************************************************************\ replace other system variables like %sysname%, %systime%, %ip% @@ -730,8 +738,6 @@ void parseSingleControllerVariable(String & s, } } - - // Simple macro to create the replacement string only when needed. #define SMART_REPL(T, S) \ if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode); } @@ -739,7 +745,7 @@ void parseSystemVariables(String& s, boolean useURLencode) { #ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER parseSpecialCharacters(s, useURLencode); - #endif + #endif // ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER SystemVariables::parseSystemVariables(s, useURLencode); } @@ -762,6 +768,7 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc } } } + if (validTaskIndex(event->TaskIndex)) { // These replacements use ExtraTaskSettings, so make sure the correct TaskIndex is set in the event. LoadTaskSettings(event->TaskIndex); @@ -771,11 +778,13 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc } const bool vname_found = s.indexOf(F("%vname")) != -1; + if (vname_found) { for (byte i = 0; i < 4; ++i) { String vname = F("%vname"); vname += (i + 1); vname += '%'; + if (validTaskIndex(event->TaskIndex)) { repl(vname, ExtraTaskSettings.TaskDeviceValueNames[i], s, useURLencode); } else { @@ -803,7 +812,8 @@ bool getConvertArgument2(const String& marker, const String& s, float& arg1, flo int pos_comma = argumentString.indexOf(','); if (pos_comma == -1) { return false; } - if (validFloatFromString(argumentString.substring(0, pos_comma), arg1)) { + + if (validFloatFromString(argumentString.substring(0, pos_comma), arg1)) { return validFloatFromString(argumentString.substring(pos_comma + 1), arg2); } } @@ -868,24 +878,26 @@ void parseStandardConversions(String& s, boolean useURLencode) { #undef SMART_CONV } - - /********************************************************************************************\ - Find positional parameter in a char string - \*********************************************************************************************/ - + Find positional parameter in a char string + \*********************************************************************************************/ bool HasArgv(const char *string, unsigned int argc) { String argvString; + return GetArgv(string, argvString, argc); } bool GetArgv(const char *string, String& argvString, unsigned int argc, char separator) { - int pos_begin, pos_end; + int pos_begin, pos_end; bool hasArgument = GetArgvBeginEnd(string, argc, pos_begin, pos_end, separator); + argvString = ""; - if (!hasArgument) return false; - if (pos_begin >= 0 && pos_end >= 0 && pos_end > pos_begin) { + + if (!hasArgument) { return false; } + + if ((pos_begin >= 0) && (pos_end >= 0) && (pos_end > pos_begin)) { argvString.reserve(pos_end - pos_begin); + for (int i = pos_begin; i < pos_end; ++i) { argvString += string[i]; } @@ -937,7 +949,7 @@ bool GetArgvBeginEnd(const char *string, const unsigned int argc, int& pos_begin } ++pos_end; - if (!parenthesis && (isParameterSeparatorChar(d) || d == separator || (d == 0))) // end of word + if (!parenthesis && (isParameterSeparatorChar(d) || (d == separator) || (d == 0))) // end of word { argc_pos++; @@ -954,4 +966,3 @@ bool GetArgvBeginEnd(const char *string, const unsigned int argc, int& pos_begin } return false; } - diff --git a/src/src/Helpers/StringConverter.h b/src/src/Helpers/StringConverter.h index e25144d3d..c1dac8b81 100644 --- a/src/src/Helpers/StringConverter.h +++ b/src/src/Helpers/StringConverter.h @@ -19,14 +19,14 @@ class IPAddress; // FIXME: change original code so it uses String and String.toInt() unsigned long str2int(const char *string); -String ull2String(uint64_t value, uint8_t base = 10); +String ull2String(uint64_t value, + uint8_t base = 10); /********************************************************************************************\ Check if valid float and convert string to float. \*********************************************************************************************/ -bool string2float(const String& string, - float & floatvalue); - +bool string2float(const String& string, + float & floatvalue); /********************************************************************************************\ @@ -113,11 +113,13 @@ String get_formatted_Controller_number(cpluginID_t cpluginID); /*********************************************************************************************\ Wrap a string with given pre- and postfix string. \*********************************************************************************************/ -void wrap_String(const String& string, - const String& wrap, - String & result); +void wrap_String(const String& string, + const String& wrap, + String & result); -String wrapIfContains(const String& value, char contains, char wrap = '\"'); +String wrapIfContains(const String& value, + char contains, + char wrap = '\"'); /*********************************************************************************************\ Format an object value pair for use in JSON. @@ -159,23 +161,23 @@ String to_internal_string(const String& input, \*********************************************************************************************/ String parseString(const String& string, byte indexFind, - char separator = ','); + char separator = ','); String parseStringKeepCase(const String& string, byte indexFind, - char separator = ','); + char separator = ','); String parseStringToEnd(const String& string, byte indexFind, - char separator = ','); + char separator = ','); String parseStringToEndKeepCase(const String& string, byte indexFind, - char separator = ','); + char separator = ','); String tolerantParseStringKeepCase(const String& string, byte indexFind, - char separator = ','); + char separator = ','); // escapes special characters in strings for use in html-forms bool htmlEscapeChar(char c, @@ -198,7 +200,7 @@ void repl(const String& key, #ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER void parseSpecialCharacters(String& s, boolean useURLencode); -#endif +#endif // ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER /********************************************************************************************\ replace other system variables like %sysname%, %systime%, %ip% @@ -244,11 +246,19 @@ void parseStandardConversions(String& s, boolean useURLencode); -bool HasArgv(const char *string, unsigned int argc); +bool HasArgv(const char *string, + unsigned int argc); -bool GetArgv(const char *string, String& argvString, unsigned int argc, char separator = ','); +bool GetArgv(const char *string, + String & argvString, + unsigned int argc, + char separator = ','); -bool GetArgvBeginEnd(const char *string, const unsigned int argc, int& pos_begin, int& pos_end, char separator = ','); +bool GetArgvBeginEnd(const char *string, + const unsigned int argc, + int & pos_begin, + int & pos_end, + char separator = ','); #endif // HELPERS_STRINGCONVERTER_H diff --git a/src/src/Helpers/StringParser.cpp b/src/src/Helpers/StringParser.cpp index b190bb099..c6bd9f66f 100644 --- a/src/src/Helpers/StringParser.cpp +++ b/src/src/Helpers/StringParser.cpp @@ -42,7 +42,7 @@ String parseTemplate_padded(String& tmpString, byte minimal_lineSize, bool useUR { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("parseTemplate_padded")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER START_TIMER // Keep current loaded taskSettings to restore at the end. @@ -95,7 +95,7 @@ String parseTemplate_padded(String& tmpString, byte minimal_lineSize, bool useUR if (validUIntFromString(valueName, varNum)) { unsigned char nr_decimals = maxNrDecimals_double(getCustomFloatVar(varNum)); - bool trimTrailingZeros = true; + bool trimTrailingZeros = true; if (deviceName.equals(F("int"))) { nr_decimals = 0; @@ -156,7 +156,7 @@ String parseTemplate_padded(String& tmpString, byte minimal_lineSize, bool useUR newString += tmpString.substring(lastStartpos); #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("parseTemplate2")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER // Restore previous loaded taskSettings if (currentTaskIndex != 255) @@ -177,7 +177,7 @@ String parseTemplate_padded(String& tmpString, byte minimal_lineSize, bool useUR STOP_TIMER(PARSE_TEMPLATE_PADDED); #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("parseTemplate3")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return newString; } @@ -198,7 +198,7 @@ void transformValue( // Is this the way it is intended to use? #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("transformValue")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER // start changes by giig1967g - 2018-04-20 // Syntax: [task#value#transformation#justification] @@ -219,7 +219,7 @@ void transformValue( // valueJust="justification" if (valueFormat.length() > 0) // do the checks only if a Format is defined to optimize loop { - int logicVal = 0; + int logicVal = 0; double valFloat = 0.0; if (validDoubleFromString(value, valFloat)) @@ -523,7 +523,7 @@ void transformValue( } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("transformValue2")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER } // Find the first (enabled) task with given name @@ -650,7 +650,6 @@ bool findNextDevValNameInString(const String& input, int& startpos, int& endpos, return true; } - /********************************************************************************************\ Check to see if a given argument is a valid taskIndex (argc = 0 => command) \*********************************************************************************************/ @@ -691,7 +690,7 @@ void parseCommandString(struct EventStruct *event, const String& string) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("parseCommandString")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER event->Par1 = parseCommandArgumentInt(string, 1); event->Par2 = parseCommandArgumentInt(string, 2); event->Par3 = parseCommandArgumentInt(string, 3); diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 0739f5e1e..4ed6fd647 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -356,12 +356,11 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task if ((Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL) || (Device[DeviceIndex].Type == DEVICE_TYPE_SERIAL_PLUS1)) { - #ifdef PLUGIN_USES_SERIAL + # ifdef PLUGIN_USES_SERIAL serialHelper_webformSave(&TempEvent); - #else - addLog(LOG_LEVEL_ERROR, F("PLUGIN_USES_SERIAL not defined")); - #endif - + # else // ifdef PLUGIN_USES_SERIAL + addLog(LOG_LEVEL_ERROR, F("PLUGIN_USES_SERIAL not defined")); + # endif // ifdef PLUGIN_USES_SERIAL } const byte valueCount = getValueCountForTask(taskIndex); @@ -526,11 +525,11 @@ void handle_devicess_ShowAllTasksTable(byte page) } case DEVICE_TYPE_SERIAL: case DEVICE_TYPE_SERIAL_PLUS1: - #ifdef PLUGIN_USES_SERIAL + # ifdef PLUGIN_USES_SERIAL addHtml(serialHelper_getSerialTypeLabel(&TempEvent)); - #else + # else // ifdef PLUGIN_USES_SERIAL addHtml(F("PLUGIN_USES_SERIAL not defined")); - #endif + # endif // ifdef PLUGIN_USES_SERIAL break; @@ -635,12 +634,12 @@ void handle_devicess_ShowAllTasksTable(byte page) // fallthrough case DEVICE_TYPE_SERIAL: { - #ifdef PLUGIN_USES_SERIAL + # ifdef PLUGIN_USES_SERIAL addHtml(serialHelper_getGpioDescription(static_cast(Settings.TaskDevicePort[x]), Settings.TaskDevicePin1[x], Settings.TaskDevicePin2[x], F("
"))); - #else + # else // ifdef PLUGIN_USES_SERIAL addHtml(F("PLUGIN_USES_SERIAL not defined")); - #endif + # endif // ifdef PLUGIN_USES_SERIAL if (showpin3) { html_BR(); @@ -905,11 +904,11 @@ void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, byte page) case DEVICE_TYPE_SERIAL: case DEVICE_TYPE_SERIAL_PLUS1: { - #ifdef PLUGIN_USES_SERIAL + # ifdef PLUGIN_USES_SERIAL devicePage_show_serial_config(taskIndex); - #else + # else // ifdef PLUGIN_USES_SERIAL addHtml(F("PLUGIN_USES_SERIAL not defined")); - #endif + # endif // ifdef PLUGIN_USES_SERIAL break; } diff --git a/src/src/WebServer/Rules.cpp b/src/src/WebServer/Rules.cpp index cff56170e..5bd65a2b8 100644 --- a/src/src/WebServer/Rules.cpp +++ b/src/src/WebServer/Rules.cpp @@ -25,20 +25,20 @@ // Web Interface rules page // ******************************************************************************** void handle_rules() { - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER if (!isLoggedIn() || !Settings.UseRules) { return; } navMenuIndex = MENU_INDEX_RULES; const byte rulesSet = getFormItemInt(F("set"), 1); - #if defined(ESP8266) + # if defined(ESP8266) String fileName = F("rules"); - #endif // if defined(ESP8266) - #if defined(ESP32) + # endif // if defined(ESP8266) + # if defined(ESP32) String fileName = F("/rules"); - #endif // if defined(ESP32) + # endif // if defined(ESP32) fileName += rulesSet; fileName += F(".txt"); @@ -117,22 +117,22 @@ void handle_rules_new() { handle_rules(); return; } - #ifdef WEBSERVER_NEW_RULES - #ifndef BUILD_NO_RAM_TRACKER + # ifdef WEBSERVER_NEW_RULES + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER navMenuIndex = 5; TXBuffer.startStream(); sendHeadandTail(F("TmplStd"), _HEAD); // define macro - #if defined(ESP8266) + # if defined(ESP8266) String rootPath = F("rules"); - #endif // if defined(ESP8266) - #if defined(ESP32) + # endif // if defined(ESP8266) + # if defined(ESP32) String rootPath = F("/rules"); - #endif // if defined(ESP32) + # endif // if defined(ESP32) // Pagionation of rules list const int rulesListPageSize = 25; @@ -160,75 +160,75 @@ void handle_rules_new() { // Build table detail int count = -1; - HandlerFileInfo renderDetail = [/*&buffer,*/ &count, endIdx](fileInfo fi) - { -#ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("Start generation of: ")); - Serial.println(fi.Name); -#endif // ifdef WEBSERVER_RULES_DEBUG + HandlerFileInfo renderDetail = [/*&buffer,*/ &count, endIdx](fileInfo fi) + { +# ifdef WEBSERVER_RULES_DEBUG + Serial.print(F("Start generation of: ")); + Serial.println(fi.Name); +# endif // ifdef WEBSERVER_RULES_DEBUG - if (fi.isDirectory) - { - html_TR_TD(); - } - else - { - count++; - addHtml(F("")); - } + if (fi.isDirectory) + { + html_TR_TD(); + } + else + { + count++; + addHtml(F("")); + } - // Event Name - addHtml(FileNameToEvent(fi.Name)); + // Event Name + addHtml(FileNameToEvent(fi.Name)); - if (fi.isDirectory) - { - addHtml(F("")); - addSaveButton(String(F("/rules/backup?directory=")) + URLEncode(fi.Name.c_str()) - , F("Backup") - ); - } - else - { - String encodedPath = URLEncode((fi.Name + F(".txt")).c_str()); + if (fi.isDirectory) + { + addHtml(F("")); + addSaveButton(String(F("/rules/backup?directory=")) + URLEncode(fi.Name.c_str()) + , F("Backup") + ); + } + else + { + String encodedPath = URLEncode((fi.Name + F(".txt")).c_str()); - // File Name - { - String html; - html.reserve(128); + // File Name + { + String html; + html.reserve(128); - html += F(""; - html += fi.Name; - html += F(".txt"); - html += F(""); + html += F(""; + html += fi.Name; + html += F(".txt"); + html += F(""); - // File size - html += F(""); - html += fi.Size; - html += F(""); - addHtml(html); - } + // File size + html += F(""); + html += fi.Size; + html += F(""); + addHtml(html); + } - // Actions - html_TD(); - addSaveButton(String(F("/rules/backup?fileName=")) + encodedPath - , F("Backup") - ); + // Actions + html_TD(); + addSaveButton(String(F("/rules/backup?fileName=")) + encodedPath + , F("Backup") + ); - addDeleteButton(String(F("/rules/delete?fileName=")) + encodedPath - , F("Delete") - ); - } - addHtml(F("")); -#ifdef WEBSERVER_RULES_DEBUG - Serial.print(F("End generation of: ")); - Serial.println(fi.Name); -#endif // ifdef WEBSERVER_RULES_DEBUG + addDeleteButton(String(F("/rules/delete?fileName=")) + encodedPath + , F("Delete") + ); + } + addHtml(F("")); +# ifdef WEBSERVER_RULES_DEBUG + Serial.print(F("End generation of: ")); + Serial.println(fi.Name); +# endif // ifdef WEBSERVER_RULES_DEBUG - return count < endIdx; - }; + return count < endIdx; + }; bool hasMore = EnumerateFileAndDirectory(rootPath @@ -257,10 +257,10 @@ void handle_rules_new() { // TXBuffer += F("

"); sendHeadandTail(F("TmplStd"), _TAIL); TXBuffer.endStream(); - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules")); - #endif - #endif // WEBSERVER_NEW_RULES + # endif // ifndef BUILD_NO_RAM_TRACKER + # endif // WEBSERVER_NEW_RULES } void handle_rules_backup() { @@ -269,17 +269,17 @@ void handle_rules_backup() { Goto_Rules_Root(); return; } - #ifdef WEBSERVER_NEW_RULES - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_NEW_RULES + # ifdef WEBSERVER_RULES_DEBUG Serial.println(F("handle rules backup")); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG if (!isLoggedIn() || !Settings.UseRules) { return; } if (!clientIPallowed()) { return; } - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_backup")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER String directory = web_server.arg(F("directory")); String fileName = web_server.arg(F("fileName")); String error; @@ -319,10 +319,10 @@ void handle_rules_backup() { addHtmlError(error); TXBuffer.endStream(); } - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_backup")); - #endif - #endif // WEBSERVER_NEW_RULES + # endif // ifndef BUILD_NO_RAM_TRACKER + # endif // WEBSERVER_NEW_RULES } void handle_rules_delete() { @@ -335,18 +335,18 @@ void handle_rules_delete() { Goto_Rules_Root(); return; } - #ifdef WEBSERVER_NEW_RULES - #ifndef BUILD_NO_RAM_TRACKER + # ifdef WEBSERVER_NEW_RULES + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_delete")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER String fileName = web_server.arg(F("fileName")); fileName = fileName.substring(0, fileName.length() - 4); bool removed = false; - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_RULES_DEBUG Serial.println(F("handle_rules_delete")); Serial.print(F("File name: ")); Serial.println(fileName); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG if (fileName.length() > 0) { @@ -368,10 +368,10 @@ void handle_rules_delete() { sendHeadandTail(F("TmplMsg"), _TAIL); TXBuffer.endStream(); } - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_delete")); - #endif - #endif // WEBSERVER_NEW_RULES + # endif // ifndef BUILD_NO_RAM_TRACKER + # endif // WEBSERVER_NEW_RULES } bool handle_rules_edit(const String& originalUri) @@ -383,15 +383,15 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { // originalUri is passed via deepcopy, since it will be converted to lower case. if (!isLoggedIn() || !Settings.UseRules) { return false; } originalUri.toLowerCase(); - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_edit")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER bool handle = false; - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_RULES_DEBUG Serial.println(originalUri); Serial.println(F("handle_rules_edit")); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG if (isAddNew || (originalUri.startsWith(F("/rules/")) && originalUri.endsWith(F(".txt")))) { @@ -400,7 +400,7 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { Goto_Rules_Root(); return true; } - #ifdef WEBSERVER_NEW_RULES + # ifdef WEBSERVER_NEW_RULES String eventName; String fileName; @@ -416,19 +416,19 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { } else { - #if defined(ESP8266) + # if defined(ESP8266) fileName = F("rules/"); - #endif // if defined(ESP8266) - #if defined(ESP32) + # endif // if defined(ESP8266) + # if defined(ESP32) fileName = F("/rules/"); - #endif // if defined(ESP32) + # endif // if defined(ESP32) fileName += originalUri.substring(7, originalUri.length() - 4); eventName = FileNameToEvent(fileName); } - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_RULES_DEBUG Serial.print(F("File name: ")); Serial.println(fileName); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG bool isEdit = fileExists(fileName); if (web_server.args() > 0) @@ -488,14 +488,14 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { // hidden field to check Overwrite addHtml(F("'); bool isReadOnly = !isOverwrite && ((isEdit && !isAddNew && !isNew) || (isAddNew && isNew)); - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_RULES_DEBUG Serial.print(F("Is Overwrite: ")); Serial.println(isOverwrite); Serial.print(F("Is edit: ")); @@ -506,7 +506,7 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { Serial.println(isNew); Serial.print(F("Is Read Only: ")); Serial.println(isReadOnly); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG addFormTextBox(F("Event name") // Label , F("eventName") // field name @@ -531,11 +531,11 @@ bool handle_rules_edit(String originalUri, bool isAddNew) { sendHeadandTail(F("TmplStd"), true); TXBuffer.endStream(); - #endif // WEBSERVER_NEW_RULES + # endif // WEBSERVER_NEW_RULES } - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("handle_rules_edit2")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER return handle; } @@ -568,10 +568,10 @@ void Rule_showRuleTextArea(const String& fileName) { bool Rule_Download(const String& path) { - #ifdef WEBSERVER_RULES_DEBUG + # ifdef WEBSERVER_RULES_DEBUG Serial.print(F("Rule_Download path: ")); Serial.println(path); - #endif // ifdef WEBSERVER_RULES_DEBUG + # endif // ifdef WEBSERVER_RULES_DEBUG fs::File dataFile = tryOpenFile(path, "r"); if (!dataFile) @@ -605,7 +605,7 @@ bool EnumerateFileAndDirectory(String & rootPath int count = 0; bool next = true; - #ifdef ESP8266 + # ifdef ESP8266 fs::Dir dir = ESPEASY_FS.openDir(rootPath); Serial.print(F("Enumerate files of ")); Serial.println(rootPath); @@ -628,8 +628,8 @@ bool EnumerateFileAndDirectory(String & rootPath next = handler(fi); } hasMore = dir.next(); - #endif // ifdef ESP8266 - #ifdef ESP32 + # endif // ifdef ESP8266 + # ifdef ESP32 File root = ESPEASY_FS.open(rootPath); if (root) @@ -656,7 +656,7 @@ bool EnumerateFileAndDirectory(String & rootPath { addLog(LOG_LEVEL_ERROR, F("Invalid root.")); } - #endif // ifdef ESP32 + # endif // ifdef ESP32 return hasMore; } diff --git a/src/src/WebServer/SysInfoPage.cpp b/src/src/WebServer/SysInfoPage.cpp index 0584270ba..c233e538a 100644 --- a/src/src/WebServer/SysInfoPage.cpp +++ b/src/src/WebServer/SysInfoPage.cpp @@ -129,10 +129,10 @@ void handle_sysinfo_json() { json_prop(F("ap_mac"), getValue(LabelType::AP_MAC)); json_prop(F("ssid"), getValue(LabelType::SSID)); json_prop(F("bssid"), getValue(LabelType::BSSID)); - json_number(F("channel"), getValue(LabelType::CHANNEL)); - json_prop(F("connected"), getValue(LabelType::CONNECTED)); - json_prop(F("ldr"), getValue(LabelType::LAST_DISC_REASON_STR)); - json_number(F("reconnects"), getValue(LabelType::NUMBER_RECONNECTS)); + json_number(F("channel"), getValue(LabelType::CHANNEL)); + json_prop(F("connected"), getValue(LabelType::CONNECTED)); + json_prop(F("ldr"), getValue(LabelType::LAST_DISC_REASON_STR)); + json_number(F("reconnects"), getValue(LabelType::NUMBER_RECONNECTS)); json_close(); # ifdef HAS_ETHERNET @@ -147,13 +147,13 @@ void handle_sysinfo_json() { # endif // ifdef HAS_ETHERNET json_open(false, F("firmware")); - json_prop(F("build"), String(BUILD)); - json_prop(F("notes"), F(BUILD_NOTES)); - json_prop(F("libraries"), getSystemLibraryString()); - json_prop(F("git_version"), F(BUILD_GIT)); - json_prop(F("plugins"), getPluginDescriptionString()); - json_prop(F("md5"), String(CRCValues.compileTimeMD5[0], HEX)); - json_number(F("md5_check"), String(CRCValues.checkPassed())); + json_prop(F("build"), String(BUILD)); + json_prop(F("notes"), F(BUILD_NOTES)); + json_prop(F("libraries"), getSystemLibraryString()); + json_prop(F("git_version"), F(BUILD_GIT)); + json_prop(F("plugins"), getPluginDescriptionString()); + json_prop(F("md5"), String(CRCValues.compileTimeMD5[0], HEX)); + json_number(F("md5_check"), String(CRCValues.checkPassed())); json_prop(F("build_time"), get_build_time()); json_prop(F("filename"), getValue(LabelType::BINARY_FILENAME)); json_prop(F("build_platform"), getValue(LabelType::BUILD_PLATFORM)); @@ -162,7 +162,7 @@ void handle_sysinfo_json() { json_open(false, F("esp")); json_prop(F("chip_id"), getValue(LabelType::ESP_CHIP_ID)); - json_number(F("cpu"), getValue(LabelType::ESP_CHIP_FREQ)); + json_number(F("cpu"), getValue(LabelType::ESP_CHIP_FREQ)); # ifdef ARDUINO_BOARD json_prop(F("board"), ARDUINO_BOARD); @@ -681,7 +681,7 @@ void handle_sysinfo_Storage() { html += F(" kB free)"); addHtml(html); } - #ifndef LIMIT_BUILD_SIZE + # ifndef LIMIT_BUILD_SIZE addRowLabel(F("Page size")); addHtmlInt(SpiffsPagesize()); @@ -692,7 +692,7 @@ void handle_sysinfo_Storage() { addHtmlInt(SpiffsTotalBytes() / SpiffsBlocksize()); { - # if defined(ESP8266) + # if defined(ESP8266) fs::FSInfo fs_info; ESPEASY_FS.info(fs_info); addRowLabel(F("Maximum open files")); @@ -701,9 +701,9 @@ void handle_sysinfo_Storage() { addRowLabel(F("Maximum path length")); addHtmlInt(fs_info.maxPathLength); - # endif // if defined(ESP8266) + # endif // if defined(ESP8266) } - #endif + # endif // ifndef LIMIT_BUILD_SIZE # ifndef BUILD_MINIMAL_OTA diff --git a/src/src/WebServer/ToolsPage.cpp b/src/src/WebServer/ToolsPage.cpp index 5560fef62..e47954b8e 100644 --- a/src/src/WebServer/ToolsPage.cpp +++ b/src/src/WebServer/ToolsPage.cpp @@ -11,12 +11,10 @@ #include "../../ESPEasy-Globals.h" - - #ifdef WEBSERVER_TOOLS -#include "../Commands/InternalCommands.h" -#include "../Helpers/WebServer_commandHelper.h" +# include "../Commands/InternalCommands.h" +# include "../Helpers/WebServer_commandHelper.h" // ******************************************************************************** // Web Interface Tools page @@ -28,6 +26,7 @@ void handle_tools() { sendHeadandTail_stdtemplate(_HEAD); String webrequest = web_server.arg(F("cmd")); + handle_command_from_web(EventValueSource::Enum::VALUE_SOURCE_WEB_FRONTEND, webrequest); printToWeb = false; printToWebJSON = false; @@ -42,11 +41,11 @@ void handle_tools() { addHtml(F("")); addHtml(F("'); - + html_TR_TD(); addSubmitButton(); addHelpButton(F("ESPEasy_Command_Reference")); @@ -64,32 +63,32 @@ void handle_tools() { addFormSubHeader(F("System")); - addWideButtonPlusDescription(F("/?cmd=reboot"), F("Reboot"), F("Reboots ESP")); + addWideButtonPlusDescription(F("/?cmd=reboot"), F("Reboot"), F("Reboots ESP")); # ifdef WEBSERVER_LOG - addWideButtonPlusDescription(F("log"), F("Log"), F("Open log output")); + addWideButtonPlusDescription(F("log"), F("Log"), F("Open log output")); # endif // ifdef WEBSERVER_LOG - #ifdef WEBSERVER_SYSINFO - addWideButtonPlusDescription(F("sysinfo"), F("Info"), F("Open system info page")); - #endif + # ifdef WEBSERVER_SYSINFO + addWideButtonPlusDescription(F("sysinfo"), F("Info"), F("Open system info page")); + # endif // ifdef WEBSERVER_SYSINFO - #ifdef WEBSERVER_ADVANCED - addWideButtonPlusDescription(F("advanced"), F("Advanced"), F("Open advanced settings")); - #endif + # ifdef WEBSERVER_ADVANCED + addWideButtonPlusDescription(F("advanced"), F("Advanced"), F("Open advanced settings")); + # endif // ifdef WEBSERVER_ADVANCED - addWideButtonPlusDescription(F("json"), F("Show JSON"), F("Open JSON output")); + addWideButtonPlusDescription(F("json"), F("Show JSON"), F("Open JSON output")); # ifdef WEBSERVER_TIMINGSTATS - addWideButtonPlusDescription(F("timingstats"), F("Timing stats"), F("Open timing statistics of system")); + addWideButtonPlusDescription(F("timingstats"), F("Timing stats"), F("Open timing statistics of system")); # endif // WEBSERVER_TIMINGSTATS - #ifdef WEBSERVER_PINSTATES - addWideButtonPlusDescription(F("pinstates"), F("Pin state buffer"), F("Show Pin state buffer")); - #endif + # ifdef WEBSERVER_PINSTATES + addWideButtonPlusDescription(F("pinstates"), F("Pin state buffer"), F("Show Pin state buffer")); + # endif // ifdef WEBSERVER_PINSTATES # ifdef WEBSERVER_SYSVARS - addWideButtonPlusDescription(F("sysvars"), F("System Variables"), F("Show all system variables and conversions")); + addWideButtonPlusDescription(F("sysvars"), F("System Variables"), F("Show all system variables and conversions")); # endif // ifdef WEBSERVER_SYSVARS addFormSubHeader(F("Wifi")); @@ -97,15 +96,15 @@ void handle_tools() { addWideButtonPlusDescription(F("/?cmd=wificonnect"), F("Connect"), F("Connects to known Wifi network")); addWideButtonPlusDescription(F("/?cmd=wifidisconnect"), F("Disconnect"), F("Disconnect from wifi network")); - #ifdef WEBSERVER_WIFI_SCANNER + # ifdef WEBSERVER_WIFI_SCANNER addWideButtonPlusDescription(F("wifiscanner"), F("Scan"), F("Scan for wifi networks")); - #endif // ifdef WEBSERVER_WIFI_SCANNER + # endif // ifdef WEBSERVER_WIFI_SCANNER - #ifdef WEBSERVER_I2C_SCANNER + # ifdef WEBSERVER_I2C_SCANNER addFormSubHeader(F("Interfaces")); addWideButtonPlusDescription(F("i2cscanner"), F("I2C Scan"), F("Scan for I2C devices")); - #endif // ifdef WEBSERVER_I2C_SCANNER + # endif // ifdef WEBSERVER_I2C_SCANNER addFormSubHeader(F("Settings")); @@ -113,8 +112,8 @@ void handle_tools() { addFormNote(F("(File MUST be renamed to \"config.dat\" before upload!)")); addWideButtonPlusDescription(F("download"), F("Save"), F("Saves a settings file")); -#ifdef WEBSERVER_NEW_UI - # if defined(ESP8266) +# ifdef WEBSERVER_NEW_UI + # if defined(ESP8266) if ((SpiffsFreeSpace() / 1024) > 50) { html_TR_TD(); @@ -123,12 +122,12 @@ void handle_tools() { addHtml(F("Download new UI")); addHtml(F("Download new UI(alpha)")); } - # endif // if defined(ESP8266) -#endif // WEBSERVER_NEW_UI + # endif // if defined(ESP8266) +# endif // WEBSERVER_NEW_UI -#if defined(ESP8266) || defined(ESP32) +# if defined(ESP8266) || defined(ESP32) { - # ifndef NO_HTTP_UPDATER + # ifndef NO_HTTP_UPDATER { uint32_t maxSketchSize; bool use2step; @@ -153,20 +152,20 @@ void handle_tools() { addHtmlInt(maxSketchSize); addHtml(F(" bytes)")); } - # endif // ifndef NO_HTTP_UPDATER + # endif // ifndef NO_HTTP_UPDATER } -#endif // if defined(ESP8266) +# endif // if defined(ESP8266) addFormSubHeader(F("Filesystem")); 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 + # ifdef USE_SETTINGS_ARCHIVE addWideButtonPlusDescription(F("/settingsarchive"), F("Settings Archive"), F("Download settings from some archive")); - #endif // ifdef USE_SETTINGS_ARCHIVE -#ifdef FEATURE_SD + # endif // ifdef USE_SETTINGS_ARCHIVE +# ifdef FEATURE_SD addWideButtonPlusDescription(F("SDfilelist"), F("SD Card"), F("Show files on SD-Card")); -#endif // ifdef FEATURE_SD +# endif // ifdef FEATURE_SD html_end_table(); html_end_form(); diff --git a/src/src/WebServer/ToolsPage.h b/src/src/WebServer/ToolsPage.h index 41a9d2509..ed3dd9f81 100644 --- a/src/src/WebServer/ToolsPage.h +++ b/src/src/WebServer/ToolsPage.h @@ -6,7 +6,7 @@ #ifdef WEBSERVER_TOOLS -#include "../Commands/InternalCommands.h" +# include "../Commands/InternalCommands.h" // ******************************************************************************** // Web Interface Tools page @@ -16,8 +16,10 @@ void handle_tools(); // ******************************************************************************** // Web Interface debug page // ******************************************************************************** -void addWideButtonPlusDescription(const String& url, const String& buttonText, const String& description); +void addWideButtonPlusDescription(const String& url, + const String& buttonText, + const String& description); #endif // ifdef WEBSERVER_TOOLS -#endif \ No newline at end of file +#endif // ifndef WEBSERVER_WEBSERVER_TOOLSPAGE_H diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 05afc7a4c..77dff74a8 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -77,7 +77,7 @@ void sendHeadandTail(const String& tmplName, boolean Tail, boolean rebooting) { #endif // ifdef USES_TIMING_STATS String pageTemplate; - String fileName = tmplName; + String fileName = tmplName; fileName += F(".htm"); fs::File f = tryOpenFile(fileName, "r"); @@ -158,6 +158,7 @@ void sendHeadandTail_stdtemplate(boolean Tail, boolean rebooting) { } #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { const int nrArgs = web_server.args(); @@ -175,7 +176,7 @@ void sendHeadandTail_stdtemplate(boolean Tail, boolean rebooting) { addLog(LOG_LEVEL_INFO, log); } } - #endif + #endif // ifndef BUILD_NO_DEBUG } } @@ -275,39 +276,39 @@ void WebServerInit() #ifdef WEBSERVER_RULES web_server.on(F("/rules"), handle_rules_new); web_server.on(F("/rules/"), Goto_Rules_Root); - #ifdef WEBSERVER_NEW_RULES + # ifdef WEBSERVER_NEW_RULES web_server.on(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); - #endif // WEBSERVER_NEW_RULES - #endif // WEBSERVER_RULES + # endif // WEBSERVER_NEW_RULES + #endif // WEBSERVER_RULES #ifdef FEATURE_SD - web_server.on(F("/SDfilelist"), handle_SDfilelist); + web_server.on(F("/SDfilelist"), handle_SDfilelist); #endif // ifdef FEATURE_SD #ifdef WEBSERVER_SETUP - web_server.on(F("/setup"), handle_setup); + web_server.on(F("/setup"), handle_setup); #endif // ifdef WEBSERVER_SETUP #ifdef WEBSERVER_SYSINFO - web_server.on(F("/sysinfo"), handle_sysinfo); + web_server.on(F("/sysinfo"), handle_sysinfo); #endif // ifdef WEBSERVER_SYSINFO #ifdef WEBSERVER_SYSVARS - web_server.on(F("/sysvars"), handle_sysvars); + web_server.on(F("/sysvars"), handle_sysvars); #endif // WEBSERVER_SYSVARS #ifdef WEBSERVER_TIMINGSTATS - web_server.on(F("/timingstats"), handle_timingstats); + web_server.on(F("/timingstats"), handle_timingstats); #endif // WEBSERVER_TIMINGSTATS #ifdef WEBSERVER_TOOLS - web_server.on(F("/tools"), handle_tools); + web_server.on(F("/tools"), handle_tools); #endif // ifdef WEBSERVER_TOOLS #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(F("/upload"), HTTP_GET, handle_upload); + web_server.on(F("/upload"), HTTP_POST, handle_upload_post, handleFileUpload); #endif // ifdef WEBSERVER_UPLOAD #ifdef WEBSERVER_WIFI_SCANNER - web_server.on(F("/wifiscanner"), handle_wifiscanner); + web_server.on(F("/wifiscanner"), handle_wifiscanner); #endif // ifdef WEBSERVER_WIFI_SCANNER #ifdef WEBSERVER_NEW_UI @@ -562,7 +563,7 @@ void getWebPageTemplateVar(const String& varName) addHtml(F("'); addHtml(getGpMenuIcon(i)); addHtml(F("")); @@ -607,12 +608,13 @@ void getWebPageTemplateVar(const String& varName) else { #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = F("Templ: Unknown Var : "); log += varName; addLog(LOG_LEVEL_ERROR, log); } - #endif + #endif // ifndef BUILD_NO_DEBUG // no return string - eat var name } @@ -1173,4 +1175,4 @@ void getPartitionTableSVG(byte pType, unsigned int partitionColor) { bool webArg2ip(const String& arg, byte *IP) { return str2ip(web_server.arg(arg), IP); -} \ No newline at end of file +} diff --git a/src/src/WebServer/WebServer.h b/src/src/WebServer/WebServer.h index 5bd6e7777..e4f0787a3 100644 --- a/src/src/WebServer/WebServer.h +++ b/src/src/WebServer/WebServer.h @@ -31,26 +31,35 @@ extern byte navMenuIndex; // Uncrustify must not be used on macros, but we're now done, so turn Uncrustify on again. // *INDENT-ON* -void sendHeadandTail(const String& tmplName, boolean Tail = false, boolean rebooting = false); -void sendHeadandTail_stdtemplate(boolean Tail = false, boolean rebooting = false); +void sendHeadandTail(const String& tmplName, + boolean Tail = false, + boolean rebooting = false); + +void sendHeadandTail_stdtemplate(boolean Tail = false, + boolean rebooting = false); size_t streamFile_htmlEscape(const String& fileName); -void WebServerInit(); +void WebServerInit(); -void setWebserverRunning(bool state); +void setWebserverRunning(bool state); -void getWebPageTemplateDefault(const String& tmplName, String& tmpl); +void getWebPageTemplateDefault(const String& tmplName, + String & tmpl); -void getWebPageTemplateDefaultHead(String& tmpl, bool addMeta, bool addJS); +void getWebPageTemplateDefaultHead(String& tmpl, + bool addMeta, + bool addJS); -void getWebPageTemplateDefaultHeader(String& tmpl, const String& title, bool addMenu); +void getWebPageTemplateDefaultHeader(String & tmpl, + const String& title, + bool addMenu); -void getWebPageTemplateDefaultContentSection(String& tmpl); +void getWebPageTemplateDefaultContentSection(String& tmpl); -void getWebPageTemplateDefaultFooter(String& tmpl); +void getWebPageTemplateDefaultFooter(String& tmpl); -void getErrorNotifications(); +void getErrorNotifications(); String getGpMenuIcon(byte index); @@ -58,10 +67,9 @@ String getGpMenuLabel(byte index); String getGpMenuURL(byte index); -void getWebPageTemplateVar(const String& varName); - -void writeDefaultCSS(void); +void getWebPageTemplateVar(const String& varName); +void writeDefaultCSS(void); // ******************************************************************************** @@ -81,7 +89,8 @@ void json_open(); void json_open(bool arr); -void json_open(bool arr, const String& name); +void json_open(bool arr, + const String& name); void json_init(); @@ -89,9 +98,11 @@ void json_close(); void json_close(bool arr); -void json_number(const String& name, const String& value); +void json_number(const String& name, + const String& value); -void json_prop(const String& name, const String& value); +void json_prop(const String& name, + const String& value); void json_prop(LabelType::Enum label); @@ -99,29 +110,40 @@ 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); // ******************************************************************************** // Add a Value select dropdown list, based on TaskIndex // This allows to select a task value, based on the existing tasks. // ******************************************************************************** -void addTaskValueSelect(const String& name, int choice, taskIndex_t TaskIndex); +void addTaskValueSelect(const String& name, + int choice, + taskIndex_t TaskIndex); // ******************************************************************************** // Login state check // ******************************************************************************** boolean isLoggedIn(); -String getControllerSymbol(byte index); +String getControllerSymbol(byte index); /* String getValueSymbol(byte index); */ -void addSVG_param(const String& key, float value); +void addSVG_param(const String& key, + float value); -void addSVG_param(const String& key, const String& value); +void addSVG_param(const String& key, + const String& value); -void createSvgRect_noStroke(unsigned int fillColor, float xoffset, float yoffset, float width, float height, float rx, float ry); +void createSvgRect_noStroke(unsigned int fillColor, + float xoffset, + float yoffset, + float width, + float height, + float rx, + float ry); void createSvgRect(unsigned int fillColor, unsigned int strokeColor, @@ -133,18 +155,30 @@ void createSvgRect(unsigned int fillColor, float rx, float ry); -void createSvgHorRectPath(unsigned int color, int xoffset, int yoffset, int size, int height, int range, float SVG_BAR_WIDTH); +void createSvgHorRectPath(unsigned int color, + int xoffset, + int yoffset, + int size, + int height, + int range, + float SVG_BAR_WIDTH); -void createSvgTextElement(const String& text, float textXoffset, float textYoffset); +void createSvgTextElement(const String& text, + float textXoffset, + float textYoffset); -void write_SVG_image_header(int width, int height); +void write_SVG_image_header(int width, + int height); -void write_SVG_image_header(int width, int height, bool useViewbox); +void write_SVG_image_header(int width, + int height, + bool useViewbox); /* void getESPeasyLogo(int width_pixels); */ -void getWiFi_RSSI_icon(int rssi, int width_pixels); +void getWiFi_RSSI_icon(int rssi, + int width_pixels); #ifndef BUILD_MINIMAL_OTA void getConfig_dat_file_layout(); @@ -155,12 +189,14 @@ void getStorageTableSVG(SettingsType::Enum settingsType); #ifdef ESP32 -int getPartionCount(byte pType); +int getPartionCount(byte pType); -void getPartitionTableSVG(byte pType, unsigned int partitionColor); +void getPartitionTableSVG(byte pType, + unsigned int partitionColor); #endif // ifdef ESP32 -bool webArg2ip(const String& arg, byte *IP); +bool webArg2ip(const String& arg, + byte *IP); -#endif \ No newline at end of file +#endif // ifndef WEBSERVER_WEBSERVER_H