Skip to content

Commit

Permalink
[light] Add initial_state configuration (esphome#7577)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesserockz authored Oct 11, 2024
1 parent cedb671 commit efe4c5e
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 770 deletions.
33 changes: 32 additions & 1 deletion esphome/components/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,39 @@
from esphome.components import mqtt, power_supply, web_server
import esphome.config_validation as cv
from esphome.const import (
CONF_BLUE,
CONF_BRIGHTNESS,
CONF_COLD_WHITE,
CONF_COLD_WHITE_COLOR_TEMPERATURE,
CONF_COLOR_BRIGHTNESS,
CONF_COLOR_CORRECT,
CONF_COLOR_MODE,
CONF_COLOR_TEMPERATURE,
CONF_DEFAULT_TRANSITION_LENGTH,
CONF_EFFECTS,
CONF_FLASH_TRANSITION_LENGTH,
CONF_GAMMA_CORRECT,
CONF_GREEN,
CONF_ID,
CONF_INITIAL_STATE,
CONF_MQTT_ID,
CONF_ON_STATE,
CONF_ON_TURN_OFF,
CONF_ON_TURN_ON,
CONF_POWER_SUPPLY,
CONF_RED,
CONF_RESTORE_MODE,
CONF_STATE,
CONF_TRIGGER_ID,
CONF_WARM_WHITE,
CONF_WARM_WHITE_COLOR_TEMPERATURE,
CONF_WEB_SERVER,
CONF_WHITE,
)
from esphome.core import coroutine_with_priority
from esphome.cpp_helpers import setup_entity

from .automation import light_control_to_code # noqa
from .automation import LIGHT_STATE_SCHEMA
from .effects import (
ADDRESSABLE_EFFECTS,
BINARY_EFFECTS,
Expand All @@ -35,8 +47,10 @@
from .types import ( # noqa
AddressableLight,
AddressableLightState,
ColorMode,
LightOutput,
LightState,
LightStateRTCState,
LightStateTrigger,
LightTurnOffTrigger,
LightTurnOnTrigger,
Expand Down Expand Up @@ -85,6 +99,7 @@
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(LightStateTrigger),
}
),
cv.Optional(CONF_INITIAL_STATE): LIGHT_STATE_SCHEMA,
}
)
)
Expand Down Expand Up @@ -145,6 +160,22 @@ async def setup_light_core_(light_var, output_var, config):

cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))

if (initial_state_config := config.get(CONF_INITIAL_STATE)) is not None:
initial_state = LightStateRTCState(
initial_state_config.get(CONF_COLOR_MODE, ColorMode.UNKNOWN),
initial_state_config.get(CONF_STATE, False),
initial_state_config.get(CONF_BRIGHTNESS, 1.0),
initial_state_config.get(CONF_COLOR_BRIGHTNESS, 1.0),
initial_state_config.get(CONF_RED, 1.0),
initial_state_config.get(CONF_GREEN, 1.0),
initial_state_config.get(CONF_BLUE, 1.0),
initial_state_config.get(CONF_WHITE, 1.0),
initial_state_config.get(CONF_COLOR_TEMPERATURE, 1.0),
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))

if (
default_transition_length := config.get(CONF_DEFAULT_TRANSITION_LENGTH)
) is not None:
Expand Down
71 changes: 39 additions & 32 deletions esphome/components/light/automation.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.const import (
CONF_ID,
CONF_COLOR_MODE,
CONF_TRANSITION_LENGTH,
CONF_STATE,
CONF_FLASH_LENGTH,
CONF_EFFECT,
CONF_BLUE,
CONF_BRIGHTNESS,
CONF_BRIGHTNESS_LIMITS,
CONF_COLD_WHITE,
CONF_COLOR_BRIGHTNESS,
CONF_RED,
CONF_GREEN,
CONF_BLUE,
CONF_WHITE,
CONF_COLOR_MODE,
CONF_COLOR_TEMPERATURE,
CONF_COLD_WHITE,
CONF_WARM_WHITE,
CONF_RANGE_FROM,
CONF_RANGE_TO,
CONF_BRIGHTNESS_LIMITS,
CONF_EFFECT,
CONF_FLASH_LENGTH,
CONF_GREEN,
CONF_ID,
CONF_LIMIT_MODE,
CONF_MIN_BRIGHTNESS,
CONF_MAX_BRIGHTNESS,
CONF_MIN_BRIGHTNESS,
CONF_RANGE_FROM,
CONF_RANGE_TO,
CONF_RED,
CONF_STATE,
CONF_TRANSITION_LENGTH,
CONF_WARM_WHITE,
CONF_WHITE,
)

