From ea1b5e19f048d4cc50ad81d14390395fc31c4d9a Mon Sep 17 00:00:00 2001 From: Alex <33379584+alexyao2015@users.noreply.github.com> Date: Mon, 30 Aug 2021 21:18:16 -0500 Subject: [PATCH] Add transitions to light flash (#2201) --- esphome/components/light/__init__.py | 8 ++++ esphome/components/light/light_state.cpp | 7 ++- esphome/components/light/light_state.h | 7 +++ esphome/components/light/transformers.h | 43 ++++++++++++++++++- .../components/power_supply/power_supply.cpp | 2 +- esphome/const.py | 1 + 6 files changed, 65 insertions(+), 3 deletions(-) diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py index 52e8984545..69cb87e539 100644 --- a/esphome/components/light/__init__.py +++ b/esphome/components/light/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_DEFAULT_TRANSITION_LENGTH, CONF_DISABLED_BY_DEFAULT, CONF_EFFECTS, + CONF_FLASH_TRANSITION_LENGTH, CONF_GAMMA_CORRECT, CONF_ID, CONF_INTERNAL, @@ -85,6 +86,9 @@ BRIGHTNESS_ONLY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend( cv.Optional( CONF_DEFAULT_TRANSITION_LENGTH, default="1s" ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_FLASH_TRANSITION_LENGTH, default="0s" + ): cv.positive_time_period_milliseconds, cv.Optional(CONF_EFFECTS): validate_effects(MONOCHROMATIC_EFFECTS), } ) @@ -132,6 +136,10 @@ async def setup_light_core_(light_var, output_var, config): config[CONF_DEFAULT_TRANSITION_LENGTH] ) ) + if CONF_FLASH_TRANSITION_LENGTH in config: + cg.add( + light_var.set_flash_transition_length(config[CONF_FLASH_TRANSITION_LENGTH]) + ) if CONF_GAMMA_CORRECT in config: cg.add(light_var.set_gamma_correct(config[CONF_GAMMA_CORRECT])) effects = await cg.build_registry_list( diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index 4c4eefdc30..945d3910d5 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -157,6 +157,11 @@ void LightState::add_new_target_state_reached_callback(std::function &&s void LightState::set_default_transition_length(uint32_t default_transition_length) { this->default_transition_length_ = default_transition_length; } +uint32_t LightState::get_default_transition_length() const { return this->default_transition_length_; } +void LightState::set_flash_transition_length(uint32_t flash_transition_length) { + this->flash_transition_length_ = 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; } bool LightState::supports_effects() { return !this->effects_.empty(); } @@ -234,7 +239,7 @@ void LightState::start_flash_(const LightColorValues &target, uint32_t length) { // If starting a flash if one is already happening, set end values to end values of current flash // Hacky but works if (this->transformer_ != nullptr) - end_colors = this->transformer_->get_target_values(); + end_colors = this->transformer_->get_start_values(); this->transformer_ = make_unique(*this); this->transformer_->setup(end_colors, target, length); diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index dfea9a15f4..dd42aa76db 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -99,6 +99,11 @@ class LightState : public Nameable, public Component { /// Set the default transition length, i.e. the transition length when no transition is provided. void set_default_transition_length(uint32_t default_transition_length); + uint32_t get_default_transition_length() const; + + /// Set the flash transition length + void set_flash_transition_length(uint32_t flash_transition_length); + uint32_t get_flash_transition_length() const; /// Set the gamma correction factor void set_gamma_correct(float gamma_correct); @@ -188,6 +193,8 @@ class LightState : public Nameable, public Component { /// Default transition length for all transitions in ms. uint32_t default_transition_length_{}; + /// Transition length to use for flash transitions. + uint32_t flash_transition_length_{}; /// Gamma correction factor for the light. float gamma_correct_{}; /// Restore mode of the light. diff --git a/esphome/components/light/transformers.h b/esphome/components/light/transformers.h index fd0bfd20f3..adcaebe0c8 100644 --- a/esphome/components/light/transformers.h +++ b/esphome/components/light/transformers.h @@ -58,7 +58,45 @@ class LightFlashTransformer : public LightTransformer { public: LightFlashTransformer(LightState &state) : state_(state) {} - optional apply() override { return this->get_target_values(); } + void start() override { + this->transition_length_ = this->state_.get_flash_transition_length(); + if (this->transition_length_ * 2 > this->length_) + this->transition_length_ = this->length_ / 2; + + // do not create transition if length is 0 + if (this->transition_length_ == 0) + return; + + // first transition to original target + this->transformer_ = this->state_.get_output()->create_default_transition(); + this->transformer_->setup(this->state_.current_values, this->target_values_, this->transition_length_); + } + + optional apply() override { + // transition transformer does not handle 0 length as progress returns nan + if (this->transition_length_ == 0) + return this->target_values_; + + if (this->transformer_ != nullptr) { + if (!this->transformer_->is_finished()) { + return this->transformer_->apply(); + } else { + this->transformer_->stop(); + this->transformer_ = nullptr; + } + } + + if (millis() > this->start_time_ + this->length_ - this->transition_length_ && + !this->secondary_transition_occurred_) { + // second transition back to start value + this->transformer_ = this->state_.get_output()->create_default_transition(); + this->transformer_->setup(this->state_.current_values, this->get_start_values(), this->transition_length_); + this->secondary_transition_occurred_ = true; + } + + // once transition is complete, don't change states until next transition + return optional(); + } // Restore the original values after the flash. void stop() override { @@ -69,6 +107,9 @@ class LightFlashTransformer : public LightTransformer { protected: LightState &state_; + uint32_t transition_length_; + bool secondary_transition_occurred_{false}; + std::unique_ptr transformer_{nullptr}; }; } // namespace light diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp index f50adac6f9..a492919202 100644 --- a/esphome/components/power_supply/power_supply.cpp +++ b/esphome/components/power_supply/power_supply.cpp @@ -42,7 +42,7 @@ void PowerSupply::request_high_power() { void PowerSupply::unrequest_high_power() { this->active_requests_--; if (this->active_requests_ < 0) { - // we're just going to use 0 as our now counter. + // we're just going to use 0 as our new counter. this->active_requests_ = 0; } diff --git a/esphome/const.py b/esphome/const.py index 579d8ef4c6..0ddc5da706 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -241,6 +241,7 @@ CONF_FILTERS = "filters" CONF_FINGER_ID = "finger_id" CONF_FINGERPRINT_COUNT = "fingerprint_count" CONF_FLASH_LENGTH = "flash_length" +CONF_FLASH_TRANSITION_LENGTH = "flash_transition_length" CONF_FLOW_CONTROL_PIN = "flow_control_pin" CONF_FOR = "for" CONF_FORCE_UPDATE = "force_update"