Stack-Based Formatting Helpers Replace Heap-Allocating Functions
Several string formatting helpers that returned std::string are now soft-deprecated in favor of stack-based alternatives. This prevents heap fragmentation on long-running ESP devices.
This is a breaking change for external components in ESPHome 2026.1.0 and later.
Background
ESP devices run for months with small heaps shared between Wi-Fi, BLE, LWIP, and application code. Over time, repeated allocations of different sizes fragment the heap. Failures occur when the largest contiguous block shrinks, even if total free heap remains large. For this reason, ESPHome treats runtime heap allocation in hot paths as a reliability bug.
These PRs soft-deprecate heap-allocating helpers and migrate internal callers:
PR #13156: Core helper deprecations
Soft-deprecates format_hex() and format_hex_pretty() in favor of buffer-based alternatives.
PR #13157: MAC address helpers
Soft-deprecates get_mac_address() and get_mac_address_pretty().
PR #13158: format_hex_pretty and MideaData
Migrates format_hex_pretty() callers; deprecates MideaData::to_string().
PR #13159: value_accuracy_to_string
Migrates 22 call sites from value_accuracy_to_string() to value_accuracy_to_buf().
PR #12799: ABBWelcome
Replaces ABBWelcomeData::to_string() with ABBWelcomeData::format_to().
PR #12629: get_object_id
Deprecates get_object_id() in favor of get_object_id_to().
What's Changing
Deprecated functions and replacements
| Deprecated Function | Replacement | Buffer Size Constant |
|---|---|---|
format_hex() |
format_hex_to() |
2 * data.size() + 1 |
format_hex_pretty() |
format_hex_pretty_to() |
3 * data.size() |
get_mac_address() |
get_mac_address_into_buffer() |
MAC_ADDRESS_BUFFER_SIZE (13) |
get_mac_address_pretty() |
get_mac_address_pretty_into_buffer() |
MAC_ADDRESS_PRETTY_BUFFER_SIZE (18) |
value_accuracy_to_string() |
value_accuracy_to_buf() |
VALUE_ACCURACY_MAX_LEN (64) |
get_object_id() |
get_object_id_to() |
OBJECT_ID_MAX_LEN (128) |
MideaData::to_string() |
MideaData::to_str() |
MideaData::TO_STR_BUFFER_SIZE |
ABBWelcomeData::to_string() |
ABBWelcomeData::format_to() |
ABBWelcomeData::FORMAT_BUFFER_SIZE (192) |
Who This Affects
- External components using any of the deprecated functions
- YAML lambdas that call these functions
Standard YAML configurations are not affected.
Migration Guide
1. format_hex()
// Before - heap allocation
std::string hex = format_hex(data);
ESP_LOGD(TAG, "Data: %s", hex.c_str());
// After - stack buffer
char hex[64]; // size = 2 * data.size() + 1
ESP_LOGD(TAG, "Data: %s", format_hex_to(hex, data));
2. format_hex_pretty()
// Before - heap allocation
std::string hex = format_hex_pretty(data);
ESP_LOGD(TAG, "Data: %s", hex.c_str());
// After - stack buffer
char hex[96]; // size = 3 * data.size()
ESP_LOGD(TAG, "Data: %s", format_hex_pretty_to(hex, data));
3. get_mac_address()
// Before - heap allocation
std::string mac = get_mac_address();
ESP_LOGD(TAG, "MAC: %s", mac.c_str());
// After - stack buffer
char mac[MAC_ADDRESS_BUFFER_SIZE];
get_mac_address_into_buffer(mac);
ESP_LOGD(TAG, "MAC: %s", mac);
4. get_mac_address_pretty()
// Before - heap allocation
std::string mac = get_mac_address_pretty();
ESP_LOGD(TAG, "MAC: %s", mac.c_str());
// After - stack buffer
char mac[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
get_mac_address_pretty_into_buffer(mac);
ESP_LOGD(TAG, "MAC: %s", mac);
5. value_accuracy_to_string()
// Before - heap allocation
std::string value = value_accuracy_to_string(sensor_value, accuracy);
ESP_LOGD(TAG, "Value: %s", value.c_str());
// After - stack buffer
char value[VALUE_ACCURACY_MAX_LEN];
value_accuracy_to_buf(value, sensor_value, accuracy);
ESP_LOGD(TAG, "Value: %s", value);
// With unit of measurement
char value_uom[VALUE_ACCURACY_MAX_LEN];
value_accuracy_with_uom_to_buf(value_uom, sensor_value, accuracy, "C");
6. get_object_id()
// Before - heap allocation
std::string id = sensor->get_object_id();
ESP_LOGD(TAG, "ID: %s", id.c_str());
// After - stack buffer (returns StringRef wrapping the buffer)
char buf[OBJECT_ID_MAX_LEN];
StringRef id = sensor->get_object_id_to(buf);
ESP_LOGD(TAG, "ID: %s", id.c_str());
// Or use get_name() for logging (often better)
ESP_LOGD(TAG, "Name: %s", sensor->get_name().c_str());
7. MideaData::to_string()
// Before - heap allocation
std::string str = midea_data.to_string();
ESP_LOGD(TAG, "Data: %s", str.c_str());
// After - stack buffer
char str[MideaData::TO_STR_BUFFER_SIZE];
ESP_LOGD(TAG, "Data: %s", midea_data.to_str(str));
8. ABBWelcomeData::to_string()
// Before - heap allocation
std::string str = abb_data.to_string();
ESP_LOGD(TAG, "Data: %s", str.c_str());
// After - stack buffer
char str[ABBWelcomeData::FORMAT_BUFFER_SIZE];
abb_data.format_to(str);
ESP_LOGD(TAG, "Data: %s", str);
Supporting Multiple ESPHome Versions
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2026, 1, 0)
// New API - stack-based
char mac[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
get_mac_address_pretty_into_buffer(mac);
ESP_LOGD(TAG, "MAC: %s", mac);
#else
// Old API - heap-allocating
ESP_LOGD(TAG, "MAC: %s", get_mac_address_pretty().c_str());
#endif
Timeline
- ESPHome 2026.1.0 (January 2026): Deprecation warnings active
- ESPHome 2026.7.0 (July 2026):
get_object_id()removed; other deprecated functions may be removed
Finding Code That Needs Updates
# Find deprecated function calls
grep -rn "format_hex(" your_component/
grep -rn "format_hex_pretty(" your_component/
grep -rn "get_mac_address(" your_component/
grep -rn "get_mac_address_pretty(" your_component/
grep -rn "value_accuracy_to_string(" your_component/
grep -rn "get_object_id(" your_component/
grep -rn "\.to_string(" your_component/
Questions?
If you have questions about migrating your external component, please ask in:
- ESPHome Discord - #devs channel
- ESPHome GitHub Discussions
Related Documentation
- Memory Management Guidelines
- PR #13156: Core helpers
- PR #13157: MAC address
- PR #13158: format_hex_pretty
- PR #13159: value_accuracy
- PR #12799: ABBWelcome
- PR #12629: get_object_id
Comments
Feel free to leave a comment here to discuss this post wth others. You can ask questions, share your experience, or suggest improvements. If you have a question about a specific feature or issue, please consider using the ESPHome Discord. Stick to English and follow ESPHome's code of conduct. These comments exist on a discussion on GitHub, so you can also comment there directly if you prefer.