From e406fb25cbe2a2992dbd5ee63e4d5f93121a9ef6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Mar 2026 16:01:39 -1000 Subject: [PATCH] [binary_sensor] Move trigger_on_initial_state out of EntityBase flags into BinarySensor 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. --- esphome/components/binary_sensor/binary_sensor.h | 5 ++++- esphome/core/entity_base.h | 15 ++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index e065088a37..6263844f7f 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -32,9 +32,10 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi */ class BinarySensor : public StatefulEntityBase { public: - explicit BinarySensor() { this->flags_.trigger_on_initial_state = true; } + explicit BinarySensor() = default; const bool &get_state() const override { return this->state; } + void set_trigger_on_initial_state(bool value) override { this->trigger_on_initial_state_ = value; } /** Publish a new state to the front-end. * @@ -65,8 +66,10 @@ class BinarySensor : public StatefulEntityBase { bool state{}; protected: + bool get_trigger_on_initial_state() const override { return this->trigger_on_initial_state_; } void set_state_value_(const bool &value) override { this->state = value; } + bool trigger_on_initial_state_{true}; #ifdef USE_BINARY_SENSOR_FILTER Filter *filter_list_{nullptr}; #endif diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index a3cbe84b13..d638434d49 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -266,9 +266,8 @@ class EntityBase { uint8_t internal : 1; uint8_t disabled_by_default : 1; uint8_t has_state : 1; - uint8_t entity_category : 2; // Supports up to 4 categories - uint8_t trigger_on_initial_state : 1; // Whether callbacks fire on first state (StatefulEntityBase) - uint8_t reserved : 1; // Reserved for future use + uint8_t entity_category : 2; // Supports up to 4 categories + uint8_t reserved : 2; // Reserved for future use } flags_{}; // String table indices — packed into the 3 padding bytes after flags_ #ifdef USE_ENTITY_DEVICE_CLASS @@ -330,11 +329,13 @@ template class StatefulEntityBase : public EntityBase { } /// Control whether state_callbacks_ fire on the very first state (before any previous state exists). - void set_trigger_on_initial_state(bool trigger_on_initial_state) { - this->flags_.trigger_on_initial_state = trigger_on_initial_state; - } + /// Subclasses must implement set_trigger_on_initial_state() to store this value. + virtual void set_trigger_on_initial_state(bool value) = 0; protected: + /// Subclasses return whether callbacks should fire on the very first state. + virtual bool get_trigger_on_initial_state() const = 0; + /** Apply a new state, de-duplicating and firing callbacks as needed. * * Pass nullopt to invalidate (clear) the state. Pass a value to set it. @@ -348,7 +349,7 @@ template class StatefulEntityBase : public EntityBase { this->set_has_state(new_state.has_value()); if (new_state.has_value()) { this->set_state_value_(new_state.value()); - if (this->flags_.trigger_on_initial_state || had_state) + if (this->get_trigger_on_initial_state() || had_state) this->state_callbacks_.call(new_state.value()); } return true;