From 6097aa9e4c254c1475e6cb7bb1a04d8c4dbce251 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 11:13:33 -0600 Subject: [PATCH 1/6] [blog] Add breaking change blog post for Event entity memory optimizations --- docs/blog/.authors.yml | 5 + .../2025-11-07-event-entity-optimizations.md | 249 ++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 docs/blog/posts/2025-11-07-event-entity-optimizations.md diff --git a/docs/blog/.authors.yml b/docs/blog/.authors.yml index 79fb79a..e9ec355 100644 --- a/docs/blog/.authors.yml +++ b/docs/blog/.authors.yml @@ -9,3 +9,8 @@ authors: description: ESPHome Maintainer avatar: https://github.com/kbx81.png url: https://github.com/kbx81 + bdraco: + name: J. Nick Koston + description: ESPHome Maintainer + avatar: https://github.com/bdraco.png + url: https://github.com/bdraco diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md new file mode 100644 index 0000000..a3eb02a --- /dev/null +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -0,0 +1,249 @@ +--- +date: 2025-11-07 +authors: + - bdraco +comments: true +--- + +# Event Entity Class: Memory Optimizations + +ESPHome 2025.11.0 introduces memory optimizations to the `Event` entity class that reduce heap usage. These changes affect external components implementing custom event devices. + + + +## Background + +### Motivation + +Event components use a set of valid event type strings to validate triggers. Using `std::set` for this small list (typically 1-5 event types) wastes significant memory: + +- **std::set overhead**: ~80 bytes of base red-black tree structure +- **Per-member overhead**: Each string requires tree node allocation (~24+ bytes) plus string data +- **Performance overhead**: O(log n) tree traversal for lookups, even for tiny datasets + +For typical event use cases with 1-5 event types, a simple vector with linear search is both faster and uses far less memory. Linear search on 1-5 items is faster than tree traversal due to better cache locality. + +### Changes + +**[PR #11463](https://github.com/esphome/esphome/pull/11463): Replace std::set with FixedVector** + +Changes event type storage from `std::set` (red-black tree on heap) to `FixedVector` (single allocation, no reallocation overhead). Saves ~80 bytes of base std::set overhead plus per-member node overhead. + +## What's Changing + +### For ESPHome 2025.11.0 and Later + +**Event Type Storage Changes (Mostly Backward Compatible - [PR #11463](https://github.com/esphome/esphome/pull/11463)):** + +```cpp +// OLD - std::set in heap +#include +std::set event_types = {"button_press", "button_release"}; +event->set_event_types(event_types); +std::set types = event->get_event_types(); + +// NEW - FixedVector (but initializer list still works!) +#include "esphome/core/helpers.h" +event->set_event_types({"button_press", "button_release"}); +const FixedVector &types = event->get_event_types(); +``` + +## Who This Affects + +**Event Type Changes (PR #11463) - External components mostly backward compatible:** +- Most components already pass initializer lists like `{"button_press", "button_release"}` which continue to work +- `set_event_types()` accepts `std::initializer_list` which works with both explicit sets and brace initialization +- No core components needed changes, so external components are unlikely to need changes +- **Breaking edge case:** Explicitly passing `std::set` to `set_event_types()` will fail to compile (no longer has std::set overload) +- **Breaking change:** `get_event_types()` now returns `const FixedVector &` instead of `std::set` by value +- Event type lookups now use linear search instead of std::set::find() + +**Standard YAML configurations** work without code changes. + +## Migration Guide for External Components + +### 1. Update Container Types (If Storing Event Types) + +```cpp +// OLD +#include +std::set event_types_; + +// NEW +#include "esphome/core/helpers.h" +FixedVector event_types_; +``` + +### 2. Update Setter Calls (Only If You Explicitly Created std::set Variables) + +**Note:** Most components already pass initializer lists directly and don't need changes. This only affects code that explicitly creates `std::set` variables (which no core components did). + +```cpp +// OLD - explicitly creating std::set (uncommon, will fail to compile) +std::set types = {"button_press", "button_release"}; +event->set_event_types(types); // No longer has std::set overload + +// NEW - initializer list (most components already did this) +event->set_event_types({"button_press", "button_release"}); + +// OR - use FixedVector +FixedVector types; +types.init(2); +types.push_back("button_press"); +types.push_back("button_release"); +event->set_event_types(types); // Still works if you convert to initializer_list +``` + +### 3. Update Getter Usage (Required If You Call get_event_types()) + +```cpp +// OLD - returns std::set by value +std::set types = event->get_event_types(); +for (const auto &type : types) { + // Use type +} + +// NEW - returns const FixedVector & +const FixedVector &types = event->get_event_types(); +for (const auto &type : types) { + // Use type (same iteration syntax) +} +``` + +### 4. Update Event Type Lookups (If You Check Valid Types Manually) + +```cpp +// OLD - std::set::find +auto types = event->get_event_types(); +if (types.find("button_press") != types.end()) { + // Type is valid +} + +// NEW - linear search (or use std::find) +const auto &types = event->get_event_types(); +bool found = false; +for (const auto &type : types) { + if (type == "button_press") { + found = true; + break; + } +} + +// OR - use std::find from +#include +const auto &types = event->get_event_types(); +if (std::find(types.begin(), types.end(), "button_press") != types.end()) { + // Type is valid +} +``` + +**Note:** For typical event use cases (1-5 event types), linear search is faster than std::set due to better cache locality. + +## Complete Migration Example + +### Custom Event Component + +**Before:** +```cpp +#include + +class MyEvent : public event::Event { + public: + void setup() override { + std::set types = {"motion_detected", "motion_cleared"}; + this->set_event_types(types); + } + + void check_valid_type(const std::string &type) { + auto types = this->get_event_types(); + if (types.find(type) != types.end()) { + ESP_LOGD("event", "Valid type: %s", type.c_str()); + } + } +}; +``` + +**After:** +```cpp +#include "esphome/core/helpers.h" + +class MyEvent : public event::Event { + public: + void setup() override { + this->set_event_types({"motion_detected", "motion_cleared"}); + } + + void check_valid_type(const std::string &type) { + const auto &types = this->get_event_types(); + bool found = std::find(types.begin(), types.end(), type) != types.end(); + if (found) { + ESP_LOGD("event", "Valid type: %s", type.c_str()); + } + } +}; +``` + +## FixedVector Details + +### What is FixedVector? + +`FixedVector` is a helper class from `esphome/core/helpers.h` that: + +- Allocates memory once during initialization (no reallocation overhead) +- Provides vector-like interface (`push_back()`, `begin()`, `end()`, `size()`) +- Eliminates STL reallocation machinery (no `_M_realloc_insert` bloat) +- Compatible with initializer_list construction + +```cpp +FixedVector types; +types.init(3); // Pre-allocate space for 3 elements +types.push_back("type1"); +types.push_back("type2"); +types.push_back("type3"); + +// Iteration works the same as std::vector +for (const auto &type : types) { + ESP_LOGD("event", "Type: %s", type.c_str()); +} +``` + +### Performance Benefits + +For typical event use cases (1-5 event types): + +- **Memory**: Single allocation vs ~80 bytes base overhead + per-node overhead +- **Lookup speed**: O(n) linear search, but faster than O(log n) tree traversal for small n due to cache locality +- **No reallocation**: FixedVector size is set once, no STL reallocation overhead + +## Timeline + +- **ESPHome 2025.11.0 (November 2025):** + - Event type storage changes are active + - Mostly backward compatible (only breaks explicit std::set passing) + +## Finding Code That Needs Updates + +Search your external component code for these patterns: + +```bash +# Find std::set usage for event types +grep -r 'std::set<.*string>.*event' --include='*.cpp' --include='*.h' + +# Find set_event_types calls +grep -r 'set_event_types' --include='*.cpp' --include='*.h' + +# Find get_event_types calls +grep -r 'get_event_types' --include='*.cpp' --include='*.h' + +# Find event type lookups +grep -r 'types.*find\|event.*find' --include='*.cpp' --include='*.h' +``` + +## Questions? + +If you have questions about these changes or need help migrating your external component, please ask in the [ESPHome Discord](https://discord.gg/KhAMKrd) or open a [discussion on GitHub](https://github.com/esphome/esphome/discussions). + +## Related Documentation + +- [Event Component Documentation](https://esphome.io/components/event/index.html) +- [PR #11463: Replace std::set with FixedVector](https://github.com/esphome/esphome/pull/11463) From 03c81e6fd4084efce19a742b6dbf8cce0a337dfc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 13:52:34 -0600 Subject: [PATCH 2/6] fixes --- .../2025-11-07-event-entity-optimizations.md | 232 ++++++++++++------ 1 file changed, 152 insertions(+), 80 deletions(-) diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md index a3eb02a..0cc34d1 100644 --- a/docs/blog/posts/2025-11-07-event-entity-optimizations.md +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -7,7 +7,7 @@ comments: true # Event Entity Class: Memory Optimizations -ESPHome 2025.11.0 introduces memory optimizations to the `Event` entity class that reduce heap usage. These changes affect external components implementing custom event devices. +ESPHome 2025.11.0 introduces memory optimizations to the `Event` entity class that reduce heap usage and store event type strings in flash. These changes affect external components implementing custom event devices. @@ -18,45 +18,64 @@ ESPHome 2025.11.0 introduces memory optimizations to the `Event` entity class th Event components use a set of valid event type strings to validate triggers. Using `std::set` for this small list (typically 1-5 event types) wastes significant memory: - **std::set overhead**: ~80 bytes of base red-black tree structure -- **Per-member overhead**: Each string requires tree node allocation (~24+ bytes) plus string data +- **Per-member overhead**: Each string requires tree node allocation (~24+ bytes) +- **std::string overhead**: Each string allocates on heap (~24 bytes overhead + string content) - **Performance overhead**: O(log n) tree traversal for lookups, even for tiny datasets For typical event use cases with 1-5 event types, a simple vector with linear search is both faster and uses far less memory. Linear search on 1-5 items is faster than tree traversal due to better cache locality. +Additionally, storing event type strings as `const char *` pointers to string literals moves the data from heap to flash (ESP32) or rodata (ESP8266), further reducing memory pressure. + ### Changes -**[PR #11463](https://github.com/esphome/esphome/pull/11463): Replace std::set with FixedVector** +Event type storage has been optimized through two PRs to eliminate memory overhead and move strings to flash: + +**[PR #11463](https://github.com/esphome/esphome/pull/11463): std::set → FixedVector** +- Eliminated ~80 bytes std::set base overhead +- Eliminated per-member tree node overhead (~24+ bytes per event type) +- Single allocation, no reallocation overhead + +**[PR #11767](https://github.com/esphome/esphome/pull/11767): FixedVector → FixedVector** +- Eliminates std::string heap allocations (~24 bytes overhead + content per event type) +- **ESP32**: Event type strings stored in flash (ROM), freeing heap +- **ESP8266**: Event type strings in rodata section (still RAM, but eliminates std::string overhead) +- Uses FixedVector (same as Select entity pattern - returned by const reference, never by value) -Changes event type storage from `std::set` (red-black tree on heap) to `FixedVector` (single allocation, no reallocation overhead). Saves ~80 bytes of base std::set overhead plus per-member node overhead. +**Combined result:** Event types changed from `std::set` → `FixedVector` + +**Performance:** O(n) linear search with strcmp, faster than O(log n) tree traversal for typical 1-5 event types due to cache locality. ## What's Changing ### For ESPHome 2025.11.0 and Later -**Event Type Storage Changes (Mostly Backward Compatible - [PR #11463](https://github.com/esphome/esphome/pull/11463)):** +**Event Type Storage Changes (Breaking - two PRs in same release):** ```cpp -// OLD - std::set in heap +// OLD (before 2025.11.0) - std::set in heap #include std::set event_types = {"button_press", "button_release"}; event->set_event_types(event_types); std::set types = event->get_event_types(); -// NEW - FixedVector (but initializer list still works!) -#include "esphome/core/helpers.h" +// NEW (2025.11.0) - FixedVector (initializer list still works!) event->set_event_types({"button_press", "button_release"}); -const FixedVector &types = event->get_event_types(); +const FixedVector &types = event->get_event_types(); ``` +**Note:** If your external component was already updated for the intermediate `FixedVector` change, you'll need to update again for `FixedVector`. Most components using initializer list syntax require minimal changes. + ## Who This Affects -**Event Type Changes (PR #11463) - External components mostly backward compatible:** -- Most components already pass initializer lists like `{"button_press", "button_release"}` which continue to work -- `set_event_types()` accepts `std::initializer_list` which works with both explicit sets and brace initialization -- No core components needed changes, so external components are unlikely to need changes -- **Breaking edge case:** Explicitly passing `std::set` to `set_event_types()` will fail to compile (no longer has std::set overload) -- **Breaking change:** `get_event_types()` now returns `const FixedVector &` instead of `std::set` by value -- Event type lookups now use linear search instead of std::set::find() +**Event Type Changes (PR #11767) - External components need updates:** +- **Breaking change:** `set_event_types()` now requires `const char *` strings (string literals) +- **Breaking change:** `get_event_types()` now returns `const FixedVector &` instead of `std::set` +- **Breaking change:** `last_event_type` is now private - use `get_last_event_type()` accessor instead +- Most components already pass string literal initializer lists like `{"button_press", "button_release"}` which continue to work +- Setter accepts initializer_list, FixedVector, or std::vector of const char * (same as Select options pattern) +- Loop variables must change from `const std::string &` to `const char *` +- Event type comparisons must use `strcmp()` instead of `==` operator +- No core ESPHome components needed changes (all used initializer list syntax) **Standard YAML configurations** work without code changes. @@ -69,75 +88,97 @@ const FixedVector &types = event->get_event_types(); #include std::set event_types_; -// NEW -#include "esphome/core/helpers.h" -FixedVector event_types_; +// NEW - Use FixedVector (most common) +FixedVector event_types_; + +// OR - Use std::vector if you need copyability +#include +std::vector event_types_; ``` -### 2. Update Setter Calls (Only If You Explicitly Created std::set Variables) +### 2. Update Setter Calls -**Note:** Most components already pass initializer lists directly and don't need changes. This only affects code that explicitly creates `std::set` variables (which no core components did). +**Most components already use string literals and won't need changes:** ```cpp -// OLD - explicitly creating std::set (uncommon, will fail to compile) -std::set types = {"button_press", "button_release"}; -event->set_event_types(types); // No longer has std::set overload - -// NEW - initializer list (most components already did this) +// STILL WORKS - string literal initializer list (most common, no changes needed) event->set_event_types({"button_press", "button_release"}); -// OR - use FixedVector -FixedVector types; -types.init(2); -types.push_back("button_press"); -types.push_back("button_release"); -event->set_event_types(types); // Still works if you convert to initializer_list +// OLD - explicitly creating std::set (will fail to compile) +std::set types = {"button_press", "button_release"}; +event->set_event_types(types); // Deleted overload, no longer supported ``` +**Note:** Accepts initializer list, FixedVector, or std::vector. Same pattern as Select options. + ### 3. Update Getter Usage (Required If You Call get_event_types()) ```cpp -// OLD - returns std::set by value +// OLD - returns std::set by value std::set types = event->get_event_types(); -for (const auto &type : types) { - // Use type +for (const std::string &type : types) { + ESP_LOGD("event", "Type: %s", type.c_str()); } -// NEW - returns const FixedVector & -const FixedVector &types = event->get_event_types(); -for (const auto &type : types) { - // Use type (same iteration syntax) +// NEW - returns const FixedVector & +const FixedVector &types = event->get_event_types(); +for (const char *type : types) { + ESP_LOGD("event", "Type: %s", type); +} + +// Or use auto +const auto &types = event->get_event_types(); +for (const char *type : types) { + ESP_LOGD("event", "Type: %s", type); } ``` -### 4. Update Event Type Lookups (If You Check Valid Types Manually) +### 4. Update last_event_type Access (If You Access This Field) ```cpp -// OLD - std::set::find +// OLD - direct field access +if (event->last_event_type != nullptr) { + ESP_LOGD("event", "Last: %s", event->last_event_type); +} + +// NEW - use getter +if (event->get_last_event_type() != nullptr) { + ESP_LOGD("event", "Last: %s", event->get_last_event_type()); +} +``` + +**Why this change?** Moving `last_event_type` to private with controlled access ensures pointer lifetime safety. The field is now guaranteed to always point to a string in `types_` (or be nullptr), preventing dangling pointer bugs when event types are reconfigured. + +### 5. Update Event Type Lookups (If You Check Valid Types Manually) + +```cpp +// OLD - std::set::find with std::string auto types = event->get_event_types(); if (types.find("button_press") != types.end()) { // Type is valid } -// NEW - linear search (or use std::find) +// NEW - linear search with strcmp const auto &types = event->get_event_types(); bool found = false; -for (const auto &type : types) { - if (type == "button_press") { +for (const char *type : types) { + if (strcmp(type, "button_press") == 0) { found = true; break; } } -// OR - use std::find from +// OR - use std::find_if with strcmp #include const auto &types = event->get_event_types(); -if (std::find(types.begin(), types.end(), "button_press") != types.end()) { +auto it = std::find_if(types.begin(), types.end(), + [](const char *t) { return strcmp(t, "button_press") == 0; }); +if (it != types.end()) { // Type is valid } ``` -**Note:** For typical event use cases (1-5 event types), linear search is faster than std::set due to better cache locality. +**Note:** For typical event use cases (1-5 event types), linear search with strcmp is faster than std::set due to better cache locality. ## Complete Migration Example @@ -160,66 +201,90 @@ class MyEvent : public event::Event { ESP_LOGD("event", "Valid type: %s", type.c_str()); } } + + void iterate_types() { + for (const std::string &type : this->get_event_types()) { + ESP_LOGD("event", "Type: %s", type.c_str()); + } + } + + void log_last_event() { + if (this->last_event_type != nullptr) { + ESP_LOGD("event", "Last event: %s", this->last_event_type); + } + } }; ``` **After:** ```cpp -#include "esphome/core/helpers.h" +#include class MyEvent : public event::Event { public: void setup() override { + // String literals work directly (most common pattern) this->set_event_types({"motion_detected", "motion_cleared"}); } void check_valid_type(const std::string &type) { const auto &types = this->get_event_types(); - bool found = std::find(types.begin(), types.end(), type) != types.end(); + bool found = false; + for (const char *t : types) { + if (strcmp(t, type.c_str()) == 0) { + found = true; + break; + } + } if (found) { ESP_LOGD("event", "Valid type: %s", type.c_str()); } } -}; -``` -## FixedVector Details + void iterate_types() { + // Loop variable changed to const char * + for (const char *type : this->get_event_types()) { + ESP_LOGD("event", "Type: %s", type); // No .c_str() needed + } + } -### What is FixedVector? + void log_last_event() { + // Use getter instead of direct field access + if (this->get_last_event_type() != nullptr) { + ESP_LOGD("event", "Last event: %s", this->get_last_event_type()); + } + } +}; +``` -`FixedVector` is a helper class from `esphome/core/helpers.h` that: +## FixedVector Benefits -- Allocates memory once during initialization (no reallocation overhead) -- Provides vector-like interface (`push_back()`, `begin()`, `end()`, `size()`) -- Eliminates STL reallocation machinery (no `_M_realloc_insert` bloat) -- Compatible with initializer_list construction +For typical event use cases (1-5 event types): -```cpp -FixedVector types; -types.init(3); // Pre-allocate space for 3 elements -types.push_back("type1"); -types.push_back("type2"); -types.push_back("type3"); - -// Iteration works the same as std::vector -for (const auto &type : types) { - ESP_LOGD("event", "Type: %s", type.c_str()); -} -``` +- **Memory**: Eliminates ~80 bytes std::set overhead + per-node overhead + std::string overhead +- **Lookup speed**: O(n) linear search with strcmp, faster than O(log n) tree traversal for small n due to cache locality +- **Flash storage**: String literals stored in flash (ESP32) or rodata (ESP8266), not heap +- **Single allocation**: FixedVector allocates once at runtime initialization, no reallocation overhead -### Performance Benefits +### Platform-Specific Benefits -For typical event use cases (1-5 event types): +**ESP32 (IDF and Arduino):** +- Event type strings stored in flash memory (ROM) +- Zero heap usage for event type strings +- Maximum heap available for other operations -- **Memory**: Single allocation vs ~80 bytes base overhead + per-node overhead -- **Lookup speed**: O(n) linear search, but faster than O(log n) tree traversal for small n due to cache locality -- **No reallocation**: FixedVector size is set once, no STL reallocation overhead +**ESP8266:** +- Event type strings in rodata section (still occupies RAM) +- Eliminates std::string heap overhead (~24 bytes per string + content) +- Reduces heap fragmentation ## Timeline - **ESPHome 2025.11.0 (November 2025):** - - Event type storage changes are active - - Mostly backward compatible (only breaks explicit std::set passing) + - Both optimizations active in same release + - [PR #11463](https://github.com/esphome/esphome/pull/11463): std::set → FixedVector (merged) + - [PR #11767](https://github.com/esphome/esphome/pull/11767): FixedVector → FixedVector (in progress) + - External components only need to migrate once (from std::set to FixedVector) ## Finding Code That Needs Updates @@ -235,8 +300,14 @@ grep -r 'set_event_types' --include='*.cpp' --include='*.h' # Find get_event_types calls grep -r 'get_event_types' --include='*.cpp' --include='*.h' -# Find event type lookups -grep -r 'types.*find\|event.*find' --include='*.cpp' --include='*.h' +# Find event type lookups with std::string +grep -r 'for.*std::string.*get_event_types' --include='*.cpp' --include='*.h' + +# Find std::string comparisons that might need strcmp +grep -r 'event_type.*==' --include='*.cpp' --include='*.h' + +# Find direct last_event_type field access +grep -r '->last_event_type\|\.last_event_type' --include='*.cpp' --include='*.h' ``` ## Questions? @@ -246,4 +317,5 @@ If you have questions about these changes or need help migrating your external c ## Related Documentation - [Event Component Documentation](https://esphome.io/components/event/index.html) -- [PR #11463: Replace std::set with FixedVector](https://github.com/esphome/esphome/pull/11463) +- [PR #11463: Replace std::set with FixedVector for event type storage](https://github.com/esphome/esphome/pull/11463) +- [PR #11767: Store event types in flash memory](https://github.com/esphome/esphome/pull/11767) From f17ef089032f1770206fc1d1c8c99dcf17ed86a6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 13:57:48 -0600 Subject: [PATCH 3/6] fixes --- docs/blog/posts/2025-11-07-event-entity-optimizations.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md index 0cc34d1..39e1a6d 100644 --- a/docs/blog/posts/2025-11-07-event-entity-optimizations.md +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -68,6 +68,7 @@ const FixedVector &types = event->get_event_types(); ## Who This Affects **Event Type Changes (PR #11767) - External components need updates:** + - **Breaking change:** `set_event_types()` now requires `const char *` strings (string literals) - **Breaking change:** `get_event_types()` now returns `const FixedVector &` instead of `std::set` - **Breaking change:** `last_event_type` is now private - use `get_last_event_type()` accessor instead @@ -282,9 +283,9 @@ For typical event use cases (1-5 event types): - **ESPHome 2025.11.0 (November 2025):** - Both optimizations active in same release - - [PR #11463](https://github.com/esphome/esphome/pull/11463): std::set → FixedVector (merged) - - [PR #11767](https://github.com/esphome/esphome/pull/11767): FixedVector → FixedVector (in progress) - - External components only need to migrate once (from std::set to FixedVector) + - [PR #11463](https://github.com/esphome/esphome/pull/11463): `std::set` → `FixedVector` + - [PR #11767](https://github.com/esphome/esphome/pull/11767): `FixedVector` → `FixedVector` + - External components only need to migrate once (from `std::set` to `FixedVector`) ## Finding Code That Needs Updates From c02cc6cdc65d96203d44d5b8050e5834f1f1e292 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 14:00:07 -0600 Subject: [PATCH 4/6] fixes --- docs/blog/posts/2025-11-07-event-entity-optimizations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md index 39e1a6d..31af58c 100644 --- a/docs/blog/posts/2025-11-07-event-entity-optimizations.md +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -30,12 +30,12 @@ Additionally, storing event type strings as `const char *` pointers to string li Event type storage has been optimized through two PRs to eliminate memory overhead and move strings to flash: -**[PR #11463](https://github.com/esphome/esphome/pull/11463): std::set → FixedVector** +**[PR #11463](https://github.com/esphome/esphome/pull/11463): `std::set` → `FixedVector`** - Eliminated ~80 bytes std::set base overhead - Eliminated per-member tree node overhead (~24+ bytes per event type) - Single allocation, no reallocation overhead -**[PR #11767](https://github.com/esphome/esphome/pull/11767): FixedVector → FixedVector** +**[PR #11767](https://github.com/esphome/esphome/pull/11767): `FixedVector` → `FixedVector`** - Eliminates std::string heap allocations (~24 bytes overhead + content per event type) - **ESP32**: Event type strings stored in flash (ROM), freeing heap - **ESP8266**: Event type strings in rodata section (still RAM, but eliminates std::string overhead) From 900ac8b9d348e37dfaad2e801b80148e06ef4817 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 14:00:37 -0600 Subject: [PATCH 5/6] fixes --- docs/blog/posts/2025-11-07-event-entity-optimizations.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md index 31af58c..b31589d 100644 --- a/docs/blog/posts/2025-11-07-event-entity-optimizations.md +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -39,7 +39,7 @@ Event type storage has been optimized through two PRs to eliminate memory overhe - Eliminates std::string heap allocations (~24 bytes overhead + content per event type) - **ESP32**: Event type strings stored in flash (ROM), freeing heap - **ESP8266**: Event type strings in rodata section (still RAM, but eliminates std::string overhead) -- Uses FixedVector (same as Select entity pattern - returned by const reference, never by value) +- Uses `FixedVector` (same as Select entity pattern - returned by const reference, never by value) **Combined result:** Event types changed from `std::set` → `FixedVector` @@ -110,7 +110,7 @@ std::set types = {"button_press", "button_release"}; event->set_event_types(types); // Deleted overload, no longer supported ``` -**Note:** Accepts initializer list, FixedVector, or std::vector. Same pattern as Select options. +**Note:** Accepts initializer list, `FixedVector`, or `std::vector`. Same pattern as Select options. ### 3. Update Getter Usage (Required If You Call get_event_types()) @@ -258,7 +258,7 @@ class MyEvent : public event::Event { }; ``` -## FixedVector Benefits +## `FixedVector` Benefits For typical event use cases (1-5 event types): From 6ca1b58964b599542ab80265785568ee7bd2cb81 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 7 Nov 2025 14:00:40 -0600 Subject: [PATCH 6/6] fixes --- docs/blog/posts/2025-11-07-event-entity-optimizations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/blog/posts/2025-11-07-event-entity-optimizations.md b/docs/blog/posts/2025-11-07-event-entity-optimizations.md index b31589d..a6c9975 100644 --- a/docs/blog/posts/2025-11-07-event-entity-optimizations.md +++ b/docs/blog/posts/2025-11-07-event-entity-optimizations.md @@ -73,7 +73,7 @@ const FixedVector &types = event->get_event_types(); - **Breaking change:** `get_event_types()` now returns `const FixedVector &` instead of `std::set` - **Breaking change:** `last_event_type` is now private - use `get_last_event_type()` accessor instead - Most components already pass string literal initializer lists like `{"button_press", "button_release"}` which continue to work -- Setter accepts initializer_list, FixedVector, or std::vector of const char * (same as Select options pattern) +- Setter accepts `initializer_list`, `FixedVector`, or `std::vector` of `const char *` (same as Select options pattern) - Loop variables must change from `const std::string &` to `const char *` - Event type comparisons must use `strcmp()` instead of `==` operator - No core ESPHome components needed changes (all used initializer list syntax)