ESPHome  2022.6.2
light_state.cpp
Go to the documentation of this file.
1 #include "esphome/core/log.h"
2 #include "light_state.h"
3 #include "light_output.h"
4 #include "transformers.h"
5 
6 namespace esphome {
7 namespace light {
8 
9 static const char *const TAG = "light";
10 
11 LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {}
13 
15 LightCall LightState::turn_on() { return this->make_call().set_state(true); }
16 LightCall LightState::turn_off() { return this->make_call().set_state(false); }
19 
20 struct LightStateRTCState {
21  ColorMode color_mode{ColorMode::UNKNOWN};
22  bool state{false};
23  float brightness{1.0f};
24  float color_brightness{1.0f};
25  float red{1.0f};
26  float green{1.0f};
27  float blue{1.0f};
28  float white{1.0f};
29  float color_temp{1.0f};
30  float cold_white{1.0f};
31  float warm_white{1.0f};
32  uint32_t effect{0};
33 };
34 
36  ESP_LOGCONFIG(TAG, "Setting up light '%s'...", this->get_name().c_str());
37 
38  this->output_->setup_state(this);
39  for (auto *effect : this->effects_) {
40  effect->init_internal(this);
41  }
42 
43  // When supported color temperature range is known, initialize color temperature setting within bounds.
44  float min_mireds = this->get_traits().get_min_mireds();
45  if (min_mireds > 0) {
46  this->remote_values.set_color_temperature(min_mireds);
47  this->current_values.set_color_temperature(min_mireds);
48  }
49 
50  auto call = this->make_call();
51  LightStateRTCState recovered{};
52  switch (this->restore_mode_) {
57  this->rtc_ = global_preferences->make_preference<LightStateRTCState>(this->get_object_id_hash());
58  // Attempt to load from preferences, else fall back to default values
59  if (!this->rtc_.load(&recovered)) {
60  recovered.state = false;
63  recovered.state = true;
64  }
67  // Inverted restore state
68  recovered.state = !recovered.state;
69  }
70  break;
73  this->rtc_ = global_preferences->make_preference<LightStateRTCState>(this->get_object_id_hash());
74  this->rtc_.load(&recovered);
75  recovered.state = (this->restore_mode_ == LIGHT_RESTORE_AND_ON);
76  break;
77  case LIGHT_ALWAYS_OFF:
78  recovered.state = false;
79  break;
80  case LIGHT_ALWAYS_ON:
81  recovered.state = true;
82  break;
83  }
84 
85  call.set_color_mode_if_supported(recovered.color_mode);
86  call.set_state(recovered.state);
87  call.set_brightness_if_supported(recovered.brightness);
88  call.set_color_brightness_if_supported(recovered.color_brightness);
89  call.set_red_if_supported(recovered.red);
90  call.set_green_if_supported(recovered.green);
91  call.set_blue_if_supported(recovered.blue);
92  call.set_white_if_supported(recovered.white);
93  call.set_color_temperature_if_supported(recovered.color_temp);
94  call.set_cold_white_if_supported(recovered.cold_white);
95  call.set_warm_white_if_supported(recovered.warm_white);
96  if (recovered.effect != 0) {
97  call.set_effect(recovered.effect);
98  } else {
99  call.set_transition_length_if_supported(0);
100  }
101  call.perform();
102 }
104  ESP_LOGCONFIG(TAG, "Light '%s'", this->get_name().c_str());
105  if (this->get_traits().supports_color_capability(ColorCapability::BRIGHTNESS)) {
106  ESP_LOGCONFIG(TAG, " Default Transition Length: %.1fs", this->default_transition_length_ / 1e3f);
107  ESP_LOGCONFIG(TAG, " Gamma Correct: %.2f", this->gamma_correct_);
108  }
109  if (this->get_traits().supports_color_capability(ColorCapability::COLOR_TEMPERATURE)) {
110  ESP_LOGCONFIG(TAG, " Min Mireds: %.1f", this->get_traits().get_min_mireds());
111  ESP_LOGCONFIG(TAG, " Max Mireds: %.1f", this->get_traits().get_max_mireds());
112  }
113 }
115  // Apply effect (if any)
116  auto *effect = this->get_active_effect_();
117  if (effect != nullptr) {
118  effect->apply();
119  }
120 
121  // Apply transformer (if any)
122  if (this->transformer_ != nullptr) {
123  auto values = this->transformer_->apply();
124  if (values.has_value()) {
125  this->current_values = *values;
126  this->output_->update_state(this);
127  this->next_write_ = true;
128  }
129 
130  if (this->transformer_->is_finished()) {
131  // if the transition has written directly to the output, current_values is outdated, so update it
132  this->current_values = this->transformer_->get_target_values();
133 
134  this->transformer_->stop();
135  this->transformer_ = nullptr;
136  this->target_state_reached_callback_.call();
137  }
138  }
139 
140  // Write state to the light
141  if (this->next_write_) {
142  this->next_write_ = false;
143  this->output_->write_state(this);
144  }
145 }
146 
148 
150 
151 LightOutput *LightState::get_output() const { return this->output_; }
153  if (this->active_effect_index_ > 0) {
154  return this->effects_[this->active_effect_index_ - 1]->get_name();
155  } else {
156  return "None";
157  }
158 }
159 
160 void LightState::add_new_remote_values_callback(std::function<void()> &&send_callback) {
161  this->remote_values_callback_.add(std::move(send_callback));
162 }
163 void LightState::add_new_target_state_reached_callback(std::function<void()> &&send_callback) {
164  this->target_state_reached_callback_.add(std::move(send_callback));
165 }
166 
167 void LightState::set_default_transition_length(uint32_t default_transition_length) {
168  this->default_transition_length_ = default_transition_length;
169 }
171 void LightState::set_flash_transition_length(uint32_t flash_transition_length) {
172  this->flash_transition_length_ = flash_transition_length;
173 }
176 void LightState::set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
177 bool LightState::supports_effects() { return !this->effects_.empty(); }
178 const std::vector<LightEffect *> &LightState::get_effects() const { return this->effects_; }
179 void LightState::add_effects(const std::vector<LightEffect *> &effects) {
180  this->effects_.reserve(this->effects_.size() + effects.size());
181  for (auto *effect : effects) {
182  this->effects_.push_back(effect);
183  }
184 }
185 
186 void LightState::current_values_as_binary(bool *binary) { this->current_values.as_binary(binary); }
188  this->current_values.as_brightness(brightness, this->gamma_correct_);
189 }
190 void LightState::current_values_as_rgb(float *red, float *green, float *blue, bool color_interlock) {
191  auto traits = this->get_traits();
192  this->current_values.as_rgb(red, green, blue, this->gamma_correct_, false);
193 }
194 void LightState::current_values_as_rgbw(float *red, float *green, float *blue, float *white, bool color_interlock) {
195  auto traits = this->get_traits();
196  this->current_values.as_rgbw(red, green, blue, white, this->gamma_correct_, false);
197 }
198 void LightState::current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white,
199  bool constant_brightness) {
200  this->current_values.as_rgbww(red, green, blue, cold_white, warm_white, this->gamma_correct_, constant_brightness);
201 }
202 void LightState::current_values_as_rgbct(float *red, float *green, float *blue, float *color_temperature,
203  float *white_brightness) {
204  auto traits = this->get_traits();
205  this->current_values.as_rgbct(traits.get_min_mireds(), traits.get_max_mireds(), red, green, blue, color_temperature,
206  white_brightness, this->gamma_correct_);
207 }
208 void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness) {
209  auto traits = this->get_traits();
210  this->current_values.as_cwww(cold_white, warm_white, this->gamma_correct_, constant_brightness);
211 }
212 void LightState::current_values_as_ct(float *color_temperature, float *white_brightness) {
213  auto traits = this->get_traits();
214  this->current_values.as_ct(traits.get_min_mireds(), traits.get_max_mireds(), color_temperature, white_brightness,
215  this->gamma_correct_);
216 }
217 
218 void LightState::start_effect_(uint32_t effect_index) {
219  this->stop_effect_();
220  if (effect_index == 0)
221  return;
222 
223  this->active_effect_index_ = effect_index;
224  auto *effect = this->get_active_effect_();
225  effect->start_internal();
226 }
228  if (this->active_effect_index_ == 0) {
229  return nullptr;
230  } else {
231  return this->effects_[this->active_effect_index_ - 1];
232  }
233 }
235  auto *effect = this->get_active_effect_();
236  if (effect != nullptr) {
237  effect->stop();
238  }
239  this->active_effect_index_ = 0;
240 }
241 
242 void LightState::start_transition_(const LightColorValues &target, uint32_t length, bool set_remote_values) {
244  this->transformer_->setup(this->current_values, target, length);
245 
246  if (set_remote_values) {
247  this->remote_values = target;
248  }
249 }
250 
251 void LightState::start_flash_(const LightColorValues &target, uint32_t length, bool set_remote_values) {
252  LightColorValues end_colors = this->remote_values;
253  // If starting a flash if one is already happening, set end values to end values of current flash
254  // Hacky but works
255  if (this->transformer_ != nullptr)
256  end_colors = this->transformer_->get_start_values();
257 
258  this->transformer_ = make_unique<LightFlashTransformer>(*this);
259  this->transformer_->setup(end_colors, target, length);
260 
261  if (set_remote_values) {
262  this->remote_values = target;
263  };
264 }
265 
266 void LightState::set_immediately_(const LightColorValues &target, bool set_remote_values) {
267  this->transformer_ = nullptr;
268  this->current_values = target;
269  if (set_remote_values) {
270  this->remote_values = target;
271  }
272  this->output_->update_state(this);
273  this->next_write_ = true;
274 }
275 
277  LightStateRTCState saved;
278  saved.color_mode = this->remote_values.get_color_mode();
279  saved.state = this->remote_values.is_on();
280  saved.brightness = this->remote_values.get_brightness();
281  saved.color_brightness = this->remote_values.get_color_brightness();
282  saved.red = this->remote_values.get_red();
283  saved.green = this->remote_values.get_green();
284  saved.blue = this->remote_values.get_blue();
285  saved.white = this->remote_values.get_white();
286  saved.color_temp = this->remote_values.get_color_temperature();
287  saved.cold_white = this->remote_values.get_cold_white();
288  saved.warm_white = this->remote_values.get_warm_white();
289  saved.effect = this->active_effect_index_;
290  this->rtc_.save(&saved);
291 }
292 
293 } // namespace light
294 } // namespace esphome
void current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white, bool constant_brightness=false)
float gamma_correct_
Gamma correction factor for the light.
Definition: light_state.h:202
ColorMode
Color modes are a combination of color capabilities that can be used at the same time.
Definition: color_mode.h:49
const char * name
Definition: stm32flash.h:78
ESPPreferenceObject rtc_
Object used to store the persisted values of the light.
Definition: light_state.h:181
void set_flash_transition_length(uint32_t flash_transition_length)
Set the flash transition length.
float get_warm_white() const
Get the warm white property of these light color values. In range 0.0 to 1.0.
uint32_t get_flash_transition_length() const
void publish_state()
Publish the currently active state to the frontend.
std::unique_ptr< LightTransformer > transformer_
The currently active transformer for this light (transition/flash).
Definition: light_state.h:176
void set_immediately_(const LightColorValues &target, bool set_remote_values)
Internal method to set the color values to target immediately (with no transition).
bool is_on() const
Get the binary true/false state of these light color values.
uint32_t default_transition_length_
Default transition length for all transitions in ms.
Definition: light_state.h:198
Interface to write LightStates to hardware.
Definition: light_output.h:12
LightColorValues current_values
The current values of the light as outputted to the light.
Definition: light_state.h:66
void set_default_transition_length(uint32_t default_transition_length)
Set the default transition length, i.e. the transition length when no transition is provided...
std::string get_effect_name()
Return the name of the current effect, or if no effect is active "None".
LightCall turn_on()
Make a light state call.
Definition: light_state.cpp:15
void start_transition_(const LightColorValues &target, uint32_t length, bool set_remote_values)
Internal method to start a transition to the target color with the given length.
void as_cwww(float *cold_white, float *warm_white, float gamma=0, bool constant_brightness=false) const
Convert these light color values to an CWWW representation with the given parameters.
float get_cold_white() const
Get the cold white property of these light color values. In range 0.0 to 1.0.
void start_effect_(uint32_t effect_index)
Internal method to start an effect with the given index.
LightRestoreMode restore_mode_
Restore mode of the light.
Definition: light_state.h:204
LightOutput * get_output() const
Get the light output associated with this object.
float get_min_mireds() const
Definition: light_traits.h:49
void as_rgbct(float color_temperature_cw, float color_temperature_ww, float *red, float *green, float *blue, float *color_temperature, float *white_brightness, float gamma=0) const
Convert these light color values to an RGB+CT+BR representation with the given parameters.
bool supports_effects()
Return whether the light has any effects that meet the trait requirements.
void start_flash_(const LightColorValues &target, uint32_t length, bool set_remote_values)
Internal method to start a flash for the specified amount of time.
float get_red() const
Get the red property of these light color values. In range 0.0 to 1.0.
virtual std::unique_ptr< LightTransformer > create_default_transition()
Return the default transformer used for transitions.
Definition: light_output.cpp:7
void add_new_target_state_reached_callback(std::function< void()> &&send_callback)
The callback is called once the state of current_values and remote_values are equal (when the transit...
Color temperature can be controlled.
const std::string & get_name() const
Definition: entity_base.cpp:11
void setup() override
Load state from preferences.
Definition: light_state.cpp:35
void dump_config() override
void current_values_as_binary(bool *binary)
The result of all the current_values_as_* methods have gamma correction applied.
bool save(const T *src)
Definition: preferences.h:21
bool next_write_
Whether the light value should be written in the next cycle.
Definition: light_state.h:178
void current_values_as_rgb(float *red, float *green, float *blue, bool color_interlock=false)
float get_blue() const
Get the blue property of these light color values. In range 0.0 to 1.0.
uint32_t flash_transition_length_
Transition length to use for flash transitions.
Definition: light_state.h:200
virtual void write_state(LightState *state)=0
Called from loop() every time the light state has changed, and should should write the new state to h...
LightOutput * output_
Store the output to allow effects to have more access.
Definition: light_state.h:172
float gamma_correct(float value, float gamma)
Applies gamma correction of gamma to value.
Definition: helpers.cpp:263
This class represents the color state for a light object.
void current_values_as_rgbct(float *red, float *green, float *blue, float *color_temperature, float *white_brightness)
LightEffect * get_active_effect_()
Internal method to get the currently active effect.
float get_white() const
Get the white property of these light color values. In range 0.0 to 1.0.
ESPPreferences * global_preferences
float get_color_temperature() const
Get the color temperature property of these light color values in mired.
void add_effects(const std::vector< LightEffect *> &effects)
Add effects for this light state.
void current_values_as_brightness(float *brightness)
uint32_t get_default_transition_length() const
void set_gamma_correct(float gamma_correct)
Set the gamma correction factor.
const std::vector< LightEffect * > & get_effects() const
Get all effects for this light state.
This class represents a requested change in a light state.
Definition: light_call.h:14
ColorMode get_color_mode() const
Get the color mode of these light color values.
LightCall & set_state(optional< bool > state)
Set the binary ON/OFF state of the light.
Definition: light_call.cpp:552
std::vector< LightEffect * > effects_
List of effects for this light.
Definition: light_state.h:206
Master brightness of the light can be controlled.
void current_values_as_ct(float *color_temperature, float *white_brightness)
void current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness=false)
float get_setup_priority() const override
Shortly after HARDWARE.
CallbackManager< void()> remote_values_callback_
Callback to call when new values for the frontend are available.
Definition: light_state.h:190
No color mode configured (cannot be a supported mode, only active when light is off).
virtual void update_state(LightState *state)
Called on every update of the current values of the associated LightState, can optionally be used to ...
Definition: light_output.h:24
This class is used to represent the capabilities of a light.
Definition: light_traits.h:11
void as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white, float gamma=0, bool constant_brightness=false) const
Convert these light color values to an RGBWW representation with the given parameters.
void add_new_remote_values_callback(std::function< void()> &&send_callback)
This lets front-end components subscribe to light change events.
void as_ct(float color_temperature_cw, float color_temperature_ww, float *color_temperature, float *white_brightness, float gamma=0) const
Convert these light color values to a CT+BR representation with the given parameters.
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition: component.cpp:17
void set_restore_mode(LightRestoreMode restore_mode)
Set the restore mode of this light.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
void set_color_temperature(float color_temperature)
Set the color temperature property of these light color values in mired.
void save_remote_values_()
Internal method to save the current remote_values to the preferences.
void as_binary(bool *binary) const
Convert these light color values to a binary representation and write them to binary.
virtual void setup_state(LightState *state)
Definition: light_output.h:20
CallbackManager< void()> target_state_reached_callback_
Callback to call when the state of current_values and remote_values are equal This should be called o...
Definition: light_state.h:195
Definition: a4988.cpp:4
uint32_t active_effect_index_
Value for storing the index of the currently active effect. 0 if no effect is active.
Definition: light_state.h:174
LightColorValues remote_values
The remote color values reported to the frontend.
Definition: light_state.h:78
virtual LightTraits get_traits()=0
Return the LightTraits of this LightOutput.
float get_color_brightness() const
Get the color brightness property of these light color values. In range 0.0 to 1.0.
void as_rgbw(float *red, float *green, float *blue, float *white, float gamma=0, bool color_interlock=false) const
Convert these light color values to an RGBW representation and write them to red, green...
void as_rgb(float *red, float *green, float *blue, float gamma=0, bool color_interlock=false) const
Convert these light color values to an RGB representation and write them to red, green, blue.
LightState(const std::string &name, LightOutput *output)
Construct this LightState using the provided traits and name.
Definition: light_state.cpp:11
void as_brightness(float *brightness, float gamma=0) const
Convert these light color values to a brightness-only representation and write them to brightness...
void stop_effect_()
Internal method to stop the current effect (if one is active).
uint32_t get_object_id_hash()
Definition: entity_base.cpp:42
float get_green() const
Get the green property of these light color values. In range 0.0 to 1.0.
float get_brightness() const
Get the brightness property of these light color values. In range 0.0 to 1.0.
void current_values_as_rgbw(float *red, float *green, float *blue, float *white, bool color_interlock=false)
bool state
Definition: fan.h:34