Skip to content

Commit 82e785a

Browse files
authored
[blog] Add breaking change blog post for action framework const ref optimization (#66)
1 parent 98f303c commit 82e785a

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

docs/blog/.authors.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ authors:
99
description: ESPHome Maintainer
1010
avatar: https://github.com/kbx81.png
1111
url: https://github.com/kbx81
12+
bdraco:
13+
name: J. Nick Koston
14+
description: ESPHome Maintainer
15+
avatar: https://github.com/bdraco.png
16+
url: https://github.com/bdraco
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
date: 2025-11-06
3+
authors:
4+
- bdraco
5+
comments: true
6+
---
7+
8+
# Action Framework Performance Optimization
9+
10+
The core automation framework (actions, triggers, and conditions) has been optimized to use const references instead of pass-by-value for parameter passing. This reduces memory allocations by 83% in the automation execution path.
11+
12+
This is a **breaking change** for external components with custom actions or conditions in **ESPHome 2025.11.0 and later**.
13+
14+
## What needs to change
15+
16+
External components must update their action/condition method signatures to use const references:
17+
18+
```cpp
19+
// ❌ Before
20+
template<typename... Ts>
21+
class MyAction : public Action<Ts...> {
22+
void play(Ts... x) override {
23+
// ...
24+
}
25+
};
26+
27+
// ✅ After
28+
template<typename... Ts>
29+
class MyAction : public Action<Ts...> {
30+
void play(const Ts&... x) override { // ← Add const&
31+
// ... (no other changes needed)
32+
}
33+
};
34+
```
35+
36+
## All signatures to update
37+
38+
- `void play(Ts... x)` → `void play(const Ts&... x)`
39+
- `void play_complex(Ts... x)` → `void play_complex(const Ts&... x)`
40+
- `bool check(Ts... x)` → `bool check(const Ts&... x)`
41+
42+
## Compilation errors
43+
44+
External components will fail to compile with clear error messages pointing to the methods that need updating:
45+
46+
```
47+
error: no declaration matches 'void MyAction::play(Ts ...)'
48+
note: candidate is: 'void MyAction::play(const Ts& ...)'
49+
```
50+
51+
## Finding code that needs updates
52+
53+
```bash
54+
# Find actions/conditions that need updating
55+
grep -rn "void play(Ts\.\.\. \w\+) override" your_component/
56+
grep -rn "void play_complex(Ts\.\.\. \w\+) override" your_component/
57+
grep -rn "bool check(Ts\.\.\. \w\+) override" your_component/
58+
```
59+
60+
## Supporting multiple ESPHome versions
61+
62+
If your external component needs to support both old and new ESPHome versions, you can ifdef just the signature:
63+
64+
```cpp
65+
// Use version guards for just the signature
66+
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2025, 11, 0)
67+
void play(const Ts&... x) override
68+
#else
69+
void play(Ts... x) override
70+
#endif
71+
{
72+
// Implementation (no duplication needed)
73+
}
74+
```
75+
76+
## Why this change
77+
78+
Previously, the automation framework made **6 copies** of every argument as it passed through the call chain. For `std::string` arguments (like logger messages), this meant 6 heap allocations per trigger event.
79+
80+
The change eliminates these copies, resulting in **83% fewer heap allocations** at runtime.
81+
82+
## No logic changes required
83+
84+
This is a purely mechanical change - you only need to update method signatures. Your implementation logic does not need to change.
85+
86+
## Reference Pull Request
87+
88+
- [esphome/esphome#11704](https://github.com/esphome/esphome/pull/11704)
89+
90+
## Questions?
91+
92+
If you have questions about migrating your external component, please ask in:
93+
94+
- [ESPHome Discord](https://discord.gg/KhAMKrd) - #devs channel
95+
- [ESPHome GitHub Discussions](https://github.com/esphome/esphome/discussions)

0 commit comments

Comments
 (0)