ESPHome  2022.12.8
tuya_light.cpp
Go to the documentation of this file.
1 #include "esphome/core/log.h"
2 #include "tuya_light.h"
3 #include "esphome/core/helpers.h"
4 
5 namespace esphome {
6 namespace tuya {
7 
8 static const char *const TAG = "tuya.light";
9 
11  if (this->color_temperature_id_.has_value()) {
12  this->parent_->register_listener(*this->color_temperature_id_, [this](const TuyaDatapoint &datapoint) {
13  if (this->state_->current_values != this->state_->remote_values) {
14  ESP_LOGD(TAG, "Light is transitioning, datapoint change ignored");
15  return;
16  }
17 
18  auto datapoint_value = datapoint.value_uint;
19  if (this->color_temperature_invert_) {
20  datapoint_value = this->color_temperature_max_value_ - datapoint_value;
21  }
22  auto call = this->state_->make_call();
23  call.set_color_temperature(this->cold_white_temperature_ +
25  (float(datapoint_value) / this->color_temperature_max_value_));
26  call.perform();
27  });
28  }
29  if (this->dimmer_id_.has_value()) {
30  this->parent_->register_listener(*this->dimmer_id_, [this](const TuyaDatapoint &datapoint) {
31  if (this->state_->current_values != this->state_->remote_values) {
32  ESP_LOGD(TAG, "Light is transitioning, datapoint change ignored");
33  return;
34  }
35 
36  auto call = this->state_->make_call();
37  call.set_brightness(float(datapoint.value_uint) / this->max_value_);
38  call.perform();
39  });
40  }
41  if (switch_id_.has_value()) {
42  this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
43  if (this->state_->current_values != this->state_->remote_values) {
44  ESP_LOGD(TAG, "Light is transitioning, datapoint change ignored");
45  return;
46  }
47 
48  auto call = this->state_->make_call();
49  call.set_state(datapoint.value_bool);
50  call.perform();
51  });
52  }
53  if (rgb_id_.has_value()) {
54  this->parent_->register_listener(*this->rgb_id_, [this](const TuyaDatapoint &datapoint) {
55  auto red = parse_hex<uint8_t>(datapoint.value_string.substr(0, 2));
56  auto green = parse_hex<uint8_t>(datapoint.value_string.substr(2, 2));
57  auto blue = parse_hex<uint8_t>(datapoint.value_string.substr(4, 2));
58  if (red.has_value() && green.has_value() && blue.has_value()) {
59  if (this->state_->current_values != this->state_->remote_values) {
60  ESP_LOGD(TAG, "Light is transitioning, datapoint change ignored");
61  return;
62  }
63 
64  auto call = this->state_->make_call();
65  call.set_rgb(float(*red) / 255, float(*green) / 255, float(*blue) / 255);
66  call.perform();
67  }
68  });
69  } else if (hsv_id_.has_value()) {
70  this->parent_->register_listener(*this->hsv_id_, [this](const TuyaDatapoint &datapoint) {
71  auto hue = parse_hex<uint16_t>(datapoint.value_string.substr(0, 4));
72  auto saturation = parse_hex<uint16_t>(datapoint.value_string.substr(4, 4));
73  auto value = parse_hex<uint16_t>(datapoint.value_string.substr(8, 4));
74  if (hue.has_value() && saturation.has_value() && value.has_value()) {
75  if (this->state_->current_values != this->state_->remote_values) {
76  ESP_LOGD(TAG, "Light is transitioning, datapoint change ignored");
77  return;
78  }
79 
80  float red, green, blue;
81  hsv_to_rgb(*hue, float(*saturation) / 1000, float(*value) / 1000, red, green, blue);
82  auto call = this->state_->make_call();
83  call.set_rgb(red, green, blue);
84  call.perform();
85  }
86  });
87  }
90  }
91 }
92 
94  ESP_LOGCONFIG(TAG, "Tuya Dimmer:");
95  if (this->dimmer_id_.has_value()) {
96  ESP_LOGCONFIG(TAG, " Dimmer has datapoint ID %u", *this->dimmer_id_);
97  }
98  if (this->switch_id_.has_value()) {
99  ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
100  }
101  if (this->rgb_id_.has_value()) {
102  ESP_LOGCONFIG(TAG, " RGB has datapoint ID %u", *this->rgb_id_);
103  } else if (this->hsv_id_.has_value()) {
104  ESP_LOGCONFIG(TAG, " HSV has datapoint ID %u", *this->hsv_id_);
105  }
106 }
107 
109  auto traits = light::LightTraits();
110  if (this->color_temperature_id_.has_value() && this->dimmer_id_.has_value()) {
111  if (this->rgb_id_.has_value() || this->hsv_id_.has_value()) {
112  if (this->color_interlock_) {
113  traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::COLOR_TEMPERATURE});
114  } else {
115  traits.set_supported_color_modes(
117  }
118  } else
119  traits.set_supported_color_modes({light::ColorMode::COLOR_TEMPERATURE});
120  traits.set_min_mireds(this->cold_white_temperature_);
121  traits.set_max_mireds(this->warm_white_temperature_);
122  } else if (this->rgb_id_.has_value() || this->hsv_id_.has_value()) {
123  if (this->dimmer_id_.has_value()) {
124  if (this->color_interlock_) {
125  traits.set_supported_color_modes({light::ColorMode::RGB, light::ColorMode::WHITE});
126  } else {
127  traits.set_supported_color_modes({light::ColorMode::RGB_WHITE});
128  }
129  } else
130  traits.set_supported_color_modes({light::ColorMode::RGB});
131  } else if (this->dimmer_id_.has_value()) {
132  traits.set_supported_color_modes({light::ColorMode::BRIGHTNESS});
133  } else {
134  traits.set_supported_color_modes({light::ColorMode::ON_OFF});
135  }
136  return traits;
137 }
138 
140 
142  float red = 0.0f, green = 0.0f, blue = 0.0f;
143  float color_temperature = 0.0f, brightness = 0.0f;
144 
145  if (this->rgb_id_.has_value() || this->hsv_id_.has_value()) {
146  if (this->color_temperature_id_.has_value()) {
147  state->current_values_as_rgbct(&red, &green, &blue, &color_temperature, &brightness);
148  } else if (this->dimmer_id_.has_value()) {
149  state->current_values_as_rgbw(&red, &green, &blue, &brightness);
150  } else {
151  state->current_values_as_rgb(&red, &green, &blue);
152  }
153  } else if (this->color_temperature_id_.has_value()) {
154  state->current_values_as_ct(&color_temperature, &brightness);
155  } else {
156  state->current_values_as_brightness(&brightness);
157  }
158 
159  if (!state->current_values.is_on() && this->switch_id_.has_value()) {
161  return;
162  }
163 
164  if (brightness > 0.0f || !color_interlock_) {
165  if (this->color_temperature_id_.has_value()) {
166  uint32_t color_temp_int = static_cast<uint32_t>(color_temperature * this->color_temperature_max_value_);
167  if (this->color_temperature_invert_) {
168  color_temp_int = this->color_temperature_max_value_ - color_temp_int;
169  }
171  }
172 
173  if (this->dimmer_id_.has_value()) {
174  auto brightness_int = static_cast<uint32_t>(brightness * this->max_value_);
175  brightness_int = std::max(brightness_int, this->min_value_);
176 
177  parent_->set_integer_datapoint_value(*this->dimmer_id_, brightness_int);
178  }
179  }
180 
181  if (brightness == 0.0f || !color_interlock_) {
182  if (this->rgb_id_.has_value()) {
183  char buffer[7];
184  sprintf(buffer, "%02X%02X%02X", int(red * 255), int(green * 255), int(blue * 255));
185  std::string rgb_value = buffer;
186  this->parent_->set_string_datapoint_value(*this->rgb_id_, rgb_value);
187  } else if (this->hsv_id_.has_value()) {
188  int hue;
189  float saturation, value;
190  rgb_to_hsv(red, green, blue, hue, saturation, value);
191  char buffer[13];
192  sprintf(buffer, "%04X%04X%04X", hue, int(saturation * 1000), int(value * 1000));
193  std::string hsv_value = buffer;
194  this->parent_->set_string_datapoint_value(*this->hsv_id_, hsv_value);
195  }
196  }
197 
198  if (this->switch_id_.has_value()) {
200  }
201 }
202 
203 } // namespace tuya
204 } // namespace esphome
void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue)
Convert hue (0-360), saturation (0-1) and value (0-1) to red, green and blue (all 0-1)...
Definition: helpers.cpp:354
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:34
optional< uint8_t > min_value_datapoint_id_
Definition: tuya_light.h:49
bool is_on() const
Get the binary true/false state of these light color values.
LightColorValues current_values
The current values of the light as outputted to the light.
Definition: light_state.h:68
optional< uint8_t > hsv_id_
Definition: tuya_light.h:52
light::LightTraits get_traits() override
Definition: tuya_light.cpp:108
RGB color output and a separate white output.
Color temperature can be controlled.
bool has_value() const
Definition: optional.h:87
void register_listener(uint8_t datapoint_id, const std::function< void(TuyaDatapoint)> &func)
Definition: tuya.cpp:621
uint32_t color_temperature_max_value_
Definition: tuya_light.h:56
optional< uint8_t > color_temperature_id_
Definition: tuya_light.h:53
void write_state(light::LightState *state) override
Definition: tuya_light.cpp:141
void current_values_as_rgb(float *red, float *green, float *blue, bool color_interlock=false)
optional< uint8_t > dimmer_id_
Definition: tuya_light.h:48
void current_values_as_rgbct(float *red, float *green, float *blue, float *color_temperature, float *white_brightness)
std::string value_string
Definition: tuya.h:37
void setup_state(light::LightState *state) override
Definition: tuya_light.cpp:139
float state_
ON / OFF, float for transition.
void dump_config() override
Definition: tuya_light.cpp:93
void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value)
Convert red, green and blue (all 0-1) values to hue (0-360), saturation (0-1) and value (0-1)...
Definition: helpers.cpp:331
void current_values_as_brightness(float *brightness)
Light can be turned on/off.
RGB color output and a separate white output with controllable color temperature. ...
Master brightness of the light can be controlled.
void current_values_as_ct(float *color_temperature, float *white_brightness)
White output only (use only if the light also has another color mode such as RGB).
This class is used to represent the capabilities of a light.
Definition: light_traits.h:11
void set_boolean_datapoint_value(uint8_t datapoint_id, bool value)
Definition: tuya.cpp:493
void set_integer_datapoint_value(uint8_t datapoint_id, uint32_t value)
Definition: tuya.cpp:497
void set_string_datapoint_value(uint8_t datapoint_id, const std::string &value)
Definition: tuya.cpp:501
Definition: a4988.cpp:4
Color can be controlled using RGB format (includes a brightness control for the color).
void setup() override
Definition: tuya_light.cpp:10
optional< uint8_t > rgb_id_
Definition: tuya_light.h:51
light::LightState * state_
Definition: tuya_light.h:61
optional< uint8_t > switch_id_
Definition: tuya_light.h:50
void current_values_as_rgbw(float *red, float *green, float *blue, float *white, bool color_interlock=false)
bool state
Definition: fan.h:34