Skip to content

Commit f66199a

Browse files
authored
Add blog post for network::get_use_address() breaking change (#78)
1 parent 08ee5ef commit f66199a

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
---
2+
date: 2025-11-20
3+
authors:
4+
- bdraco
5+
comments: true
6+
---
7+
8+
# Network get_use_address() Optimization
9+
10+
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.
11+
12+
This is a **breaking change** for external components that call `network::get_use_address()` in **ESPHome 2025.11.0 and later**.
13+
14+
<!-- more -->
15+
16+
## What needs to change
17+
18+
External components must remove `.c_str()` calls when using `get_use_address()`:
19+
20+
```cpp
21+
// ❌ Before 2025.11
22+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
23+
esphome::network::get_use_address().c_str(), this->port_);
24+
25+
// ✅ After 2025.11
26+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
27+
esphome::network::get_use_address(), this->port_);
28+
```
29+
30+
## Compilation errors
31+
32+
External components using `.c_str()` will fail with:
33+
34+
```
35+
error: member reference base type 'const char *' is not a structure or union
36+
esphome::network::get_use_address().c_str()
37+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
38+
```
39+
40+
The fix is simple: remove `.c_str()`.
41+
42+
## Common usage patterns
43+
44+
### Logging (most common)
45+
46+
```cpp
47+
// Before 2025.11
48+
ESP_LOGD(TAG, "Connecting to %s",
49+
esphome::network::get_use_address().c_str());
50+
51+
// After 2025.11
52+
ESP_LOGD(TAG, "Connecting to %s",
53+
esphome::network::get_use_address());
54+
```
55+
56+
### Storing the address
57+
58+
If you need to store the address in a `std::string`:
59+
60+
```cpp
61+
// Before 2025.11
62+
std::string address = esphome::network::get_use_address();
63+
64+
// After 2025.11 (still works - implicit conversion)
65+
std::string address = esphome::network::get_use_address();
66+
67+
// After 2025.11 (more efficient if you don't need mutation)
68+
const char *address = esphome::network::get_use_address();
69+
```
70+
71+
### Passing to functions
72+
73+
```cpp
74+
// Before 2025.11
75+
this->client_->connect(esphome::network::get_use_address().c_str(), port);
76+
77+
// After 2025.11
78+
this->client_->connect(esphome::network::get_use_address(), port);
79+
```
80+
81+
## Supporting multiple ESPHome versions
82+
83+
If your external component needs to support both old and new ESPHome versions:
84+
85+
```cpp
86+
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
87+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
88+
esphome::network::get_use_address(), this->port_);
89+
#else
90+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
91+
esphome::network::get_use_address().c_str(), this->port_);
92+
#endif
93+
```
94+
95+
### Cleaner version with macro
96+
97+
For components with many uses:
98+
99+
```cpp
100+
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
101+
#define GET_USE_ADDRESS() esphome::network::get_use_address()
102+
#else
103+
#define GET_USE_ADDRESS() esphome::network::get_use_address().c_str()
104+
#endif
105+
106+
// Then use throughout your code:
107+
ESP_LOGCONFIG(TAG, " Address: %s:%u", GET_USE_ADDRESS(), this->port_);
108+
```
109+
110+
## Affected components
111+
112+
This change affects the following network components:
113+
114+
- `wifi` - `wifi::get_use_address()`
115+
- `ethernet` - `ethernet::get_use_address()`
116+
- `openthread` - `openthread::get_use_address()`
117+
118+
All three now return `const char*` instead of `const std::string&`.
119+
120+
> **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()`, or `openthread::get_use_address()`) depending on your network configuration. Most external components should use the `network::` wrapper for generic code. Only use component-specific functions if your code explicitly depends on a particular network type.
121+
122+
## Why this change
123+
124+
The previous implementation stored the address internally as a `std::string` and returned a reference to it. This meant:
125+
126+
1. **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
127+
2. **Extra memory usage** - The `std::string` object itself uses heap memory plus object overhead (typically 24-32 bytes)
128+
3. **API complexity** - Callers needed to use `.c_str()` to access the raw address for logging, even though no conversion or copy was performed
129+
130+
By returning `const char*` directly and storing the address as a pointer to flash memory (RODATA):
131+
132+
- **Zero string object overhead** - No `std::string` objects are created or stored for the address
133+
- **Simpler API** - The address can be used directly in logging and C-style string functions
134+
- **Memory savings** - Eliminates the `std::string` overhead, saving 32-72 bytes of RAM per network component
135+
136+
## Real-world example
137+
138+
Here's the fix applied to [esphome-stream-server](https://github.com/oxan/esphome-stream-server/pull/58):
139+
140+
```cpp
141+
void StreamServerComponent::dump_config() {
142+
ESP_LOGCONFIG(TAG, "Stream Server:");
143+
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
144+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
145+
esphome::network::get_use_address(), this->port_);
146+
#else
147+
ESP_LOGCONFIG(TAG, " Address: %s:%u",
148+
esphome::network::get_use_address().c_str(), this->port_);
149+
#endif
150+
// ... rest of dump_config
151+
}
152+
```
153+
154+
## Finding code that needs updates
155+
156+
```bash
157+
# Find uses of get_use_address().c_str()
158+
grep -rn "get_use_address()\.c_str()" your_component/
159+
160+
# Check for all get_use_address() calls to review
161+
grep -rn "get_use_address()" your_component/
162+
```
163+
164+
## Reference Pull Request
165+
166+
- [esphome/esphome#11707](https://github.com/esphome/esphome/pull/11707)
167+
168+
## Questions?
169+
170+
If you have questions about migrating your external component, please ask in:
171+
172+
- [ESPHome Discord](https://discord.gg/KhAMKrd) - #devs channel
173+
- [ESPHome GitHub Discussions](https://github.com/esphome/esphome/discussions)

0 commit comments

Comments
 (0)