From 14c54597cef47ff446753a74a1e43394d7728b73 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Mar 2026 16:20:29 -1000 Subject: [PATCH] [binary_sensor] Make set_new_state non-virtual, add on_state_changed_ hook 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. --- esphome/components/binary_sensor/binary_sensor.cpp | 12 ++++-------- esphome/components/binary_sensor/binary_sensor.h | 2 +- esphome/core/entity_base.h | 10 +++++++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/binary_sensor/binary_sensor.cpp b/esphome/components/binary_sensor/binary_sensor.cpp index 3ccaaf8f03..564cb48f64 100644 --- a/esphome/components/binary_sensor/binary_sensor.cpp +++ b/esphome/components/binary_sensor/binary_sensor.cpp @@ -33,16 +33,12 @@ void BinarySensor::publish_initial_state(bool new_state) { this->publish_state(new_state); } -bool BinarySensor::set_new_state(const optional &new_state) { - if (StatefulEntityBase::set_new_state(new_state)) { - // weirdly, this file could be compiled even without USE_BINARY_SENSOR defined +void BinarySensor::on_state_changed_(const optional &old_state, const optional &new_state, bool had_state) { + StatefulEntityBase::on_state_changed_(old_state, new_state, had_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)); - return true; - } - return false; + ESP_LOGD(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state)); } #ifdef USE_BINARY_SENSOR_FILTER diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index 6e6f77e010..31e8f92b96 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -74,7 +74,7 @@ class BinarySensor : public StatefulEntityBase { Filter *filter_list_{nullptr}; #endif - bool set_new_state(const optional &new_state) override; + void on_state_changed_(const optional &old_state, const optional &new_state, bool had_state) override; }; class BinarySensorInitiallyOff : public BinarySensor { diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index d19ef558ec..60132a4c18 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -342,8 +342,8 @@ template 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. */ - virtual bool set_new_state(const optional &new_state) { - // Access flags_ directly to avoid virtual/function call overhead in this hot path + bool set_new_state(const optional &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()) { if (had_state && this->get_state() == new_state.value()) @@ -358,10 +358,14 @@ template 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 &old_state, const optional &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;