mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 11:06:04 +00:00
[binary_sensor] Restore virtual set_new_state, remove on_state_changed hook
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.
This commit is contained in:
@@ -32,17 +32,19 @@ void BinarySensor::publish_initial_state(bool new_state) {
|
||||
this->invalidate_state();
|
||||
this->publish_state(new_state);
|
||||
}
|
||||
// Defined out-of-line to prevent set_new_state template from being inlined at each call site,
|
||||
// which would duplicate ~189 bytes of template code per caller (publish_state, Filter::output, etc.)
|
||||
void BinarySensor::send_state_internal(bool new_state) { this->set_new_state_(new_state); }
|
||||
void BinarySensor::invalidate_state() { this->set_new_state_({}); }
|
||||
// Defined out-of-line: set_new_state is virtual so callers in other TUs (filter.cpp, automation.h)
|
||||
// dispatch here without inlining the ~189 byte template body at each call site.
|
||||
void BinarySensor::send_state_internal(bool new_state) { this->set_new_state(new_state); }
|
||||
|
||||
void BinarySensor::on_state_changed(const optional<bool> &old_state, const optional<bool> &new_state, bool had_state) {
|
||||
StatefulEntityBase::on_state_changed(old_state, new_state, had_state);
|
||||
bool BinarySensor::set_new_state(const optional<bool> &new_state) {
|
||||
if (StatefulEntityBase::set_new_state(new_state)) {
|
||||
#if defined(USE_BINARY_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_binary_sensor_update(this);
|
||||
ControllerRegistry::notify_binary_sensor_update(this);
|
||||
#endif
|
||||
ESP_LOGD(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
|
||||
ESP_LOGD(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_BINARY_SENSOR_FILTER
|
||||
|
||||
@@ -57,10 +57,7 @@ class BinarySensor : public StatefulEntityBase<bool> {
|
||||
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
/// Defined in .cpp to avoid inlining set_new_state_ template code at every call site.
|
||||
void send_state_internal(bool new_state);
|
||||
/// Hides base class inline version to prevent template bloat from automation.h and filter.cpp callers.
|
||||
void invalidate_state();
|
||||
|
||||
/// Return whether this binary sensor has outputted a state.
|
||||
virtual bool is_status_binary_sensor() const;
|
||||
@@ -77,7 +74,7 @@ class BinarySensor : public StatefulEntityBase<bool> {
|
||||
Filter *filter_list_{nullptr};
|
||||
#endif
|
||||
|
||||
void on_state_changed(const optional<bool> &old_state, const optional<bool> &new_state, bool had_state) override;
|
||||
bool set_new_state(const optional<bool> &new_state) override;
|
||||
};
|
||||
|
||||
class BinarySensorInitiallyOff : public BinarySensor {
|
||||
|
||||
@@ -302,7 +302,8 @@ void log_entity_unit_of_measurement(const char *tag, const char *prefix, const E
|
||||
* - get_state(): return a const reference to the current value
|
||||
* - set_state_value(): store a new value (called only when the state actually changes)
|
||||
* - get_trigger_on_initial_state() / set_trigger_on_initial_state(): control initial callback behavior
|
||||
* - on_state_changed() (optional override): called after state updates, for logging/notifications
|
||||
*
|
||||
* Subclasses may override set_new_state() for additional behavior (logging, notifications).
|
||||
*
|
||||
* This class does not store the state value — subclasses own their storage. Whether a state
|
||||
* has been set is tracked by EntityBase::has_state().
|
||||
@@ -312,6 +313,9 @@ void log_entity_unit_of_measurement(const char *tag, const char *prefix, const E
|
||||
* - state_callbacks_: fired only when the new state has a value, and either this is not the
|
||||
* first state (had_state) or trigger_on_initial_state is set
|
||||
*
|
||||
* invalidate_state() and callers of set_new_state() should be defined out-of-line in the
|
||||
* subclass .cpp to avoid inlining the template body (~189 bytes) at every call site.
|
||||
*
|
||||
* @tparam T The type of the state value
|
||||
*/
|
||||
template<typename T> class StatefulEntityBase : public EntityBase {
|
||||
@@ -321,7 +325,7 @@ template<typename T> class StatefulEntityBase : public EntityBase {
|
||||
/// Return the current state if available, otherwise return the provided default.
|
||||
T get_state_default(T default_value) const { return this->has_state() ? this->get_state() : default_value; }
|
||||
/// Clear the state — sets has_state() to false and fires callbacks with nullopt.
|
||||
void invalidate_state() { this->set_new_state_({}); }
|
||||
void invalidate_state() { this->set_new_state({}); }
|
||||
|
||||
template<typename F> void add_full_state_callback(F &&callback) {
|
||||
this->full_state_callbacks_.add(std::forward<F>(callback));
|
||||
@@ -342,8 +346,9 @@ template<typename T> class StatefulEntityBase : public EntityBase {
|
||||
*
|
||||
* Pass nullopt to invalidate (clear) the state. Pass a value to set it.
|
||||
* Returns true if the state actually changed, false if it was the same.
|
||||
* Subclasses may override to add logging/notifications after calling the base.
|
||||
*/
|
||||
bool set_new_state_(const optional<T> &new_state) {
|
||||
virtual bool set_new_state(const optional<T> &new_state) {
|
||||
// Access flags_ directly to avoid function call overhead in this hot path
|
||||
bool had_state = this->flags_.has_state;
|
||||
if (new_state.has_value()) {
|
||||
@@ -362,14 +367,10 @@ template<typename T> class StatefulEntityBase : public EntityBase {
|
||||
if (new_state.has_value()) {
|
||||
this->set_state_value(new_state.value());
|
||||
}
|
||||
this->on_state_changed(old_state, new_state, had_state);
|
||||
return true;
|
||||
}
|
||||
/// Called after state storage is updated. Subclasses override for logging/notifications.
|
||||
virtual void on_state_changed(const optional<T> &old_state, const optional<T> &new_state, bool had_state) {
|
||||
this->full_state_callbacks_.call(old_state, new_state);
|
||||
if (new_state.has_value() && (this->get_trigger_on_initial_state() || had_state))
|
||||
this->state_callbacks_.call(new_state.value());
|
||||
return true;
|
||||
}
|
||||
/// Subclasses implement this to store the actual value into their own storage.
|
||||
virtual void set_state_value(const T &value) = 0;
|
||||
|
||||
Reference in New Issue
Block a user