From 524845bc11aaa67b2bc529435acf9c548b47cd4f Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 18 Jan 2025 15:13:05 +0100 Subject: [PATCH 01/13] [P137] Add predefined settings for M5StickC Plus --- src/_P137_AXP192.ino | 3 +++ src/src/PluginStructs/P137_data_struct.cpp | 9 +++++++++ src/src/PluginStructs/P137_data_struct.h | 11 ++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/_P137_AXP192.ino b/src/_P137_AXP192.ino index 02b214217a..e96fb80eb9 100644 --- a/src/_P137_AXP192.ino +++ b/src/_P137_AXP192.ino @@ -9,6 +9,7 @@ /** * Changelog: + * 2025-01-18 tonhuisman: Add predefined config settings for M5Stack StickC Plus units * 2022-12-27 tonhuisman: Add predefined config settings for LilyGO T-Beam LoRa units * 2022-12-07 tonhuisman: Re-order device configuration to use PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR * Enable PluginStats feature @@ -181,6 +182,7 @@ boolean Plugin_137(uint8_t function, struct EventStruct *event, String& string) toString(P137_PredefinedDevices_e::M5Stack_StickC), toString(P137_PredefinedDevices_e::M5Stack_Core2), toString(P137_PredefinedDevices_e::LilyGO_TBeam), + toString(P137_PredefinedDevices_e::M5Stack_StickCPlus), toString(P137_PredefinedDevices_e::UserDefined) // keep last and at 99 !! }; const int predefinedValues[] = { @@ -188,6 +190,7 @@ boolean Plugin_137(uint8_t function, struct EventStruct *event, String& string) static_cast(P137_PredefinedDevices_e::M5Stack_StickC), static_cast(P137_PredefinedDevices_e::M5Stack_Core2), static_cast(P137_PredefinedDevices_e::LilyGO_TBeam), + static_cast(P137_PredefinedDevices_e::M5Stack_StickCPlus), static_cast(P137_PredefinedDevices_e::UserDefined) }; // keep last and at 99 !! constexpr size_t optionCount = NR_ELEMENTS(predefinedValues); addFormSelector(F("Predefined device configuration"), F("predef"), diff --git a/src/src/PluginStructs/P137_data_struct.cpp b/src/src/PluginStructs/P137_data_struct.cpp index 5350174fad..188cdf1848 100644 --- a/src/src/PluginStructs/P137_data_struct.cpp +++ b/src/src/PluginStructs/P137_data_struct.cpp @@ -73,6 +73,14 @@ void P137_CheckPredefinedParameters(struct EventStruct *event) { P137_CONFIG_DISABLEBITS = 0b1111111000; // NC pins disabled break; } + case P137_PredefinedDevices_e::M5Stack_StickCPlus: // M5Stack StickC Plus + { + P137_REG_DCDC2_LDO2 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC2) << 16) | P137_valueToSetting(2800, P137_CONST_MAX_LDO); + P137_REG_DCDC3_LDO3 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC) << 16) | P137_valueToSetting(3000, P137_CONST_MAX_LDO); + P137_REG_LDOIO = P137_valueToSetting(2800, P137_CONST_MAX_LDOIO); + P137_CONFIG_DISABLEBITS = 0b1111110000; // NC pins disabled + break; + } case P137_PredefinedDevices_e::UserDefined: // User defined { P137_REG_DCDC2_LDO2 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC2) << 16) | P137_valueToSetting(3300, P137_CONST_MAX_LDO); @@ -137,6 +145,7 @@ const __FlashStringHelper* toString(const P137_PredefinedDevices_e device) { case P137_PredefinedDevices_e::M5Stack_StickC: return F("M5Stack StickC"); case P137_PredefinedDevices_e::M5Stack_Core2: return F("M5Stack Core2 (Default)"); case P137_PredefinedDevices_e::LilyGO_TBeam: return F("LilyGO T-Beam"); + case P137_PredefinedDevices_e::M5Stack_StickCPlus: return F("M5Stack StickC Plus"); case P137_PredefinedDevices_e::UserDefined: return F("User defined"); } return F("*Undefined*"); diff --git a/src/src/PluginStructs/P137_data_struct.h b/src/src/PluginStructs/P137_data_struct.h index ee49529161..066f58b83f 100644 --- a/src/src/PluginStructs/P137_data_struct.h +++ b/src/src/PluginStructs/P137_data_struct.h @@ -78,11 +78,12 @@ enum class P137_GPIOBootState_e: uint8_t { // Will be applied by subtracting 1 ! }; enum class P137_PredefinedDevices_e : uint8_t { - Unselected = 0u, - M5Stack_StickC = 1u, - M5Stack_Core2 = 2u, - LilyGO_TBeam = 3u, - UserDefined = 99u // Keep as last + Unselected = 0u, + M5Stack_StickC = 1u, + M5Stack_Core2 = 2u, + LilyGO_TBeam = 3u, + M5Stack_StickCPlus = 4u, + UserDefined = 99u // Keep as last }; int16_t P137_settingToValue(uint16_t data, From 5a6eb0bad15fc0b2f163cb7617d52a31cfa63d13 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 18 Jan 2025 16:36:03 +0100 Subject: [PATCH 02/13] [P137] String deduplication improvement --- src/src/PluginStructs/P137_data_struct.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/src/PluginStructs/P137_data_struct.cpp b/src/src/PluginStructs/P137_data_struct.cpp index 188cdf1848..65c2f6901c 100644 --- a/src/src/PluginStructs/P137_data_struct.cpp +++ b/src/src/PluginStructs/P137_data_struct.cpp @@ -119,7 +119,7 @@ const __FlashStringHelper* toString(const P137_valueOptions_e value, case P137_valueOptions_e::DCDC2: return displayString ? F("DCDC2 Voltage") : F("dcdc2voltage"); case P137_valueOptions_e::DCDC3: return displayString ? F("DCDC3 Voltage") : F("dcdc3voltage"); } - return F("*Undefined*"); + return F("Undefined"); } // **************************************************************************/ @@ -133,7 +133,7 @@ const __FlashStringHelper* toString(const P137_GPIOBootState_e value) { case P137_GPIOBootState_e::Input: return F("Input"); case P137_GPIOBootState_e::PWM: return F("PWM"); } - return F("*Undefined*"); + return F("Undefined"); } // **************************************************************************/ @@ -148,7 +148,7 @@ const __FlashStringHelper* toString(const P137_PredefinedDevices_e device) { case P137_PredefinedDevices_e::M5Stack_StickCPlus: return F("M5Stack StickC Plus"); case P137_PredefinedDevices_e::UserDefined: return F("User defined"); } - return F("*Undefined*"); + return F("Undefined"); } // **************************************************************************/ From 836afae465d85593f39a22375fa69b9710bd8a82 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sun, 19 Jan 2025 13:47:45 +0100 Subject: [PATCH 03/13] [P137] Update documentation --- docs/source/Plugin/P137.rst | 2 ++ .../Plugin/P137_PredefinedDeviceOptions.png | Bin 19882 -> 23044 bytes 2 files changed, 2 insertions(+) diff --git a/docs/source/Plugin/P137.rst b/docs/source/Plugin/P137.rst index 4ef35bfe2c..87f9ae9db8 100644 --- a/docs/source/Plugin/P137.rst +++ b/docs/source/Plugin/P137.rst @@ -65,6 +65,8 @@ Hardware outputs AXP192 * *LilyGO T-Beam* Settings for the LilyGO T-Beam series of GPS/LoRa devices with optional OLed display. +* *M5Stack StickC Plus* Settings for the M5Stack StickC Plus hardware. (Not applicable for the M5Stack StickC Plus 2, as that unit doesn't have an AXP192 power management controller). + * *User defined* To be able to configure are available output pins the User defined option is available, f.e. when using a custom designed, or not yet supported, hardware setup. When available, new predefined devices will be added. The User defined option will stay the last option. diff --git a/docs/source/Plugin/P137_PredefinedDeviceOptions.png b/docs/source/Plugin/P137_PredefinedDeviceOptions.png index 4502c4b397a8aa79d2c062382db4e3c7ecd4d08c..baac03ca6953488d336bf45b1417ed4fb8cebd00 100644 GIT binary patch literal 23044 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 S2j_x-&)(L_rsA|u;{O5dL5vju From 03394acb620f83610a9300b894ed2047a8a7a931 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 21 Jan 2025 20:56:09 +0100 Subject: [PATCH 04/13] [P137] Bugfix: commands axp,ldo2,x .. axp,dcdc3,x weren't working as intended --- src/_P137_AXP192.ino | 1 + src/src/PluginStructs/P137_data_struct.cpp | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/_P137_AXP192.ino b/src/_P137_AXP192.ino index e96fb80eb9..c53784ff2c 100644 --- a/src/_P137_AXP192.ino +++ b/src/_P137_AXP192.ino @@ -9,6 +9,7 @@ /** * Changelog: + * 2025-01-21 tonhuisman: Bugfix: commands axp,ldo2,x to axp,dcdc3,x weren't working as intended * 2025-01-18 tonhuisman: Add predefined config settings for M5Stack StickC Plus units * 2022-12-27 tonhuisman: Add predefined config settings for LilyGO T-Beam LoRa units * 2022-12-07 tonhuisman: Re-order device configuration to use PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR diff --git a/src/src/PluginStructs/P137_data_struct.cpp b/src/src/PluginStructs/P137_data_struct.cpp index 65c2f6901c..400b1f29fa 100644 --- a/src/src/PluginStructs/P137_data_struct.cpp +++ b/src/src/PluginStructs/P137_data_struct.cpp @@ -70,7 +70,7 @@ void P137_CheckPredefinedParameters(struct EventStruct *event) { P137_REG_DCDC2_LDO2 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC2) << 16) | P137_valueToSetting(3300, P137_CONST_MAX_LDO); P137_REG_DCDC3_LDO3 = (P137_valueToSetting(3300, P137_CONST_MAX_DCDC) << 16) | P137_valueToSetting(3300, P137_CONST_MAX_LDO); P137_REG_LDOIO = P137_valueToSetting(3300, P137_CONST_MAX_LDOIO); - P137_CONFIG_DISABLEBITS = 0b1111111000; // NC pins disabled + P137_CONFIG_DISABLEBITS = 0b1111111000; // NC pins disabled break; } case P137_PredefinedDevices_e::M5Stack_StickCPlus: // M5Stack StickC Plus @@ -78,7 +78,7 @@ void P137_CheckPredefinedParameters(struct EventStruct *event) { P137_REG_DCDC2_LDO2 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC2) << 16) | P137_valueToSetting(2800, P137_CONST_MAX_LDO); P137_REG_DCDC3_LDO3 = (P137_valueToSetting(-1, P137_CONST_MAX_DCDC) << 16) | P137_valueToSetting(3000, P137_CONST_MAX_LDO); P137_REG_LDOIO = P137_valueToSetting(2800, P137_CONST_MAX_LDOIO); - P137_CONFIG_DISABLEBITS = 0b1111110000; // NC pins disabled + P137_CONFIG_DISABLEBITS = 0b1111110000; // NC pins disabled break; } case P137_PredefinedDevices_e::UserDefined: // User defined @@ -268,7 +268,10 @@ bool P137_data_struct::plugin_write(struct EventStruct *event, if (isInitialized() && equals(cmd, F("axp"))) { // Command trigger cmd = parseString(string, 2); // sub command - const int subcommand_i = GetCommandCode(cmd.c_str(), P137_subcommands); + const int subcommand_i = GetCommandCode(cmd.c_str(), P137_subcommands); + + if (subcommand_i < 0) { return success; } // fail fast + const P137_subcommands_e subcmd = static_cast(subcommand_i); const String var3 = parseString(string, 3); @@ -277,7 +280,8 @@ bool P137_data_struct::plugin_write(struct EventStruct *event, const bool state3 = !empty3 && (event->Par2 == 0 || event->Par2 == 1); success = true; - if ((event->Par2 >= 0) && (event->Par2 <= P137_CONST_100_PERCENT) && !empty3 && empty4) { + if ((event->Par2 >= 0) && (event->Par2 <= P137_CONST_100_PERCENT) && !empty3 && empty4 && + (subcmd >= P137_subcommands_e::ldo2perc) && (subcmd <= P137_subcommands_e::dcdc3perc)) { // percentage 0..100, 0 turns off switch (subcmd) { @@ -331,7 +335,9 @@ bool P137_data_struct::plugin_write(struct EventStruct *event, success = false; break; } - } else if ((event->Par2 >= 0) && (event->Par3 <= P137_CONST_MAX_LDO) && (event->Par2 < event->Par3) && !empty3 && !empty4) { + } else + if ((event->Par2 >= 0) && (event->Par3 <= P137_CONST_MAX_LDO) && (event->Par2 < event->Par3) && !empty3 && !empty4 && + (subcmd >= P137_subcommands_e::ldo2map) && (subcmd <= P137_subcommands_e::dcdc3map)) { // map range , switch (subcmd) { From 478da66a3b02c3d61d812f244b6a62fd20311ccc Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 31 Jan 2025 22:07:18 +0100 Subject: [PATCH 05/13] [N001] Use a non-TLS client for SMTP on port 25 --- src/src/NotifierStructs/N001_data_struct.cpp | 54 +++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/src/NotifierStructs/N001_data_struct.cpp b/src/src/NotifierStructs/N001_data_struct.cpp index 908ee77062..b5602d7193 100644 --- a/src/src/NotifierStructs/N001_data_struct.cpp +++ b/src/src/NotifierStructs/N001_data_struct.cpp @@ -25,30 +25,38 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St bool myStatus = false; bool failFlag = false; + WiFiClient *client = nullptr; + # if FEATURE_EMAIL_TLS // values are based on the NPLUGIN_001_PKT_SZ - BearSSL::WiFiClientSecure_light client(4096, 4096); - client.setUtcTime_fcn(getUnixTime); - client.setCfgTime_fcn(get_build_unixtime); - client.setTrustAnchor(Tasmota_TA, Tasmota_TA_size); - client.setInsecure(); + BearSSL::WiFiClientSecure_light secureClient(4096, 4096); + + if (notificationsettings.Port != 25) { // Port 25 is a standard WiFiClient, all else is a secure client... + secureClient.setUtcTime_fcn(getUnixTime); + secureClient.setCfgTime_fcn(get_build_unixtime); + secureClient.setTrustAnchor(Tasmota_TA, Tasmota_TA_size); + secureClient.setInsecure(); + client = &secureClient; + } else { + client = new WiFiClient(); + } # else // if FEATURE_EMAIL_TLS // Use WiFiClient class to create TCP connections - WiFiClient client; + client = new WiFiClient(); # endif // if FEATURE_EMAIL_TLS # ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS // See: https://github.com/espressif/arduino-esp32/pull/6676 - client.setTimeout((notificationsettings.Timeout_ms + 500) / 1000); // in seconds!!!! - Client *pClient = &client; + client->setTimeout((notificationsettings.Timeout_ms + 500) / 1000); // in seconds!!!! + Client *pClient = client; pClient->setTimeout(notificationsettings.Timeout_ms); # else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS - client.setTimeout(notificationsettings.Timeout_ms); // in msec as it should be! + client->setTimeout(notificationsettings.Timeout_ms); // in msec as it should be! # endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS # ifndef BUILD_NO_DEBUG @@ -61,14 +69,14 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } # endif // ifndef BUILD_NO_DEBUG - if (!connectClient(client, notificationsettings.Server, notificationsettings.Port, notificationsettings.Timeout_ms)) { + if (!connectClient(*client, notificationsettings.Server, notificationsettings.Port, notificationsettings.Timeout_ms)) { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { # if FEATURE_EMAIL_TLS addLog(LOG_LEVEL_ERROR, strformat( F("Email: Error connecting to %s:%u Error code: %d"), notificationsettings.Server, notificationsettings.Port, - client.getLastError())); + secureClient.getLastError())); # else // if FEATURE_EMAIL_TLS addLog(LOG_LEVEL_ERROR, strformat( @@ -176,7 +184,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } # if FEATURE_EMAIL_TLS - client.setDomainName(notificationsettings.Domain); + secureClient.setDomainName(notificationsettings.Domain); # endif // if FEATURE_EMAIL_TLS @@ -201,7 +209,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St // exit using break; // However this is way too complex using both a failFlag and break // and not even consistently. - if (!NPlugin_001_MTA(client, EMPTY_STRING, 220, clientTimeout)) { + if (!NPlugin_001_MTA(*client, EMPTY_STRING, 220, clientTimeout)) { # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { @@ -220,7 +228,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St const String astr = strformat(F("EHLO %s"), notificationsettings.Domain); if (!NPlugin_001_MTA( - client, + *client, astr, 250, clientTimeout)) { @@ -239,12 +247,12 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St bool done = false; - while (client.available() && !done) { + while (client->available() && !done) { if (timeOutReached(timer)) { failFlag = true; break; } - done = safeReadStringUntil(client, replyStr, '\n', NPLUGIN_001_PKT_SZ); + done = safeReadStringUntil(*client, replyStr, '\n', NPLUGIN_001_PKT_SZ); catStr += replyStr; } @@ -269,7 +277,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } # endif // ifndef BUILD_NO_DEBUG - if (!NPlugin_001_Auth(client, notificationsettings.User, notificationsettings.Pass, clientTimeout)) { + if (!NPlugin_001_Auth(*client, notificationsettings.User, notificationsettings.Pass, clientTimeout)) { # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("Email: User/Pass Fail")); @@ -286,7 +294,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St const String astr = strformat(F("MAIL FROM:<%s>"), email_address.c_str()); - if (!NPlugin_001_MTA(client, astr, 250, clientTimeout)) { + if (!NPlugin_001_MTA(*client, astr, 250, clientTimeout)) { # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, F("Email: Addr Fail")); # endif // ifndef BUILD_NO_DEBUG @@ -313,7 +321,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St addLog(LOG_LEVEL_INFO, concat(F("Email: To "), emailTo)); } - if (!NPlugin_001_MTA(client, strformat(F("RCPT TO:<%s>"), emailTo.c_str()), 250, clientTimeout)) + if (!NPlugin_001_MTA(*client, strformat(F("RCPT TO:<%s>"), emailTo.c_str()), 250, clientTimeout)) { break; } @@ -323,14 +331,14 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } if (!failFlag) { - if (!NPlugin_001_MTA(client, F("DATA"), 354, clientTimeout)) { + if (!NPlugin_001_MTA(*client, F("DATA"), 354, clientTimeout)) { failFlag = true; break; } } if (!failFlag) { - if (!NPlugin_001_MTA(client, strformat(F("%s%s\r\n.\r\n"), mailheader.c_str(), body.c_str()), 250, clientTimeout)) { + if (!NPlugin_001_MTA(*client, strformat(F("%s%s\r\n.\r\n"), mailheader.c_str(), body.c_str()), 250, clientTimeout)) { failFlag = true; break; } @@ -341,13 +349,13 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St myStatus = true; } - NPlugin_001_MTA(client, F("QUIT"), 221, clientTimeout); // Sent successfully, close SMTP protocol, ignore failure + NPlugin_001_MTA(*client, F("QUIT"), 221, clientTimeout); // Sent successfully, close SMTP protocol, ignore failure break; } } // client.PR_9453_FLUSH_TO_CLEAR(); - client.stop(); + client->stop(); if (myStatus == true) { addLog(LOG_LEVEL_INFO, F("Email: Connection Closed Successfully")); From 042ed7132f040926ede86ee5c526fb42d2fe8b50 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 31 Jan 2025 22:41:37 +0100 Subject: [PATCH 06/13] [MQTT] Don't subscribe to empty topics --- src/_P037_MQTTImport.ino | 5 +++-- src/src/ESPEasyCore/Controller.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/_P037_MQTTImport.ino b/src/_P037_MQTTImport.ino index 3acc31a90f..3d5980a3d5 100644 --- a/src/_P037_MQTTImport.ino +++ b/src/_P037_MQTTImport.ino @@ -761,9 +761,10 @@ bool MQTTSubscribe_037(struct EventStruct *event) for (uint8_t x = 0; x < VARS_PER_TASK; x++) { String subscribeTo = P037_data->getFullMQTTTopic(x); - if (!subscribeTo.isEmpty()) { - parseSystemVariables(subscribeTo, false); + parseSystemVariables(subscribeTo, false); + subscribeTo.trim(); + if (!subscribeTo.isEmpty()) { if (MQTTclient.subscribe(subscribeTo.c_str())) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, strformat(F("IMPT : [%s#%s] subscribed to %s"), diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index d01eed6780..451219d831 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -560,11 +560,15 @@ bool MQTTConnect(controllerIndex_t controller_idx) String subscribeTo = ControllerSettings->Subscribe; parseSystemVariables(subscribeTo, false); - MQTTclient.subscribe(subscribeTo.c_str()); + subscribeTo.trim(); - if (loglevelActiveFor(LOG_LEVEL_INFO)) - { - addLogMove(LOG_LEVEL_INFO, concat(F("Subscribed to: "), subscribeTo)); + if (!subscribeTo.isEmpty()) { + MQTTclient.subscribe(subscribeTo.c_str()); + + if (loglevelActiveFor(LOG_LEVEL_INFO)) + { + addLogMove(LOG_LEVEL_INFO, concat(F("Subscribed to: "), subscribeTo)); + } } updateMQTTclient_connected(); From db9a08cc6f58ca8634a335ea5a8cf9a39dd6423e Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 31 Jan 2025 23:02:22 +0100 Subject: [PATCH 07/13] [N001] Allso apply to port 2525 --- src/src/NotifierStructs/N001_data_struct.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/NotifierStructs/N001_data_struct.cpp b/src/src/NotifierStructs/N001_data_struct.cpp index b5602d7193..9d0f2d91f0 100644 --- a/src/src/NotifierStructs/N001_data_struct.cpp +++ b/src/src/NotifierStructs/N001_data_struct.cpp @@ -33,7 +33,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St BearSSL::WiFiClientSecure_light secureClient(4096, 4096); - if (notificationsettings.Port != 25) { // Port 25 is a standard WiFiClient, all else is a secure client... + if ((notificationsettings.Port != 25) && (notificationsettings.Port != 2525)) { // Port 25 or 2525 is a standard WiFiClient, all else is a secure client... secureClient.setUtcTime_fcn(getUnixTime); secureClient.setCfgTime_fcn(get_build_unixtime); secureClient.setTrustAnchor(Tasmota_TA, Tasmota_TA_size); From 93601daa49e193eee185757328ce432f7c4b82fd Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 31 Jan 2025 23:15:14 +0100 Subject: [PATCH 08/13] [N001] And clean up object after use --- src/src/NotifierStructs/N001_data_struct.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/src/NotifierStructs/N001_data_struct.cpp b/src/src/NotifierStructs/N001_data_struct.cpp index 9d0f2d91f0..25e878e60a 100644 --- a/src/src/NotifierStructs/N001_data_struct.cpp +++ b/src/src/NotifierStructs/N001_data_struct.cpp @@ -33,7 +33,8 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St BearSSL::WiFiClientSecure_light secureClient(4096, 4096); - if ((notificationsettings.Port != 25) && (notificationsettings.Port != 2525)) { // Port 25 or 2525 is a standard WiFiClient, all else is a secure client... + // Port 25 or 2525 is a standard WiFiClient, all else is a secure client... + if ((notificationsettings.Port != 25) && (notificationsettings.Port != 2525)) { secureClient.setUtcTime_fcn(getUnixTime); secureClient.setCfgTime_fcn(get_build_unixtime); secureClient.setTrustAnchor(Tasmota_TA, Tasmota_TA_size); @@ -356,6 +357,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St // client.PR_9453_FLUSH_TO_CLEAR(); client->stop(); + delete client; if (myStatus == true) { addLog(LOG_LEVEL_INFO, F("Email: Connection Closed Successfully")); From 91d27bdeb9e9a761d0b4d787d3b7362eed5b8797 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 1 Feb 2025 15:26:38 +0100 Subject: [PATCH 09/13] [N001] Documentation update about port 25 and 2525 (ESP32 with TLS) --- docs/source/Notify/N001.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/Notify/N001.rst b/docs/source/Notify/N001.rst index c5bea31931..1ad5d16887 100644 --- a/docs/source/Notify/N001.rst +++ b/docs/source/Notify/N001.rst @@ -79,7 +79,7 @@ From the *Notifications* page, press *Edit* on an available *Nr* option. Next, C * SMTP Server Settings * **Domain :** Mail provider domain. - * **Server :** Mail server address (DNS or IP number). Must support non-secure SMTP. + * **Server :** Mail server address (DNS or IP number). * **Port :** Server port number. (see note below) * **Timeout :** Maximum allowed time for server reply. Increase value if server timeouts occur. @@ -114,6 +114,8 @@ ESP8266 simply doesn't have enough free memory available to setup a SSL connecti Only SSL port 465 is supported, as for using port 587 (typically named "TLS") extra steps are required to make a connection. This may be added later. + +ESP32: (With TLS enabled in the build) To use the basic SMTP protocol (not SMTPS), configure port ``25`` or ``2525``. For other port numbers, a secure SMTP connection will be attempted. | Email Server Requirements with SSL From 130418da86735ee53aa72b7d6e696eb6dff4c6a1 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 1 Feb 2025 17:04:09 +0100 Subject: [PATCH 10/13] [P139] Update predefined settings for LilyGO T-Beam S3 --- lib/AXP2101/src/AXP2101_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AXP2101/src/AXP2101_settings.cpp b/lib/AXP2101/src/AXP2101_settings.cpp index c44ae79cd9..a43f18db27 100644 --- a/lib/AXP2101/src/AXP2101_settings.cpp +++ b/lib/AXP2101/src/AXP2101_settings.cpp @@ -525,7 +525,7 @@ AXP2101_settings AXP2101_deviceSettingsArray[] = /* M5Stack Core2 v1.1 */ { 3300, 0, 3300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP2101_chargeled_d::Off }, /* M5Stack CoreS3 */ { 3300, 0, 3300, 0, 0, 1800, 3300, 3300, 3300, 0, 0, 0, 0, 0, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Protected, AXP_pin_s::Protected, AXP_pin_s::Default, AXP_pin_s::Protected, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP2101_chargeled_d::Off }, /* LilyGo TBeam v1.2 */ { 3300, 0, 2500, 0, 0, 0, 3300, 3300, 0, 0, 0, 0, 0, 0, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Default, AXP2101_chargeled_d::Off }, -/* LilyGo TBeamS3 */ { 3300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP2101_chargeled_d::Off }, +/* LilyGo TBeamS3 */ { 3300, 500, 500, 1800, 3300, 1800, 3300, 3300, 3300, 1800, 3300, 3300, 2300, 2300, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP2101_chargeled_d::Off }, /* LilyGo TPCie v1.2 */ { 3300, 900, 900, 1100, 1200, 1800, 2800, 3300, 2900, 1800, 2800, 500, 1900, 1300, AXP_pin_s::Protected, AXP_pin_s::Disabled, AXP_pin_s::Protected, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP_pin_s::Disabled, AXP2101_chargeled_d::Off }, /* Userdefined */ { 3300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP_pin_s::Default, AXP2101_chargeled_d::Off }, }; From c4f3a53007d974b45eb7d9c5c176947a454703f6 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 1 Feb 2025 17:36:33 +0100 Subject: [PATCH 11/13] [N001] Add pointer null-checks, close client also when connection fails --- src/src/NotifierStructs/N001_data_struct.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/src/NotifierStructs/N001_data_struct.cpp b/src/src/NotifierStructs/N001_data_struct.cpp index 25e878e60a..584f74967b 100644 --- a/src/src/NotifierStructs/N001_data_struct.cpp +++ b/src/src/NotifierStructs/N001_data_struct.cpp @@ -41,13 +41,17 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St secureClient.setInsecure(); client = &secureClient; } else { - client = new WiFiClient(); + client = new (std::nothrow) WiFiClient(); + + if (!client) { return false; } } # else // if FEATURE_EMAIL_TLS // Use WiFiClient class to create TCP connections - client = new WiFiClient(); + client = new (std::nothrow) WiFiClient(); + + if (!client) { return false; } # endif // if FEATURE_EMAIL_TLS # ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS @@ -355,11 +359,7 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } } - // client.PR_9453_FLUSH_TO_CLEAR(); - client->stop(); - delete client; - - if (myStatus == true) { + if (myStatus) { addLog(LOG_LEVEL_INFO, F("Email: Connection Closed Successfully")); } else { if (loglevelActiveFor(LOG_LEVEL_ERROR)) { @@ -367,6 +367,10 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } } } + + client->stop(); + delete client; + return myStatus; } From 3a07319f90f106d634efc3b720166946d04009be Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 1 Feb 2025 17:51:09 +0100 Subject: [PATCH 12/13] [N001] Only delect object if created via new --- src/src/NotifierStructs/N001_data_struct.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/src/NotifierStructs/N001_data_struct.cpp b/src/src/NotifierStructs/N001_data_struct.cpp index 584f74967b..38cee7e007 100644 --- a/src/src/NotifierStructs/N001_data_struct.cpp +++ b/src/src/NotifierStructs/N001_data_struct.cpp @@ -22,8 +22,9 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, String& subject, String& body) { - bool myStatus = false; - bool failFlag = false; + bool myStatus = false; + bool failFlag = false; + bool deleteClient = true; WiFiClient *client = nullptr; @@ -39,7 +40,8 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St secureClient.setCfgTime_fcn(get_build_unixtime); secureClient.setTrustAnchor(Tasmota_TA, Tasmota_TA_size); secureClient.setInsecure(); - client = &secureClient; + client = &secureClient; + deleteClient = false; } else { client = new (std::nothrow) WiFiClient(); @@ -369,7 +371,8 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St } client->stop(); - delete client; + + if (deleteClient) { delete client; } return myStatus; } From 381737af0f7e8405c2e712964579b6681f3a9f47 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 3 Feb 2025 22:26:45 +0100 Subject: [PATCH 13/13] [Build] Add Powermanagement plugins to ESP32 Climate builds --- src/src/CustomBuild/define_plugin_sets.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 0f695283d5..be1d53aea2 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1989,6 +1989,12 @@ To create/register a plugin, you have to : #ifndef USES_P135 #define USES_P135 // SCD4x #endif + #if !defined(USES_P137) && defined(ESP32) + #define USES_P137 // AXP192 + #endif + #if !defined(USES_P139) && defined(ESP32) + #define USES_P139 // AXP2101 + #endif #ifndef USES_P144 #define USES_P144 // Dust - PM1006(K) (Vindriktning) #endif