ESPHome  2024.12.2
light_color_values.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "esphome/core/helpers.h"
4 #include "color_mode.h"
5 #include <cmath>
6 
7 namespace esphome {
8 namespace light {
9 
10 inline static uint8_t to_uint8_scale(float x) { return static_cast<uint8_t>(roundf(x * 255.0f)); }
11 
46  public:
50  state_(0.0f),
51  brightness_(1.0f),
52  color_brightness_(1.0f),
53  red_(1.0f),
54  green_(1.0f),
55  blue_(1.0f),
56  white_(1.0f),
57  color_temperature_{0.0f},
58  cold_white_{1.0f},
59  warm_white_{1.0f} {}
60 
61  LightColorValues(ColorMode color_mode, float state, float brightness, float color_brightness, float red, float green,
62  float blue, float white, float color_temperature, float cold_white, float warm_white) {
63  this->set_color_mode(color_mode);
64  this->set_state(state);
65  this->set_brightness(brightness);
66  this->set_color_brightness(color_brightness);
67  this->set_red(red);
68  this->set_green(green);
69  this->set_blue(blue);
70  this->set_white(white);
71  this->set_color_temperature(color_temperature);
72  this->set_cold_white(cold_white);
73  this->set_warm_white(warm_white);
74  }
75 
86  static LightColorValues lerp(const LightColorValues &start, const LightColorValues &end, float completion) {
89  v.set_state(esphome::lerp(completion, start.get_state(), end.get_state()));
90  v.set_brightness(esphome::lerp(completion, start.get_brightness(), end.get_brightness()));
92  v.set_red(esphome::lerp(completion, start.get_red(), end.get_red()));
93  v.set_green(esphome::lerp(completion, start.get_green(), end.get_green()));
94  v.set_blue(esphome::lerp(completion, start.get_blue(), end.get_blue()));
95  v.set_white(esphome::lerp(completion, start.get_white(), end.get_white()));
97  v.set_cold_white(esphome::lerp(completion, start.get_cold_white(), end.get_cold_white()));
98  v.set_warm_white(esphome::lerp(completion, start.get_warm_white(), end.get_warm_white()));
99  return v;
100  }
101 
112  if (this->color_mode_ & ColorCapability::RGB) {
113  float max_value = fmaxf(this->get_red(), fmaxf(this->get_green(), this->get_blue()));
114  if (max_value == 0.0f) {
115  this->set_red(1.0f);
116  this->set_green(1.0f);
117  this->set_blue(1.0f);
118  } else {
119  this->set_red(this->get_red() / max_value);
120  this->set_green(this->get_green() / max_value);
121  this->set_blue(this->get_blue() / max_value);
122  }
123  }
124  }
125 
126  // Note that method signature of as_* methods is kept as-is for compatibility reasons, so not all parameters
127  // are always used or necessary. Methods will be deprecated later.
128 
130  void as_binary(bool *binary) const { *binary = this->state_ == 1.0f; }
131 
133  void as_brightness(float *brightness, float gamma = 0) const {
134  *brightness = gamma_correct(this->state_ * this->brightness_, gamma);
135  }
136 
138  void as_rgb(float *red, float *green, float *blue, float gamma = 0, bool color_interlock = false) const {
139  if (this->color_mode_ & ColorCapability::RGB) {
140  float brightness = this->state_ * this->brightness_ * this->color_brightness_;
141  *red = gamma_correct(brightness * this->red_, gamma);
142  *green = gamma_correct(brightness * this->green_, gamma);
143  *blue = gamma_correct(brightness * this->blue_, gamma);
144  } else {
145  *red = *green = *blue = 0;
146  }
147  }
148 
150  void as_rgbw(float *red, float *green, float *blue, float *white, float gamma = 0,
151  bool color_interlock = false) const {
152  this->as_rgb(red, green, blue, gamma);
153  if (this->color_mode_ & ColorCapability::WHITE) {
154  *white = gamma_correct(this->state_ * this->brightness_ * this->white_, gamma);
155  } else {
156  *white = 0;
157  }
158  }
159 
161  void as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white, float gamma = 0,
162  bool constant_brightness = false) const {
163  this->as_rgb(red, green, blue, gamma);
164  this->as_cwww(cold_white, warm_white, gamma, constant_brightness);
165  }
166 
168  void as_rgbct(float color_temperature_cw, float color_temperature_ww, float *red, float *green, float *blue,
169  float *color_temperature, float *white_brightness, float gamma = 0) const {
170  this->as_rgb(red, green, blue, gamma);
171  this->as_ct(color_temperature_cw, color_temperature_ww, color_temperature, white_brightness, gamma);
172  }
173 
175  void as_cwww(float *cold_white, float *warm_white, float gamma = 0, bool constant_brightness = false) const {
177  const float cw_level = gamma_correct(this->cold_white_, gamma);
178  const float ww_level = gamma_correct(this->warm_white_, gamma);
179  const float white_level = gamma_correct(this->state_ * this->brightness_, gamma);
180  if (!constant_brightness) {
181  *cold_white = white_level * cw_level;
182  *warm_white = white_level * ww_level;
183  } else {
184  // Just multiplying by cw_level / (cw_level + ww_level) would divide out the brightness information from the
185  // cold_white and warm_white settings (i.e. cw=0.8, ww=0.4 would be identical to cw=0.4, ww=0.2), which breaks
186  // transitions. Use the highest value as the brightness for the white channels (the alternative, using cw+ww/2,
187  // reduces to cw/2 and ww/2, which would still limit brightness to 100% of a single channel, but isn't very
188  // useful in all other aspects -- that behaviour can also be achieved by limiting the output power).
189  const float sum = cw_level > 0 || ww_level > 0 ? cw_level + ww_level : 1; // Don't divide by zero.
190  *cold_white = white_level * std::max(cw_level, ww_level) * cw_level / sum;
191  *warm_white = white_level * std::max(cw_level, ww_level) * ww_level / sum;
192  }
193  } else {
194  *cold_white = *warm_white = 0;
195  }
196  }
197 
199  void as_ct(float color_temperature_cw, float color_temperature_ww, float *color_temperature, float *white_brightness,
200  float gamma = 0) const {
201  const float white_level = this->color_mode_ & ColorCapability::RGB ? this->white_ : 1;
203  *color_temperature =
204  (this->color_temperature_ - color_temperature_cw) / (color_temperature_ww - color_temperature_cw);
205  *white_brightness = gamma_correct(this->state_ * this->brightness_ * white_level, gamma);
206  } else { // Probably won't get here but put this here anyway.
207  *white_brightness = 0;
208  }
209  }
210 
212  bool operator==(const LightColorValues &rhs) const {
213  return color_mode_ == rhs.color_mode_ && state_ == rhs.state_ && brightness_ == rhs.brightness_ &&
214  color_brightness_ == rhs.color_brightness_ && red_ == rhs.red_ && green_ == rhs.green_ &&
215  blue_ == rhs.blue_ && white_ == rhs.white_ && color_temperature_ == rhs.color_temperature_ &&
217  }
218  bool operator!=(const LightColorValues &rhs) const { return !(rhs == *this); }
219 
221  ColorMode get_color_mode() const { return this->color_mode_; }
223  void set_color_mode(ColorMode color_mode) { this->color_mode_ = color_mode; }
224 
226  float get_state() const { return this->state_; }
228  bool is_on() const { return this->get_state() != 0.0f; }
230  void set_state(float state) { this->state_ = clamp(state, 0.0f, 1.0f); }
232  void set_state(bool state) { this->state_ = state ? 1.0f : 0.0f; }
233 
235  float get_brightness() const { return this->brightness_; }
237  void set_brightness(float brightness) { this->brightness_ = clamp(brightness, 0.0f, 1.0f); }
238 
240  float get_color_brightness() const { return this->color_brightness_; }
242  void set_color_brightness(float brightness) { this->color_brightness_ = clamp(brightness, 0.0f, 1.0f); }
243 
245  float get_red() const { return this->red_; }
247  void set_red(float red) { this->red_ = clamp(red, 0.0f, 1.0f); }
248 
250  float get_green() const { return this->green_; }
252  void set_green(float green) { this->green_ = clamp(green, 0.0f, 1.0f); }
253 
255  float get_blue() const { return this->blue_; }
257  void set_blue(float blue) { this->blue_ = clamp(blue, 0.0f, 1.0f); }
258 
260  float get_white() const { return white_; }
262  void set_white(float white) { this->white_ = clamp(white, 0.0f, 1.0f); }
263 
265  float get_color_temperature() const { return this->color_temperature_; }
267  void set_color_temperature(float color_temperature) { this->color_temperature_ = color_temperature; }
268 
271  if (this->color_temperature_ <= 0) {
272  return this->color_temperature_;
273  }
274  return 1000000.0 / this->color_temperature_;
275  }
277  void set_color_temperature_kelvin(float color_temperature) {
278  if (color_temperature <= 0) {
279  return;
280  }
281  this->color_temperature_ = 1000000.0 / color_temperature;
282  }
283 
285  float get_cold_white() const { return this->cold_white_; }
287  void set_cold_white(float cold_white) { this->cold_white_ = clamp(cold_white, 0.0f, 1.0f); }
288 
290  float get_warm_white() const { return this->warm_white_; }
292  void set_warm_white(float warm_white) { this->warm_white_ = clamp(warm_white, 0.0f, 1.0f); }
293 
294  protected:
296  float state_;
297  float brightness_;
299  float red_;
300  float green_;
301  float blue_;
302  float white_;
304  float cold_white_;
305  float warm_white_;
306 };
307 
308 } // namespace light
309 } // namespace esphome
ColorMode
Color modes are a combination of color capabilities that can be used at the same time.
Definition: color_mode.h:49
float get_warm_white() const
Get the warm white property of these light color values. In range 0.0 to 1.0.
bool is_on() const
Get the binary true/false state of these light color values.
float color_temperature_
Color Temperature in Mired.
void set_warm_white(float warm_white)
Set the warm white property of these light color values. In range 0.0 to 1.0.
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.
void set_state(bool state)
Set the state of these light color values as a binary true/false.
float get_cold_white() const
Get the cold white property of these light color values. In range 0.0 to 1.0.
uint16_t x
Definition: tt21100.cpp:17
void set_green(float green)
Set the green property of these light color values. In range 0.0 to 1.0.
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.
void set_state(float state)
Set the state of these light color values. In range from 0.0 (off) to 1.0 (on)
float get_red() const
Get the red property of these light color values. In range 0.0 to 1.0.
LightColorValues(ColorMode color_mode, float state, float brightness, float color_brightness, float red, float green, float blue, float white, float color_temperature, float cold_white, float warm_white)
float lerp(float completion, float start, float end)
Linearly interpolate between start and end by completion (between 0 and 1).
Definition: helpers.cpp:94
Color temperature can be controlled.
float get_color_temperature_kelvin() const
Get the color temperature property of these light color values in kelvin.
LightColorValues()
Construct the LightColorValues with all attributes enabled, but state set to off. ...
void set_color_mode(ColorMode color_mode)
Set the color mode of these light color values.
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition: helpers.h:93
bool operator==(const LightColorValues &rhs) const
Compare this LightColorValues to rhs, return true if and only if all attributes match.
void set_red(float red)
Set the red property of these light color values. In range 0.0 to 1.0.
float get_blue() const
Get the blue property of these light color values. In range 0.0 to 1.0.
float gamma_correct(float value, float gamma)
Applies gamma correction of gamma to value.
Definition: helpers.cpp:559
This class represents the color state for a light object.
Brightness of cold and warm white output can be controlled.
float get_white() const
Get the white property of these light color values. In range 0.0 to 1.0.
float state_
ON / OFF, float for transition.
float get_color_temperature() const
Get the color temperature property of these light color values in mired.
Brightness of white channel can be controlled separately from other channels.
float get_state() const
Get the state of these light color values. In range from 0.0 (off) to 1.0 (on)
ColorMode get_color_mode() const
Get the color mode of these light color values.
void set_white(float white)
Set the white property of these light color values. In range 0.0 to 1.0.
No color mode configured (cannot be a supported mode, only active when light is off).
void set_color_brightness(float brightness)
Set the color brightness property of these light color values. In range 0.0 to 1.0.
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 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.
void normalize_color()
Normalize the color (RGB/W) component.
void set_color_temperature(float color_temperature)
Set the color temperature property of these light color values in mired.
void set_brightness(float brightness)
Set the brightness property of these light color values. In range 0.0 to 1.0.
void set_blue(float blue)
Set the blue property of these light color values. In range 0.0 to 1.0.
void as_binary(bool *binary) const
Convert these light color values to a binary representation and write them to binary.
void set_cold_white(float cold_white)
Set the cold white property of these light color values. In range 0.0 to 1.0.
void set_color_temperature_kelvin(float color_temperature)
Set the color temperature property of these light color values in kelvin.
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
Color can be controlled using RGB format (includes a brightness control for the color).
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...
bool operator!=(const LightColorValues &rhs) const
uint8_t end[39]
Definition: sun_gtil2.cpp:31
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.
void as_brightness(float *brightness, float gamma=0) const
Convert these light color values to a brightness-only representation and write them to brightness...
static LightColorValues lerp(const LightColorValues &start, const LightColorValues &end, float completion)
Linearly interpolate between the values in start to the values in end.
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.
bool state
Definition: fan.h:34