From 6453fdf057451332d2963e5c802f05c47ce0f1af Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Sat, 14 Aug 2021 13:22:12 +0200 Subject: [PATCH] Work in progress. --- ...ndler.h => color_transition_handler.h.bak} | 0 components/xiaomi_bslamp2/light/interfaces.h | 16 ---- .../xiaomi_bslamp2/light/light_output.h | 44 +++++----- components/xiaomi_bslamp2/light/light_state.h | 16 +--- .../xiaomi_bslamp2/light/light_transformer.h | 80 +++++++++++++++++++ 5 files changed, 102 insertions(+), 54 deletions(-) rename components/xiaomi_bslamp2/light/{color_transition_handler.h => color_transition_handler.h.bak} (100%) create mode 100644 components/xiaomi_bslamp2/light/light_transformer.h diff --git a/components/xiaomi_bslamp2/light/color_transition_handler.h b/components/xiaomi_bslamp2/light/color_transition_handler.h.bak similarity index 100% rename from components/xiaomi_bslamp2/light/color_transition_handler.h rename to components/xiaomi_bslamp2/light/color_transition_handler.h.bak diff --git a/components/xiaomi_bslamp2/light/interfaces.h b/components/xiaomi_bslamp2/light/interfaces.h index f9e47cb..1c69a41 100644 --- a/components/xiaomi_bslamp2/light/interfaces.h +++ b/components/xiaomi_bslamp2/light/interfaces.h @@ -4,22 +4,6 @@ namespace esphome { namespace xiaomi { namespace bslamp2 { -/** - * This is an interface definition that is used to extend the LightState - * class with functionality to inspect LightTransformer data from - * within other classes. - * - * This interface is required for the ColorTransitionHandler, so it can - * check whether or not a light color transition is in progress. - */ -class LightStateTransformerInspector { - public: - virtual bool is_active() = 0; - virtual bool is_transition() = 0; - virtual light::LightColorValues get_end_values() = 0; - virtual float get_progress() = 0; -}; - /** * This is an interface definition that is used to extend the LightState * class with functionality for disco actions (immediate light updates, diff --git a/components/xiaomi_bslamp2/light/light_output.h b/components/xiaomi_bslamp2/light/light_output.h index 4a399c8..99fe7e4 100644 --- a/components/xiaomi_bslamp2/light/light_output.h +++ b/components/xiaomi_bslamp2/light/light_output.h @@ -3,7 +3,7 @@ #include "../common.h" #include "../light_hal.h" #include "color_instant_handler.h" -#include "color_transition_handler.h" +#include "light_transformer.h" #include "esphome/components/ledc/ledc_output.h" namespace esphome { @@ -42,6 +42,10 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput { return traits; } + std::unique_ptr create_default_transition() override { + return make_unique(light_); + } + void add_on_light_mode_callback(std::function &&callback) { light_mode_callback_.add(std::move(callback)); } @@ -60,17 +64,17 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput { // transitioning to an end color. The transition handler will do its // own inspection to see if a transition is currently active or not. // Based on the outcome, use either the instant or transition handler. - GPIOOutputs *delegate; - if (transition_handler_->set_light_color_values(values)) { - delegate = transition_handler_; - light_mode_callback_.call(delegate->light_mode); - state_callback_.call(transition_handler_->get_end_values()); - } else { - instant_handler_->set_light_color_values(values); - delegate = instant_handler_; - light_mode_callback_.call(delegate->light_mode); - state_callback_.call(values); - } + //GPIOOutputs *delegate; + //if (transition_handler_->set_light_color_values(values)) { + // delegate = transition_handler_; + // light_mode_callback_.call(delegate->light_mode); + // state_callback_.call(transition_handler_->get_end_values()); + //} else { + instant_handler_->set_light_color_values(values); + //delegate = instant_handler_; + light_mode_callback_.call(instant_handler_->light_mode); + state_callback_.call(values); + //} // Note: one might think that it is more logical to turn on the LED // circuitry master switch after setting the individual channels, @@ -81,7 +85,9 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput { light_->turn_on(); // Apply the current GPIO output levels from the selected handler. - light_->set_rgbw(delegate->red, delegate->green, delegate->blue, delegate->white); + light_->set_rgbw( + instant_handler_->red, instant_handler_->green, instant_handler_->blue, + instant_handler_->white); if (values.get_state() == 0) light_->turn_off(); @@ -89,21 +95,9 @@ class XiaomiBslamp2LightOutput : public Component, public light::LightOutput { protected: LightHAL *light_; - ColorTransitionHandler *transition_handler_; ColorInstantHandler *instant_handler_ = new ColorInstantHandler(); CallbackManager light_mode_callback_{}; CallbackManager state_callback_{}; - - friend class XiaomiBslamp2LightState; - - /** - * Called by the XiaomiBslamp2LightState class, to set the object that can be - * used to access the protected LightTransformer data from the LightState - * object. - */ - void set_transformer_inspector(LightStateTransformerInspector *exposer) { - transition_handler_ = new ColorTransitionHandler(exposer); - } }; } // namespace bslamp2 diff --git a/components/xiaomi_bslamp2/light/light_state.h b/components/xiaomi_bslamp2/light/light_state.h index 5ff05b4..1f18cd3 100644 --- a/components/xiaomi_bslamp2/light/light_state.h +++ b/components/xiaomi_bslamp2/light/light_state.h @@ -24,22 +24,12 @@ struct MyLightStateRTCState { /** * A custom LightState class for the Xiaomi Bedside Lamp 2. * - * This class is used by the ColorTransitionHandler class to inspect if - * an ongoing light color transition is active in the LightState object. - * - * It is also used by the DiscoAction to apply immediate light output + * It is used by the DiscoAction to apply immediate light output * updates, without saving or publishing the new state. */ -class XiaomiBslamp2LightState : public light::LightState, public LightStateTransformerInspector, public LightStateDiscoSupport { +class XiaomiBslamp2LightState : public light::LightState, public LightStateDiscoSupport { public: - XiaomiBslamp2LightState(const std::string &name, XiaomiBslamp2LightOutput *output) : light::LightState(name, output) { - output->set_transformer_inspector(this); - } - - bool is_active() { return transformer_ != nullptr; } - bool is_transition() { return transformer_->is_transition(); } - light::LightColorValues get_end_values() { return transformer_->get_end_values(); } - float get_progress() { return transformer_->get_progress(); } + XiaomiBslamp2LightState(const std::string &name, XiaomiBslamp2LightOutput *output) : light::LightState(name, output) { } void disco_stop() { MyLightStateRTCState recovered{}; diff --git a/components/xiaomi_bslamp2/light/light_transformer.h b/components/xiaomi_bslamp2/light/light_transformer.h new file mode 100644 index 0000000..8b0abac --- /dev/null +++ b/components/xiaomi_bslamp2/light/light_transformer.h @@ -0,0 +1,80 @@ +#pragma once + +#include "../common.h" +#include "../light_hal.h" +#include "color_instant_handler.h" +#include "gpio_outputs.h" +#include "esphome/components/light/light_transformer.h" +#include "esphome/components/light/light_color_values.h" + +namespace esphome { +namespace xiaomi { +namespace bslamp2 { + +/** + * A LightTransitionTransformer class for the Xiaomi Mijia Bedside Lamp 2. + */ +class XiaomiBslamp2LightTransitionTransformer : public light::LightTransitionTransformer { + public: + explicit XiaomiBslamp2LightTransitionTransformer(LightHAL *light) : light_(light) { } + + bool is_completed() override { + return is_completed_ || get_progress_() >= 1.0f; + } + + void start() override { + // When a fresh transition is started, then compute the GPIO outputs + // to use for both the start and end point. This light transition transformer + // will then transition linearly between these two. + start_->set_light_color_values(start_values_); + target_->set_light_color_values(target_values_); + + // When a transition is modified, then use the current GPIO outputs + // as the new starting point. + // ... TODO + // + ESP_LOGE("DEBUG", "Start this thing"); // TODO + } + + void finish() override { + ESP_LOGE("DEBUG", "Finish this thing"); // TODO + } + + void abort() override { + ESP_LOGE("DEBUG", "Abort this thing"); // TODO + } + + optional apply() override { + if (target_->light_mode == "night") { + ESP_LOGE("DEBUG", "Set night light directly"); // DEBUG + light_->set_rgbw(target_->red, target_->green, target_->blue, target_->white); + is_completed_ = true; + } + else { + auto smoothed = light::LightTransitionTransformer::smoothed_progress(get_progress_()); + light_->set_rgbw( + esphome::lerp(smoothed, start_->red, target_->red), + esphome::lerp(smoothed, start_->green, target_->green), + esphome::lerp(smoothed, start_->blue, target_->blue), + esphome::lerp(smoothed, start_->white, target_->white)); + } + + if (is_completed()) { + ESP_LOGE("DEBUG", "We're done, publish target values"); // TODO + is_completed_ = true; + return target_values_; + } else { + return {}; + } + } + + protected: + LightHAL *light_; + bool is_completed_ = false; + GPIOOutputs *start_ = new ColorInstantHandler(); + GPIOOutputs *target_ = new ColorInstantHandler(); +}; + +} // namespace bslamp2 +} // namespace xiaomi +} // namespace esphome