From da1e8bddee634c27af8ddd38d811682d3d4ae3ec Mon Sep 17 00:00:00 2001 From: valmir1989 Date: Sun, 17 Aug 2025 12:43:45 +0200 Subject: [PATCH 01/18] Update HeatPumpType.md Issue #702. --- HeatPumpType.md | 1 + 1 file changed, 1 insertion(+) diff --git a/HeatPumpType.md b/HeatPumpType.md index 114fec8e..52cea7f6 100644 --- a/HeatPumpType.md +++ b/HeatPumpType.md @@ -60,6 +60,7 @@ Assuming that bytes from #129 to #138 are unique for each model of Aquarea heat |53 | 42 D4 0B 83 71 32 D2 0C 44 55 | WH-ADC0309J3E5C | WH-UD03JE5 | KIT-ADC03JE5C-S | 3.2 | 1ph | HP - All-In-One Compact | |54 | E2 CF 0C 74 09 12 D0 0E 94 05 | WH-ADC0916H9E8 | WH-UX09HE8 | KIT-AXC9HE8 | 9 | 3ph | T-CAP - All-In-One | |55 | 12 D7 0D 98 11 33 94 0C 83 10 | WH-ADC0316M9E8AN2 | WH-WXG09ME8 | Monoblock | 9 | 2ph | T-CAP - M-series DHW 185l | +|56 | 12 D7 01 18 21 33 94 0C 83 10 | WH-CME8 + CZ-NS7P | WH-WXG09ME8 | Monoblock| 9 | 3ph | T-CAP - M-series | All bytes are used for Heat Pump model identification in the code. From 86f7cfadaa8d878b8acadbac5b0265fe561b9ce4 Mon Sep 17 00:00:00 2001 From: Bart van der Velden Date: Tue, 2 Sep 2025 17:00:57 +0200 Subject: [PATCH 02/18] Add KIT-SDC07KE5 and missing trailing pipe --- HeatPumpType.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HeatPumpType.md b/HeatPumpType.md index 114fec8e..6cd6b3ae 100644 --- a/HeatPumpType.md +++ b/HeatPumpType.md @@ -36,7 +36,7 @@ Assuming that bytes from #129 to #138 are unique for each model of Aquarea heat |29 | E2 CF 0B 83 05 12 D0 0D 92 05 | WH-SQC12H9E8 | WH-UQ12HE8 | KIT-WQC12H9E8 | 12 | 3ph | T-CAP - Super Quiet | |30 | E2 CF 0C 78 09 12 D0 0B 06 11 | WH-SXC12H6E5 | WH-UX12HE5 | KIT-WXC12H6E5 | 12 | 1ph | T-CAP | |31 | C2 D3 0C 35 65 B2 D3 0B 96 65 | Monoblock | WH-MDC09J3E5 | Monoblock | 9 | 1ph | HP (new version?) | -|32 | 32 D4 0B 99 77 62 90 0B 01 78 | Monoblock | WH-MXC09J3E5 | Monoblock | 9 | 1ph | T-CAP +|32 | 32 D4 0B 99 77 62 90 0B 01 78 | Monoblock | WH-MXC09J3E5 | Monoblock | 9 | 1ph | T-CAP | |33 | 42 D4 0B 15 76 12 D0 0B 10 11 | WH-ADC1216H6E5C | WH-UD12HE5 | KIT-ADC12HE5C-CL | 12 | 1ph| HP - All-In-One Compact | |34 | E2 D5 0C 29 99 83 92 0C 28 98 | WH-ADC0509L3E5 | WH-WDG07LE5 | KIT-ADC07L3E5 | 7 | 1ph | HP - All-In-One L-series | |35 | E2 CF 0D 85 05 12 D0 0E 94 05 | WH-SXC09H3E8 | WH-UX09HE8 | KIT-WXC09H3E8 | 9 | 3ph | T-CAP - new version | @@ -60,6 +60,7 @@ Assuming that bytes from #129 to #138 are unique for each model of Aquarea heat |53 | 42 D4 0B 83 71 32 D2 0C 44 55 | WH-ADC0309J3E5C | WH-UD03JE5 | KIT-ADC03JE5C-S | 3.2 | 1ph | HP - All-In-One Compact | |54 | E2 CF 0C 74 09 12 D0 0E 94 05 | WH-ADC0916H9E8 | WH-UX09HE8 | KIT-AXC9HE8 | 9 | 3ph | T-CAP - All-In-One | |55 | 12 D7 0D 98 11 33 94 0C 83 10 | WH-ADC0316M9E8AN2 | WH-WXG09ME8 | Monoblock | 9 | 2ph | T-CAP - M-series DHW 185l | +|56 | E2 D5 0B 08 95 02 D6 0F 67 95 | WH-SDC0309K3E5 | WH-UDZ07KE5 | KIT-SDC07KE5 | 7 | 1ph | HP - split K-series (sold in Poland) | All bytes are used for Heat Pump model identification in the code. From b270f331b4e55c820844355a7cc8a1b7e8181ad6 Mon Sep 17 00:00:00 2001 From: CurlyMoo Date: Wed, 12 Nov 2025 16:15:30 +0100 Subject: [PATCH 03/18] Fix wrong rounding of floats --- HeishaMon/src/rules/functions/round.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HeishaMon/src/rules/functions/round.cpp b/HeishaMon/src/rules/functions/round.cpp index 64996337..a6bdc854 100755 --- a/HeishaMon/src/rules/functions/round.cpp +++ b/HeishaMon/src/rules/functions/round.cpp @@ -49,9 +49,9 @@ int8_t rule_function_round_callback(struct rules_t *obj) { if(modff(x, &z) == 0) { #ifdef DEBUG - printf("\tround = %d\n", (int)x); + printf("\tround = %d\n", round(x)); #endif - rules_pushinteger(obj, x); + rules_pushinteger(obj, round(x)); } else { if(y == 2) { uint8_t size = snprintf(NULL, 0, "%.*f", dec, x)+1; @@ -63,9 +63,9 @@ int8_t rule_function_round_callback(struct rules_t *obj) { rules_pushfloat(obj, atof(buf)); } else { #ifdef DEBUG - printf("\tround = %d\n", (int)x); + printf("\tround = %d\n", round(x)); #endif - rules_pushinteger(obj, (int)x); + rules_pushinteger(obj, round(x)); } } From e29e4ceb57421c26df71f04328c369463dc65442 Mon Sep 17 00:00:00 2001 From: "Christian P." Date: Mon, 17 Nov 2025 23:08:10 +0100 Subject: [PATCH 04/18] Add Quiet Mode Level configuration Added configuration for Quiet Mode Level in aquareaHeatPump.yaml. --- Integrations/Openhab3/aquareaHeatPump.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Integrations/Openhab3/aquareaHeatPump.yaml b/Integrations/Openhab3/aquareaHeatPump.yaml index b02f2c57..02d7497e 100644 --- a/Integrations/Openhab3/aquareaHeatPump.yaml +++ b/Integrations/Openhab3/aquareaHeatPump.yaml @@ -413,3 +413,11 @@ channels: configuration: stateTopic: panasonic_heat_pump/main/DHW_Energy_Consumption unit: Watt + - id: quietModeLevel + channelTypeUID: mqtt:number + label: Quiet Mode Level + configuration: + commandTopic: panasonic_heat_pump/commands/SetQuietMode + min: 0 + stateTopic: panasonic_heat_pump/main/Quiet_Mode_Level + max: 3 From c6a2c64abfba088620526ef8594eff02142dbe50 Mon Sep 17 00:00:00 2001 From: confuzius0815 <136562234+confuzius0815@users.noreply.github.com> Date: Sat, 29 Nov 2025 09:00:23 +0100 Subject: [PATCH 05/18] Update HeishaMon.ino - added TLS support-part1 Only for ESP32. The ESP8266 version is hardly changed --- HeishaMon/HeishaMon.ino | 148 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 4 deletions(-) diff --git a/HeishaMon/HeishaMon.ino b/HeishaMon/HeishaMon.ino index ad16a391..a0c88b29 100644 --- a/HeishaMon/HeishaMon.ino +++ b/HeishaMon/HeishaMon.ino @@ -132,9 +132,19 @@ static uint8_t cmdnrel = 0; // mqtt +#ifdef TLS_SUPPORT +#include +WiFiClientSecure mqtt_tls_client; WiFiClient mqtt_wifi_client; +bool loadTlsCaFromFS(WiFiClientSecure &client); +static bool last_tls_enabled = false; +static bool new_ca_stored = false; +static std::unique_ptr persistent_ca_pem; PubSubClient mqtt_client; - +#else +WiFiClient mqtt_wifi_client; +PubSubClient mqtt_client(mqtt_wifi_client); +#endif bool firstConnectSinceBoot = true; //if this is true there is no first connection made yet @@ -307,6 +317,34 @@ void check_wifi() { } +#ifdef TLS_SUPPORT +bool loadTlsCaFromFS(WiFiClientSecure &client) { + if (!LittleFS.exists("/ca.pem")) { + log_message(_F("[TLS] /ca.pem not found")); + return false; + } + File certFile = LittleFS.open("/ca.pem", "r"); + if (!certFile) { + log_message(_F("[TLS] open(/ca.pem) failed")); + return false; + } + size_t certSize = certFile.size(); + if (certSize == 0) { + log_message(_F("[TLS] /ca.pem is empty")); + certFile.close(); + return false; + } + persistent_ca_pem.reset(new char[certSize + 1]); + size_t n = certFile.readBytes(persistent_ca_pem.get(), certSize); + persistent_ca_pem[n] = '\0'; + certFile.close(); + client.setCACert(persistent_ca_pem.get()); + log_message(_F("[TLS] CA loaded into client")); + return true; +} +#endif + + void mqtt_reconnect() { unsigned long now = millis(); @@ -319,6 +357,36 @@ void mqtt_reconnect() } char topic[256]; sprintf(topic, "%s/%s", heishamonSettings.mqtt_topic_base, mqtt_willtopic); +#ifdef TLS_SUPPORT + if (heishamonSettings.mqtt_tls_enabled != last_tls_enabled) { + mqtt_client.disconnect(); + if (last_tls_enabled) { + mqtt_tls_client.stop(); + } else { + mqtt_wifi_client.stop(); + if (!loadTlsCaFromFS(mqtt_tls_client)) { + log_message(_F("[TLS] Proceeding without valid CA (expect failure)")); + } + } + last_tls_enabled = heishamonSettings.mqtt_tls_enabled; + } + + if (new_ca_stored) { + log_message(_F("[TLS] Trying to load new CA ertificate")); + if (!loadTlsCaFromFS(mqtt_tls_client)) { + log_message(_F("[TLS] Proceeding without valid CA (expect failure)")); + } + new_ca_stored = false; + } + if (heishamonSettings.mqtt_tls_enabled) { + mqtt_client.setClient(mqtt_tls_client); + } else { + mqtt_client.setClient(mqtt_wifi_client); + } + mqtt_client.setSocketTimeout(10); + mqtt_client.setKeepAlive(30); + mqtt_client.setServer(heishamonSettings.mqtt_server, atoi(heishamonSettings.mqtt_port)); +#endif if (mqtt_client.connect(heishamonSettings.wifi_hostname, heishamonSettings.mqtt_username, heishamonSettings.mqtt_password, topic, 1, true, "Offline")) { mqttReconnects++; @@ -363,6 +431,20 @@ void mqtt_reconnect() } #endif } +//#ifdef TLS_SUPPORT // error state is useful in any case + else { + int8_t err = mqtt_client.state(); + log_message(_F("MQTT connect failed, state:")); + switch (err) { + case -1: log_message(_F(" -1 → TLS handshake or network error")); break; + case -2: log_message(_F(" -2 → Connection timeout – cannot reach broker or CA/time error")); break; + case -3: log_message(_F(" -3 → Server not found or rejected")); break; + case -4: log_message(_F(" -4 → Connection lost")); break; + case -5: log_message(_F(" -5 → Check username/password")); break; + default: log_message(_F(" → Unknown error")); break; + } + } +//#endif } } @@ -809,6 +891,18 @@ int8_t webserver_cb(struct webserver_t *client, void *dat) { LittleFS.remove("/rules.new"); client->userdata = new File(LittleFS.open("/rules.new", "a+")); } +#ifdef TLS_SUPPORT + } else if (strcmp_P((char *)dat, PSTR("/cacert")) == 0) { + client->route = 165; + if (LittleFS.begin()) { + LittleFS.remove("/ca.tmp"); + File cf = LittleFS.open("/ca.tmp", "w"); + if (cf) { + client->userdata = new File(cf); + } + new_ca_stored = true; + } +#endif } else if (strcmp_P((char *)dat, PSTR("/firmware")) == 0) { if (!Update.isRunning()) { #ifdef ESP8266 @@ -836,6 +930,10 @@ int8_t webserver_cb(struct webserver_t *client, void *dat) { client->route = 140; } else if (strcmp_P((char *)dat, PSTR("/rules")) == 0) { client->route = 160; +#ifdef TLS_SUPPORT + } else if (strcmp_P((char *)dat, PSTR("/cacert")) == 0) { + client->route = 166; +#endif } else if (strcmp_P((char *)dat, PSTR("/scandallas")) == 0) { client->route = 180; } else { @@ -940,6 +1038,15 @@ int8_t webserver_cb(struct webserver_t *client, void *dat) { f->write(args->value, args->len); } } break; +#ifdef TLS_SUPPORT + case 165: { + File *f = (File *)client->userdata; + if (f && *f && args->len > 0) { + f->write((const uint8_t*)args->value, (size_t)args->len); + } + return 0; + } break; +#endif } } break; case WEBSERVER_CLIENT_HEADER: { @@ -1065,6 +1172,20 @@ int8_t webserver_cb(struct webserver_t *client, void *dat) { case 160: { return showRules(client); } break; +#ifdef TLS_SUPPORT + case 165: { + if (client->userdata) { + File *pf = (File *)client->userdata; + pf->close(); + delete pf; + client->userdata = NULL; + } + return handleCACert(client); + } break; + case 166: { + return showCACert(client); + } break; +#endif case 170: { File *f = (File *)client->userdata; if (f) { @@ -1127,6 +1248,9 @@ int8_t webserver_cb(struct webserver_t *client, void *dat) { } } break; case 160: +#ifdef TLS_SUPPORT + case 165: +#endif case 170: { if (client->userdata != NULL) { File *f = (File *)client->userdata; @@ -1270,9 +1394,21 @@ void switchSerial() { } void setupMqtt() { - mqtt_client.setClient(mqtt_wifi_client); mqtt_client.setBufferSize(1024); +#ifdef TLS_SUPPORT + mqtt_client.setSocketTimeout(8); mqtt_client.setKeepAlive(30); //fast timeout, any slower than 10s will block the main loop too long (8s might be even safer to avoid reboots on bad wifi); short keepalive may lead to problems with TLS + if (heishamonSettings.mqtt_tls_enabled) { + if (!loadTlsCaFromFS(mqtt_tls_client)) { + log_message(_F("[TLS] Proceeding without valid CA (expect failure)")); + } + mqtt_client.setClient(mqtt_tls_client); + } else { + mqtt_client.setClient(mqtt_wifi_client); + } + last_tls_enabled = heishamonSettings.mqtt_tls_enabled; +#else mqtt_client.setSocketTimeout(10); mqtt_client.setKeepAlive(5); //fast timeout, any slower will block the main loop too long +#endif mqtt_client.setServer(heishamonSettings.mqtt_server, atoi(heishamonSettings.mqtt_port)); mqtt_client.setCallback(mqtt_callback); } @@ -1447,8 +1583,9 @@ void setup() { setupETH(); #endif - loggingSerial.println(F("Setup MQTT...")); - setupMqtt(); +// loggingSerial.println(F("Setup MQTT...")); +// setupMqtt(); +//shifted - TLS requires correct time loggingSerial.println(F("Setup HTTP...")); setupHttp(); @@ -1458,6 +1595,9 @@ void setup() { sntp_setoperatingmode(SNTP_OPMODE_POLL); sntp_init(); + loggingSerial.println(F("Setup MQTT...")); + setupMqtt(); + loggingSerial.println(F("Switch serial...")); switchSerial(); //switch serial to gpio13/gpio15 From 0c42e9d6d26c956f683222db657e8776d42a9a91 Mon Sep 17 00:00:00 2001 From: confuzius0815 <136562234+confuzius0815@users.noreply.github.com> Date: Sat, 29 Nov 2025 09:06:39 +0100 Subject: [PATCH 06/18] Update htmlcode.h added TLS support, part 2 ESP32 only. Added error handling for settings page. --- HeishaMon/htmlcode.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/HeishaMon/htmlcode.h b/HeishaMon/htmlcode.h index c364e268..c3964d59 100644 --- a/HeishaMon/htmlcode.h +++ b/HeishaMon/htmlcode.h @@ -345,6 +345,37 @@ static const char settingsJS[] PROGMEM = " }" ""; +#ifdef TLS_SUPPORT +static const char caUploadJS[] PROGMEM = + ""; +#endif + /*static const char heatingCurveJS[] PROGMEM = "" ""; -#ifdef TLS_SUPPORT +#ifdef TLS_SUPPORT static const char caUploadJS[] PROGMEM = "