From a1395af7636e787dda0e1e916d8afc4fbcd2b046 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 10 Jan 2026 17:07:21 -1000 Subject: [PATCH] [helpers] Add format_hex_prefixed_to for "0x" prefixed hex formatting (#13115) --- esphome/components/one_wire/one_wire.cpp | 6 +++-- .../sml/text_sensor/sml_text_sensor.cpp | 6 ++--- esphome/core/helpers.h | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/esphome/components/one_wire/one_wire.cpp b/esphome/components/one_wire/one_wire.cpp index fd139d0ddc..187f559ca6 100644 --- a/esphome/components/one_wire/one_wire.cpp +++ b/esphome/components/one_wire/one_wire.cpp @@ -6,8 +6,10 @@ namespace one_wire { static const char *const TAG = "one_wire"; const std::string &OneWireDevice::get_address_name() { - if (this->address_name_.empty()) - this->address_name_ = std::string("0x") + format_hex(this->address_); + if (this->address_name_.empty()) { + char hex_buf[19]; // "0x" + 16 hex chars + null + this->address_name_ = format_hex_prefixed_to(hex_buf, this->address_); + } return this->address_name_; } diff --git a/esphome/components/sml/text_sensor/sml_text_sensor.cpp b/esphome/components/sml/text_sensor/sml_text_sensor.cpp index 6ceff26fe5..17b93ecccf 100644 --- a/esphome/components/sml/text_sensor/sml_text_sensor.cpp +++ b/esphome/components/sml/text_sensor/sml_text_sensor.cpp @@ -24,11 +24,9 @@ void SmlTextSensor::publish_val(const ObisInfo &obis_info) { case SML_HEX: { // Buffer for "0x" + up to 32 bytes as hex + null char buf[67]; - buf[0] = '0'; - buf[1] = 'x'; - // Max 32 bytes of data fit in remaining buffer ((65-1)/2) + // Max 32 bytes of data fit in buffer ((67-3)/2) size_t hex_bytes = std::min(obis_info.value.size(), size_t(32)); - format_hex_to(buf + 2, sizeof(buf) - 2, obis_info.value.begin(), hex_bytes); + format_hex_prefixed_to(buf, obis_info.value.begin(), hex_bytes); publish_state(buf, 2 + hex_bytes * 2); break; } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 05d2d475c1..cd43709f7d 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -759,6 +759,29 @@ inline char *format_hex_to(char (&buffer)[N], T val) { /// Calculate buffer size needed for format_hex_to: "XXXXXXXX...\0" = bytes * 2 + 1 constexpr size_t format_hex_size(size_t byte_count) { return byte_count * 2 + 1; } +/// Calculate buffer size needed for format_hex_prefixed_to: "0xXXXXXXXX...\0" = bytes * 2 + 3 +constexpr size_t format_hex_prefixed_size(size_t byte_count) { return byte_count * 2 + 3; } + +/// Format an unsigned integer as "0x" prefixed lowercase hex to buffer. +template::value, int> = 0> +inline char *format_hex_prefixed_to(char (&buffer)[N], T val) { + static_assert(N >= sizeof(T) * 2 + 3, "Buffer too small for prefixed hex"); + buffer[0] = '0'; + buffer[1] = 'x'; + val = convert_big_endian(val); + format_hex_to(buffer + 2, N - 2, reinterpret_cast(&val), sizeof(T)); + return buffer; +} + +/// Format byte array as "0x" prefixed lowercase hex to buffer. +template inline char *format_hex_prefixed_to(char (&buffer)[N], const uint8_t *data, size_t length) { + static_assert(N >= 5, "Buffer must hold at least '0x' + one hex byte + null"); + buffer[0] = '0'; + buffer[1] = 'x'; + format_hex_to(buffer + 2, N - 2, data, length); + return buffer; +} + /// Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0" constexpr size_t format_hex_pretty_size(size_t byte_count) { return byte_count * 3; }