From 04b6f5c044b174a3ea8a2837a4d4f64d2c37a73c Mon Sep 17 00:00:00 2001 From: ElVit Date: Mon, 24 Nov 2025 18:42:51 +0100 Subject: [PATCH 1/7] Fix breaking changes caused by ESPHome 2025.11 (fixes #14) --- .../climate/panasonic_heatpump_climate.cpp | 17 ++++++++--------- .../climate/panasonic_heatpump_climate.h | 2 +- .../select/panasonic_heatpump_select.cpp | 14 +++++++------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp index 0a04bfb..8ef3958 100644 --- a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp +++ b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp @@ -18,17 +18,16 @@ namespace esphome auto traits = climate::ClimateTraits(); //traits.set_supports_action(true); - traits.set_supports_current_temperature(true); + traits.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE); + traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT}); if (this->cool_mode_ && (this->id_ == ClimateIds::CONF_CLIMATE_ZONE1 || this->id_ == ClimateIds::CONF_CLIMATE_ZONE2)) { - traits.set_supports_two_point_target_temperature(true); - this->supported_modes_.insert(climate::CLIMATE_MODE_COOL); - this->supported_modes_.insert(climate::CLIMATE_MODE_AUTO); + traits.add_feature_flags(climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE); + traits.add_supported_mode(climate::CLIMATE_MODE_COOL); + traits.add_supported_mode(climate::CLIMATE_MODE_AUTO); } - - traits.set_supported_modes(this->supported_modes_); traits.set_visual_min_temperature(this->min_temperature_); traits.set_visual_max_temperature(this->max_temperature_); traits.set_visual_temperature_step(this->temperature_step_); @@ -132,11 +131,11 @@ namespace esphome default: return; }; - if (!this->get_traits().get_supports_two_point_target_temperature() && + if (!this->get_traits().has_feature_flags(climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE) && this->mode == new_mode && this->target_temperature == new_target_temp_heat && this->current_temperature == new_current_temp) return; - if (this->get_traits().get_supports_two_point_target_temperature() && + if (this->get_traits().has_feature_flags(climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE) && this->mode == new_mode && this->target_temperature_high == new_target_temp_heat && this->target_temperature_low == new_target_temp_cool && @@ -144,7 +143,7 @@ namespace esphome if (new_mode != 255) this->mode = (climate::ClimateMode)new_mode; //this->action = climate::CLIMATE_ACTION_IDLE; - if (this->get_traits().get_supports_two_point_target_temperature()) + if (this->get_traits().has_feature_flags(climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) { this->target_temperature_high = new_target_temp_heat; this->target_temperature_low = new_target_temp_cool; diff --git a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h index 4c11d90..10edc20 100644 --- a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h +++ b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h @@ -4,6 +4,7 @@ #include "../panasonic_heatpump.h" #include "../decode.h" #include "../commands.h" +#include namespace esphome @@ -40,7 +41,6 @@ namespace esphome float min_temperature_ { -5.0 }; float max_temperature_ { 5.0 }; float temperature_step_ { 0.5 }; - std::set supported_modes_ { climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT }; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp b/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp index fa8a0c1..002a148 100644 --- a/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp +++ b/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp @@ -63,31 +63,31 @@ namespace esphome { case SelectIds::CONF_SET9: new_state = PanasonicDecode::getTextState(PanasonicDecode::OperationMode, PanasonicDecode::getOperationMode(data[6])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET4: new_state = PanasonicDecode::getTextState(PanasonicDecode::PowerfulMode, PanasonicDecode::getBit6and7and8(data[7])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET3: new_state = PanasonicDecode::getTextState(PanasonicDecode::QuietMode, PanasonicDecode::getBit3and4and5(data[7])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET2: new_state = PanasonicDecode::getTextState(PanasonicDecode::HolidayState, PanasonicDecode::getBit3and4(data[5])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET17: new_state = PanasonicDecode::getTextState(PanasonicDecode::ZoneState, PanasonicDecode::getBit1and2(data[6])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET26: new_state = PanasonicDecode::getTextState(PanasonicDecode::ExtPadHeaterType, PanasonicDecode::getBit3and4(data[25])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; case SelectIds::CONF_SET35: new_state = PanasonicDecode::getTextState(PanasonicDecode::BivalentMode, PanasonicDecode::getBit5and6(data[26])); - if (this->has_state() && this->state == new_state) return; + if (this->has_state() && this->current_option() == new_state) return; break; default: return; }; From c7212af657b51eb73cbb1c12a226831adb010959 Mon Sep 17 00:00:00 2001 From: ElVit Date: Mon, 24 Nov 2025 18:44:09 +0100 Subject: [PATCH 2/7] Updated warning text for invalid message (fixes #13) --- components/panasonic_heatpump/helpers.cpp | 28 ++++++++++++----- components/panasonic_heatpump/helpers.h | 2 ++ .../panasonic_heatpump/panasonic_heatpump.cpp | 30 ++++++++++++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/components/panasonic_heatpump/helpers.cpp b/components/panasonic_heatpump/helpers.cpp index 81c00fb..6a6460a 100644 --- a/components/panasonic_heatpump/helpers.cpp +++ b/components/panasonic_heatpump/helpers.cpp @@ -34,13 +34,7 @@ namespace esphome ESP_LOGI(TAG, "%s %s[%i]", msgDir.c_str(), msgType.c_str(), length); delay(10); - char buffer[5]; - for (size_t i = 0; i < length; i++) - { - if (i > 0) logStr += separator; - sprintf(buffer, "%02X", data[i]); - logStr += buffer; - } + logStr += byte_array_to_hex_string(data, length, separator); for (size_t i = 0; i < logStr.length(); i += UART_LOG_CHUNK_SIZE) { @@ -48,5 +42,25 @@ namespace esphome delay(10); } } + + std::string PanasonicHelpers::byte_array_to_hex_string(const std::vector& data, const char separator) + { + return PanasonicHelpers::byte_array_to_hex_string(&data[0], data.size(), separator); + } + + std::string PanasonicHelpers::byte_array_to_hex_string(const uint8_t* data, const size_t length, const char separator) + { + std::string hexStr = ""; + char buffer[5]; + + for (size_t i = 0; i < length; i++) + { + if (i > 0) hexStr += separator; + sprintf(buffer, "%02X", data[i]); + hexStr += buffer; + } + + return hexStr; + } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/helpers.h b/components/panasonic_heatpump/helpers.h index fc868ab..478dfdd 100644 --- a/components/panasonic_heatpump/helpers.h +++ b/components/panasonic_heatpump/helpers.h @@ -25,6 +25,8 @@ namespace esphome public: static void log_uart_hex(UartLogDirection direction, const std::vector& data, const char separator); static void log_uart_hex(UartLogDirection direction, const uint8_t* data, const size_t length, const char separator); + static std::string byte_array_to_hex_string(const std::vector& data, const char separator); + static std::string byte_array_to_hex_string(const uint8_t* data, const size_t length, const char separator); }; } } \ No newline at end of file diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 4561ce5..347f9bb 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -149,12 +149,19 @@ namespace esphome this->payload_length_ = byte_; } // Discard message if format is wrong - if ((this->response_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) || - (this->response_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21)) + if (this->response_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) { this->response_receiving_ = false; - ESP_LOGW(TAG, "Invalid response message: %d. byte is 0x%02X but expexted is 0x01, 0x10 or 0x21", - response_message_.size(), byte_); + ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x01 or 0x10", + PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); + delay(10); // NOLINT + continue; + } + if (this->response_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21) + { + this->response_receiving_ = false; + ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x10 or 0x21", + PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); delay(10); // NOLINT continue; } @@ -226,12 +233,19 @@ namespace esphome this->payload_length_ = byte_; } // Discard message if format is wrong - if ((this->request_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) || - (this->request_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21)) + if (this->request_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) { this->request_receiving_ = false; - ESP_LOGW(TAG, "Invalid request message: %d. byte is 0x%02X but expexted is 0x01, 0x10 or 0x21", - request_message_.size(), byte_); + ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x01 or 0x10", + PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); + delay(10); // NOLINT + continue; + } + if (this->request_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21) + { + this->request_receiving_ = false; + ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x10 or 0x21", + PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); delay(10); // NOLINT continue; } From 9c37e20a4b1028503474a8f9737fb83d81e47e0e Mon Sep 17 00:00:00 2001 From: ElVit <54866762+ElVit@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:53:36 +0100 Subject: [PATCH 3/7] Update comments for byte validation checks --- components/panasonic_heatpump/panasonic_heatpump.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 347f9bb..7390e58 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -148,7 +148,7 @@ namespace esphome { this->payload_length_ = byte_; } - // Discard message if format is wrong + // 3. byte shall be 0x01 or 0x10 if (this->response_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) { this->response_receiving_ = false; @@ -157,6 +157,7 @@ namespace esphome delay(10); // NOLINT continue; } + // 4. byte shall be 0x10 or 0x21 if (this->response_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21) { this->response_receiving_ = false; @@ -232,7 +233,7 @@ namespace esphome { this->payload_length_ = byte_; } - // Discard message if format is wrong + // 3. byte shall be 0x01 or 0x10 if (this->request_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) { this->request_receiving_ = false; @@ -241,6 +242,7 @@ namespace esphome delay(10); // NOLINT continue; } + // 4. byte shall be 0x10 or 0x21 if (this->request_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21) { this->request_receiving_ = false; From 8a04ee967037eb0292b168e59bf5f0a869a10a36 Mon Sep 17 00:00:00 2001 From: ElVit <54866762+ElVit@users.noreply.github.com> Date: Wed, 26 Nov 2025 09:20:52 +0100 Subject: [PATCH 4/7] Update panasonic_heatpump.cpp --- components/panasonic_heatpump/panasonic_heatpump.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 7390e58..5bf5f07 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -152,8 +152,8 @@ namespace esphome if (this->response_message_.size() == 3 && byte_ != 0x01 && byte_ != 0x10) { this->response_receiving_ = false; - ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x01 or 0x10", - PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); + ESP_LOGW(TAG, "Invalid response message: 0x%s. Expected last byte to be 0x01 or 0x10", + PanasonicHelpers::byte_array_to_hex_string(this->response_message_, ',')); delay(10); // NOLINT continue; } @@ -161,8 +161,8 @@ namespace esphome if (this->response_message_.size() == 4 && byte_ != 0x10 && byte_ != 0x21) { this->response_receiving_ = false; - ESP_LOGW(TAG, "Invalid request message: 0x%s. Expected last byte to be 0x10 or 0x21", - PanasonicHelpers::byte_array_to_hex_string(this->request_message_, ',')); + ESP_LOGW(TAG, "Invalid response message: 0x%s. Expected last byte to be 0x10 or 0x21", + PanasonicHelpers::byte_array_to_hex_string(this->response_message_, ',')); delay(10); // NOLINT continue; } From d39826a8458eb824880c35b52e76164125c5d67f Mon Sep 17 00:00:00 2001 From: ElVit <54866762+ElVit@users.noreply.github.com> Date: Thu, 27 Nov 2025 19:13:28 +0100 Subject: [PATCH 5/7] Add version constant to heatpump header Define version constant for Panasonic Heatpump. --- components/panasonic_heatpump/panasonic_heatpump.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/panasonic_heatpump/panasonic_heatpump.h b/components/panasonic_heatpump/panasonic_heatpump.h index faf9f69..277c17e 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.h +++ b/components/panasonic_heatpump/panasonic_heatpump.h @@ -92,6 +92,8 @@ namespace esphome void add_extra_sensor(PanasonicHeatpumpEntity *sensor) { extra_sensors_.push_back(sensor); } protected: + const std::string version = "0.0.5"; + // options variables uart::UARTComponent* uart_client_ { nullptr }; bool log_uart_msg_ { false }; From fdca338a4a405ca4820e9dcd998843391ec37761 Mon Sep 17 00:00:00 2001 From: ElVit <54866762+ElVit@users.noreply.github.com> Date: Thu, 27 Nov 2025 19:14:13 +0100 Subject: [PATCH 6/7] Update log message to include version number --- components/panasonic_heatpump/panasonic_heatpump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 5bf5f07..e063914 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -10,7 +10,7 @@ namespace esphome void PanasonicHeatpumpComponent::dump_config() { - ESP_LOGW(TAG, "*** Panasonic Heatpump Component v0.0.4 ***"); + ESP_LOGW(TAG, "*** Panasonic Heatpump Component v%s ***", PanasonicHeatpumpComponent::version); delay(10); // NOLINT } From 0ded598e9e40393f220c58af675687857c501d83 Mon Sep 17 00:00:00 2001 From: ElVit <54866762+ElVit@users.noreply.github.com> Date: Thu, 27 Nov 2025 19:29:24 +0100 Subject: [PATCH 7/7] panasonic_heatpump.cpp updated --- components/panasonic_heatpump/panasonic_heatpump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index e063914..0ecf56b 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -10,7 +10,7 @@ namespace esphome void PanasonicHeatpumpComponent::dump_config() { - ESP_LOGW(TAG, "*** Panasonic Heatpump Component v%s ***", PanasonicHeatpumpComponent::version); + ESP_LOGW(TAG, "*** Panasonic Heatpump Component v%s ***", PanasonicHeatpumpComponent::version.c_str()); delay(10); // NOLINT }