from .types import (
ColorMode,
COLOR_MODES,
LIMIT_MODES,
DimRelativeAction,
ToggleAction,
LightState,
LightControlAction,
AddressableLightState,
AddressableSet,
LightIsOnCondition,
ColorMode,
DimRelativeAction,
LightControlAction,
LightIsOffCondition,
LightIsOnCondition,
LightState,
ToggleAction,
)


Expand All @@ -62,18 +63,10 @@ async def light_toggle_to_code(config, action_id, template_arg, args):
return var


LIGHT_CONTROL_ACTION_SCHEMA = cv.Schema(
LIGHT_STATE_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(LightState),
cv.Optional(CONF_COLOR_MODE): cv.enum(COLOR_MODES, upper=True, space="_"),
cv.Optional(CONF_STATE): cv.templatable(cv.boolean),
cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable(
cv.positive_time_period_milliseconds
),
cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable(
cv.positive_time_period_milliseconds
),
cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string),
cv.Optional(CONF_BRIGHTNESS): cv.templatable(cv.percentage),
cv.Optional(CONF_COLOR_BRIGHTNESS): cv.templatable(cv.percentage),
cv.Optional(CONF_RED): cv.templatable(cv.percentage),
Expand All @@ -85,6 +78,20 @@ async def light_toggle_to_code(config, action_id, template_arg, args):
cv.Optional(CONF_WARM_WHITE): cv.templatable(cv.percentage),
}
)

LIGHT_CONTROL_ACTION_SCHEMA = LIGHT_STATE_SCHEMA.extend(
{
cv.Required(CONF_ID): cv.use_id(LightState),
cv.Exclusive(CONF_TRANSITION_LENGTH, "transformer"): cv.templatable(
cv.positive_time_period_milliseconds
),
cv.Exclusive(CONF_FLASH_LENGTH, "transformer"): cv.templatable(
cv.positive_time_period_milliseconds
),
cv.Exclusive(CONF_EFFECT, "transformer"): cv.templatable(cv.string),
}
)

LIGHT_TURN_OFF_ACTION_SCHEMA = automation.maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(LightState),
Expand Down
72 changes: 36 additions & 36 deletions esphome/components/light/effects.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,59 @@
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation

from esphome.const import (
CONF_NAME,
CONF_LAMBDA,
CONF_UPDATE_INTERVAL,
CONF_TRANSITION_LENGTH,
CONF_COLORS,
CONF_STATE,
CONF_DURATION,
CONF_ALPHA,
CONF_BLUE,
CONF_BRIGHTNESS,
CONF_COLOR_MODE,
CONF_COLD_WHITE,
CONF_COLOR_BRIGHTNESS,
CONF_RED,
CONF_GREEN,
CONF_BLUE,
CONF_WHITE,
CONF_COLOR_MODE,
CONF_COLOR_TEMPERATURE,
CONF_COLD_WHITE,
CONF_WARM_WHITE,
CONF_ALPHA,
CONF_COLORS,
CONF_DURATION,
CONF_GREEN,
CONF_INTENSITY,
CONF_SPEED,
CONF_WIDTH,
CONF_LAMBDA,
CONF_MAX_BRIGHTNESS,
CONF_MIN_BRIGHTNESS,
CONF_NAME,
CONF_NUM_LEDS,
CONF_RANDOM,
CONF_RED,
CONF_SEQUENCE,
CONF_MAX_BRIGHTNESS,
CONF_MIN_BRIGHTNESS,
CONF_SPEED,
CONF_STATE,
CONF_TRANSITION_LENGTH,
CONF_UPDATE_INTERVAL,
CONF_WARM_WHITE,
CONF_WHITE,
CONF_WIDTH,
)
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
from esphome.util import Registry

