From 10cc0c3bffd52c6b2b1baa0767559e577383d6f6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Nov 2025 20:43:51 -0600 Subject: [PATCH 1/5] overload --- esphome/core/helpers.cpp | 13 +++++++------ esphome/core/helpers.h | 9 +++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 50af71649c..6d8f2f02ec 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -238,27 +238,28 @@ std::string str_sprintf(const char *fmt, ...) { // Maximum size for name with suffix: 120 (max friendly name) + 1 (separator) + 6 (MAC suffix) + 1 (null term) static constexpr size_t MAX_NAME_WITH_SUFFIX_SIZE = 128; -std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len) { +std::string make_name_with_suffix(const char *name, char sep, const char *suffix_ptr, size_t suffix_len) { char buffer[MAX_NAME_WITH_SUFFIX_SIZE]; - size_t name_len = name.size(); + size_t name_len = strlen(name); size_t total_len = name_len + 1 + suffix_len; // Silently truncate if needed: prioritize keeping the full suffix if (total_len >= MAX_NAME_WITH_SUFFIX_SIZE) { - // NOTE: This calculation could underflow if suffix_len >= MAX_NAME_WITH_SUFFIX_SIZE - 2, - // but this is safe because this helper is only called with small suffixes: - // MAC suffixes (6-12 bytes), ".local" (5 bytes), etc. name_len = MAX_NAME_WITH_SUFFIX_SIZE - suffix_len - 2; // -2 for separator and null terminator total_len = name_len + 1 + suffix_len; } - memcpy(buffer, name.c_str(), name_len); + memcpy(buffer, name, name_len); buffer[name_len] = sep; memcpy(buffer + name_len + 1, suffix_ptr, suffix_len); buffer[total_len] = '\0'; return std::string(buffer, total_len); } +std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len) { + return make_name_with_suffix(name.c_str(), sep, suffix_ptr, suffix_len); +} + // Parsing & formatting size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index d8c1f4647e..810b486011 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -512,6 +512,15 @@ std::string __attribute__((format(printf, 1, 2))) str_sprintf(const char *fmt, . /// @return The concatenated string: name + sep + suffix std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len); +/// Optimized string concatenation: name + separator + suffix (const char* overload) +/// Uses a fixed stack buffer to avoid heap allocations. +/// @param name The base name (null-terminated string) +/// @param sep Single character separator +/// @param suffix_ptr Pointer to the suffix characters +/// @param suffix_len Length of the suffix +/// @return The concatenated string: name + sep + suffix +std::string make_name_with_suffix(const char *name, char sep, const char *suffix_ptr, size_t suffix_len); + ///@} /// @name Parsing & formatting From cd9323ce704a94d58e82b5d81bb086897b8e06f3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Nov 2025 20:45:31 -0600 Subject: [PATCH 2/5] overload --- esphome/components/esp32_ble/ble.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 787b01295b..b0683b9e65 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -258,13 +258,14 @@ bool ESP32BLE::ble_setup_() { std::string name; if (this->name_ != nullptr) { - name = this->name_; if (App.is_name_add_mac_suffix_enabled()) { // MAC address suffix length (last 6 characters of 12-char MAC address string) constexpr size_t mac_address_suffix_len = 6; const std::string mac_addr = get_mac_address(); const char *mac_suffix_ptr = mac_addr.c_str() + mac_address_suffix_len; - name = make_name_with_suffix(name, '-', mac_suffix_ptr, mac_address_suffix_len); + name = make_name_with_suffix(this->name_, '-', mac_suffix_ptr, mac_address_suffix_len); + } else { + name = this->name_; } } else { name = App.get_name(); From b432c056dc58454f21c2fcdf76fb2e8d2f52ddec Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Nov 2025 20:48:27 -0600 Subject: [PATCH 3/5] [esp32_ble] Store device name in flash to reduce RAM usage --- esphome/components/esp32_ble/ble.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index b0683b9e65..86c750e8f8 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -261,8 +261,9 @@ bool ESP32BLE::ble_setup_() { if (App.is_name_add_mac_suffix_enabled()) { // MAC address suffix length (last 6 characters of 12-char MAC address string) constexpr size_t mac_address_suffix_len = 6; - const std::string mac_addr = get_mac_address(); - const char *mac_suffix_ptr = mac_addr.c_str() + mac_address_suffix_len; + char mac_addr[13]; + get_mac_address_into_buffer(mac_addr); + const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len; name = make_name_with_suffix(this->name_, '-', mac_suffix_ptr, mac_address_suffix_len); } else { name = this->name_; From 531af6a277929c77f1615e6c18ef10c9db2add2c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Nov 2025 20:50:31 -0600 Subject: [PATCH 4/5] [esp32_ble] Store device name in flash to reduce RAM usage --- esphome/components/esp32_ble/ble.cpp | 2 +- esphome/core/helpers.cpp | 9 ++++++--- esphome/core/helpers.h | 6 ++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 86c750e8f8..226ff1952e 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -264,7 +264,7 @@ bool ESP32BLE::ble_setup_() { char mac_addr[13]; get_mac_address_into_buffer(mac_addr); const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len; - name = make_name_with_suffix(this->name_, '-', mac_suffix_ptr, mac_address_suffix_len); + name = make_name_with_suffix(this->name_, strlen(this->name_), '-', mac_suffix_ptr, mac_address_suffix_len); } else { name = this->name_; } diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 6d8f2f02ec..1f675563c7 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -238,13 +238,16 @@ std::string str_sprintf(const char *fmt, ...) { // Maximum size for name with suffix: 120 (max friendly name) + 1 (separator) + 6 (MAC suffix) + 1 (null term) static constexpr size_t MAX_NAME_WITH_SUFFIX_SIZE = 128; -std::string make_name_with_suffix(const char *name, char sep, const char *suffix_ptr, size_t suffix_len) { +std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr, + size_t suffix_len) { char buffer[MAX_NAME_WITH_SUFFIX_SIZE]; - size_t name_len = strlen(name); size_t total_len = name_len + 1 + suffix_len; // Silently truncate if needed: prioritize keeping the full suffix if (total_len >= MAX_NAME_WITH_SUFFIX_SIZE) { + // NOTE: This calculation could underflow if suffix_len >= MAX_NAME_WITH_SUFFIX_SIZE - 2, + // but this is safe because this helper is only called with small suffixes: + // MAC suffixes (6-12 bytes), ".local" (5 bytes), etc. name_len = MAX_NAME_WITH_SUFFIX_SIZE - suffix_len - 2; // -2 for separator and null terminator total_len = name_len + 1 + suffix_len; } @@ -257,7 +260,7 @@ std::string make_name_with_suffix(const char *name, char sep, const char *suffix } std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len) { - return make_name_with_suffix(name.c_str(), sep, suffix_ptr, suffix_len); + return make_name_with_suffix(name.c_str(), name.size(), sep, suffix_ptr, suffix_len); } // Parsing & formatting diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 810b486011..a43c55e06b 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -514,12 +514,14 @@ std::string make_name_with_suffix(const std::string &name, char sep, const char /// Optimized string concatenation: name + separator + suffix (const char* overload) /// Uses a fixed stack buffer to avoid heap allocations. -/// @param name The base name (null-terminated string) +/// @param name The base name string +/// @param name_len Length of the name /// @param sep Single character separator /// @param suffix_ptr Pointer to the suffix characters /// @param suffix_len Length of the suffix /// @return The concatenated string: name + sep + suffix -std::string make_name_with_suffix(const char *name, char sep, const char *suffix_ptr, size_t suffix_len); +std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr, + size_t suffix_len); ///@} From 1e886b88851cfb47a9a2d6dffbe54b4eca570be8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 23 Nov 2025 20:56:27 -0600 Subject: [PATCH 5/5] [esp32_ble] Store device name in flash to reduce RAM usage --- esphome/components/esp32_ble/ble.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 226ff1952e..2e1aaadeb7 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -256,7 +256,9 @@ bool ESP32BLE::ble_setup_() { } #endif - std::string name; + const char *device_name; + std::string name_with_suffix; + if (this->name_ != nullptr) { if (App.is_name_add_mac_suffix_enabled()) { // MAC address suffix length (last 6 characters of 12-char MAC address string) @@ -264,23 +266,26 @@ bool ESP32BLE::ble_setup_() { char mac_addr[13]; get_mac_address_into_buffer(mac_addr); const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len; - name = make_name_with_suffix(this->name_, strlen(this->name_), '-', mac_suffix_ptr, mac_address_suffix_len); + name_with_suffix = + make_name_with_suffix(this->name_, strlen(this->name_), '-', mac_suffix_ptr, mac_address_suffix_len); + device_name = name_with_suffix.c_str(); } else { - name = this->name_; + device_name = this->name_; } } else { - name = App.get_name(); - if (name.length() > 20) { + name_with_suffix = App.get_name(); + if (name_with_suffix.length() > 20) { if (App.is_name_add_mac_suffix_enabled()) { // Keep first 13 chars and last 7 chars (MAC suffix), remove middle - name.erase(13, name.length() - 20); + name_with_suffix.erase(13, name_with_suffix.length() - 20); } else { - name.resize(20); + name_with_suffix.resize(20); } } + device_name = name_with_suffix.c_str(); } - err = esp_ble_gap_set_device_name(name.c_str()); + err = esp_ble_gap_set_device_name(device_name); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gap_set_device_name failed: %d", err); return false;