From 39cbc6b183c69fce10eb77c1c9393687335b7a30 Mon Sep 17 00:00:00 2001 From: Oleg Tarasov Date: Tue, 26 Nov 2024 00:47:01 +0300 Subject: [PATCH] [opentherm] Fix out of memory errors on ESP8266 (#7835) --- esphome/components/opentherm/hub.cpp | 13 ++++---- esphome/components/opentherm/opentherm.cpp | 36 ++++++---------------- esphome/components/opentherm/opentherm.h | 7 ++--- esphome/core/helpers.cpp | 12 ++++++++ esphome/core/helpers.h | 8 +++++ 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/esphome/components/opentherm/hub.cpp b/esphome/components/opentherm/hub.cpp index dfa8ea95c5..aac2966ed1 100644 --- a/esphome/components/opentherm/hub.cpp +++ b/esphome/components/opentherm/hub.cpp @@ -138,7 +138,7 @@ OpenthermHub::OpenthermHub() : Component(), in_pin_{}, out_pin_{} {} void OpenthermHub::process_response(OpenthermData &data) { ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id, this->opentherm_->message_id_to_str((MessageId) data.id)); - ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str()); + this->opentherm_->debug_data(data); switch (data.id) { OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_RESPONSE_MESSAGE, OPENTHERM_MESSAGE_RESPONSE_ENTITY, , @@ -315,7 +315,7 @@ void OpenthermHub::start_conversation_() { ESP_LOGD(TAG, "Sending request with id %d (%s)", request.id, this->opentherm_->message_id_to_str((MessageId) request.id)); - ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(request).c_str()); + this->opentherm_->debug_data(request); // Send the request this->last_conversation_start_ = millis(); this->opentherm_->send(request); @@ -340,19 +340,18 @@ void OpenthermHub::stop_opentherm_() { this->opentherm_->stop(); this->last_conversation_end_ = millis(); } - void OpenthermHub::handle_protocol_write_error_() { ESP_LOGW(TAG, "Error while sending request: %s", this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode())); - ESP_LOGW(TAG, "%s", this->opentherm_->debug_data(this->last_request_).c_str()); + this->opentherm_->debug_data(this->last_request_); } - void OpenthermHub::handle_protocol_read_error_() { OpenThermError error; this->opentherm_->get_protocol_error(error); - ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", this->opentherm_->debug_error(error).c_str()); + ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", + this->opentherm_->protocol_error_to_to_str(error.error_type)); + this->opentherm_->debug_error(error); } - void OpenthermHub::handle_timeout_error_() { ESP_LOGW(TAG, "Receive response timed out at a protocol level"); this->stop_opentherm_(); diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index 26c707f9a0..62cfcdceea 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -15,15 +15,11 @@ #include "Arduino.h" #endif #include -#include -#include namespace esphome { namespace opentherm { using std::string; -using std::bitset; -using std::stringstream; using std::to_string; static const char *const TAG = "opentherm"; @@ -545,29 +541,17 @@ const char *OpenTherm::message_id_to_str(MessageId id) { } } -string OpenTherm::debug_data(OpenthermData &data) { - stringstream result; - result << bitset<8>(data.type) << " " << bitset<8>(data.id) << " " << bitset<8>(data.valueHB) << " " - << bitset<8>(data.valueLB) << "\n"; - result << "type: " << this->message_type_to_str((MessageType) data.type) << "; "; - result << "id: " << to_string(data.id) << "; "; - result << "HB: " << to_string(data.valueHB) << "; "; - result << "LB: " << to_string(data.valueLB) << "; "; - result << "uint_16: " << to_string(data.u16()) << "; "; - result << "float: " << to_string(data.f88()); - - return result.str(); +void OpenTherm::debug_data(OpenthermData &data) { + ESP_LOGD(TAG, "%s %s %s %s", format_bin(data.type).c_str(), format_bin(data.id).c_str(), + format_bin(data.valueHB).c_str(), format_bin(data.valueLB).c_str()); + ESP_LOGD(TAG, "type: %s; id: %s; HB: %s; LB: %s; uint_16: %s; float: %s", + this->message_type_to_str((MessageType) data.type), to_string(data.id).c_str(), + to_string(data.valueHB).c_str(), to_string(data.valueLB).c_str(), to_string(data.u16()).c_str(), + to_string(data.f88()).c_str()); } -std::string OpenTherm::debug_error(OpenThermError &error) { - stringstream result; - result << "type: " << this->protocol_error_to_to_str(error.error_type) << "; "; - result << "data: "; - result << format_hex(error.data); - result << "; clock: " << to_string(clock_); - result << "; capture: " << bitset<32>(error.capture); - result << "; bit_pos: " << to_string(error.bit_pos); - - return result.str(); +void OpenTherm::debug_error(OpenThermError &error) const { + ESP_LOGD(TAG, "data: %s; clock: %s; capture: %s; bit_pos: %s", format_hex(error.data).c_str(), + to_string(clock_).c_str(), format_bin(error.capture).c_str(), to_string(error.bit_pos).c_str()); } float OpenthermData::f88() { return ((float) this->s16()) / 256.0; } diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index 85f4611125..76710af5f5 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -8,10 +8,9 @@ #pragma once #include -#include -#include #include "esphome/core/hal.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #if defined(ESP32) || defined(USE_ESP_IDF) #include "driver/timer.h" @@ -318,8 +317,8 @@ class OpenTherm { OperationMode get_mode() { return mode_; } - std::string debug_data(OpenthermData &data); - std::string debug_error(OpenThermError &error); + void debug_data(OpenthermData &data); + void debug_error(OpenThermError &error) const; const char *protocol_error_to_to_str(ProtocolErrorType error_type); const char *message_type_to_str(MessageType message_type); diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index dae60a4e1d..befc84516c 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -397,6 +397,18 @@ std::string format_hex_pretty(const uint16_t *data, size_t length) { } std::string format_hex_pretty(const std::vector &data) { return format_hex_pretty(data.data(), data.size()); } +std::string format_bin(const uint8_t *data, size_t length) { + std::string result; + result.resize(length * 8); + for (size_t byte_idx = 0; byte_idx < length; byte_idx++) { + for (size_t bit_idx = 0; bit_idx < 8; bit_idx++) { + result[byte_idx * 8 + bit_idx] = ((data[byte_idx] >> (7 - bit_idx)) & 1) + '0'; + } + } + + return result; +} + ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) { if (on == nullptr && strcasecmp(str, "on") == 0) return PARSE_ON; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 43001bafdd..305ec47f76 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -420,6 +420,14 @@ template::value, int> = 0> std::stri return format_hex_pretty(reinterpret_cast(&val), sizeof(T)); } +/// Format the byte array \p data of length \p len in binary. +std::string format_bin(const uint8_t *data, size_t length); +/// Format an unsigned integer in binary, starting with the most significant byte. +template::value, int> = 0> std::string format_bin(T val) { + val = convert_big_endian(val); + return format_bin(reinterpret_cast(&val), sizeof(T)); +} + /// Return values for parse_on_off(). enum ParseOnOffState { PARSE_NONE = 0,