From 4a200f8a2ba72e1950ce4262e0df22adec8b38f7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Mar 2026 18:16:49 -1000 Subject: [PATCH] [binary_sensor] Reduce flash: cache get_state(), guard full_state_callbacks call - Cache get_state() result to avoid calling the virtual method twice (once for comparison, once for old_state construction) - Move full_state_callbacks_.call() inside the !empty() guard so both the optional construction and the call are skipped when no callbacks - Swap to had_state || get_trigger_on_initial_state() so the virtual call is skipped on the common path (every change except the first) Saves ~21 bytes of flash in set_new_state. --- esphome/core/entity_base.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 187894fea0..869981eb7a 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -347,24 +347,29 @@ template class StatefulEntityBase : public EntityBase { virtual 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; + // Cache get_state() result to avoid calling the virtual method twice + T current{}; + if (had_state) + current = this->get_state(); if (new_state.has_value()) { - if (had_state && this->get_state() == new_state.value()) + if (had_state && current == new_state.value()) return false; // same value, no change } else if (!had_state) { return false; // already invalidated, no change } // State changed — update storage before firing callbacks so callback code // can inspect the entity's current state via get_state()/has_state() - // Only construct old_state optional when full_state_callbacks need it - optional old_state; - if (!this->full_state_callbacks_.empty()) - old_state = had_state ? optional(this->get_state()) : nullopt; this->flags_.has_state = new_state.has_value(); if (new_state.has_value()) { this->set_state_value(new_state.value()); } - this->full_state_callbacks_.call(old_state, new_state); - if (new_state.has_value() && (this->get_trigger_on_initial_state() || had_state)) + // Only construct old_state and call full_state_callbacks when callbacks are registered + if (!this->full_state_callbacks_.empty()) { + optional old_state = had_state ? optional(current) : nullopt; + this->full_state_callbacks_.call(old_state, new_state); + } + // had_state first: on every change except the first, skips the virtual call + if (new_state.has_value() && (had_state || this->get_trigger_on_initial_state())) this->state_callbacks_.call(new_state.value()); return true; }