from .types import (
ColorMode,
COLOR_MODES,
LambdaLightEffect,
PulseLightEffect,
RandomLightEffect,
StrobeLightEffect,
StrobeLightEffectColor,
LightColorValues,
AddressableLightRef,
AddressableLambdaLightEffect,
FlickerLightEffect,
AddressableRainbowLightEffect,
AddressableColorWipeEffect,
AddressableColorWipeEffectColor,
AddressableScanEffect,
AddressableTwinkleEffect,
AddressableRandomTwinkleEffect,
AddressableFireworksEffect,
AddressableFlickerEffect,
AddressableLambdaLightEffect,
AddressableLightRef,
AddressableRainbowLightEffect,
AddressableRandomTwinkleEffect,
AddressableScanEffect,
AddressableTwinkleEffect,
AutomationLightEffect,
Color,
ColorMode,
FlickerLightEffect,
LambdaLightEffect,
LightColorValues,
PulseLightEffect,
RandomLightEffect,
StrobeLightEffect,
StrobeLightEffectColor,
)

CONF_ADD_LED_INTERVAL = "add_led_interval"
Expand Down
22 changes: 6 additions & 16 deletions esphome/components/light/light_state.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "esphome/core/log.h"
#include "light_state.h"

#include "light_output.h"
#include "light_state.h"
#include "transformers.h"

namespace esphome {
Expand All @@ -16,21 +17,6 @@ LightCall LightState::turn_off() { return this->make_call().set_state(false); }
LightCall LightState::toggle() { return this->make_call().set_state(!this->remote_values.is_on()); }
LightCall LightState::make_call() { return LightCall(this); }

struct LightStateRTCState {
ColorMode color_mode{ColorMode::UNKNOWN};
bool state{false};
float brightness{1.0f};
float color_brightness{1.0f};
float red{1.0f};
float green{1.0f};
float blue{1.0f};
float white{1.0f};
float color_temp{1.0f};
float cold_white{1.0f};
float warm_white{1.0f};
uint32_t effect{0};
};

void LightState::setup() {
ESP_LOGCONFIG(TAG, "Setting up light '%s'...", this->get_name().c_str());

Expand All @@ -48,6 +34,9 @@ void LightState::setup() {

auto call = this->make_call();
LightStateRTCState recovered{};
if (this->initial_state_.has_value()) {
recovered = *this->initial_state_;
}
switch (this->restore_mode_) {
case LIGHT_RESTORE_DEFAULT_OFF:
case LIGHT_RESTORE_DEFAULT_ON:
Expand Down Expand Up @@ -175,6 +164,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; }
bool LightState::supports_effects() { return !this->effects_.empty(); }
const std::vector<LightEffect *> &LightState::get_effects() const { return this->effects_; }
void LightState::add_effects(const std::vector<LightEffect *> &effects) {
Expand Down
34 changes: 34 additions & 0 deletions esphome/components/light/light_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,35 @@ enum LightRestoreMode {
LIGHT_RESTORE_AND_ON,
};

struct LightStateRTCState {
LightStateRTCState(ColorMode color_mode, bool state, float brightness, float color_brightness, float red, float green,
float blue, float white, float color_temp, float cold_white, float warm_white)
: color_mode(color_mode),
state(state),
brightness(brightness),
color_brightness(color_brightness),
red(red),
green(green),
blue(blue),
white(white),
color_temp(color_temp),
cold_white(cold_white),
warm_white(warm_white) {}
LightStateRTCState() = default;
ColorMode color_mode{ColorMode::UNKNOWN};
bool state{false};
float brightness{1.0f};
float color_brightness{1.0f};
float red{1.0f};
float green{1.0f};
float blue{1.0f};
float white{1.0f};
float color_temp{1.0f};
float cold_white{1.0f};
float warm_white{1.0f};
uint32_t effect{0};
};

/** This class represents the communication layer between the front-end MQTT layer and the
* hardware output layer.
*/
Expand Down Expand Up @@ -116,6 +145,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);

/// Return whether the light has any effects that meet the trait requirements.
bool supports_effects();

Expand Down Expand Up @@ -212,6 +244,8 @@ class LightState : public EntityBase, public Component {
float gamma_correct_{};
/// Restore mode of the light.
LightRestoreMode restore_mode_;
/// Initial state of the light.
optional<LightStateRTCState> initial_state_{};
/// List of effects for this light.
std::vector<LightEffect *> effects_;

Expand Down
Loading

0 comments on commit efe4c5e

Please sign in to comment.