Network get_use_address() Optimization
The network::get_use_address() function has been optimized to return const char* instead of const std::string& to reduce memory overhead. This eliminates unnecessary string object storage when accessing the device's network address.
This is a breaking change for external components that call network::get_use_address() in ESPHome 2025.11.0 and later.
What needs to change
External components must remove .c_str() calls when using get_use_address():
// ❌ Before 2025.11
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address().c_str(), this->port_);
// ✅ After 2025.11
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address(), this->port_);
Compilation errors
External components using .c_str() will fail with:
error: member reference base type 'const char *' is not a structure or union
esphome::network::get_use_address().c_str()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
The fix is simple: remove .c_str().
Common usage patterns
Logging (most common)
// Before 2025.11
ESP_LOGD(TAG, "Connecting to %s",
esphome::network::get_use_address().c_str());
// After 2025.11
ESP_LOGD(TAG, "Connecting to %s",
esphome::network::get_use_address());
Storing the address
If you need to store the address in a std::string:
// Before 2025.11
std::string address = esphome::network::get_use_address();
// After 2025.11 (still works - implicit conversion)
std::string address = esphome::network::get_use_address();
// After 2025.11 (more efficient if you don't need mutation)
const char *address = esphome::network::get_use_address();
Passing to functions
// Before 2025.11
this->client_->connect(esphome::network::get_use_address().c_str(), port);
// After 2025.11
this->client_->connect(esphome::network::get_use_address(), port);
Supporting multiple ESPHome versions
If your external component needs to support both old and new ESPHome versions:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address(), this->port_);
#else
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address().c_str(), this->port_);
#endif
Cleaner version with macro
For components with many uses:
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
#define GET_USE_ADDRESS() esphome::network::get_use_address()
#else
#define GET_USE_ADDRESS() esphome::network::get_use_address().c_str()
#endif
// Then use throughout your code:
ESP_LOGCONFIG(TAG, " Address: %s:%u", GET_USE_ADDRESS(), this->port_);
Affected components
This change affects the following network components:
wifi-wifi::get_use_address()ethernet-ethernet::get_use_address()openthread-openthread::get_use_address()
All three now return const char* instead of const std::string&.
Note:
esphome::network::get_use_address()is a wrapper function that delegates to the appropriate component-specific function (wifi::get_use_address(),ethernet::get_use_address(), oropenthread::get_use_address()) depending on your network configuration. Most external components should use thenetwork::wrapper for generic code. Only use component-specific functions if your code explicitly depends on a particular network type.
Why this change
The previous implementation stored the address internally as a std::string and returned a reference to it. This meant:
- Unnecessary string object overhead - The address was stored as a
std::string, even though it is typically a static configuration value set once during setup - Extra memory usage - The
std::stringobject itself uses heap memory plus object overhead (typically 24-32 bytes) - API complexity - Callers needed to use
.c_str()to access the raw address for logging, even though no conversion or copy was performed
By returning const char* directly and storing the address as a pointer to flash memory (RODATA):
- Zero string object overhead - No
std::stringobjects are created or stored for the address - Simpler API - The address can be used directly in logging and C-style string functions
- Memory savings - Eliminates the
std::stringoverhead, saving 32-72 bytes of RAM per network component
Real-world example
Here's the fix applied to esphome-stream-server:
void StreamServerComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Stream Server:");
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address(), this->port_);
#else
ESP_LOGCONFIG(TAG, " Address: %s:%u",
esphome::network::get_use_address().c_str(), this->port_);
#endif
// ... rest of dump_config
}
Finding code that needs updates
# Find uses of get_use_address().c_str()
grep -rn "get_use_address()\.c_str()" your_component/
# Check for all get_use_address() calls to review
grep -rn "get_use_address()" your_component/
Reference Pull Request
Questions?
If you have questions about migrating your external component, please ask in:
- ESPHome Discord - #devs channel
- ESPHome GitHub Discussions
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.