From 1240e7907ecfb0a06f295419ac0874af07e3fdfd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:35:44 -1000 Subject: [PATCH 01/10] [api] Use stack-based format_hex_pretty_to for packet logging macros (#12788) --- esphome/components/api/api_frame_helper.cpp | 18 ++++++++++++++++-- .../components/api/api_frame_helper_noise.cpp | 18 ++++++++++++++++-- .../api/api_frame_helper_plaintext.cpp | 18 ++++++++++++++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index 20f8fcaf61..420f42a90a 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -13,12 +13,26 @@ namespace esphome::api { static const char *const TAG = "api.frame_helper"; +// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512) +static constexpr size_t API_MAX_LOG_BYTES = 168; + #define HELPER_LOG(msg, ...) \ ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) #ifdef HELPER_LOG_PACKETS -#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) -#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) +#define LOG_PACKET_RECEIVED(buffer) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Received frame: %s", \ + format_hex_pretty_to(hex_buf_, (buffer).data(), \ + (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \ + } while (0) +#define LOG_PACKET_SENDING(data, len) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Sending raw: %s", \ + format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \ + } while (0) #else #define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0) diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index 1d6f32ee9d..37b497e2a1 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -24,12 +24,26 @@ static const char *const PROLOGUE_INIT = "NoiseAPIInit"; #endif static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit") +// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512) +static constexpr size_t API_MAX_LOG_BYTES = 168; + #define HELPER_LOG(msg, ...) \ ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) #ifdef HELPER_LOG_PACKETS -#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) -#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) +#define LOG_PACKET_RECEIVED(buffer) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Received frame: %s", \ + format_hex_pretty_to(hex_buf_, (buffer).data(), \ + (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \ + } while (0) +#define LOG_PACKET_SENDING(data, len) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Sending raw: %s", \ + format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \ + } while (0) #else #define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0) diff --git a/esphome/components/api/api_frame_helper_plaintext.cpp b/esphome/components/api/api_frame_helper_plaintext.cpp index b5d90b2429..8b7d002d7c 100644 --- a/esphome/components/api/api_frame_helper_plaintext.cpp +++ b/esphome/components/api/api_frame_helper_plaintext.cpp @@ -18,12 +18,26 @@ namespace esphome::api { static const char *const TAG = "api.plaintext"; +// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512) +static constexpr size_t API_MAX_LOG_BYTES = 168; + #define HELPER_LOG(msg, ...) \ ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) #ifdef HELPER_LOG_PACKETS -#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) -#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) +#define LOG_PACKET_RECEIVED(buffer) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Received frame: %s", \ + format_hex_pretty_to(hex_buf_, (buffer).data(), \ + (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \ + } while (0) +#define LOG_PACKET_SENDING(data, len) \ + do { \ + char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \ + ESP_LOGVV(TAG, "Sending raw: %s", \ + format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \ + } while (0) #else #define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0) From a57011b50bc4e4a4e22bab83f2605c7003a030c0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:36:57 -1000 Subject: [PATCH 02/10] [kuntze] Use stack buffer for hex formatting in verbose logging (#12775) --- esphome/components/kuntze/kuntze.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/esphome/components/kuntze/kuntze.cpp b/esphome/components/kuntze/kuntze.cpp index 30f98aaa99..1b772d062c 100644 --- a/esphome/components/kuntze/kuntze.cpp +++ b/esphome/components/kuntze/kuntze.cpp @@ -1,4 +1,5 @@ #include "kuntze.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/core/application.h" @@ -10,11 +11,17 @@ static const char *const TAG = "kuntze"; static const uint8_t CMD_READ_REG = 0x03; static const uint16_t REGISTER[] = {4136, 4160, 4680, 6000, 4688, 4728, 5832}; +// Maximum bytes to log for Modbus responses (2 registers = 4, plus count = 5) +static constexpr size_t KUNTZE_MAX_LOG_BYTES = 8; + void Kuntze::on_modbus_data(const std::vector &data) { auto get_16bit = [&](int i) -> uint16_t { return (uint16_t(data[i * 2]) << 8) | uint16_t(data[i * 2 + 1]); }; this->waiting_ = false; - ESP_LOGV(TAG, "Data: %s", format_hex_pretty(data).c_str()); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char hex_buf[format_hex_pretty_size(KUNTZE_MAX_LOG_BYTES)]; +#endif + ESP_LOGV(TAG, "Data: %s", format_hex_pretty_to(hex_buf, data.data(), data.size())); float value = (float) get_16bit(0); for (int i = 0; i < data[3]; i++) From d946ddabfd312b552890d5516ca2445a8e6641d8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:37:16 -1000 Subject: [PATCH 03/10] [xiaomi_ble] Use stack-based hex formatting in verbose logging (#12793) --- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 32 ++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 564870d74e..9f25063133 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -12,6 +12,9 @@ namespace xiaomi_ble { static const char *const TAG = "xiaomi_ble"; +// Maximum bytes to log in very verbose hex output (covers largest packet of ~24 bytes) +static constexpr size_t XIAOMI_MAX_LOG_BYTES = 32; + bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result) { // button pressed, 3 bytes, only byte 3 is used for supported devices so far if ((value_type == 0x1001) && (value_length == 3)) { @@ -263,7 +266,10 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, const uint64_t &address) { if ((raw.size() != 19) && ((raw.size() < 22) || (raw.size() > 24))) { ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): data packet has wrong size (%d)!", raw.size()); - ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str()); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE + char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)]; +#endif + ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty_to(hex_buf, raw.data(), raw.size())); return false; } @@ -320,12 +326,17 @@ bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, c memcpy(mac_address + 4, mac_reverse + 1, 1); memcpy(mac_address + 5, mac_reverse, 1); ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption failed."); - ESP_LOGVV(TAG, " MAC address : %s", format_mac_address_pretty(mac_address).c_str()); - ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str()); - ESP_LOGVV(TAG, " Key : %s", format_hex_pretty(vector.key, vector.keysize).c_str()); - ESP_LOGVV(TAG, " Iv : %s", format_hex_pretty(vector.iv, vector.ivsize).c_str()); - ESP_LOGVV(TAG, " Cipher : %s", format_hex_pretty(vector.ciphertext, vector.datasize).c_str()); - ESP_LOGVV(TAG, " Tag : %s", format_hex_pretty(vector.tag, vector.tagsize).c_str()); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE + char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE]; + format_mac_addr_upper(mac_address, mac_buf); + char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)]; +#endif + ESP_LOGVV(TAG, " MAC address : %s", mac_buf); + ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty_to(hex_buf, raw.data(), raw.size())); + ESP_LOGVV(TAG, " Key : %s", format_hex_pretty_to(hex_buf, vector.key, vector.keysize)); + ESP_LOGVV(TAG, " Iv : %s", format_hex_pretty_to(hex_buf, vector.iv, vector.ivsize)); + ESP_LOGVV(TAG, " Cipher : %s", format_hex_pretty_to(hex_buf, vector.ciphertext, vector.datasize)); + ESP_LOGVV(TAG, " Tag : %s", format_hex_pretty_to(hex_buf, vector.tag, vector.tagsize)); mbedtls_ccm_free(&ctx); return false; } @@ -341,8 +352,11 @@ bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, c raw[0] &= ~0x08; ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption passed."); - ESP_LOGVV(TAG, " Plaintext : %s, Packet : %d", format_hex_pretty(raw.data() + cipher_pos, vector.datasize).c_str(), - static_cast(raw[4])); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE + char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)]; +#endif + ESP_LOGVV(TAG, " Plaintext : %s, Packet : %d", + format_hex_pretty_to(hex_buf, raw.data() + cipher_pos, vector.datasize), static_cast(raw[4])); mbedtls_ccm_free(&ctx); return true; From 64ba37633019b46e18e011b87285ee5922a90c72 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:37:38 -1000 Subject: [PATCH 04/10] [hte501] Use stack-based hex formatting in verbose logging (#12794) --- esphome/components/hte501/hte501.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/hte501/hte501.cpp b/esphome/components/hte501/hte501.cpp index b7d3be63fe..cde6886109 100644 --- a/esphome/components/hte501/hte501.cpp +++ b/esphome/components/hte501/hte501.cpp @@ -7,6 +7,8 @@ namespace hte501 { static const char *const TAG = "hte501"; +static constexpr size_t HTE501_SERIAL_NUMBER_SIZE = 7; + void HTE501Component::setup() { uint8_t address[] = {0x70, 0x29}; uint8_t identification[9]; @@ -16,7 +18,10 @@ void HTE501Component::setup() { this->mark_failed(); return; } - ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex(identification + 0, 7).c_str()); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char serial_hex[format_hex_size(HTE501_SERIAL_NUMBER_SIZE)]; +#endif + ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex_to(serial_hex, identification, HTE501_SERIAL_NUMBER_SIZE)); } void HTE501Component::dump_config() { From ace48464a8f435f43369a3dd791dede7f2b83647 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:39:44 -1000 Subject: [PATCH 05/10] [addressable_light] Use StringRef to avoid allocation when saving effect name (#12759) --- .../addressable_light/addressable_light_display.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/esphome/components/addressable_light/addressable_light_display.h b/esphome/components/addressable_light/addressable_light_display.h index f47389fd05..53f8604b7d 100644 --- a/esphome/components/addressable_light/addressable_light_display.h +++ b/esphome/components/addressable_light/addressable_light_display.h @@ -25,11 +25,13 @@ class AddressableLightDisplay : public display::DisplayBuffer { if (enabled_ && !enabled) { // enabled -> disabled // - Tell the parent light to refresh, effectively wiping the display. Also // restores the previous effect (if any). - light_state_->make_call().set_effect(this->last_effect_).perform(); + if (this->last_effect_index_.has_value()) { + light_state_->make_call().set_effect(*this->last_effect_index_).perform(); + } } else if (!enabled_ && enabled) { // disabled -> enabled - // - Save the current effect. - this->last_effect_ = light_state_->get_effect_name(); + // - Save the current effect index. + this->last_effect_index_ = light_state_->get_current_effect_index(); // - Disable any current effect. light_state_->make_call().set_effect(0).perform(); } @@ -56,7 +58,7 @@ class AddressableLightDisplay : public display::DisplayBuffer { int32_t width_; int32_t height_; std::vector addressable_light_buffer_; - optional last_effect_; + optional last_effect_index_; optional> pixel_mapper_f_; }; } // namespace addressable_light From 016eeef04afcdb5665ad7a882d97ee4e01b4ffc4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:40:06 -1000 Subject: [PATCH 06/10] [tee501] Use stack-based hex formatting in verbose logging (#12795) --- esphome/components/tee501/tee501.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/tee501/tee501.cpp b/esphome/components/tee501/tee501.cpp index d6513dbbe0..06481b628b 100644 --- a/esphome/components/tee501/tee501.cpp +++ b/esphome/components/tee501/tee501.cpp @@ -7,6 +7,8 @@ namespace tee501 { static const char *const TAG = "tee501"; +static constexpr size_t TEE501_SERIAL_NUMBER_SIZE = 7; + void TEE501Component::setup() { uint8_t address[] = {0x70, 0x29}; uint8_t identification[9]; @@ -17,7 +19,10 @@ void TEE501Component::setup() { this->mark_failed(); return; } - ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex(identification + 0, 7).c_str()); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char serial_hex[format_hex_size(TEE501_SERIAL_NUMBER_SIZE)]; +#endif + ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex_to(serial_hex, identification, TEE501_SERIAL_NUMBER_SIZE)); } void TEE501Component::dump_config() { From c3ffc1635d90fdf73258b4140c8c682b7693b7f7 Mon Sep 17 00:00:00 2001 From: Thomas Rupprecht Date: Sat, 3 Jan 2026 03:40:28 +0100 Subject: [PATCH 07/10] =?UTF-8?q?[gps]=20add=20icon=20for=20HDOP=20and=20u?= =?UTF-8?q?se=20correct=20state=5Fclass=20for=20longitude=20and=E2=80=A6?= =?UTF-8?q?=20(#12718)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/components/gps/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py index a872cf7015..2135189bd5 100644 --- a/esphome/components/gps/__init__.py +++ b/esphome/components/gps/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_SPEED, DEVICE_CLASS_SPEED, STATE_CLASS_MEASUREMENT, + STATE_CLASS_MEASUREMENT_ANGLE, UNIT_DEGREES, UNIT_KILOMETER_PER_HOUR, UNIT_METER, @@ -21,6 +22,7 @@ CONF_HDOP = "hdop" ICON_ALTIMETER = "mdi:altimeter" ICON_COMPASS = "mdi:compass" +ICON_CIRCLE_DOUBLE = "mdi:circle-double" ICON_LATITUDE = "mdi:latitude" ICON_LONGITUDE = "mdi:longitude" ICON_SATELLITE = "mdi:satellite-variant" @@ -50,7 +52,7 @@ CONFIG_SCHEMA = cv.All( unit_of_measurement=UNIT_DEGREES, icon=ICON_LONGITUDE, accuracy_decimals=6, - state_class=STATE_CLASS_MEASUREMENT, + state_class=STATE_CLASS_MEASUREMENT_ANGLE, ), cv.Optional(CONF_SPEED): sensor.sensor_schema( unit_of_measurement=UNIT_KILOMETER_PER_HOUR, @@ -63,7 +65,7 @@ CONFIG_SCHEMA = cv.All( unit_of_measurement=UNIT_DEGREES, icon=ICON_COMPASS, accuracy_decimals=2, - state_class=STATE_CLASS_MEASUREMENT, + state_class=STATE_CLASS_MEASUREMENT_ANGLE, ), cv.Optional(CONF_ALTITUDE): sensor.sensor_schema( unit_of_measurement=UNIT_METER, @@ -72,11 +74,14 @@ CONFIG_SCHEMA = cv.All( state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_SATELLITES): sensor.sensor_schema( + # no unit_of_measurement icon=ICON_SATELLITE, accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_HDOP): sensor.sensor_schema( + # no unit_of_measurement + icon=ICON_CIRCLE_DOUBLE, accuracy_decimals=3, state_class=STATE_CLASS_MEASUREMENT, ), From bc1af007b44d2bb67a72f966d58eba556253e6d4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:40:47 -1000 Subject: [PATCH 08/10] [vbus] Use stack-based hex formatting in verbose logging (#12796) --- esphome/components/vbus/vbus.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/vbus/vbus.cpp b/esphome/components/vbus/vbus.cpp index e474dcfe17..b9496a08de 100644 --- a/esphome/components/vbus/vbus.cpp +++ b/esphome/components/vbus/vbus.cpp @@ -8,6 +8,9 @@ namespace vbus { static const char *const TAG = "vbus"; +// Maximum bytes to log in verbose hex output (16 frames * 4 bytes = 64 bytes typical) +static constexpr size_t VBUS_MAX_LOG_BYTES = 64; + void VBus::dump_config() { ESP_LOGCONFIG(TAG, "VBus:"); check_uart_settings(9600); @@ -101,8 +104,11 @@ void VBus::loop() { this->buffer_.push_back(this->fbytes_[i]); if (++this->cframe_ < this->frames_) continue; +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char hex_buf[format_hex_size(VBUS_MAX_LOG_BYTES)]; +#endif ESP_LOGV(TAG, "P2 C%04x %04x->%04x: %s", this->command_, this->source_, this->dest_, - format_hex(this->buffer_).c_str()); + format_hex_to(hex_buf, this->buffer_.data(), this->buffer_.size())); for (auto &listener : this->listeners_) listener->on_message(this->command_, this->source_, this->dest_, this->buffer_); this->state_ = 0; From 6409970f6e5e64c2694f685138ee1888f2140f58 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:41:02 -1000 Subject: [PATCH 09/10] [uponor_smatrix] Use stack-based hex formatting in verbose logging (#12797) Co-authored-by: Stefan Rado <628587+kroimon@users.noreply.github.com> --- esphome/components/uponor_smatrix/uponor_smatrix.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/components/uponor_smatrix/uponor_smatrix.cpp b/esphome/components/uponor_smatrix/uponor_smatrix.cpp index 221f07c80e..4c3a4b05df 100644 --- a/esphome/components/uponor_smatrix/uponor_smatrix.cpp +++ b/esphome/components/uponor_smatrix/uponor_smatrix.cpp @@ -8,6 +8,9 @@ namespace uponor_smatrix { static const char *const TAG = "uponor_smatrix"; +// Maximum bytes to log in verbose hex output +static constexpr size_t UPONOR_MAX_LOG_BYTES = 36; + void UponorSmatrixComponent::setup() { #ifdef USE_TIME if (this->time_id_ != nullptr) { @@ -97,8 +100,11 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) { return false; } +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + char hex_buf[format_hex_size(UPONOR_MAX_LOG_BYTES)]; +#endif ESP_LOGV(TAG, "Received packet: addr=%08X, data=%s, crc=%04X", device_address, - format_hex(&packet[4], packet_len - 6).c_str(), crc); + format_hex_to(hex_buf, &packet[4], packet_len - 6), crc); // Handle packet size_t data_len = (packet_len - 6) / 3; From 114624acbdbea09e9f60bee0ce95bb9ff442922a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 2 Jan 2026 16:57:41 -1000 Subject: [PATCH 10/10] fix conflicts --- esphome/components/api/api_connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 6005cdbf22..86651bbcf5 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1714,12 +1714,12 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes // Create null-terminated state for callback (parse_number needs null-termination) // HA state max length is 255, so 256 byte buffer covers all cases char state_buf[256]; - size_t copy_len = msg.state_len; + size_t copy_len = msg.state.size(); if (copy_len >= sizeof(state_buf)) { copy_len = sizeof(state_buf) - 1; // Truncate to leave space for null terminator } if (copy_len > 0) { - memcpy(state_buf, msg.state, copy_len); + memcpy(state_buf, msg.state.data(), copy_len); } state_buf[copy_len] = '\0'; it.callback(StringRef(state_buf, copy_len));