The owned vectors add 48 bytes to ClimateTraits copies — this is the
cost of backward compat and will be removed in 2026.11.0.
Add ClimatePublish_WithCustomModes benchmark to show the improvement
for climate devices that use custom fan modes and presets (the case
that previously heap-allocated on every publish).
FanTraits contained a std::vector<const char *> for preset modes.
Every get_traits() call reconstructed this vector, causing heap
allocations on every publish_state() and control()/perform() call.
Move the vector storage to the Fan base class and have FanTraits hold
a const pointer instead. Internal callers (save_state_, find_preset_mode_)
search the Fan-owned vector directly, avoiding traits reconstruction.
The old FanTraits setters are preserved as deprecated compatibility
overloads (removed in 2026.11.0) that self-own the data, so external
components continue to compile — they just get a deprecation warning
and still heap-allocate until they migrate.
Keep the old set_supported_custom_fan_modes() and
set_supported_custom_presets() overloads on ClimateTraits as deprecated
compatibility shims. They self-own the data so external components
continue to compile without changes (heap alloc but functional).
Restores get_supported_custom_fan_modes() / get_supported_custom_presets()
to return const vector & (not pointer) for full backward compat.
ClimateTraits contained two std::vector<const char *> members for custom
fan modes and custom presets. Every get_traits() / traits() call
reconstructed these vectors, causing heap allocations on every
publish_state() and control()/perform() call — the hottest paths in the
climate component.
Move the vector storage to the Climate base class and have ClimateTraits
hold const pointers instead. get_traits() wires the pointers
automatically. This eliminates all heap allocation from ClimateTraits
copies, making the struct trivially copyable (floats + bitmasks +
2 pointers).
Additionally, set_custom_fan_mode_() and set_custom_preset_() no longer
need to call get_traits() just to search for a mode — they search the
Climate-owned vectors directly, removing another traits rebuild from the
control/perform path.
The compiled ESPHOME_LOG_LEVEL is what matters - all log calls up
to that level are in the binary and will format/block UART regardless
of runtime initial_level.
Add a warning in dump_config() when the active log level is
VERBOSE or VERY_VERBOSE to remind users these levels are intended
for short-term debugging only.
VERY_VERBOSE triggers an ESP_LOGW, VERBOSE triggers an ESP_LOGI.
Both are guarded by compile-time #if/#elif so no code is added
when compiled at a lower log level.