diff --git a/esphome/components/binary_sensor/binary_sensor.cpp b/esphome/components/binary_sensor/binary_sensor.cpp index 3ccaaf8f03..7f46291e2d 100644 --- a/esphome/components/binary_sensor/binary_sensor.cpp +++ b/esphome/components/binary_sensor/binary_sensor.cpp @@ -32,6 +32,7 @@ void BinarySensor::publish_initial_state(bool new_state) { this->invalidate_state(); this->publish_state(new_state); } +void BinarySensor::send_state_internal(bool new_state) { this->set_new_state(new_state); } bool BinarySensor::set_new_state(const optional &new_state) { if (StatefulEntityBase::set_new_state(new_state)) { diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index 6e6f77e010..6263844f7f 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -57,7 +57,7 @@ class BinarySensor : public StatefulEntityBase { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) - void send_state_internal(bool new_state) { this->set_new_state(new_state); } + void send_state_internal(bool new_state); /// Return whether this binary sensor has outputted a state. virtual bool is_status_binary_sensor() const; diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index e3a1891da6..c3ab0c55f5 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -343,19 +343,25 @@ template class StatefulEntityBase : public EntityBase { * Returns true if the state actually changed, false if it was the same. */ virtual bool set_new_state(const optional &new_state) { - optional old_state = this->has_state() ? optional(this->get_state()) : nullopt; - if (old_state != new_state) { - this->full_state_callbacks_.call(old_state, new_state); - auto had_state = this->has_state(); - this->set_has_state(new_state.has_value()); - if (new_state.has_value()) { - this->set_state_value_(new_state.value()); - if (this->get_trigger_on_initial_state() || had_state) - this->state_callbacks_.call(new_state.value()); - } - return true; + // Compare without constructing optional — avoid unnecessary codegen + bool had_state = this->has_state(); + if (new_state.has_value()) { + if (had_state && this->get_state() == new_state.value()) + return false; // same value, no change + } else { + if (!had_state) + return false; // already invalidated, no change } - return false; + // State changed — construct optionals only for callbacks that need them + optional old_state = had_state ? optional(this->get_state()) : nullopt; + this->full_state_callbacks_.call(old_state, new_state); + this->set_has_state(new_state.has_value()); + if (new_state.has_value()) { + this->set_state_value_(new_state.value()); + if (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;