From da36ad7f2a5974f974b19c0b97df76a9abf32507 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 8 Sep 2020 09:40:53 +0200 Subject: [PATCH 01/14] [Docs] Add some documentation on C011 Generic HTTP Advanced --- docs/source/Controller/C011.rst | 58 +++++++++++++++++++ .../Controller/_controller_substitutions.repl | 4 +- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/docs/source/Controller/C011.rst b/docs/source/Controller/C011.rst index 8052f14ac8..1edcd85d36 100644 --- a/docs/source/Controller/C011.rst +++ b/docs/source/Controller/C011.rst @@ -37,3 +37,61 @@ Change log Description ----------- + +Many systems provide a simple HTTP API where data can be changed using a HTTP request with a properly constructed querystring. + +This Controller allows you to send HTTP GET, POST and PUT Requests to the given webserver. + +For every device you have to choose to which Controllers it is sending its data. When configuring the Controller you can access this data and use them to generate your querystring. + +You can use this placeholders in http header and in the http body: + +* ``%systime%`` will be replaced with the local system time +* ``%vcc%`` will be replaced with the power supply voltage (if enable in this build) +* ``%ip%`` will be replaced with the local ip adress +* ``%sysload%`` will be replaced with the system load +* ``%uptime%`` will be replaced with the system uptime +* ``%CR%`` will be replaced with "\r" +* ``%LF%`` will be replaced with "\n" (newline) +* ``%sysname%`` will be replaced with the system name +* ``%tskname%`` will be replaced with the name of the device which is sending data to this controller +* ``%id%`` +* ``%vname1%`` will be replaced with Valuename 1 +* ``%vname2%`` will be replaced with Valuename 2 +* ``%vname3%`` will be replaced with Valuename 3 +* ``%vname4%`` will be replaced with Valuename 4 +* ``%val1%`` will be replaced with the value 1 of the device which is sending data to this controller +* ``%val2%`` will be replaced with the value 2 of the device which is sending data to this controller + +You can also write things like this: + +``%1%_some_text_and_placeholder_%/1%`` everything between ``%1%`` and ``%/1%`` will only print when there is a value ``1`` + + +Examples +-------- + +InfluxDB HTTP Api +^^^^^^^^^^^^^^^^^ + +* HTTP Method: ``POST`` +* HTTP URI: ``write?db=testdb`` +* HTTP Header: ``Content-Type: application/x-www-form-urlencoded`` +* HTTP Body: + +.. code-block:: none + + %1%%vname1%,Standort=%tskname% + Wert=%val1%%/1%%2%%LF%%vname2%,Standort=%taskname% + Wert=%val2%%/2%%3%%LF%%vname2%,Standort=%taskname% + Wert=%val3%%/3%%4%%LF%%vname2%,Standort=%taskname% + Wert=%val4%%/4% + +See also `InfluxDB API description `_ + +Nettemp HTTP Api +^^^^^^^^^^^^^^^^ + +untested but should work with something like this: + +``/receiver.php?device=ip&type=%1%%vname1%%/1%%2%;%vname2%%/2%%3%;%vname3%%/3%%4%;%vname4%%/4%&value=%1%%val1%%/1%%2%;%val2%%/2%%3%;%val3%%/3%%4%;%val4%%/4%`` \ No newline at end of file diff --git a/docs/source/Controller/_controller_substitutions.repl b/docs/source/Controller/_controller_substitutions.repl index 7bbefccd00..46555d7463 100644 --- a/docs/source/Controller/_controller_substitutions.repl +++ b/docs/source/Controller/_controller_substitutions.repl @@ -111,9 +111,9 @@ .. |C010_maintainer| replace:: `.` .. |C010_compileinfo| replace:: `.` -.. |C011_name| replace:: :cyan:`Generic HTTP` +.. |C011_name| replace:: :cyan:`Generic HTTP Advanced` .. |C011_type| replace:: :cyan:`Controller` -.. |C011_typename| replace:: :cyan:`Controller - Generic HTTP` +.. |C011_typename| replace:: :cyan:`Controller - Generic HTTP Advanced` .. |C011_status| replace:: :yellow:`TESTING` .. |C011_github| replace:: C011.ino .. _C011_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_C011.ino From 1ba290edc97c19d45881b210e21c25cba7d371ea Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 8 Sep 2020 13:21:27 +0200 Subject: [PATCH 02/14] [HTTP Advanced] Do not percent-encode body (#1306) The replaced values are percent-encoded, which causes issues like described here: https://github.com/letscontrolit/ESPEasy/issues/1306# --- src/_C011.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_C011.ino b/src/_C011.ino index db227415c8..b7034a0790 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -324,7 +324,7 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event) addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); - parseControllerVariables(s, event, true); + parseControllerVariables(s, event, false); addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); From 09cc6b4fb1a5ea4037155ff6c60c7960882e7bdc Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 8 Sep 2020 17:43:52 +0200 Subject: [PATCH 03/14] [HTTP Advanced] Optimize load/save settings + add send binary option. --- docs/source/Controller/C011.rst | 2 +- src/WebServer_ControllerPage.ino | 186 ++++++++++-------- src/_C011.ino | 96 ++++++--- src/_C018.ino | 1 + src/_CPlugin_Helper_webform.ino | 21 ++ .../DataStructs/ControllerSettingsStruct.cpp | 36 ++-- .../DataStructs/ControllerSettingsStruct.h | 8 +- 7 files changed, 217 insertions(+), 133 deletions(-) diff --git a/docs/source/Controller/C011.rst b/docs/source/Controller/C011.rst index 1edcd85d36..d37662a46e 100644 --- a/docs/source/Controller/C011.rst +++ b/docs/source/Controller/C011.rst @@ -55,7 +55,7 @@ You can use this placeholders in http header and in the http body: * ``%LF%`` will be replaced with "\n" (newline) * ``%sysname%`` will be replaced with the system name * ``%tskname%`` will be replaced with the name of the device which is sending data to this controller -* ``%id%`` +* ``%id%`` will be replaced with IDX value. * ``%vname1%`` will be replaced with Valuename 1 * ``%vname2%`` will be replaced with Valuename 2 * ``%vname3%`` will be replaced with Valuename 3 diff --git a/src/WebServer_ControllerPage.ino b/src/WebServer_ControllerPage.ino index 4b719b9591..d8fdde4e26 100644 --- a/src/WebServer_ControllerPage.ino +++ b/src/WebServer_ControllerPage.ino @@ -23,6 +23,7 @@ void handle_controllers() { if ((protocol != -1) && !controllerNotSet) { bool mustInit = false; + bool mustCallCpluginSave = false; { // Place in a scope to free ControllerSettings memory ASAP MakeControllerSettings(ControllerSettings); @@ -48,10 +49,18 @@ void handle_controllers() { { mustInit = true; handle_controllers_CopySubmittedSettings(controllerindex, ControllerSettings); + mustCallCpluginSave = true; } } addHtmlError(SaveControllerSettings(controllerindex, ControllerSettings)); } + if (mustCallCpluginSave) { + // Call CPLUGIN_WEBFORM_SAVE after destructing ControllerSettings object to reduce RAM usage. + // Controller plugin almost only deals with custom controller settings. + // Even if they need to save things to the ControllerSettings, then the changes must + // already be saved first as the CPluginCall does not have the ControllerSettings as argument. + handle_controllers_CopySubmittedSettings_CPluginCall(controllerindex); + } addHtmlError(SaveSettings()); if (mustInit) { @@ -133,7 +142,9 @@ void handle_controllers_CopySubmittedSettings(byte controllerindex, ControllerSe ControllerSettingsStruct::VarType varType = static_cast(parameterIdx); saveControllerParameterForm(ControllerSettings, controllerindex, varType); } +} +void handle_controllers_CopySubmittedSettings_CPluginCall(byte controllerindex) { protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); if (validProtocolIndex(ProtocolIndex)) { @@ -257,108 +268,113 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex const protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); if (Settings.Protocol[controllerindex]) - { - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - addHtmlError(F("Out of memory, cannot load page")); - } else { - LoadControllerSettings(controllerindex, ControllerSettings); - - if (!Protocol[ProtocolIndex].Custom) - { - if (Protocol[ProtocolIndex].usesHost) { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USE_DNS); + { + { + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addHtmlError(F("Out of memory, cannot load page")); + } else { + LoadControllerSettings(controllerindex, ControllerSettings); - if (ControllerSettings.UseDNS) - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_HOSTNAME); + if (!Protocol[ProtocolIndex].Custom) + { + if (Protocol[ProtocolIndex].usesHost) { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USE_DNS); + + if (ControllerSettings.UseDNS) + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_HOSTNAME); + } + else + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_IP); + } } - else - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_IP); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PORT); + + if (Protocol[ProtocolIndex].usesQueue) { + addTableSeparator(F("Controller Queue"), 2, 3); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MIN_SEND_INTERVAL); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); } - } - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PORT); - - if (Protocol[ProtocolIndex].usesQueue) { - addTableSeparator(F("Controller Queue"), 2, 3); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MIN_SEND_INTERVAL); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_QUEUE_DEPTH); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_MAX_RETRIES); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_FULL_QUEUE_ACTION); - } - if (Protocol[ProtocolIndex].usesCheckReply) { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CHECK_REPLY); - } + if (Protocol[ProtocolIndex].usesCheckReply) { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CHECK_REPLY); + } - if (Protocol[ProtocolIndex].usesTimeout) { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_TIMEOUT); - } + if (Protocol[ProtocolIndex].usesTimeout) { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_TIMEOUT); + } - if (Protocol[ProtocolIndex].usesSampleSets) { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR); - } + if (Protocol[ProtocolIndex].usesSampleSets) { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR); + } - if (Protocol[ProtocolIndex].useExtendedCredentials()) { - addTableSeparator(F("Credentials"), 2, 3); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USE_EXTENDED_CREDENTIALS); - } + if (Protocol[ProtocolIndex].useExtendedCredentials()) { + addTableSeparator(F("Credentials"), 2, 3); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USE_EXTENDED_CREDENTIALS); + } - if (Protocol[ProtocolIndex].usesAccount) - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USER); - } + if (Protocol[ProtocolIndex].usesAccount) + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_USER); + } - if (Protocol[ProtocolIndex].usesPassword) - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PASS); - } - #ifdef USES_MQTT - if (Protocol[ProtocolIndex].usesMQTT) { - addTableSeparator(F("MQTT"), 2, 3); - - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLIENT_ID); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT); - addRowLabel(F("Current Client ID")); - addHtml(getMQTTclientID(ControllerSettings)); - addFormNote(F("Updated on load of this page")); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_RETAINFLAG); - } - #endif // USES_MQTT + if (Protocol[ProtocolIndex].usesPassword) + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PASS); + } + #ifdef USES_MQTT + if (Protocol[ProtocolIndex].usesMQTT) { + addTableSeparator(F("MQTT"), 2, 3); + + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLIENT_ID); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT); + addRowLabel(F("Current Client ID")); + addHtml(getMQTTclientID(ControllerSettings)); + addFormNote(F("Updated on load of this page")); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_RETAINFLAG); + } + #endif // USES_MQTT - if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT) - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SUBSCRIBE); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PUBLISH); - } - #ifdef USES_MQTT - if (Protocol[ProtocolIndex].usesMQTT) - { - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_TOPIC); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_CONNECT_MESSAGE); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_DISCONNECT_MESSAGE); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SEND_LWT); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_WILL_RETAIN); - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLEAN_SESSION); + if (Protocol[ProtocolIndex].usesTemplate || Protocol[ProtocolIndex].usesMQTT) + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SUBSCRIBE); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_PUBLISH); + } + #ifdef USES_MQTT + if (Protocol[ProtocolIndex].usesMQTT) + { + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_TOPIC); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_CONNECT_MESSAGE); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_LWT_DISCONNECT_MESSAGE); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_SEND_LWT); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_WILL_RETAIN); + addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_CLEAN_SESSION); + } + #endif // USES_MQTT } - #endif // USES_MQTT } - { - // Load controller specific settings - struct EventStruct TempEvent; - TempEvent.ControllerIndex = controllerindex; + // End of scope for ControllerSettings, destruct it to save memory. + } + { + // Load controller specific settings + struct EventStruct TempEvent; + TempEvent.ControllerIndex = controllerindex; - String webformLoadString; - CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_WEBFORM_LOAD, &TempEvent, webformLoadString); + String webformLoadString; + CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_WEBFORM_LOAD, &TempEvent, webformLoadString); - if (webformLoadString.length() > 0) { - addHtmlError(F("Bug in CPlugin::Function::CPLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead")); - } + if (webformLoadString.length() > 0) { + addHtmlError(F("Bug in CPlugin::Function::CPLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead")); } - addControllerParameterForm(ControllerSettings, controllerindex, ControllerSettingsStruct::CONTROLLER_ENABLED); } + // Separate enabled checkbox as it doesn't need to use the ControllerSettings. + // So ControllerSettings object can be destructed before controller specific settings are loaded. + addControllerEnabledForm(controllerindex); } addFormSeparator(2); diff --git a/src/_C011.ino b/src/_C011.ino index b7034a0790..69d3c8fed6 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -67,35 +67,48 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { - String escapeBuffer; - std::shared_ptr customConfig(new C011_ConfigStruct); - - if (customConfig) { - LoadCustomControllerSettings(event->ControllerIndex, (byte *)customConfig.get(), sizeof(C011_ConfigStruct)); - customConfig->zero_last(); + { + String HttpMethod; + String HttpUri; + String HttpHeader; + String HttpBody; + if (!load_C011_ConfigStruct(event->ControllerIndex, HttpMethod, HttpUri, HttpHeader, HttpBody)) + { + return false; + } + addTableSeparator(F("HTTP Config"), 2, 3); { byte choice = 0; String methods[] = { F("GET"), F("POST"), F("PUT"), F("HEAD"), F("PATCH") }; for (byte i = 0; i < 5; i++) { - if (methods[i].equals(customConfig->HttpMethod)) { + if (methods[i].equals(HttpMethod)) { choice = i; } } - addFormSelector(F("HTTP Method"), F("P011httpmethod"), 5, methods, NULL, choice); + addFormSelector(F("Method"), F("P011httpmethod"), 5, methods, NULL, choice); } - addFormTextBox(F("HTTP URI"), F("P011httpuri"), customConfig->HttpUri, C011_HTTP_URI_MAX_LEN - 1); + addFormTextBox(F("URI"), F("P011httpuri"), HttpUri, C011_HTTP_URI_MAX_LEN - 1); { - String escapeBuffer = customConfig->HttpHeader; - htmlEscape(escapeBuffer); - addFormTextArea(F("HTTP Header"), F("P011httpheader"), escapeBuffer, C011_HTTP_HEADER_MAX_LEN - 1, 4, 50); + htmlEscape(HttpHeader); + addFormTextArea(F("Header"), F("P011httpheader"), HttpHeader, C011_HTTP_HEADER_MAX_LEN - 1, 4, 50); } { - String escapeBuffer = customConfig->HttpBody; - htmlEscape(escapeBuffer); - addFormTextArea(F("HTTP Body"), F("P011httpbody"), escapeBuffer, C011_HTTP_BODY_MAX_LEN - 1, 8, 50); + htmlEscape(HttpBody); + addFormTextArea(F("Body"), F("P011httpbody"), HttpBody, C011_HTTP_BODY_MAX_LEN - 1, 8, 50); + } + } + { + // 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 { + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + addControllerParameterForm(ControllerSettings, event->ControllerIndex, ControllerSettingsStruct::CONTROLLER_SEND_BINARY); + addFormNote(F("Do not 'percent escape' body when send binary checked")); } } break; @@ -173,6 +186,22 @@ bool do_process_c011_delay_queue(int controller_number, const C011_queue_element return send_via_http(controller_number, client, element.txt, ControllerSettings.MustCheckReply); } +bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMethod, String& HttpUri, String& HttpHeader, String& HttpBody) { + // Just copy the needed strings and destruct the C011_ConfigStruct as soon as possible + std::shared_ptr customConfig(new C011_ConfigStruct); + + if (!customConfig) { + return false; + } + LoadCustomControllerSettings(ControllerIndex, (byte *)customConfig.get(), sizeof(C011_ConfigStruct)); + customConfig->zero_last(); + HttpMethod = customConfig->HttpMethod; + HttpUri = customConfig->HttpUri; + HttpHeader = customConfig->HttpHeader; + HttpBody = customConfig->HttpBody; + return true; +} + // ******************************************************************************** // Create request // ******************************************************************************** @@ -184,6 +213,7 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) String authHeader; String hostportString; + bool sendBinary = false; if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { String dummy; @@ -202,24 +232,27 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) authHeader = get_auth_header(event->ControllerIndex, ControllerSettings); const bool defaultport = ControllerSettings.Port == 0 || ControllerSettings.Port == 80; hostportString = defaultport ? ControllerSettings.getHost() : ControllerSettings.getHostPortString(); + sendBinary = ControllerSettings.sendBinary(); } - std::shared_ptr customConfig(new C011_ConfigStruct); - - if (!customConfig) { + String HttpMethod; + String HttpUri; + String HttpHeader; + String HttpBody; + if (!load_C011_ConfigStruct(event->ControllerIndex, HttpMethod, HttpUri, HttpHeader, HttpBody)) + { return false; } - LoadCustomControllerSettings(event->ControllerIndex, (byte *)customConfig.get(), sizeof(C011_ConfigStruct)); - customConfig->zero_last(); + bool success = false; { String payload = do_create_http_request( hostportString, - customConfig->HttpMethod, - customConfig->HttpUri, + HttpMethod, + HttpUri, authHeader, "", -1); @@ -237,21 +270,20 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) // and thus preventing the need to create a long string only to copy it to a queue element. C011_queue_element& element = C011_DelayHandler->sendQueue.back(); - if (strlen(customConfig->HttpHeader) > 0) { - element.txt += customConfig->HttpHeader; + if (HttpHeader.length() > 0) { + element.txt += HttpHeader; removeExtraNewLine(element.txt); } - ReplaceTokenByValue(element.txt, event); + ReplaceTokenByValue(element.txt, event, false); - if (strlen(customConfig->HttpBody) > 0) + if (HttpBody.length() > 0) { - String body = String(customConfig->HttpBody); - ReplaceTokenByValue(body, event); + ReplaceTokenByValue(HttpBody, event, sendBinary); element.txt += F("Content-Length: "); - element.txt += String(body.length()); + element.txt += String(HttpBody.length()); addNewLine(element.txt); addNewLine(element.txt); // Need 2 CRLF between header and body. - element.txt += body; + element.txt += HttpBody; } addNewLine(element.txt); } @@ -309,7 +341,7 @@ void DeleteNotNeededValues(String& s, byte numberOfValuesWanted) // in case of a sensor with 2 values: // SENSORVALUENAME1____TASKNAME1____VALUE1__SENSORVALUENAME2____TASKNAME2____VALUE2 // ******************************************************************************** -void ReplaceTokenByValue(String& s, struct EventStruct *event) +void ReplaceTokenByValue(String& s, struct EventStruct *event, bool sendBinary) { // example string: // write?db=testdb&type=%1%%vname1%%/1%%2%;%vname2%%/2%%3%;%vname3%%/3%%4%;%vname4%%/4%&value=%1%%val1%%/1%%2%;%val2%%/2%%3%;%val3%%/3%%4%;%val4%%/4% @@ -324,7 +356,7 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event) addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); - parseControllerVariables(s, event, false); + parseControllerVariables(s, event, !sendBinary); addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: ")); addLog(LOG_LEVEL_DEBUG_MORE, s); diff --git a/src/_C018.ino b/src/_C018.ino index 02e4cde761..9fe720d6e7 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -477,6 +477,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& LoadCustomControllerSettings(event->ControllerIndex, (byte *)&customConfig, sizeof(customConfig)); customConfig.validate(); + addTableSeparator(F("Credentials"), 2, 3); { // Script to toggle visibility of OTAA/ABP field, based on the activation method selector. protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(event->ControllerIndex); diff --git a/src/_CPlugin_Helper_webform.ino b/src/_CPlugin_Helper_webform.ino index 569a4b3bee..5f91c8435c 100644 --- a/src/_CPlugin_Helper_webform.ino +++ b/src/_CPlugin_Helper_webform.ino @@ -48,6 +48,7 @@ String getControllerParameterName(protocolIndex_t ProtocolIndex, ControllerSetti case ControllerSettingsStruct::CONTROLLER_WILL_RETAIN: name = F("Will Retain"); break; case ControllerSettingsStruct::CONTROLLER_CLEAN_SESSION: name = F("Clean Session"); break; case ControllerSettingsStruct::CONTROLLER_USE_EXTENDED_CREDENTIALS: name = F("Use Extended Credentials"); break; + case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: name = F("Send Binary"); break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: name = F("Client Timeout"); break; case ControllerSettingsStruct::CONTROLLER_SAMPLE_SET_INITIATOR: name = F("Sample Set Initiator"); break; @@ -82,6 +83,20 @@ String getControllerParameterDisplayName(protocolIndex_t ProtocolIndex, Controll return getControllerParameterName(ProtocolIndex, parameterIdx, displayName, isAlternative); } +void addControllerEnabledForm(controllerIndex_t controllerindex) { + protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); + if (!validProtocolIndex(ProtocolIndex)) { + return; + } + + ControllerSettingsStruct::VarType varType = ControllerSettingsStruct::CONTROLLER_ENABLED; + + bool isAlternativeDisplayName = false; + String displayName = getControllerParameterDisplayName(ProtocolIndex, varType, isAlternativeDisplayName); + String internalName = getControllerParameterInternalName(ProtocolIndex, varType); + addFormCheckBox(displayName, internalName, Settings.ControllerEnabled[controllerindex]); +} + void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettings, controllerIndex_t controllerindex, ControllerSettingsStruct::VarType varType) { protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); if (!validProtocolIndex(ProtocolIndex)) { @@ -210,6 +225,9 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin case ControllerSettingsStruct::CONTROLLER_USE_EXTENDED_CREDENTIALS: addFormCheckBox(displayName, internalName, ControllerSettings.useExtendedCredentials()); break; + case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: + addFormCheckBox(displayName, internalName, ControllerSettings.sendBinary()); + break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: addFormNumericBox(displayName, internalName, ControllerSettings.ClientTimeout, 10, CONTROLLER_CLIENTTIMEOUT_MAX); addUnit(F("ms")); @@ -320,6 +338,9 @@ void saveControllerParameterForm(ControllerSettingsStruct& ControllerSettings, c case ControllerSettingsStruct::CONTROLLER_USE_EXTENDED_CREDENTIALS: ControllerSettings.useExtendedCredentials(isFormItemChecked(internalName)); break; + case ControllerSettingsStruct::CONTROLLER_SEND_BINARY: + ControllerSettings.sendBinary(isFormItemChecked(internalName)); + break; case ControllerSettingsStruct::CONTROLLER_TIMEOUT: ControllerSettings.ClientTimeout = getFormItemInt(internalName, ControllerSettings.ClientTimeout); break; diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index cc6ccbed2f..3f1a7e3caa 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -25,7 +25,7 @@ void ControllerSettingsStruct::reset() { ClientTimeout = CONTROLLER_CLIENTTIMEOUT_DFLT; MustCheckReply = false; SampleSetInitiator = INVALID_TASK_INDEX; - MQTT_flags = 0; + VariousFlags = 0; for (byte i = 0; i < 4; ++i) { IP[i] = 0; @@ -184,60 +184,70 @@ bool ControllerSettingsStruct::updateIPcache() { bool ControllerSettingsStruct::mqtt_cleanSession() const { - return bitRead(MQTT_flags, 1); + return bitRead(VariousFlags, 1); } void ControllerSettingsStruct::mqtt_cleanSession(bool value) { - bitWrite(MQTT_flags, 1, value); + bitWrite(VariousFlags, 1, value); } bool ControllerSettingsStruct::mqtt_sendLWT() const { - return !bitRead(MQTT_flags, 2); + return !bitRead(VariousFlags, 2); } void ControllerSettingsStruct::mqtt_sendLWT(bool value) { - bitWrite(MQTT_flags, 2, !value); + bitWrite(VariousFlags, 2, !value); } bool ControllerSettingsStruct::mqtt_willRetain() const { - return !bitRead(MQTT_flags, 3); + return !bitRead(VariousFlags, 3); } void ControllerSettingsStruct::mqtt_willRetain(bool value) { - bitWrite(MQTT_flags, 3, !value); + bitWrite(VariousFlags, 3, !value); } bool ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect() const { - return bitRead(MQTT_flags, 4); + return bitRead(VariousFlags, 4); } void ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect(bool value) { - bitWrite(MQTT_flags, 4, value); + bitWrite(VariousFlags, 4, value); } bool ControllerSettingsStruct::mqtt_retainFlag() const { - return bitRead(MQTT_flags, 5); + return bitRead(VariousFlags, 5); } void ControllerSettingsStruct::mqtt_retainFlag(bool value) { - bitWrite(MQTT_flags, 5, value); + bitWrite(VariousFlags, 5, value); } bool ControllerSettingsStruct::useExtendedCredentials() const { - return bitRead(MQTT_flags, 6); + return bitRead(VariousFlags, 6); } void ControllerSettingsStruct::useExtendedCredentials(bool value) { - bitWrite(MQTT_flags, 6, value); + bitWrite(VariousFlags, 6, value); +} + +bool ControllerSettingsStruct::sendBinary() const +{ + return bitRead(VariousFlags, 7); +} + +void ControllerSettingsStruct::sendBinary(bool value) +{ + bitWrite(VariousFlags, 7, value); } diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 9d66a628be..5183747714 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -82,6 +82,7 @@ struct ControllerSettingsStruct CONTROLLER_CLEAN_SESSION, CONTROLLER_TIMEOUT, CONTROLLER_SAMPLE_SET_INITIATOR, + CONTROLLER_SEND_BINARY, // Keep this as last, is used to loop over all parameters CONTROLLER_ENABLED @@ -110,7 +111,7 @@ struct ControllerSettingsStruct String getHostPortString() const; - // MQTT_flags defaults to 0, keep in mind when adding bit lookups. + // VariousFlags defaults to 0, keep in mind when adding bit lookups. bool mqtt_cleanSession() const; void mqtt_cleanSession(bool value); @@ -129,6 +130,9 @@ struct ControllerSettingsStruct bool useExtendedCredentials() const; void useExtendedCredentials(bool value); + bool sendBinary() const; + void sendBinary(bool value); + boolean UseDNS; byte IP[4]; unsigned int Port; @@ -145,7 +149,7 @@ struct ControllerSettingsStruct unsigned int ClientTimeout; bool MustCheckReply; // When set to false, a sent message is considered always successful. taskIndex_t SampleSetInitiator; // The first task to start a sample set. - uint32_t MQTT_flags; // Various flags for MQTT controllers + uint32_t VariousFlags; // Various flags char ClientID[65]; // Used to define the Client ID used by the controller private: From 79856d8da1f1c403d4f073c7c1a4b7412fd80507 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Tue, 8 Sep 2020 23:59:56 +0200 Subject: [PATCH 04/14] [Cleanup] Reduce memory usage on load/save C018 LoRaWAN RN2483 controller --- src/_C018.ino | 257 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 153 insertions(+), 104 deletions(-) diff --git a/src/_C018.ino b/src/_C018.ino index 9fe720d6e7..e691c409eb 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -6,27 +6,24 @@ // ########################### Controller Plugin 018: LoRa TTN - RN2483/RN2903 ########################### // ####################################################################################################### -#define CPLUGIN_018 -#define CPLUGIN_ID_018 18 -#define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903 [TESTING]" +# define CPLUGIN_018 +# define CPLUGIN_ID_018 18 +# define CPLUGIN_NAME_018 "LoRa TTN - RN2483/RN2903 [TESTING]" +# define C018_BAUDRATE_LABEL "baudrate" -#define C018_BAUDRATE 9600 -#define C018_BAUDRATE_LABEL "baudrate" - - -#include -#include -#include "src/Globals/CPlugins.h" -#include "src/Globals/Protocol.h" -#include "src/ControllerQueue/C018_queue_element.h" -#include "ESPEasy_plugindefs.h" -#include "ESPEasy_fdwdecl.h" +# include +# include +# include "ESPEasy_fdwdecl.h" +# include "ESPEasy_plugindefs.h" +# include "src/ControllerQueue/C018_queue_element.h" +# include "src/Globals/CPlugins.h" +# include "src/Globals/Protocol.h" // Have this define after the includes, so we can set it in Custom.h -#ifndef C018_FORCE_SW_SERIAL -#define C018_FORCE_SW_SERIAL false -#endif +# ifndef C018_FORCE_SW_SERIAL +# define C018_FORCE_SW_SERIAL false +# endif // ifndef C018_FORCE_SW_SERIAL struct C018_data_struct { C018_data_struct() : C018_easySerial(nullptr), myLora(nullptr) {} @@ -102,6 +99,7 @@ struct C018_data_struct { bool useOTAA() const { if (!isInitialized()) { return true; } bool res = myLora->useOTAA(); + C018_logError(F("useOTA()")); return res; } @@ -130,6 +128,7 @@ struct C018_data_struct { bool setFrequencyPlan(RN2xx3_datatypes::Freq_plan plan) { if (!isInitialized()) { return false; } bool res = myLora->setFrequencyPlan(plan); + C018_logError(F("setFrequencyPlan()")); return res; } @@ -137,6 +136,7 @@ struct C018_data_struct { bool setSF(uint8_t sf) { if (!isInitialized()) { return false; } bool res = myLora->setSF(sf); + C018_logError(F("setSF()")); return res; } @@ -144,6 +144,7 @@ struct C018_data_struct { bool initOTAA(const String& AppEUI = "", const String& AppKey = "", const String& DevEUI = "") { if (myLora == nullptr) { return false; } bool success = myLora->initOTAA(AppEUI, AppKey, DevEUI); + C018_logError(F("initOTAA()")); updateCacheOnInit(); return success; @@ -152,6 +153,7 @@ struct C018_data_struct { bool initABP(const String& addr, const String& AppSKey, const String& NwkSKey) { if (myLora == nullptr) { return false; } bool success = myLora->initABP(addr, AppSKey, NwkSKey); + C018_logError(F("initABP()")); updateCacheOnInit(); return success; @@ -166,6 +168,7 @@ struct C018_data_struct { addLog(LOG_LEVEL_INFO, log); } String res = myLora->sendRawCommand(command); + C018_logError(F("sendRawCommand()")); return res; } @@ -188,6 +191,7 @@ struct C018_data_struct { String getDataRate() { if (!isInitialized()) { return ""; } String res = myLora->getDataRate(); + C018_logError(F("getDataRate()")); return res; } @@ -210,6 +214,7 @@ struct C018_data_struct { bool getFrameCounters(uint32_t& dnctr, uint32_t& upctr) { if (!isInitialized()) { return false; } bool res = myLora->getFrameCounters(dnctr, upctr); + C018_logError(F("getFrameCounters()")); return res; } @@ -217,6 +222,7 @@ struct C018_data_struct { bool setFrameCounters(uint32_t dnctr, uint32_t upctr) { if (!isInitialized()) { return false; } bool res = myLora->setFrameCounters(dnctr, upctr); + C018_logError(F("setFrameCounters()")); return res; } @@ -286,22 +292,22 @@ private: void updateCacheOnInit() { cacheDevAddr = ""; - if (!isInitialized()) { - return; - } - - if (myLora->getStatus().Joined) - { - cacheDevAddr = myLora->sendRawCommand(F("mac get devaddr")); + if (isInitialized()) { + if (myLora->getStatus().Joined) + { + cacheDevAddr = myLora->sendRawCommand(F("mac get devaddr")); - if (cacheDevAddr == F("00000000")) { - cacheDevAddr = ""; + if (cacheDevAddr == F("00000000")) { + cacheDevAddr = ""; + } } } } void triggerAutobaud() { - if (C018_easySerial == nullptr || myLora == nullptr) return; + if ((C018_easySerial == nullptr) || (myLora == nullptr)) { + return; + } int retries = 2; while (retries > 0 && !autobaud_success) { @@ -348,8 +354,6 @@ private: } } - - ESPeasySerial *C018_easySerial = nullptr; rn2xx3 *myLora = nullptr; String cacheDevAddr; @@ -358,17 +362,17 @@ private: unsigned long _baudrate = 57600; uint8_t sampleSetCounter = 0; taskIndex_t sampleSetInitiator = INVALID_TASK_INDEX; - int8_t _resetPin = -1; + int8_t _resetPin = -1; bool autobaud_success = false; } C018_data; -#define C018_DEVICE_EUI_LEN 17 -#define C018_DEVICE_ADDR_LEN 33 -#define C018_NETWORK_SESSION_KEY_LEN 33 -#define C018_APP_SESSION_KEY_LEN 33 -#define C018_USE_OTAA 0 -#define C018_USE_ABP 1 +# define C018_DEVICE_EUI_LEN 17 +# define C018_DEVICE_ADDR_LEN 33 +# define C018_NETWORK_SESSION_KEY_LEN 33 +# define C018_APP_SESSION_KEY_LEN 33 +# define C018_USE_OTAA 0 +# define C018_USE_ABP 1 struct C018_ConfigStruct { C018_ConfigStruct() { @@ -432,7 +436,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& Protocol[protocolCount].usesCheckReply = false; Protocol[protocolCount].usesTimeout = false; Protocol[protocolCount].usesSampleSets = true; - Protocol[protocolCount].needsNetwork = false; + Protocol[protocolCount].needsNetwork = false; break; } @@ -457,6 +461,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_INIT: { success = init_c018_delay_queue(event->ControllerIndex); + if (success) { C018_init(event); } @@ -472,11 +477,6 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { - C018_ConfigStruct customConfig; - - LoadCustomControllerSettings(event->ControllerIndex, (byte *)&customConfig, sizeof(customConfig)); - customConfig.validate(); - addTableSeparator(F("Credentials"), 2, 3); { // Script to toggle visibility of OTAA/ABP field, based on the activation method selector. @@ -495,51 +495,79 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& html_add_script_end(); } + unsigned long baudrate; + int8_t rxpin; + int8_t txpin; + int8_t resetpin; + uint8_t sf; + uint8_t frequencyplan; + uint8_t joinmethod; + { - addFormTextBox(F("Device EUI"), F("deveui"), customConfig.DeviceEUI, C018_DEVICE_EUI_LEN - 1); - String deveui_note = F("Leave empty to use HW DevEUI: "); - deveui_note += C018_data.hweui(); - addFormNote(deveui_note, F("deveui_note")); - } + // Keep this object in a small scope so we can destruct it as soon as possible again. + std::shared_ptr customConfig(new C018_ConfigStruct); + + if (!customConfig) { + break; + } + LoadCustomControllerSettings(event->ControllerIndex, (byte *)customConfig.get(), sizeof(C018_ConfigStruct)); + customConfig->validate(); + baudrate = customConfig->baudrate; + rxpin = customConfig->rxpin; + txpin = customConfig->txpin; + resetpin = customConfig->resetpin; + sf = customConfig->sf; + frequencyplan = customConfig->frequencyplan; + joinmethod = customConfig->joinmethod; + + { + addFormTextBox(F("Device EUI"), F("deveui"), customConfig->DeviceEUI, C018_DEVICE_EUI_LEN - 1); + String deveui_note = F("Leave empty to use HW DevEUI: "); + deveui_note += C018_data.hweui(); + addFormNote(deveui_note, F("deveui_note")); + } - addFormTextBox(F("Device Addr"), F("devaddr"), customConfig.DeviceAddr, C018_DEVICE_ADDR_LEN - 1); - addFormTextBox(F("Network Session Key"), F("nskey"), customConfig.NetworkSessionKey, C018_NETWORK_SESSION_KEY_LEN - 1); - addFormTextBox(F("App Session Key"), F("appskey"), customConfig.AppSessionKey, C018_APP_SESSION_KEY_LEN - 1); + addFormTextBox(F("Device Addr"), F("devaddr"), customConfig->DeviceAddr, C018_DEVICE_ADDR_LEN - 1); + addFormTextBox(F("Network Session Key"), F("nskey"), customConfig->NetworkSessionKey, C018_NETWORK_SESSION_KEY_LEN - 1); + addFormTextBox(F("App Session Key"), F("appskey"), customConfig->AppSessionKey, C018_APP_SESSION_KEY_LEN - 1); + } { - byte choice = customConfig.joinmethod; String options[2] = { F("OTAA"), F("ABP") }; int values[2] = { C018_USE_OTAA, C018_USE_ABP }; addFormSelector_script(F("Activation Method"), F("joinmethod"), 2, - options, values, NULL, choice, + options, values, NULL, joinmethod, F("joinChanged(this)")); // Script to toggle OTAA/ABP fields visibility when changing selection. } html_add_script(F("document.getElementById('joinmethod').onchange();"), false); addTableSeparator(F("Connection Configuration"), 2, 3); { - byte choice = customConfig.frequencyplan; String options[4] = { F("SINGLE_CHANNEL_EU"), F("TTN_EU"), F("TTN_US"), F("DEFAULT_EU") }; - int values[4] = - { RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU, RN2xx3_datatypes::Freq_plan::TTN_EU, RN2xx3_datatypes::Freq_plan::TTN_US, - RN2xx3_datatypes::Freq_plan::DEFAULT_EU }; - - addFormSelector(F("Frequency Plan"), F("frequencyplan"), 4, options, values, NULL, choice, false); + int values[4] = + { + RN2xx3_datatypes::Freq_plan::SINGLE_CHANNEL_EU, + RN2xx3_datatypes::Freq_plan::TTN_EU, + RN2xx3_datatypes::Freq_plan::TTN_US, + RN2xx3_datatypes::Freq_plan::DEFAULT_EU + }; + + addFormSelector(F("Frequency Plan"), F("frequencyplan"), 4, options, values, NULL, frequencyplan, false); } - addFormNumericBox(F("Spread Factor"), F("sf"), customConfig.sf, 7, 12); + addFormNumericBox(F("Spread Factor"), F("sf"), sf, 7, 12); addTableSeparator(F("Serial Port Configuration"), 2, 3); // Optional reset pin RN2xx3 - addFormPinSelect(formatGpioName_output_optional(F("Reset")), F("taskdevicepin3"), customConfig.resetpin); + addFormPinSelect(formatGpioName_output_optional(F("Reset")), F("taskdevicepin3"), resetpin); // Show serial port selection - addFormPinSelect(formatGpioName_RX(false), F("taskdevicepin1"), customConfig.rxpin); - addFormPinSelect(formatGpioName_TX(false), F("taskdevicepin2"), customConfig.txpin); - serialHelper_webformLoad(customConfig.rxpin, customConfig.txpin, true); + addFormPinSelect(formatGpioName_RX(false), F("taskdevicepin1"), rxpin); + addFormPinSelect(formatGpioName_TX(false), F("taskdevicepin2"), txpin); + serialHelper_webformLoad(rxpin, txpin, true); - addFormNumericBox(F("Baudrate"), F(C018_BAUDRATE_LABEL), customConfig.baudrate, 2400, 115200); + addFormNumericBox(F("Baudrate"), F(C018_BAUDRATE_LABEL), baudrate, 2400, 115200); addUnit(F("baud")); addFormNote(F("Module default baudrate: 57600 bps")); @@ -591,26 +619,29 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& } case CPlugin::Function::CPLUGIN_WEBFORM_SAVE: { - C018_ConfigStruct customConfig; - customConfig.reset(); - String deveui = web_server.arg(F("deveui")); - String devaddr = web_server.arg(F("devaddr")); - String nskey = web_server.arg(F("nskey")); - String appskey = web_server.arg(F("appskey")); - - strlcpy(customConfig.DeviceEUI, deveui.c_str(), sizeof(customConfig.DeviceEUI)); - strlcpy(customConfig.DeviceAddr, devaddr.c_str(), sizeof(customConfig.DeviceAddr)); - strlcpy(customConfig.NetworkSessionKey, nskey.c_str(), sizeof(customConfig.NetworkSessionKey)); - strlcpy(customConfig.AppSessionKey, appskey.c_str(), sizeof(customConfig.AppSessionKey)); - customConfig.baudrate = getFormItemInt(F(C018_BAUDRATE_LABEL), customConfig.baudrate); - customConfig.rxpin = getFormItemInt(F("taskdevicepin1"), customConfig.rxpin); - customConfig.txpin = getFormItemInt(F("taskdevicepin2"), customConfig.txpin); - customConfig.resetpin = getFormItemInt(F("taskdevicepin3"), customConfig.resetpin); - customConfig.sf = getFormItemInt(F("sf"), customConfig.sf); - customConfig.frequencyplan = getFormItemInt(F("frequencyplan"), customConfig.frequencyplan); - customConfig.joinmethod = getFormItemInt(F("joinmethod"), customConfig.joinmethod); - serialHelper_webformSave(customConfig.rxpin, customConfig.txpin); - SaveCustomControllerSettings(event->ControllerIndex, (byte *)&customConfig, sizeof(customConfig)); + std::shared_ptr customConfig(new C018_ConfigStruct); + + if (customConfig) { + customConfig->reset(); + String deveui = web_server.arg(F("deveui")); + String devaddr = web_server.arg(F("devaddr")); + String nskey = web_server.arg(F("nskey")); + String appskey = web_server.arg(F("appskey")); + + strlcpy(customConfig->DeviceEUI, deveui.c_str(), sizeof(customConfig->DeviceEUI)); + strlcpy(customConfig->DeviceAddr, devaddr.c_str(), sizeof(customConfig->DeviceAddr)); + strlcpy(customConfig->NetworkSessionKey, nskey.c_str(), sizeof(customConfig->NetworkSessionKey)); + strlcpy(customConfig->AppSessionKey, appskey.c_str(), sizeof(customConfig->AppSessionKey)); + customConfig->baudrate = getFormItemInt(F(C018_BAUDRATE_LABEL), customConfig->baudrate); + customConfig->rxpin = getFormItemInt(F("taskdevicepin1"), customConfig->rxpin); + customConfig->txpin = getFormItemInt(F("taskdevicepin2"), customConfig->txpin); + customConfig->resetpin = getFormItemInt(F("taskdevicepin3"), customConfig->resetpin); + customConfig->sf = getFormItemInt(F("sf"), customConfig->sf); + customConfig->frequencyplan = getFormItemInt(F("frequencyplan"), customConfig->frequencyplan); + customConfig->joinmethod = getFormItemInt(F("joinmethod"), customConfig->joinmethod); + serialHelper_webformSave(customConfig->rxpin, customConfig->txpin); + SaveCustomControllerSettings(event->ControllerIndex, (byte *)customConfig.get(), sizeof(C018_ConfigStruct)); + } break; } @@ -647,6 +678,7 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& 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()); + if (!C018_data.isInitialized()) { // Sometimes the module does need some time after power on to respond. // So it may not be initialized well at the call of CPLUGIN_INIT @@ -686,51 +718,68 @@ bool CPlugin_018(CPlugin::Function function, struct EventStruct *event, String& } bool C018_init(struct EventStruct *event) { - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - return false; + String AppEUI; + String AppKey; + taskIndex_t SampleSetInitiator = INVALID_TASK_INDEX; + unsigned int Port = 0; + { + // Allocate ControllerSettings object in a scope, so we can destruct it as soon as possible. + MakeControllerSettings(ControllerSettings); + + if (!AllocatedControllerSettings()) { + return false; + } + + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + C018_DelayHandler->configureControllerSettings(ControllerSettings); + AppEUI = getControllerUser(event->ControllerIndex, ControllerSettings); + AppKey = getControllerPass(event->ControllerIndex, ControllerSettings); + SampleSetInitiator = ControllerSettings.SampleSetInitiator; + Port = ControllerSettings.Port; } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - C018_DelayHandler->configureControllerSettings(ControllerSettings); + std::shared_ptr customConfig(new C018_ConfigStruct); - C018_ConfigStruct customConfig; - LoadCustomControllerSettings(event->ControllerIndex, (byte *)&customConfig, sizeof(customConfig)); - customConfig.validate(); + if (!customConfig) { + return false; + } + LoadCustomControllerSettings(event->ControllerIndex, (byte *)customConfig.get(), sizeof(C018_ConfigStruct)); + customConfig->validate(); - if (!C018_data.init(customConfig.rxpin, customConfig.txpin, customConfig.baudrate, - customConfig.joinmethod == C018_USE_OTAA, - ControllerSettings.SampleSetInitiator, customConfig.resetpin)) + if (!C018_data.init(customConfig->rxpin, customConfig->txpin, customConfig->baudrate, + (customConfig->joinmethod == C018_USE_OTAA), + SampleSetInitiator, customConfig->resetpin)) { return false; } - C018_data.setFrequencyPlan(static_cast(customConfig.frequencyplan)); + C018_data.setFrequencyPlan(static_cast(customConfig->frequencyplan)); - if (customConfig.joinmethod == C018_USE_OTAA) { - String AppEUI = getControllerUser(event->ControllerIndex, ControllerSettings); - String AppKey = getControllerPass(event->ControllerIndex, ControllerSettings); + if (customConfig->joinmethod == C018_USE_OTAA) { String log = F("OTAA: AppEUI: "); log += AppEUI; log += F(" AppKey: "); log += AppKey; log += F(" DevEUI: "); - log += customConfig.DeviceEUI; + log += customConfig->DeviceEUI; addLog(LOG_LEVEL_INFO, log); - if (!C018_data.initOTAA(AppEUI, AppKey, customConfig.DeviceEUI)) { + + if (!C018_data.initOTAA(AppEUI, AppKey, customConfig->DeviceEUI)) { return false; } } else { - if (!C018_data.initABP(customConfig.DeviceAddr, customConfig.AppSessionKey, customConfig.NetworkSessionKey)) { + if (!C018_data.initABP(customConfig->DeviceAddr, customConfig->AppSessionKey, customConfig->NetworkSessionKey)) { return false; } } - if (!C018_data.setSF(customConfig.sf)) { + + if (!C018_data.setSF(customConfig->sf)) { return false; } - if (!C018_data.txUncnf("ESPeasy (TTN)", ControllerSettings.Port)) { + + if (!C018_data.txUncnf("ESPeasy (TTN)", Port)) { return false; } return true; From 95bef799c1d781395cfd1d50f02f33628be39484 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 9 Sep 2020 00:01:39 +0200 Subject: [PATCH 05/14] [RN2483] Call LoRaWAN module reset when LoRaWAN stack hangs (#3225 ) See #3225 --- lib/RN2483-Arduino-Library/src/rn2xx3.cpp | 5 +++++ lib/RN2483-Arduino-Library/src/rn2xx3.h | 2 ++ lib/RN2483-Arduino-Library/src/rn2xx3_handler.cpp | 6 +++++- lib/RN2483-Arduino-Library/src/rn2xx3_handler.h | 2 ++ src/_C018.ino | 15 ++++++++++++++- 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/RN2483-Arduino-Library/src/rn2xx3.cpp b/lib/RN2483-Arduino-Library/src/rn2xx3.cpp index 240b90a37a..eee40e7d43 100644 --- a/lib/RN2483-Arduino-Library/src/rn2xx3.cpp +++ b/lib/RN2483-Arduino-Library/src/rn2xx3.cpp @@ -160,6 +160,11 @@ rn2xx3_handler::RN_state rn2xx3::async_loop() return _rn2xx3_handler.get_state(); } +uint8_t rn2xx3::get_busy_count() const +{ + return _rn2xx3_handler.get_busy_count(); +} + rn2xx3_handler::RN_state rn2xx3::wait_command_finished(unsigned long timeout) { return _rn2xx3_handler.wait_command_finished(timeout); diff --git a/lib/RN2483-Arduino-Library/src/rn2xx3.h b/lib/RN2483-Arduino-Library/src/rn2xx3.h index a39291ef10..06bd5cfd60 100644 --- a/lib/RN2483-Arduino-Library/src/rn2xx3.h +++ b/lib/RN2483-Arduino-Library/src/rn2xx3.h @@ -206,6 +206,8 @@ class rn2xx3 { */ rn2xx3_handler::RN_state async_loop(); + uint8_t get_busy_count() const; + rn2xx3_handler::RN_state wait_command_finished(unsigned long timeout = 10000); rn2xx3_handler::RN_state wait_command_accepted(unsigned long timeout = 10000); diff --git a/lib/RN2483-Arduino-Library/src/rn2xx3_handler.cpp b/lib/RN2483-Arduino-Library/src/rn2xx3_handler.cpp index 143ecc0fdb..789544d7f6 100644 --- a/lib/RN2483-Arduino-Library/src/rn2xx3_handler.cpp +++ b/lib/RN2483-Arduino-Library/src/rn2xx3_handler.cpp @@ -678,6 +678,10 @@ rn2xx3_handler::RN_state rn2xx3_handler::get_state() const { return _state; } +uint8_t rn2xx3_handler::get_busy_count() const { + return _busy_count; +} + String rn2xx3_handler::sysver() { String ver = sendRawCommand(F("sys get ver")); @@ -1014,7 +1018,7 @@ void rn2xx3_handler::handle_reply_received() { } else { - delay(1000); + delay(100); } break; } diff --git a/lib/RN2483-Arduino-Library/src/rn2xx3_handler.h b/lib/RN2483-Arduino-Library/src/rn2xx3_handler.h index 1b4e01b540..3504a63656 100644 --- a/lib/RN2483-Arduino-Library/src/rn2xx3_handler.h +++ b/lib/RN2483-Arduino-Library/src/rn2xx3_handler.h @@ -181,6 +181,8 @@ class rn2xx3_handler { RN_state get_state() const; + uint8_t get_busy_count() const; + String sysver(); // delay from last moment of sending to receive RX1 and RX2 window diff --git a/src/_C018.ino b/src/_C018.ino index e691c409eb..9e928e1568 100644 --- a/src/_C018.ino +++ b/src/_C018.ino @@ -269,7 +269,20 @@ struct C018_data_struct { void async_loop() { if (isInitialized()) { - myLora->async_loop(); + rn2xx3_handler::RN_state state = myLora->async_loop(); + if (rn2xx3_handler::RN_state::must_perform_init == state) { + if (myLora->get_busy_count() > 10) { + if (_resetPin != -1) { + pinMode(_resetPin, OUTPUT); + digitalWrite(_resetPin, LOW); + delay(50); + digitalWrite(_resetPin, HIGH); + delay(200); + } + autobaud_success = false; +// triggerAutobaud(); + } + } } } From 63c4dfddc047116661f87934232a22e7bb785683 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 9 Sep 2020 15:16:51 +0200 Subject: [PATCH 06/14] [C011] Use ESP8266HTTPClient library --- docs/source/Controller/_Controller.rst | 5 + src/Controller.ino | 1 + src/_C011.ino | 159 +++++++----------- src/_CPlugin_Helper.cpp | 139 ++++++++++++++- src/_CPlugin_Helper.h | 36 +++- src/_CPlugin_Helper_webform.ino | 34 ++-- .../ControllerQueue/C011_queue_element.cpp | 20 +++ src/src/ControllerQueue/C011_queue_element.h | 39 +++++ .../ControllerQueue/DelayQueueElements.cpp | 1 - src/src/ControllerQueue/DelayQueueElements.h | 2 +- .../DataStructs/ControllerSettingsStruct.h | 2 +- 11 files changed, 318 insertions(+), 120 deletions(-) create mode 100644 src/src/ControllerQueue/C011_queue_element.cpp create mode 100644 src/src/ControllerQueue/C011_queue_element.h diff --git a/docs/source/Controller/_Controller.rst b/docs/source/Controller/_Controller.rst index 8a88239d81..cdc80d9207 100644 --- a/docs/source/Controller/_Controller.rst +++ b/docs/source/Controller/_Controller.rst @@ -67,6 +67,11 @@ before WiFi connection is made or during lost connection. Especially useful for controllers which cannot send samples in a burst. This makes the receiving time stamp useless to detect what samples were taken around the same time. The sample set counter value can help matching received samples to a single set. +.. note:: + Be careful when setting the timeout too high. + For almost all controllers, sending data is a blocking call, so it may halt execution of other code on the node. + With timouts longer than 2 seconds, the ESP may reboot as the software watchdog may step in. + Sample ThingSpeak configuration diff --git a/src/Controller.ino b/src/Controller.ino index 162e74602d..16dc1a9d9f 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -153,6 +153,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) } updateMQTTclient_connected(); // mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864 + yield(); mqtt.setTimeout(ControllerSettings.ClientTimeout); MQTTclient.setClient(mqtt); diff --git a/src/_C011.ino b/src/_C011.ino index 69d3c8fed6..b889fb4206 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -5,14 +5,14 @@ // ########################### Controller Plugin 011: Generic HTTP Advanced ############################## // ####################################################################################################### -#define CPLUGIN_011 -#define CPLUGIN_ID_011 11 -#define CPLUGIN_NAME_011 "Generic HTTP Advanced [TESTING]" +# define CPLUGIN_011 +# define CPLUGIN_ID_011 11 +# define CPLUGIN_NAME_011 "Generic HTTP Advanced [TESTING]" -#define C011_HTTP_METHOD_MAX_LEN 16 -#define C011_HTTP_URI_MAX_LEN 240 -#define C011_HTTP_HEADER_MAX_LEN 256 -#define C011_HTTP_BODY_MAX_LEN 512 +# define C011_HTTP_METHOD_MAX_LEN 16 +# define C011_HTTP_URI_MAX_LEN 240 +# define C011_HTTP_HEADER_MAX_LEN 256 +# define C011_HTTP_BODY_MAX_LEN 512 struct C011_ConfigStruct { @@ -54,16 +54,16 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& } case CPlugin::Function::CPLUGIN_INIT: - { - success = init_c011_delay_queue(event->ControllerIndex); - break; - } + { + success = init_c011_delay_queue(event->ControllerIndex); + break; + } case CPlugin::Function::CPLUGIN_EXIT: - { - exit_c011_delay_queue(); - break; - } + { + exit_c011_delay_queue(); + break; + } case CPlugin::Function::CPLUGIN_WEBFORM_LOAD: { @@ -72,6 +72,7 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& String HttpUri; String HttpHeader; String HttpBody; + if (!load_C011_ConfigStruct(event->ControllerIndex, HttpMethod, HttpUri, HttpHeader, HttpBody)) { return false; @@ -101,15 +102,17 @@ 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 { - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - addControllerParameterForm(ControllerSettings, event->ControllerIndex, ControllerSettingsStruct::CONTROLLER_SEND_BINARY); - addFormNote(F("Do not 'percent escape' body when send binary checked")); - } + /* + // 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 { + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + addControllerParameterForm(ControllerSettings, event->ControllerIndex, ControllerSettingsStruct::CONTROLLER_SEND_BINARY); + addFormNote(F("Do not 'percent escape' body when send binary checked")); + } + */ } break; } @@ -146,10 +149,6 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_PROTOCOL_SEND: { - if (C011_DelayHandler == nullptr) { - break; - } - success = Create_schedule_HTTP_C011(event); break; } @@ -179,11 +178,21 @@ bool do_process_c011_delay_queue(int controller_number, const C011_queue_element bool do_process_c011_delay_queue(int controller_number, const C011_queue_element& element, ControllerSettingsStruct& ControllerSettings) { WiFiClient client; - if (!try_connect_host(controller_number, client, ControllerSettings)) { - return false; - } - - return send_via_http(controller_number, client, element.txt, ControllerSettings.MustCheckReply); + if (!NetworkConnected()) { return false; } + + int httpCode = -1; + + send_via_http( + controller_number, + ControllerSettings, + element.controller_idx, + client, + element.uri, + element.HttpMethod, + element.header, + element.postStr, + httpCode); + return httpCode > 0; } bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMethod, String& HttpUri, String& HttpHeader, String& HttpBody) { @@ -196,9 +205,9 @@ bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMetho LoadCustomControllerSettings(ControllerIndex, (byte *)customConfig.get(), sizeof(C011_ConfigStruct)); customConfig->zero_last(); HttpMethod = customConfig->HttpMethod; - HttpUri = customConfig->HttpUri; + HttpUri = customConfig->HttpUri; HttpHeader = customConfig->HttpHeader; - HttpBody = customConfig->HttpBody; + HttpBody = customConfig->HttpBody; return true; } @@ -208,61 +217,17 @@ bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMetho boolean Create_schedule_HTTP_C011(struct EventStruct *event) { if (C011_DelayHandler == nullptr) { + addLog(LOG_LEVEL_ERROR, F("No C011_DelayHandler")); return false; } - String authHeader; - String hostportString; - bool sendBinary = false; - if (ExtraTaskSettings.TaskIndex != event->TaskIndex) { String dummy; PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - { - // Have the ControllerSettings in a separate scope so we can free it as soon as possible - MakeControllerSettings(ControllerSettings); - - if (!AllocatedControllerSettings()) { - return false; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - - authHeader = get_auth_header(event->ControllerIndex, ControllerSettings); - const bool defaultport = ControllerSettings.Port == 0 || ControllerSettings.Port == 80; - hostportString = defaultport ? ControllerSettings.getHost() : ControllerSettings.getHostPortString(); - sendBinary = ControllerSettings.sendBinary(); - } - - - String HttpMethod; - String HttpUri; - String HttpHeader; - String HttpBody; - if (!load_C011_ConfigStruct(event->ControllerIndex, HttpMethod, HttpUri, HttpHeader, HttpBody)) - { - return false; - } - - - bool success = false; - - { - String payload = do_create_http_request( - hostportString, - HttpMethod, - HttpUri, - authHeader, - "", - -1); - - // Remove extra newline, see https://github.com/letscontrolit/ESPEasy/issues/1970 - removeExtraNewLine(payload); - - // Add a new element to the queue with the minimal payload - success = C011_DelayHandler->addToQueue(C011_queue_element(event->ControllerIndex, payload)); - } + // Add a new element to the queue with the minimal payload + bool success = C011_DelayHandler->addToQueue(C011_queue_element(event)); if (success) { // Element was added. @@ -270,22 +235,28 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) // and thus preventing the need to create a long string only to copy it to a queue element. C011_queue_element& element = C011_DelayHandler->sendQueue.back(); - if (HttpHeader.length() > 0) { - element.txt += HttpHeader; - removeExtraNewLine(element.txt); + if (!load_C011_ConfigStruct(event->ControllerIndex, element.HttpMethod, element.uri, element.header, element.postStr)) + { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log = F("C011 : "); + log += element.HttpMethod; + log += element.uri; + log += element.header; + log += element.postStr; + addLog(LOG_LEVEL_ERROR, log); + } + C011_DelayHandler->sendQueue.pop_back(); + return false; } - ReplaceTokenByValue(element.txt, event, false); - if (HttpBody.length() > 0) + ReplaceTokenByValue(element.header, event, false); + + if (element.postStr.length() > 0) { - ReplaceTokenByValue(HttpBody, event, sendBinary); - element.txt += F("Content-Length: "); - element.txt += String(HttpBody.length()); - addNewLine(element.txt); - addNewLine(element.txt); // Need 2 CRLF between header and body. - element.txt += HttpBody; + ReplaceTokenByValue(element.postStr, event, false); } - addNewLine(element.txt); + } else { + addLog(LOG_LEVEL_ERROR, F("C011 : Could not add to delay handler")); } Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C011_DELAY_QUEUE, C011_DelayHandler->getNextScheduleTime()); diff --git a/src/_CPlugin_Helper.cpp b/src/_CPlugin_Helper.cpp index 69069b4a0b..54bcbaf857 100644 --- a/src/_CPlugin_Helper.cpp +++ b/src/_CPlugin_Helper.cpp @@ -23,6 +23,14 @@ #include #include + +#ifdef ESP8266 +# include +#endif // ifdef ESP8266 +#ifdef ESP32 +# include "HTTPClient.h" +#endif // ifdef ESP32 + bool safeReadStringUntil(Stream & input, String & str, char terminator, @@ -132,6 +140,7 @@ String do_create_http_request( if (content_length >= 0) { estimated_size += 45; } String request; + request.reserve(estimated_size); request += method; request += ' '; @@ -262,6 +271,7 @@ bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettings if (!NetworkConnected()) { return false; } client.setTimeout(ControllerSettings.ClientTimeout); + yield(); #ifndef BUILD_NO_DEBUG log_connecting_to(F("UDP : "), controller_number, ControllerSettings); #endif // ifndef BUILD_NO_DEBUG @@ -274,8 +284,8 @@ bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettings } bool try_connect_host(int controller_number, WiFiClient& client, ControllerSettingsStruct& ControllerSettings) { - return try_connect_host(controller_number, client, ControllerSettings, F("HTTP : ")); -} + return try_connect_host(controller_number, client, ControllerSettings, F("HTTP : ")); +} bool try_connect_host(int controller_number, WiFiClient& client, ControllerSettingsStruct& ControllerSettings, const String& loglabel) { START_TIMER; @@ -283,6 +293,7 @@ bool try_connect_host(int controller_number, WiFiClient& client, ControllerSetti if (!NetworkConnected()) { return false; } // Use WiFiClient class to create TCP connections + yield(); client.setTimeout(ControllerSettings.ClientTimeout); #ifndef BUILD_NO_DEBUG log_connecting_to(loglabel, controller_number, ControllerSettings); @@ -415,10 +426,121 @@ bool send_via_http(int controller_number, WiFiClient& client, const String& post return send_via_http(get_formatted_Controller_number(controller_number), client, postStr, must_check_reply); } +String send_via_http(int controller_number, + const ControllerSettingsStruct& ControllerSettings, + controllerIndex_t controller_idx, + WiFiClient & client, + const String & uri, + const String & HttpMethod, + const String & header, + const String & postStr, + int & httpCode) { + client.setTimeout(ControllerSettings.ClientTimeout); + return send_via_http( + get_formatted_Controller_number(controller_number), + client, + ControllerSettings.ClientTimeout, + getControllerUser(controller_idx, ControllerSettings), + getControllerPass(controller_idx, ControllerSettings), + ControllerSettings.getHost(), + ControllerSettings.Port, + uri, + HttpMethod, + header, + postStr, + httpCode); +} + +String send_via_http(const String& logIdentifier, + WiFiClient & client, + uint16_t timeout, + const String& user, + const String& pass, + const String& host, + uint16_t port, + const String& uri, + const String& HttpMethod, + const String& header, + const String& postStr, + int & httpCode) { + HTTPClient http; + + http.setAuthorization(user.c_str(), pass.c_str()); + http.setTimeout(timeout); + yield(); + http.begin(client, host, port, uri, false); // HTTP + { + int colonPos = header.indexOf(':'); + + if (colonPos > 0) { + String key = header.substring(0, colonPos); + String value = header.substring(colonPos + 1); + value.trim(); + http.addHeader(key, value); + } + } + + + // start connection and send HTTP header and body + if (HttpMethod.equalsIgnoreCase(F("post"))) { + httpCode = http.POST(postStr); + } else if (HttpMethod.equalsIgnoreCase(F("get"))) { + httpCode = http.GET(); + } else if (HttpMethod.equalsIgnoreCase(F("put"))) { + httpCode = http.PUT(postStr); + } else if (HttpMethod.equalsIgnoreCase(F("head"))) { + // The HEAD method is identical to GET + // except that the server MUST NOT return a message-body in the response. + // However, HTTPClient library has no HEAD function. + httpCode = http.GET(); + } else if (HttpMethod.equalsIgnoreCase(F("patch"))) { + httpCode = http.PATCH(postStr); + } else { + addLog(LOG_LEVEL_ERROR, F("HTTP : Unknown method")); + } + String response; + + // httpCode will be negative on error + if (httpCode > 0) { + response = http.getString(); + + if (httpCode == HTTP_CODE_OK) { + // response = http.getString(); + } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = F("HTTP : "); + log += logIdentifier; + log += ' '; + log += HttpMethod; + log += F("... HTTP code: "); + log += String(httpCode); + + if (response.length() > 0) { + log += ' '; + log += response; + } + addLog(LOG_LEVEL_DEBUG, log); + } + } else { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + String log = F("HTTP : "); + log += logIdentifier; + log += ' '; + log += HttpMethod; + log += F("... failed, error: "); + log += http.errorToString(httpCode); + addLog(LOG_LEVEL_ERROR, log); + } + } + http.end(); + return response; +} String getControllerUser(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings) { - if (!validControllerIndex(controller_idx)) return ""; + if (!validControllerIndex(controller_idx)) { return ""; } + if (ControllerSettings.useExtendedCredentials()) { return ExtendedControllerCredentials.getControllerUser(controller_idx); } @@ -427,7 +549,8 @@ String getControllerUser(controllerIndex_t controller_idx, const ControllerSetti String getControllerPass(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings) { - if (!validControllerIndex(controller_idx)) return ""; + if (!validControllerIndex(controller_idx)) { return ""; } + if (ControllerSettings.useExtendedCredentials()) { return ExtendedControllerCredentials.getControllerPass(controller_idx); } @@ -436,7 +559,8 @@ String getControllerPass(controllerIndex_t controller_idx, const ControllerSetti void setControllerUser(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings, const String& value) { - if (!validControllerIndex(controller_idx)) return; + if (!validControllerIndex(controller_idx)) { return; } + if (ControllerSettings.useExtendedCredentials()) { ExtendedControllerCredentials.setControllerUser(controller_idx, value); } else { @@ -446,7 +570,8 @@ void setControllerUser(controllerIndex_t controller_idx, const ControllerSetting void setControllerPass(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings, const String& value) { - if (!validControllerIndex(controller_idx)) return; + if (!validControllerIndex(controller_idx)) { return; } + if (ControllerSettings.useExtendedCredentials()) { ExtendedControllerCredentials.setControllerPass(controller_idx, value); } else { @@ -458,4 +583,4 @@ bool hasControllerCredentialsSet(controllerIndex_t controller_idx, const Control { return getControllerUser(controller_idx, ControllerSettings).length() != 0 && getControllerPass(controller_idx, ControllerSettings).length() != 0; -} \ No newline at end of file +} diff --git a/src/_CPlugin_Helper.h b/src/_CPlugin_Helper.h index 5f29716dbf..d8374626f5 100644 --- a/src/_CPlugin_Helper.h +++ b/src/_CPlugin_Helper.h @@ -72,9 +72,39 @@ bool try_connect_host(int controller_number, WiFiClient& client, ControllerSetti // https://github.com/esp8266/Arduino/pull/1829 bool client_available(WiFiClient& client); -bool send_via_http(const String& logIdentifier, WiFiClient& client, const String& postStr, bool must_check_reply); - -bool send_via_http(int controller_number, WiFiClient& client, const String& postStr, bool must_check_reply); +bool send_via_http(const String& logIdentifier, + WiFiClient & client, + const String& postStr, + bool must_check_reply); + +bool send_via_http(int controller_number, + WiFiClient & client, + const String& postStr, + bool must_check_reply); + +String send_via_http(const String& logIdentifier, + WiFiClient & client, + uint16_t timeout, + const String& user, + const String& pass, + const String& host, + uint16_t port, + const String& uri, + const String& HttpMethod, + const String& header, + const String& postStr, + int & httpCode); + +String send_via_http(int controller_number, + const ControllerSettingsStruct& ControllerSettings, + controllerIndex_t controller_idx, + WiFiClient & client, + const String & uri, + const String & HttpMethod, + const String & header, + const String & postStr, + int & httpCode); + String getControllerUser(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings); String getControllerPass(controllerIndex_t controller_idx, const ControllerSettingsStruct& ControllerSettings); diff --git a/src/_CPlugin_Helper_webform.ino b/src/_CPlugin_Helper_webform.ino index 5f91c8435c..2a943f9e6e 100644 --- a/src/_CPlugin_Helper_webform.ino +++ b/src/_CPlugin_Helper_webform.ino @@ -7,7 +7,10 @@ /*********************************************************************************************\ * Functions to load and store controller settings on the web page. \*********************************************************************************************/ -String getControllerParameterName(protocolIndex_t ProtocolIndex, ControllerSettingsStruct::VarType parameterIdx, bool displayName, bool& isAlternative) { +String getControllerParameterName(protocolIndex_t ProtocolIndex, + ControllerSettingsStruct::VarType parameterIdx, + bool displayName, + bool & isAlternative) { String name; if (displayName) { @@ -84,7 +87,8 @@ String getControllerParameterDisplayName(protocolIndex_t ProtocolIndex, Controll } void addControllerEnabledForm(controllerIndex_t controllerindex) { - protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); + protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); + if (!validProtocolIndex(ProtocolIndex)) { return; } @@ -134,7 +138,8 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin } case ControllerSettingsStruct::CONTROLLER_USER: { - size_t fieldMaxLength = ControllerSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.ControllerUser[0]) - 1; + size_t fieldMaxLength = + ControllerSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.ControllerUser[0]) - 1; addFormTextBox(displayName, internalName, getControllerUser(controllerindex, ControllerSettings), @@ -153,7 +158,6 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin addFormPasswordBox(displayName, internalName, getControllerPass(controllerindex, ControllerSettings), fieldMaxLength); - } break; } @@ -190,7 +194,7 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin break; } case ControllerSettingsStruct::CONTROLLER_CLIENT_ID: - addFormTextBox(displayName, internalName, ControllerSettings.ClientID, sizeof(ControllerSettings.ClientID) - 1); + addFormTextBox(displayName, internalName, ControllerSettings.ClientID, sizeof(ControllerSettings.ClientID) - 1); break; case ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT: addFormCheckBox(displayName, internalName, ControllerSettings.mqtt_uniqueMQTTclientIdReconnect()); @@ -241,12 +245,15 @@ void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettin } } -void saveControllerParameterForm(ControllerSettingsStruct& ControllerSettings, controllerIndex_t controllerindex, ControllerSettingsStruct::VarType varType) { +void saveControllerParameterForm(ControllerSettingsStruct & ControllerSettings, + controllerIndex_t controllerindex, + ControllerSettingsStruct::VarType varType) { protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex); + if (!validProtocolIndex(ProtocolIndex)) { return; } - String internalName = getControllerParameterInternalName(ProtocolIndex, varType); + String internalName = getControllerParameterInternalName(ProtocolIndex, varType); switch (varType) { case ControllerSettingsStruct::CONTROLLER_USE_DNS: ControllerSettings.UseDNS = getFormItemInt(internalName); break; @@ -278,13 +285,14 @@ void saveControllerParameterForm(ControllerSettingsStruct& ControllerSettings, c setControllerUser(controllerindex, ControllerSettings, web_server.arg(internalName)); break; case ControllerSettingsStruct::CONTROLLER_PASS: - { - String password; - if (getFormPassword(internalName, password)) { - setControllerPass(controllerindex, ControllerSettings, password); - } + { + String password; + + if (getFormPassword(internalName, password)) { + setControllerPass(controllerindex, ControllerSettings, password); } break; + } case ControllerSettingsStruct::CONTROLLER_MIN_SEND_INTERVAL: ControllerSettings.MinimalTimeBetweenMessages = getFormItemInt(internalName, ControllerSettings.MinimalTimeBetweenMessages); @@ -303,7 +311,7 @@ void saveControllerParameterForm(ControllerSettingsStruct& ControllerSettings, c break; case ControllerSettingsStruct::CONTROLLER_CLIENT_ID: - strncpy_webserver_arg(ControllerSettings.ClientID, internalName); + strncpy_webserver_arg(ControllerSettings.ClientID, internalName); break; case ControllerSettingsStruct::CONTROLLER_UNIQUE_CLIENT_ID_RECONNECT: ControllerSettings.mqtt_uniqueMQTTclientIdReconnect(isFormItemChecked(internalName)); diff --git a/src/src/ControllerQueue/C011_queue_element.cpp b/src/src/ControllerQueue/C011_queue_element.cpp new file mode 100644 index 0000000000..dac10333ec --- /dev/null +++ b/src/src/ControllerQueue/C011_queue_element.cpp @@ -0,0 +1,20 @@ +#include "../ControllerQueue/C011_queue_element.h" + +#include "../DataStructs/ESPEasy_EventStruct.h" + +C011_queue_element::C011_queue_element() {} + +C011_queue_element::C011_queue_element(const struct EventStruct *event) : + idx(event->idx), + TaskIndex(event->TaskIndex), + controller_idx(event->ControllerIndex), + sensorType(event->sensorType) {} + +size_t C011_queue_element::getSize() const { + size_t total = sizeof(*this); + total += uri.length(); + total += HttpMethod.length(); + total += header.length(); + total += postStr.length(); + return total; +} diff --git a/src/src/ControllerQueue/C011_queue_element.h b/src/src/ControllerQueue/C011_queue_element.h new file mode 100644 index 0000000000..115dcb4966 --- /dev/null +++ b/src/src/ControllerQueue/C011_queue_element.h @@ -0,0 +1,39 @@ +#ifndef CONTROLLERQUEUE_C011_QUEUE_ELEMENT_H +#define CONTROLLERQUEUE_C011_QUEUE_ELEMENT_H + +#include "../../ESPEasy_common.h" +#include "../DataStructs/ESPEasyLimits.h" +#include "../Globals/CPlugins.h" +#include "../Globals/Plugins.h" + +struct EventStruct; + + +// #ifdef USES_C011 + +/*********************************************************************************************\ +* C011_queue_element for queueing requests for C011: Generic HTTP Advanced. +\*********************************************************************************************/ +class C011_queue_element { +public: + + C011_queue_element(); + + C011_queue_element(const struct EventStruct *event); + + size_t getSize() const; + + String uri; + String HttpMethod; + String header; + String postStr; + int idx = 0; + taskIndex_t TaskIndex = INVALID_TASK_INDEX; + controllerIndex_t controller_idx = INVALID_CONTROLLER_INDEX; + byte sensorType = 0; +}; + +// #endif //USES_C011 + + +#endif // CONTROLLERQUEUE_C011_QUEUE_ELEMENT_H diff --git a/src/src/ControllerQueue/DelayQueueElements.cpp b/src/src/ControllerQueue/DelayQueueElements.cpp index 87f6f83d28..04e82d729b 100644 --- a/src/src/ControllerQueue/DelayQueueElements.cpp +++ b/src/src/ControllerQueue/DelayQueueElements.cpp @@ -87,7 +87,6 @@ DEFINE_Cxxx_DELAY_QUEUE_MACRO_CPP( 0, 10) * C011_queue_element for queueing requests for 011: Generic HTTP Advanced \*********************************************************************************************/ #ifdef USES_C011 -# define C011_queue_element simple_queue_element_string_only DEFINE_Cxxx_DELAY_QUEUE_MACRO_CPP( 0, 11) #endif // ifdef USES_C011 diff --git a/src/src/ControllerQueue/DelayQueueElements.h b/src/src/ControllerQueue/DelayQueueElements.h index 8bc0935b7d..2282c8fc90 100644 --- a/src/src/ControllerQueue/DelayQueueElements.h +++ b/src/src/ControllerQueue/DelayQueueElements.h @@ -93,7 +93,7 @@ DEFINE_Cxxx_DELAY_QUEUE_MACRO( 0, 10) * C011_queue_element for queueing requests for 011: Generic HTTP Advanced \*********************************************************************************************/ #ifdef USES_C011 -# define C011_queue_element simple_queue_element_string_only +# include "../ControllerQueue/C011_queue_element.h" DEFINE_Cxxx_DELAY_QUEUE_MACRO( 0, 11) #endif // ifdef USES_C011 diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index 5183747714..ff2a8f5624 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -41,7 +41,7 @@ class WiFiUDP; // Timeout of the client in msec. #ifndef CONTROLLER_CLIENTTIMEOUT_MAX -# define CONTROLLER_CLIENTTIMEOUT_MAX 1000 +# define CONTROLLER_CLIENTTIMEOUT_MAX 4000 // Not sure if this may trigger SW watchdog. #endif // ifndef CONTROLLER_CLIENTTIMEOUT_MAX #ifndef CONTROLLER_CLIENTTIMEOUT_DFLT # define CONTROLLER_CLIENTTIMEOUT_DFLT 100 From c33e98f8d838812e80884a0f849062289fbfa696 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 9 Sep 2020 16:01:07 +0200 Subject: [PATCH 07/14] [C011] Fix build issue for older ESP8266 core versions --- src/_CPlugin_Helper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/_CPlugin_Helper.cpp b/src/_CPlugin_Helper.cpp index 54bcbaf857..0fdc43ad59 100644 --- a/src/_CPlugin_Helper.cpp +++ b/src/_CPlugin_Helper.cpp @@ -468,7 +468,11 @@ String send_via_http(const String& logIdentifier, http.setAuthorization(user.c_str(), pass.c_str()); http.setTimeout(timeout); yield(); +#if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri, false); // HTTP +#else + http.begin(host, port, uri); +#endif { int colonPos = header.indexOf(':'); From 6a616e319782da52b5528ab5685b192e825a31ba Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 9 Sep 2020 16:55:43 +0200 Subject: [PATCH 08/14] [Travis] Disable core 2.4.2 builds as Travis can't install it anymore For some strange reason.... Build log: ``` $ PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e $ENV Processing minimal_core_242_ESP8266_1M_OTA (platform: https://github.com/TD-er/platform-espressif8266.git#patch/v1.8.0_Puya; board: esp01_1m; framework: arduino) -------------------------------------------------------------------------------- Platform Manager: Installing git+https://github.com/TD-er/platform-espressif8266.git#patch/v1.8.0_Puya git version 2.27.0 Cloning into '/home/travis/.platformio/.cache/tmp/pkg-installing-aktun99x'... Platform Manager: espressif8266 @ 1.8.0+sha.9ffc857 has been installed! The platform 'https://github.com/TD-er/platform-espressif8266.git#patch/v1.8.0_Puya' has been successfully installed! The rest of the packages will be installed later depending on your build environment. Tool Manager: Installing toolchain-xtensa @ ~1.40802.0 Downloading... Unpacking... Tool Manager: toolchain-xtensa @ 1.40802.0 has been installed! Tool Manager: Installing framework-arduinoespressif8266 @ 2.20402.4-puya Tool Manager: Warning! More than one package has been found by framework-arduinoespressif8266 @ 2.20402.4-puya requirements: - platformio/framework-arduinoespressif8266 @ 3.20704.0 - jason2866/framework-arduinoespressif8266 @ 2.7.4.1 Tool Manager: Please specify detailed REQUIREMENTS using package owner and version (showed above) to avoid name conflicts Error: Could not find the package with 'framework-arduinoespressif8266 @ 2.20402.4-puya' requirements for your system 'linux_x86_64' The command "PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e $ENV" exited with 1. ``` Maybe @jason2866 does have an idea? --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 83dc99ed01..b166580ae5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,8 +45,8 @@ env: - ENV=minimal_IRext_ESP8266_1M - ENV=minimal_IRext_ESP8266_4M1M - ENV=minimal_IRext_ESP8266_4M2M - - ENV=minimal_core_242_ESP8266_1M_OTA - - ENV=minimal_core_242_ESP8285_1M_OTA + #- ENV=minimal_core_242_ESP8266_1M_OTA + #- ENV=minimal_core_242_ESP8285_1M_OTA - ENV=minimal_core_274_ESP8266_1M_OTA_Domoticz - ENV=minimal_core_274_ESP8266_1M_OTA_FHEM_HA - ENV=minimal_core_274_ESP8285_1M_OTA_Domoticz From fcc60632644b00122006568224bdb3c548097d6e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 10 Sep 2020 00:09:15 +0200 Subject: [PATCH 09/14] [C011] Improve logging + connection tracking. --- src/Controller.ino | 2 +- src/_C011.ino | 6 ++- src/_CPlugin_Helper.cpp | 83 +++++++++++++++++++++++++---------------- src/_CPlugin_Helper.h | 4 +- 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index 16dc1a9d9f..4f76988894 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -199,7 +199,7 @@ bool MQTTConnect(controllerIndex_t controller_idx) byte controller_number = Settings.Protocol[controller_idx]; - count_connection_results(MQTTresult, F("MQTT : Broker "), controller_number, ControllerSettings); + count_connection_results(MQTTresult, F("MQTT : Broker "), controller_number); if (!MQTTresult) { MQTTclient.disconnect(); diff --git a/src/_C011.ino b/src/_C011.ino index b889fb4206..2bd3fe6ff5 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -192,7 +192,11 @@ bool do_process_c011_delay_queue(int controller_number, const C011_queue_element element.header, element.postStr, httpCode); - return httpCode > 0; + + // HTTP codes: + // 1xx Informational response + // 2xx Success + return httpCode >= 100 && httpCode < 300; } bool load_C011_ConfigStruct(controllerIndex_t ControllerIndex, String& HttpMethod, String& HttpUri, String& HttpHeader, String& HttpBody) { diff --git a/src/_CPlugin_Helper.cpp b/src/_CPlugin_Helper.cpp index 0fdc43ad59..36aa4c9946 100644 --- a/src/_CPlugin_Helper.cpp +++ b/src/_CPlugin_Helper.cpp @@ -111,18 +111,27 @@ String get_auth_header(int controller_index, const ControllerSettingsStruct& Con return authHeader; } +String get_user_agent_string() { + static unsigned int agent_size = 20; + String userAgent; + userAgent.reserve(agent_size); + userAgent += F("ESP Easy/"); + userAgent += BUILD; + userAgent += '/'; + userAgent += get_build_date(); + userAgent += ' '; + userAgent += get_build_time(); + agent_size = userAgent.length(); + return userAgent; +} + String get_user_agent_request_header_field() { static unsigned int agent_size = 20; String request; request.reserve(agent_size); request = F("User-Agent: "); - request += F("ESP Easy/"); - request += BUILD; - request += '/'; - request += get_build_date(); - request += ' '; - request += get_build_time(); + request += get_user_agent_string(); request += "\r\n"; agent_size = request.length(); return request; @@ -238,7 +247,7 @@ void log_connecting_to(const String& prefix, int controller_number, ControllerSe #endif // ifndef BUILD_NO_DEBUG -void log_connecting_fail(const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings) { +void log_connecting_fail(const String& prefix, int controller_number) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { String log = prefix; log += get_formatted_Controller_number(controller_number); @@ -251,11 +260,11 @@ void log_connecting_fail(const String& prefix, int controller_number, Controller } } -bool count_connection_results(bool success, const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings) { +bool count_connection_results(bool success, const String& prefix, int controller_number) { if (!success) { ++connectionFailures; - log_connecting_fail(prefix, controller_number, ControllerSettings); + log_connecting_fail(prefix, controller_number); return false; } statusLED(true); @@ -278,7 +287,7 @@ bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettings bool success = ControllerSettings.beginPacket(client); const bool result = count_connection_results( success, - F("UDP : "), controller_number, ControllerSettings); + F("UDP : "), controller_number); STOP_TIMER(TRY_CONNECT_HOST_UDP); return result; } @@ -301,7 +310,7 @@ bool try_connect_host(int controller_number, WiFiClient& client, ControllerSetti const bool success = ControllerSettings.connectToHost(client); const bool result = count_connection_results( success, - loglabel, controller_number, ControllerSettings); + loglabel, controller_number); STOP_TIMER(TRY_CONNECT_HOST_TCP); return result; } @@ -436,7 +445,7 @@ String send_via_http(int controller_number, const String & postStr, int & httpCode) { client.setTimeout(ControllerSettings.ClientTimeout); - return send_via_http( + const String result = send_via_http( get_formatted_Controller_number(controller_number), client, ControllerSettings.ClientTimeout, @@ -449,6 +458,15 @@ String send_via_http(int controller_number, header, postStr, httpCode); + + const bool success = httpCode > 0; + + count_connection_results( + success, + F("HTTP : "), + controller_number); + + return result; } String send_via_http(const String& logIdentifier, @@ -467,6 +485,13 @@ String send_via_http(const String& logIdentifier, http.setAuthorization(user.c_str(), pass.c_str()); http.setTimeout(timeout); + http.setUserAgent(get_user_agent_string()); + + // Add request header as fall back. + // When adding another "accept" header, it may be interpreted as: + // "if you have XXX, send it; or failing that, just give me what you've got." + http.addHeader(F("Accept"), F("*/*;q=0.1")); + yield(); #if defined(CORE_POST_2_6_0) || defined(ESP32) http.begin(client, host, port, uri, false); // HTTP @@ -484,35 +509,29 @@ String send_via_http(const String& logIdentifier, } } - - // start connection and send HTTP header and body - if (HttpMethod.equalsIgnoreCase(F("post"))) { - httpCode = http.POST(postStr); - } else if (HttpMethod.equalsIgnoreCase(F("get"))) { - httpCode = http.GET(); - } else if (HttpMethod.equalsIgnoreCase(F("put"))) { - httpCode = http.PUT(postStr); - } else if (HttpMethod.equalsIgnoreCase(F("head"))) { - // The HEAD method is identical to GET - // except that the server MUST NOT return a message-body in the response. - // However, HTTPClient library has no HEAD function. - httpCode = http.GET(); - } else if (HttpMethod.equalsIgnoreCase(F("patch"))) { - httpCode = http.PATCH(postStr); + // start connection and send HTTP header (and body) + if (HttpMethod.equals(F("HEAD")) || HttpMethod.equals(F("GET"))) { + httpCode = http.sendRequest(HttpMethod.c_str()); } else { - addLog(LOG_LEVEL_ERROR, F("HTTP : Unknown method")); + httpCode = http.sendRequest(HttpMethod.c_str(), postStr); } + String response; // httpCode will be negative on error if (httpCode > 0) { response = http.getString(); - if (httpCode == HTTP_CODE_OK) { - // response = http.getString(); + byte loglevel = LOG_LEVEL_ERROR; + // HTTP codes: + // 1xx Informational response + // 2xx Success + if (httpCode >= 100 && httpCode < 300) { + loglevel = LOG_LEVEL_INFO; } - if (loglevelActiveFor(LOG_LEVEL_INFO)) { + + if (loglevelActiveFor(loglevel)) { String log = F("HTTP : "); log += logIdentifier; log += ' '; @@ -524,7 +543,7 @@ String send_via_http(const String& logIdentifier, log += ' '; log += response; } - addLog(LOG_LEVEL_DEBUG, log); + addLog(loglevel, log); } } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { diff --git a/src/_CPlugin_Helper.h b/src/_CPlugin_Helper.h index d8374626f5..6905aadaa9 100644 --- a/src/_CPlugin_Helper.h +++ b/src/_CPlugin_Helper.h @@ -57,9 +57,9 @@ String create_http_request_auth(int controller_number, int controller_index, Con void log_connecting_to(const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings); #endif // ifndef BUILD_NO_DEBUG -void log_connecting_fail(const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings); +void log_connecting_fail(const String& prefix, int controller_number); -bool count_connection_results(bool success, const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings); +bool count_connection_results(bool success, const String& prefix, int controller_number); bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettingsStruct& ControllerSettings); From 9b4c7960626d68d62ebdef2af5029296111f49be Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 11 Sep 2020 12:14:36 +0200 Subject: [PATCH 10/14] [C011] Split multiline headers + also parse url Allowing to use variables in the URL --- src/_C011.ino | 34 ++++++++++++++++++++++------------ src/_CPlugin_Helper.cpp | 35 ++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/_C011.ino b/src/_C011.ino index 2bd3fe6ff5..8341bd1d00 100644 --- a/src/_C011.ino +++ b/src/_C011.ino @@ -14,6 +14,9 @@ # define C011_HTTP_HEADER_MAX_LEN 256 # define C011_HTTP_BODY_MAX_LEN 512 + +bool C011_sendBinary = false; + struct C011_ConfigStruct { void zero_last() { @@ -55,6 +58,13 @@ bool CPlugin_011(CPlugin::Function function, struct EventStruct *event, String& case CPlugin::Function::CPLUGIN_INIT: { + { + MakeControllerSettings(ControllerSettings); + if (AllocatedControllerSettings()) { + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + C011_sendBinary = ControllerSettings.sendBinary(); + } + } success = init_c011_delay_queue(event->ControllerIndex); break; } @@ -102,17 +112,16 @@ 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 { - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - addControllerParameterForm(ControllerSettings, event->ControllerIndex, ControllerSettingsStruct::CONTROLLER_SEND_BINARY); - addFormNote(F("Do not 'percent escape' body when send binary checked")); - } - */ + + // 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 { + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + addControllerParameterForm(ControllerSettings, event->ControllerIndex, ControllerSettingsStruct::CONTROLLER_SEND_BINARY); + addFormNote(F("Do not 'percent escape' body when send binary checked")); + } } break; } @@ -253,11 +262,12 @@ boolean Create_schedule_HTTP_C011(struct EventStruct *event) return false; } + ReplaceTokenByValue(element.uri, event, false); ReplaceTokenByValue(element.header, event, false); if (element.postStr.length() > 0) { - ReplaceTokenByValue(element.postStr, event, false); + ReplaceTokenByValue(element.postStr, event, C011_sendBinary); } } else { addLog(LOG_LEVEL_ERROR, F("C011 : Could not add to delay handler")); diff --git a/src/_CPlugin_Helper.cpp b/src/_CPlugin_Helper.cpp index 36aa4c9946..502f8d7dd9 100644 --- a/src/_CPlugin_Helper.cpp +++ b/src/_CPlugin_Helper.cpp @@ -469,6 +469,29 @@ String send_via_http(int controller_number, return result; } +bool splitHeaders(int& strpos, const String& multiHeaders, String& name, String& value) { + if (strpos < 0) { + return false; + } + int colonPos = multiHeaders.indexOf(':', strpos); + + if (colonPos < 0) { + return false; + } + name = multiHeaders.substring(strpos, colonPos); + int valueEndPos = multiHeaders.indexOf('\n', colonPos + 1); + if (valueEndPos < 0) { + value = multiHeaders.substring(colonPos + 1); + strpos = -1; + } else { + value = multiHeaders.substring(colonPos + 1, valueEndPos); + strpos = valueEndPos + 1; + } + value.replace('\r', ' '); + value.trim(); + return true; +} + String send_via_http(const String& logIdentifier, WiFiClient & client, uint16_t timeout, @@ -498,14 +521,12 @@ String send_via_http(const String& logIdentifier, #else http.begin(host, port, uri); #endif + { - int colonPos = header.indexOf(':'); - - if (colonPos > 0) { - String key = header.substring(0, colonPos); - String value = header.substring(colonPos + 1); - value.trim(); - http.addHeader(key, value); + int headerpos = 0; + String name, value; + while (splitHeaders(headerpos, header, name, value)) { + http.addHeader(name, value); } } From 52ecb96977b89895d0a088c7e89c22d147fe7c5f Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 11 Sep 2020 12:15:47 +0200 Subject: [PATCH 11/14] [Cleanup] Reduce memory usage when using ControllerSettings struct --- src/Controller.ino | 71 +++++++++++++++++++++----------------- src/_C009.ino | 6 ---- src/_C010.ino | 34 +++++++++--------- src/_C012.ino | 7 ---- src/_C017.ino | 6 ---- src/_P037_MQTTImport.ino | 44 +++++++++++++---------- src/src/Commands/Blynk.cpp | 47 +++++++++++++++---------- 7 files changed, 112 insertions(+), 103 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index 4f76988894..20fd09f10f 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -273,46 +273,55 @@ bool MQTTCheck(controllerIndex_t controller_idx) if (Protocol[ProtocolIndex].usesMQTT) { - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot check, out of RAM")); - return false; - } + bool mqtt_sendLWT = false; + String LWTTopic, LWTMessageConnect; + bool willRetain = false; + { + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Cannot check, out of RAM")); + return false; + } + + LoadControllerSettings(controller_idx, ControllerSettings); - LoadControllerSettings(controller_idx, ControllerSettings); + // FIXME TD-er: Is this still needed? + /* + #ifdef USES_ESPEASY_NOW + if (!MQTTclient.connected()) { + if (ControllerSettings.enableESPEasyNowFallback()) { + return true; + } + } + #endif + */ - // FIXME TD-er: Is this still needed? - /* - #ifdef USES_ESPEASY_NOW - if (!MQTTclient.connected()) { - if (ControllerSettings.enableESPEasyNowFallback()) { + if (!ControllerSettings.isSet()) { return true; } + + if (ControllerSettings.mqtt_sendLWT()) { + mqtt_sendLWT = true; + LWTTopic = getLWT_topic(ControllerSettings); + LWTMessageConnect = getLWT_messageConnect(ControllerSettings); + willRetain = ControllerSettings.mqtt_willRetain(); + } } - #endif - */ - - if (ControllerSettings.isSet()) { - if (MQTTclient_should_reconnect || !MQTTclient.connected()) - { - if (MQTTclient_should_reconnect) { - addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect")); - } - return MQTTConnect(controller_idx); + if (MQTTclient_should_reconnect || !MQTTclient.connected()) + { + if (MQTTclient_should_reconnect) { + addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect")); } + return MQTTConnect(controller_idx); + } - if (MQTTclient_must_send_LWT_connected) { - if (ControllerSettings.mqtt_sendLWT()) { - String LWTTopic = getLWT_topic(ControllerSettings); - String LWTMessageConnect = getLWT_messageConnect(ControllerSettings); - bool willRetain = ControllerSettings.mqtt_willRetain(); - - if (MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), willRetain)) { - MQTTclient_must_send_LWT_connected = false; - } - } else { + if (MQTTclient_must_send_LWT_connected) { + if (mqtt_sendLWT) { + if (MQTTclient.publish(LWTTopic.c_str(), LWTMessageConnect.c_str(), willRetain)) { MQTTclient_must_send_LWT_connected = false; } + } else { + MQTTclient_must_send_LWT_connected = false; } } } diff --git a/src/_C009.ino b/src/_C009.ino index 6c81bab404..ef9604e8cb 100644 --- a/src/_C009.ino +++ b/src/_C009.ino @@ -78,12 +78,6 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& byte valueCount = getValueCountFromSensorType(event->sensorType); C009_queue_element element(event); - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - break; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - for (byte x = 0; x < valueCount; x++) { element.txt[x] = formatUserVarNoCheck(event, x); diff --git a/src/_C010.ino b/src/_C010.ino index e863b89ae8..b692859a39 100644 --- a/src/_C010.ino +++ b/src/_C010.ino @@ -64,23 +64,25 @@ bool CPlugin_010(CPlugin::Function function, struct EventStruct *event, String& PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - break; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - - for (byte x = 0; x < valueCount; x++) { - bool isvalid; - String formattedValue = formatUserVar(event, x, isvalid); - if (isvalid) { - element.txt[x] = ""; - element.txt[x] += ControllerSettings.Publish; - parseControllerVariables(element.txt[x], event, false); - element.txt[x].replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); - element.txt[x].replace(F("%value%"), formattedValue); - addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + break; + } + LoadControllerSettings(event->ControllerIndex, ControllerSettings); + + for (byte x = 0; x < valueCount; x++) + { + bool isvalid; + String formattedValue = formatUserVar(event, x, isvalid); + if (isvalid) { + element.txt[x] = ""; + element.txt[x] += ControllerSettings.Publish; + parseControllerVariables(element.txt[x], event, false); + element.txt[x].replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); + element.txt[x].replace(F("%value%"), formattedValue); + addLog(LOG_LEVEL_DEBUG_MORE, element.txt[x]); + } } } // FIXME TD-er must define a proper move operator diff --git a/src/_C012.ino b/src/_C012.ino index 0672963539..808d1aee11 100644 --- a/src/_C012.ino +++ b/src/_C012.ino @@ -61,13 +61,6 @@ bool CPlugin_012(CPlugin::Function function, struct EventStruct *event, String& PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummy); } - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - break; - } - - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - for (byte x = 0; x < valueCount; x++) { bool isvalid; diff --git a/src/_C017.ino b/src/_C017.ino index c2f35e6beb..81c2dde9e9 100644 --- a/src/_C017.ino +++ b/src/_C017.ino @@ -65,12 +65,6 @@ bool CPlugin_017(CPlugin::Function function, struct EventStruct *event, String & byte valueCount = getValueCountFromSensorType(event->sensorType); C017_queue_element element(event); - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - break; - } - LoadControllerSettings(event->ControllerIndex, ControllerSettings); - for (byte x = 0; x < valueCount; x++) { element.txt[x] = formatUserVarNoCheck(event, x); diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index ecc156998d..b6e7515f6d 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -420,33 +420,41 @@ boolean MQTTConnect_037() Plugin_037_update_connect_status(); return false; // Not connected, so no use in wasting time to connect to a host. } - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - addLog(LOG_LEVEL_ERROR, F("IMPT : Cannot load controller settings, out of RAM")); - return false; - } + + String user, pass; + bool hasCredentials = false; - LoadControllerSettings(enabledMqttController, ControllerSettings); - if (ControllerSettings.UseDNS) { - MQTTclient_037->setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port); - } else { - MQTTclient_037->setServer(ControllerSettings.getIP(), ControllerSettings.Port); + { + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("IMPT : Cannot load controller settings, out of RAM")); + return false; + } + + LoadControllerSettings(enabledMqttController, ControllerSettings); + if (ControllerSettings.UseDNS) { + MQTTclient_037->setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port); + } else { + MQTTclient_037->setServer(ControllerSettings.getIP(), ControllerSettings.Port); + } + MQTTclient_037->setCallback(mqttcallback_037); + if (hasControllerCredentialsSet(enabledMqttController, ControllerSettings)) { + hasCredentials = true; + user = getControllerUser(enabledMqttController, ControllerSettings); + pass = getControllerPass(enabledMqttController, ControllerSettings); + } } - MQTTclient_037->setCallback(mqttcallback_037); // Try three times for a connection - for (byte x = 1; x < 4; x++) { String log = ""; - if (hasControllerCredentialsSet(enabledMqttController, ControllerSettings)) - result = MQTTclient_037->connect(clientid.c_str(), - getControllerUser(enabledMqttController, ControllerSettings).c_str(), - getControllerPass(enabledMqttController, ControllerSettings).c_str()); - else + if (hasCredentials) { + result = MQTTclient_037->connect(clientid.c_str(), user.c_str(), pass.c_str()); + } else { result = MQTTclient_037->connect(clientid.c_str()); - + } if (result) { diff --git a/src/src/Commands/Blynk.cpp b/src/src/Commands/Blynk.cpp index 4dc5ebfb9a..5832b5f359 100644 --- a/src/src/Commands/Blynk.cpp +++ b/src/src/Commands/Blynk.cpp @@ -66,41 +66,50 @@ String Command_Blynk_Get(struct EventStruct *event, const char *Line) bool Blynk_get(const String& command, controllerIndex_t controllerIndex, float *data) { - MakeControllerSettings(ControllerSettings); - if (!AllocatedControllerSettings()) { - addLog(LOG_LEVEL_ERROR, F("Blynk : Cannot run GET, out of RAM")); - return false; - } + bool MustCheckReply = false; + String hostname, pass; + unsigned int ClientTimeout = 0; + WiFiClient client; - LoadControllerSettings(controllerIndex, ControllerSettings); + { + // Place ControllerSettings in its own scope, as it is quite big. + MakeControllerSettings(ControllerSettings); + if (!AllocatedControllerSettings()) { + addLog(LOG_LEVEL_ERROR, F("Blynk : Cannot run GET, out of RAM")); + return false; + } - if ((getControllerPass(controllerIndex, ControllerSettings).length() == 0)) { - addLog(LOG_LEVEL_ERROR, F("Blynk : No password set")); - return false; - } + LoadControllerSettings(controllerIndex, ControllerSettings); + MustCheckReply = ControllerSettings.MustCheckReply; + hostname = ControllerSettings.getHost(); + pass = getControllerPass(controllerIndex, ControllerSettings); + ClientTimeout = ControllerSettings.ClientTimeout; - WiFiClient client; + if (pass.length() == 0) { + addLog(LOG_LEVEL_ERROR, F("Blynk : No password set")); + return false; + } - if (!try_connect_host(/* CPLUGIN_ID_012 */ 12, client, ControllerSettings)) { - return false; + if (!try_connect_host(/* CPLUGIN_ID_012 */ 12, client, ControllerSettings)) { + return false; + } } - // We now create a URI for the request { // Place this stack allocated array in its own scope, as it is quite big. char request[300] = { 0 }; sprintf_P(request, PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"), - getControllerPass(controllerIndex, ControllerSettings).c_str(), + pass.c_str(), command.c_str(), - ControllerSettings.getHost().c_str()); + hostname.c_str()); addLog(LOG_LEVEL_DEBUG, request); client.print(request); } - bool success = !ControllerSettings.MustCheckReply; + bool success = !MustCheckReply; - if (ControllerSettings.MustCheckReply || data) { + if (MustCheckReply || data) { unsigned long timer = millis() + 200; while (!client_available(client) && !timeOutReached(timer)) { @@ -155,7 +164,7 @@ bool Blynk_get(const String& command, controllerIndex_t controllerIndex, float * client.stop(); // important - backgroundtasks - free mem - unsigned long timer = millis() + ControllerSettings.ClientTimeout; + unsigned long timer = millis() + ClientTimeout; while (!timeOutReached(timer)) { backgroundtasks(); From 45395a6bcac450c7aef96218840ecb0b84ad269e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Fri, 11 Sep 2020 13:28:00 +0200 Subject: [PATCH 12/14] [VCC Build] Strip Servo, Blynk and Zabbix from test build to make it fit. --- .travis.yml | 2 +- src/define_plugin_sets.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b166580ae5..52abd9ec1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,7 +80,7 @@ env: - ENV=test_ESP8266_4M1M_VCC #- ENV=test_ESP8266_4M1M_VCC_MDNS_SD - ENV=test_alt_wifi_ESP8266_4M1M_VCC - - ENV=test_beta_ESP8266_16M_LittleFS + #- ENV=test_beta_ESP8266_16M_LittleFS - ENV=test_beta_ESP8266_4M1M script: diff --git a/src/define_plugin_sets.h b/src/define_plugin_sets.h index 8b61564eb2..32705c16fd 100644 --- a/src/define_plugin_sets.h +++ b/src/define_plugin_sets.h @@ -1107,6 +1107,15 @@ To create/register a plugin, you have to : #ifdef FEATURE_I2CMULTIPLEXER #undef FEATURE_I2CMULTIPLEXER #endif + #ifdef USE_SERVO + #undef USE_SERVO + #endif + #ifdef USES_BLYNK + #undef USES_BLYNK + #endif + #ifdef USES_C017 // Zabbix + #undef USES_C017 + #endif #endif // Timing stats page needs timing stats @@ -1130,5 +1139,15 @@ To create/register a plugin, you have to : #endif +// It may have gotten undefined to fit a build. Make sure the Blynk controllers are not defined +#ifndef USES_BLYNK + #ifdef USES_C012 + #undef USES_C012 + #endif + #ifdef USES_C015 + #undef USES_C015 + #endif +#endif + #endif // DEFINE_PLUGIN_SETS_H From 5f3d5fda309a911c1d755634b2bc191a34ac5ebd Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 11 Sep 2020 22:50:47 +0200 Subject: [PATCH 13/14] [ESP32] Core 2.0.0 released --- platformio_core_defs.ini | 3 +++ platformio_esp32_envs.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index e45aa30d92..8e7ab8df62 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -143,6 +143,9 @@ platform_packages = [core_esp32_1_12_2] platform = espressif32@1.12.4 +[core_esp32_2_0_0] +platform = espressif32@2.0.0 + [core_esp32_stage] platform = https://github.com/platformio/platform-espressif32.git#feature/stage diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index f3954e119b..014dae8410 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -8,7 +8,7 @@ [esp32_common] extends = common -platform = ${core_esp32_1_12_2.platform} +platform = ${core_esp32_2_0_0.platform} lib_ignore = ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, ESP32_ping, HeatpumpIR lib_deps = https://github.com/TD-er/ESPEasySerial.git#v2.0.3, Adafruit ILI9341, Adafruit GFX Library, LOLIN_EPD, Adafruit BusIO board_build.f_flash = 80000000L From a341cd2f25ea5f9a2eadd787d8c8c3c52862ac02 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 12 Sep 2020 15:14:21 +0200 Subject: [PATCH 14/14] [PIO] Set minimum PlatformIO library to 5.0.1 Does save extra update step, as ESP32 already demands PIO 5 as minimum version. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fce7245695..fb629fc3a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ MarkupSafe==1.1.1 marshmallow==3.7.1 packaging==20.4 pathtools==0.1.2 -platformio>=4.3.4 +platformio>=5.0.1 port-for==0.3.1 pycparser==2.20 pyelftools==0.26