mirror of
https://github.com/esphome/esphome.git
synced 2026-08-31 18:16:03 +00:00
[light] Replace initial_state storage with flash-resident callback
Replace the inline optional<LightStateRTCState> (~44 bytes) with a function pointer callback (4 bytes) that populates the initial state during setup. The callback is a stateless lambda whose values live in flash as code, not in the LightState object. Saves ~40 bytes per LightState instance unconditionally — the optional reserved space for the struct even when initial_state was not configured (the common case).
This commit is contained in:
@@ -38,7 +38,7 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
CONF_WHITE,
|
||||
)
|
||||
from esphome.core import CORE, ID, CoroPriority, HexInt, coroutine_with_priority
|
||||
from esphome.core import CORE, ID, CoroPriority, HexInt, Lambda, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
|
||||
@@ -52,6 +52,7 @@ from .effects import (
|
||||
validate_effects,
|
||||
)
|
||||
from .types import ( # noqa
|
||||
COLOR_MODES,
|
||||
AddressableLight,
|
||||
AddressableLightState,
|
||||
ColorMode,
|
||||
@@ -262,8 +263,12 @@ async def setup_light_core_(light_var, config, output_var):
|
||||
cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
if (initial_state_config := config.get(CONF_INITIAL_STATE)) is not None:
|
||||
# Emit a stateless lambda that constructs the initial state — values live
|
||||
# in flash as code, not stored in the LightState object (~40 bytes saved).
|
||||
color_mode_str = initial_state_config.get(CONF_COLOR_MODE)
|
||||
color_mode_expr = COLOR_MODES.get(color_mode_str, ColorMode.UNKNOWN)
|
||||
initial_state = LightStateRTCState(
|
||||
initial_state_config.get(CONF_COLOR_MODE, ColorMode.UNKNOWN),
|
||||
color_mode_expr,
|
||||
initial_state_config.get(CONF_STATE, False),
|
||||
initial_state_config.get(CONF_BRIGHTNESS, 1.0),
|
||||
initial_state_config.get(CONF_COLOR_BRIGHTNESS, 1.0),
|
||||
@@ -275,7 +280,13 @@ async def setup_light_core_(light_var, config, output_var):
|
||||
initial_state_config.get(CONF_COLD_WHITE, 1.0),
|
||||
initial_state_config.get(CONF_WARM_WHITE, 1.0),
|
||||
)
|
||||
cg.add(light_var.set_initial_state(initial_state))
|
||||
args = [(LightStateRTCState.operator("ref"), "s")]
|
||||
lamb = await cg.process_lambda(
|
||||
Lambda(f"s = {initial_state};"),
|
||||
args,
|
||||
return_type=cg.void,
|
||||
)
|
||||
cg.add(light_var.set_initial_state(lamb))
|
||||
|
||||
if (
|
||||
default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH)
|
||||
|
||||
@@ -37,8 +37,9 @@ void LightState::setup() {
|
||||
|
||||
auto call = this->make_call();
|
||||
LightStateRTCState recovered{};
|
||||
if (this->initial_state_.has_value()) {
|
||||
recovered = *this->initial_state_;
|
||||
if (this->initial_state_callback_) {
|
||||
this->initial_state_callback_(recovered);
|
||||
this->initial_state_callback_ = nullptr; // One-shot — no longer needed
|
||||
}
|
||||
switch (this->restore_mode_) {
|
||||
case LIGHT_RESTORE_DEFAULT_OFF:
|
||||
@@ -195,7 +196,7 @@ void LightState::set_flash_transition_length(uint32_t flash_transition_length) {
|
||||
uint32_t LightState::get_flash_transition_length() const { return this->flash_transition_length_; }
|
||||
void LightState::set_gamma_correct(float gamma_correct) { this->gamma_correct_ = gamma_correct; }
|
||||
void LightState::set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
||||
void LightState::set_initial_state(const LightStateRTCState &initial_state) { this->initial_state_ = initial_state; }
|
||||
void LightState::set_initial_state(void (*callback)(LightStateRTCState &)) { this->initial_state_callback_ = callback; }
|
||||
bool LightState::supports_effects() { return !this->effects_.empty(); }
|
||||
const FixedVector<LightEffect *> &LightState::get_effects() const { return this->effects_; }
|
||||
void LightState::add_effects(const std::initializer_list<LightEffect *> &effects) {
|
||||
|
||||
@@ -188,8 +188,9 @@ class LightState : public EntityBase, public Component {
|
||||
/// Set the restore mode of this light
|
||||
void set_restore_mode(LightRestoreMode restore_mode);
|
||||
|
||||
/// Set the initial state of this light
|
||||
void set_initial_state(const LightStateRTCState &initial_state);
|
||||
/// Set a callback to populate the initial state defaults during setup.
|
||||
/// The callback is called once, then cleared. Values live in flash as code.
|
||||
void set_initial_state(void (*callback)(LightStateRTCState &));
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
@@ -342,8 +343,9 @@ class LightState : public EntityBase, public Component {
|
||||
*/
|
||||
std::unique_ptr<std::vector<LightTargetStateReachedListener *>> target_state_reached_listeners_;
|
||||
|
||||
/// Initial state of the light.
|
||||
optional<LightStateRTCState> initial_state_{};
|
||||
/// Callback to populate initial state defaults — called once during setup, then cleared.
|
||||
/// Values live in flash as function body; no per-instance data storage beyond this pointer.
|
||||
void (*initial_state_callback_)(LightStateRTCState &){nullptr};
|
||||
|
||||
/// Value for storing the index of the currently active effect. 0 if no effect is active
|
||||
uint32_t active_effect_index_{};
|
||||
|
||||
Reference in New Issue
Block a user