When Pvariable types contain template arguments with :: (e.g.
Automation<std::optional<bool>>), the namespace extraction logic
incorrectly split on :: inside the template params, producing
invalid C++ identifiers like Automation<std__automation_id__pstorage.
Fix by stripping template arguments before extracting the namespace.
Extract the logic into a testable _extract_component_ns helper.
add_on_raw_state_callback is always available now (delegates to
callback_ without filters). SensorRawStateTrigger doesn't need
the guard, and on_raw_value doesn't need to set USE_SENSOR_FILTER.
Without filters raw == filtered, so the trigger fires with the
correct value either way — no wasted RAM on filter infrastructure.
Delegate to callback_ when USE_SENSOR_FILTER is off since raw state
equals filtered state without filters. This avoids requiring external
components to know about USE_SENSOR_FILTER.
set_trigger_on_initial_state is only called from codegen on concrete
BinarySensor instances. It's an implementation detail of BinarySensor,
not part of the StatefulEntityBase contract. Only get_trigger_on_initial_state
remains as a pure virtual — subclasses decide how to control it.
Making set_new_state virtual means callers like send_state_internal
and invalidate_state resolve via vtable dispatch to the .cpp, avoiding
template bloat without needing out-of-line tricks or hiding declarations.
BinarySensor overrides set_new_state directly for logging and
ControllerRegistry notification, matching the original pattern.
invalidate_state() can't be declaration-only on a template class.
Keep it inline on StatefulEntityBase, and add a hiding declaration
on BinarySensor with an out-of-line definition in the .cpp to prevent
template bloat from automation.h and filter.cpp callers.
set_new_state is a template method (~189 bytes when instantiated).
Inlining callers like send_state_internal and invalidate_state causes
the template code to be duplicated at every call site (publish_state,
Filter::output, BinarySensorInvalidateAction::play, etc.), adding
~384 bytes of flash.
Keep these as out-of-line definitions in the .cpp so the template
is instantiated once.
set_new_state is only called internally. Making it non-virtual
eliminates a vtable entry and allows the compiler to inline it.
BinarySensor now overrides on_state_changed_() for logging and
ControllerRegistry notification instead of overriding set_new_state.
Move set_has_state and set_state_value_ before callback invocations
so callback code can inspect the entity's current state via
get_state()/has_state(). The old state is passed as a parameter.
Addresses Copilot review feedback.
Move send_state_internal back to .cpp to avoid duplicating it at each
call site (publish_state and Filter::output).
Optimize set_new_state to compare has_state + value directly instead
of constructing optional<T> on stack for the comparison. Optionals
are only constructed in the changed path for callbacks that need them.
Use pure virtual get/set methods on StatefulEntityBase instead of
storing the flag in EntityBase::flags_. This keeps EntityBase clean
and avoids mixing binary_sensor-specific state into the base entity.
Replace optional<T> state_ in StatefulEntityBase with pure virtual
get_state()/set_state_value_() that subclasses implement. BinarySensor
stores its value in the existing public bool state member and uses
EntityBase::flags_.has_state instead of the optional's discriminant.
Move trigger_on_initial_state_ into EntityBase::flags_ (1 bit from
reserved), eliminating the standalone bool and its padding.
Saves 8 bytes per BinarySensor instance:
- optional<bool> (2B) + padding (2B) = 4B removed
- bool trigger_on_initial_state_ (1B) + padding (3B) = 4B removed
Deprecate direct access to sensor .raw_state member in favor of
get_raw_state(). This prepares for eventually compiling out raw_state
on builds without sensor filters, saving 4 bytes per sensor instance.
Guard raw_callback_ and add_on_raw_state_callback behind
USE_SENSOR_FILTER, saving 4 bytes per sensor on builds without
filters immediately.
Guard SensorRawStateTrigger behind USE_SENSOR_FILTER and ensure
on_raw_value automation sets USE_SENSOR_FILTER define.
Fix nextion sensor to stop directly writing .raw_state/.state
members - the publish=false path was redundantly setting already-current
values.
Migrate haier hon_climate from .raw_state to get_raw_state().
Embed component namespace in storage variable names so analyze-memory
can reliably attribute them. Display as "storage for {id}" in reports
and always show regardless of size threshold.