1 // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include "errno.h"
19
20 #include "freertos/FreeRTOS.h"
21 #include "freertos/queue.h"
22 #include "freertos/task.h"
23 #include "freertos/timers.h"
24 #include "freertos/event_groups.h"
25
26 #include "esp_err.h"
27 #include "esp_log.h"
28 #include "esp_system.h"
29 #include "esp_partition.h"
30
31 #include "lwip/sockets.h"
32 #include "lwip/netdb.h"
33 #include "lwip/sockets.h"
34
35 #include "nvs.h"
36 #include "nvs_flash.h"
37 #include "driver/i2c.h"
38 #include "sys/param.h"
39 #include "driver/gpio.h"
40
41 #include "light_driver.h"
42 #include "ble_mesh_example_nvs.h"
43
44 /**
45 * @brief The state of the five-color light
46 */
47 typedef struct {
48 uint8_t mode;
49 uint8_t on;
50 uint16_t hue;
51 uint8_t saturation;
52 uint8_t value;
53 uint8_t lightness;
54 uint8_t color_temperature;
55 uint8_t brightness;
56 uint32_t fade_period_ms;
57 uint32_t blink_period_ms;
58 } light_status_t;
59
60 /**
61 * @brief The channel of the five-color light
62 */
63 enum light_channel {
64 CHANNEL_ID_RED = 0,
65 CHANNEL_ID_GREEN,
66 CHANNEL_ID_BLUE,
67 CHANNEL_ID_WARM,
68 CHANNEL_ID_COLD,
69 };
70
71 #define LIGHT_FADE_PERIOD_MAX_MS (3 * 1000)
72
73 static const char *TAG = "light_driver";
74 static light_status_t g_light_status = {0};
75 static bool g_light_blink_flag = false;
76 static TimerHandle_t g_fade_timer = NULL;
77 static int g_fade_mode = MODE_NONE;
78 static uint16_t g_fade_hue = 0;
79 extern nvs_handle_t NVS_HANDLE;
80
light_driver_init(light_driver_config_t * config)81 esp_err_t light_driver_init(light_driver_config_t *config)
82 {
83 LIGHT_PARAM_CHECK(config);
84 bool exist = false;
85
86 if (ble_mesh_nvs_restore(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t), &exist) != ESP_OK) {
87 memset(&g_light_status, 0, sizeof(light_status_t));
88 g_light_status.mode = MODE_HSV;
89 g_light_status.on = 1;
90 g_light_status.hue = 360;
91 g_light_status.saturation = 0;
92 g_light_status.value = 100;
93 g_light_status.lightness = 100;
94 g_light_status.color_temperature = 0;
95 g_light_status.brightness = 30;
96 }
97
98 #if CONFIG_IDF_TARGET_ESP32C3
99 iot_led_init(LEDC_TIMER_0, LEDC_LOW_SPEED_MODE, 1000);
100 #elif CONFIG_IDF_TARGET_ESP32
101 iot_led_init(LEDC_TIMER_0, LEDC_HIGH_SPEED_MODE, 1000);
102 #endif
103
104 g_light_status.fade_period_ms = config->fade_period_ms;
105 g_light_status.blink_period_ms = config->blink_period_ms;
106
107 iot_led_regist_channel(CHANNEL_ID_RED, config->gpio_red);
108 iot_led_regist_channel(CHANNEL_ID_GREEN, config->gpio_green);
109 iot_led_regist_channel(CHANNEL_ID_BLUE, config->gpio_blue);
110 iot_led_regist_channel(CHANNEL_ID_WARM, config->gpio_warm);
111 iot_led_regist_channel(CHANNEL_ID_COLD, config->gpio_cold);
112
113 ESP_LOGI(TAG, "hue: %d, saturation: %d, value: %d, lightness: %d",
114 g_light_status.hue, g_light_status.saturation, g_light_status.value, g_light_status.lightness);
115 ESP_LOGI(TAG, "brightness: %d, color_temperature: %d",
116 g_light_status.brightness, g_light_status.color_temperature);
117
118 return ESP_OK;
119 }
120
light_driver_deinit(void)121 esp_err_t light_driver_deinit(void)
122 {
123 esp_err_t ret = ESP_OK;
124
125 iot_led_deinit();
126
127 return ret;
128 }
129
light_driver_config(uint32_t fade_period_ms,uint32_t blink_period_ms)130 esp_err_t light_driver_config(uint32_t fade_period_ms, uint32_t blink_period_ms)
131 {
132 g_light_status.fade_period_ms = fade_period_ms;
133 g_light_status.blink_period_ms = blink_period_ms;
134
135 return ESP_OK;
136 }
137
light_driver_set_rgb(uint8_t red,uint8_t green,uint8_t blue)138 esp_err_t light_driver_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
139 {
140 esp_err_t ret = 0;
141
142 ret = iot_led_set_channel(CHANNEL_ID_RED, red, 0);
143 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
144
145 ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, 0);
146 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
147
148 ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, 0);
149 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
150
151 ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
152 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
153
154 ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
155 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
156
157 return ESP_OK;
158 }
159
light_driver_hsv2rgb(uint16_t hue,uint8_t saturation,uint8_t value,uint8_t * red,uint8_t * green,uint8_t * blue)160 static esp_err_t light_driver_hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value,
161 uint8_t *red, uint8_t *green, uint8_t *blue)
162 {
163 uint16_t hi = (hue / 60) % 6;
164 uint16_t F = 100 * hue / 60 - 100 * hi;
165 uint16_t P = value * (100 - saturation) / 100;
166 uint16_t Q = value * (10000 - F * saturation) / 10000;
167 uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;
168
169 switch (hi) {
170 case 0:
171 *red = value;
172 *green = T;
173 *blue = P;
174 break;
175
176 case 1:
177 *red = Q;
178 *green = value;
179 *blue = P;
180 break;
181
182 case 2:
183 *red = P;
184 *green = value;
185 *blue = T;
186 break;
187
188 case 3:
189 *red = P;
190 *green = Q;
191 *blue = value;
192 break;
193
194 case 4:
195 *red = T;
196 *green = P;
197 *blue = value;
198 break;
199
200 case 5:
201 *red = value;
202 *green = P;
203 *blue = Q;
204 break;
205
206 default:
207 return ESP_FAIL;
208 }
209
210 *red = *red * 255 / 100;
211 *green = *green * 255 / 100;
212 *blue = *blue * 255 / 100;
213
214 return ESP_OK;
215 }
216
light_driver_rgb2hsv(uint16_t red,uint16_t green,uint16_t blue,uint16_t * h,uint8_t * s,uint8_t * v)217 static void light_driver_rgb2hsv(uint16_t red, uint16_t green, uint16_t blue,
218 uint16_t *h, uint8_t *s, uint8_t *v)
219 {
220 double hue, saturation, value;
221 double m_max = MAX(red, MAX(green, blue));
222 double m_min = MIN(red, MIN(green, blue));
223 double m_delta = m_max - m_min;
224
225 value = m_max / 255.0;
226
227 if (m_delta == 0) {
228 hue = 0;
229 saturation = 0;
230 } else {
231 saturation = m_delta / m_max;
232
233 if (red == m_max) {
234 hue = (green - blue) / m_delta;
235 } else if (green == m_max) {
236 hue = 2 + (blue - red) / m_delta;
237 } else {
238 hue = 4 + (red - green) / m_delta;
239 }
240
241 hue = hue * 60;
242
243 if (hue < 0) {
244 hue = hue + 360;
245 }
246 }
247
248 *h = (int)(hue + 0.5);
249 *s = (int)(saturation * 100 + 0.5);
250 *v = (int)(value * 100 + 0.5);
251 }
252
253 // refence: https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
light_driver_hsl2rgb(uint16_t hue,uint8_t saturation,uint8_t lightness,uint8_t * red,uint8_t * green,uint8_t * blue)254 static esp_err_t light_driver_hsl2rgb(uint16_t hue, uint8_t saturation, uint8_t lightness,
255 uint8_t *red, uint8_t *green, uint8_t *blue)
256 {
257 uint16_t hi = (hue / 60) % 6;
258 uint16_t C = (100 - abs(2 * lightness - 100)) * saturation / 100;
259 uint16_t M = 100 * (lightness - 0.5 * C) / 100;
260 uint16_t X = C * (100 - abs((hue * 100 / 60 ) % 200 - 100)) / 100;
261
262 switch (hi) {
263 case 0: /* hue 0~60 */
264 *red = C + M;
265 *green = X + M;
266 *blue = M;
267 break;
268
269 case 1: /* hue 60~120 */
270 *red = X + M;
271 *green = C + M;
272 *blue = M;
273 break;
274
275 case 2: /* hue 120~180 */
276 *red = M;
277 *green = C + M;
278 *blue = X + M;
279 break;
280
281 case 3: /* hue 180~240 */
282 *red = M;
283 *green = X + M;
284 *blue = C + M;
285 break;
286
287 case 4: /* hue 240~300 */
288 *red = X + M;
289 *green = M;
290 *blue = C + M;
291 break;
292
293 case 5: /* hue 300~360 */
294 *red = C + M;
295 *green = M;
296 *blue = X + M;
297 break;
298
299 default:
300 return ESP_FAIL;
301 }
302
303 *red = *red * 255 / 100;
304 *green = *green * 255 / 100;
305 *blue = *blue * 255 / 100;
306
307 return ESP_OK;
308 }
309
light_driver_set_hsv(uint16_t hue,uint8_t saturation,uint8_t value)310 esp_err_t light_driver_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value)
311 {
312 LIGHT_PARAM_CHECK(hue <= 360);
313 LIGHT_PARAM_CHECK(saturation <= 100);
314 LIGHT_PARAM_CHECK(value <= 100);
315
316 esp_err_t ret = ESP_OK;
317 uint8_t red = 0;
318 uint8_t green = 0;
319 uint8_t blue = 0;
320
321 ret = light_driver_hsv2rgb(hue, saturation, value, &red, &green, &blue);
322 LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
323
324 ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
325
326 ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
327 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
328
329 ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
330 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
331
332 ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
333 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
334
335 if (g_light_status.mode != MODE_HSV) {
336 ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
337 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
338
339 ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
340 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
341 }
342
343 g_light_status.mode = MODE_HSV;
344 g_light_status.on = 1;
345 g_light_status.hue = hue;
346 g_light_status.value = value;
347 g_light_status.saturation = saturation;
348
349 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
350 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
351
352 return ESP_OK;
353 }
354
light_driver_set_hue(uint16_t hue)355 esp_err_t light_driver_set_hue(uint16_t hue)
356 {
357 if (g_light_status.mode == MODE_HSV) {
358 return light_driver_set_hsv(hue, g_light_status.saturation, g_light_status.value);
359 } else if (g_light_status.mode == MODE_HSL) {
360 return light_driver_set_hsl(hue, g_light_status.saturation, g_light_status.lightness);
361 } else {
362 return ESP_FAIL;
363 }
364 }
365
light_driver_set_saturation(uint8_t saturation)366 esp_err_t light_driver_set_saturation(uint8_t saturation)
367 {
368 if (g_light_status.mode == MODE_HSV) {
369 return light_driver_set_hsv(g_light_status.hue, saturation, g_light_status.value);
370 } else if (g_light_status.mode == MODE_HSL) {
371 return light_driver_set_hsl(g_light_status.hue, saturation, g_light_status.lightness);
372 } else {
373 return ESP_FAIL;
374 }
375 }
376
light_driver_set_value(uint8_t value)377 esp_err_t light_driver_set_value(uint8_t value)
378 {
379 return light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, value);
380 }
381
light_driver_get_hsv(uint16_t * hue,uint8_t * saturation,uint8_t * value)382 esp_err_t light_driver_get_hsv(uint16_t *hue, uint8_t *saturation, uint8_t *value)
383 {
384 LIGHT_PARAM_CHECK(hue);
385 LIGHT_PARAM_CHECK(saturation);
386 LIGHT_PARAM_CHECK(value);
387
388 *hue = g_light_status.hue;
389 *saturation = g_light_status.saturation;
390 *value = g_light_status.value;
391
392 return ESP_OK;
393 }
394
light_driver_get_hue(void)395 uint16_t light_driver_get_hue(void)
396 {
397 return g_light_status.hue;
398 }
399
light_driver_get_saturation(void)400 uint8_t light_driver_get_saturation(void)
401 {
402 return g_light_status.saturation;
403 }
404
light_driver_get_value(void)405 uint8_t light_driver_get_value(void)
406 {
407 return g_light_status.value;
408 }
409
light_driver_get_mode(void)410 uint8_t light_driver_get_mode(void)
411 {
412 return g_light_status.mode;
413 }
414
light_driver_set_ctb(uint8_t color_temperature,uint8_t brightness)415 esp_err_t light_driver_set_ctb(uint8_t color_temperature, uint8_t brightness)
416 {
417 LIGHT_PARAM_CHECK(brightness <= 100);
418 LIGHT_PARAM_CHECK(color_temperature <= 100);
419
420 esp_err_t ret = ESP_OK;
421 uint8_t warm_tmp = color_temperature * brightness / 100;
422 uint8_t cold_tmp = (100 - color_temperature) * brightness / 100;
423 warm_tmp = warm_tmp < 15 ? warm_tmp : 14 + warm_tmp * 86 / 100;
424 cold_tmp = cold_tmp < 15 ? cold_tmp : 14 + cold_tmp * 86 / 100;
425
426 ret = iot_led_set_channel(CHANNEL_ID_COLD,
427 cold_tmp * 255 / 100, g_light_status.fade_period_ms);
428 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
429
430 ret = iot_led_set_channel(CHANNEL_ID_WARM,
431 warm_tmp * 255 / 100, g_light_status.fade_period_ms);
432 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
433
434 if (g_light_status.mode != MODE_CTB) {
435 ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
436 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
437
438 ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
439 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
440
441 ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
442 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
443 }
444
445 g_light_status.mode = MODE_CTB;
446 g_light_status.on = 1;
447 g_light_status.brightness = brightness;
448 g_light_status.color_temperature = color_temperature;
449
450 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
451 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
452
453 return ESP_OK;
454 }
455
light_driver_set_color_temperature(uint8_t color_temperature)456 esp_err_t light_driver_set_color_temperature(uint8_t color_temperature)
457 {
458 return light_driver_set_ctb(color_temperature, g_light_status.brightness);
459 }
460
light_driver_set_brightness(uint8_t brightness)461 esp_err_t light_driver_set_brightness(uint8_t brightness)
462 {
463 return light_driver_set_ctb(g_light_status.color_temperature, brightness);
464 }
465
light_driver_get_ctb(uint8_t * color_temperature,uint8_t * brightness)466 esp_err_t light_driver_get_ctb(uint8_t *color_temperature, uint8_t *brightness)
467 {
468 LIGHT_PARAM_CHECK(color_temperature);
469 LIGHT_PARAM_CHECK(brightness);
470
471 *brightness = g_light_status.brightness;
472 *color_temperature = g_light_status.color_temperature;
473
474 return ESP_OK;
475 }
476
light_driver_get_color_temperature(void)477 uint8_t light_driver_get_color_temperature(void)
478 {
479 return g_light_status.color_temperature;
480 }
481
light_driver_get_brightness(void)482 uint8_t light_driver_get_brightness(void)
483 {
484 return g_light_status.brightness;
485 }
486
light_driver_set_hsl(uint16_t hue,uint8_t saturation,uint8_t lightness)487 esp_err_t light_driver_set_hsl(uint16_t hue, uint8_t saturation, uint8_t lightness)
488 {
489 LIGHT_PARAM_CHECK(hue <= 360);
490 LIGHT_PARAM_CHECK(saturation <= 100);
491 LIGHT_PARAM_CHECK(lightness <= 100);
492
493 esp_err_t ret = ESP_OK;
494 uint8_t red = 0;
495 uint8_t green = 0;
496 uint8_t blue = 0;
497
498 ret = light_driver_hsl2rgb(hue, saturation, lightness, &red, &green, &blue);
499 LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsl2rgb, ret: %d", ret);
500
501 ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
502
503 ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
504 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
505
506 ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
507 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
508
509 ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
510 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
511
512 if (g_light_status.mode != MODE_HSL) {
513 ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
514 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
515
516 ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
517 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
518 }
519
520 g_light_status.mode = MODE_HSL;
521 g_light_status.on = 1;
522 g_light_status.hue = hue;
523 g_light_status.saturation = saturation;
524 g_light_status.lightness = lightness;
525
526 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
527 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
528
529 return ESP_OK;
530 }
531
light_driver_set_lightness(uint8_t lightness)532 esp_err_t light_driver_set_lightness(uint8_t lightness)
533 {
534 return light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, lightness);
535 }
536
light_driver_get_lightness(void)537 uint8_t light_driver_get_lightness(void)
538 {
539 return g_light_status.lightness;
540 }
541
light_driver_get_hsl(uint16_t * hue,uint8_t * saturation,uint8_t * lightness)542 esp_err_t light_driver_get_hsl(uint16_t *hue, uint8_t *saturation, uint8_t *lightness)
543 {
544 LIGHT_PARAM_CHECK(hue);
545 LIGHT_PARAM_CHECK(saturation);
546 LIGHT_PARAM_CHECK(lightness);
547
548 *hue = g_light_status.hue;
549 *saturation = g_light_status.saturation;
550 *lightness = g_light_status.lightness;
551
552 return ESP_OK;
553 }
554
light_driver_set_switch(bool on)555 esp_err_t light_driver_set_switch(bool on)
556 {
557 esp_err_t ret = ESP_OK;
558 g_light_status.on = on;
559
560 if (!g_light_status.on) {
561 ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
562 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
563
564 ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
565 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
566
567 ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
568 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
569
570 ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
571 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
572
573 ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
574 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
575
576 } else {
577 switch (g_light_status.mode) {
578 case MODE_HSV:
579 g_light_status.value = (g_light_status.value) ? g_light_status.value : 100;
580 ret = light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, g_light_status.value);
581 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsv, ret: %d", ret);
582 break;
583
584 case MODE_HSL:
585 g_light_status.lightness = (g_light_status.lightness) ? g_light_status.lightness : 100;
586 ret = light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, g_light_status.lightness);
587 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsl, ret: %d", ret);
588 break;
589
590 case MODE_CTB:
591 g_light_status.brightness = (g_light_status.brightness) ? g_light_status.brightness : 100;
592 ret = light_driver_set_ctb(g_light_status.color_temperature, g_light_status.brightness);
593 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_ctb, ret: %d", ret);
594 break;
595
596 default:
597 ESP_LOGW(TAG, "This operation is not supported");
598 break;
599 }
600 }
601
602 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
603 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "ble_mesh_nvs_store, ret: %d", ret);
604
605 return ESP_OK;
606 }
607
light_driver_set_mode(light_mode_t mode)608 esp_err_t light_driver_set_mode(light_mode_t mode)
609 {
610 g_light_status.mode = mode;
611
612 return ESP_OK;
613 }
614
light_driver_get_switch(void)615 bool light_driver_get_switch(void)
616 {
617 return g_light_status.on;
618 }
619
light_driver_breath_start(uint8_t red,uint8_t green,uint8_t blue)620 esp_err_t light_driver_breath_start(uint8_t red, uint8_t green, uint8_t blue)
621 {
622 esp_err_t ret = ESP_OK;
623
624 ret = iot_led_start_blink(CHANNEL_ID_RED,
625 red, g_light_status.blink_period_ms, true);
626 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
627 ret = iot_led_start_blink(CHANNEL_ID_GREEN,
628 green, g_light_status.blink_period_ms, true);
629 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
630 ret = iot_led_start_blink(CHANNEL_ID_BLUE,
631 blue, g_light_status.blink_period_ms, true);
632 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
633
634 g_light_blink_flag = true;
635
636 return ESP_OK;
637 }
638
light_driver_breath_stop(void)639 esp_err_t light_driver_breath_stop(void)
640 {
641 esp_err_t ret = ESP_OK;
642
643 if (g_light_blink_flag == false) {
644 return ESP_OK;
645 }
646
647 ret = iot_led_stop_blink(CHANNEL_ID_RED);
648 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
649
650 ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
651 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
652
653 ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
654 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
655
656 light_driver_set_switch(true);
657
658 return ESP_OK;
659 }
660
light_driver_fade_brightness(uint8_t brightness)661 esp_err_t light_driver_fade_brightness(uint8_t brightness)
662 {
663 esp_err_t ret = ESP_OK;
664 g_fade_mode = MODE_ON;
665 uint32_t fade_period_ms = 0;
666
667 if (g_light_status.mode == MODE_HSV) {
668 uint8_t red = 0;
669 uint8_t green = 0;
670 uint8_t blue = 0;
671
672 ret = light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
673 LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
674
675 if (brightness != 0) {
676 ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_RED, &red);
677 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
678 ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_GREEN, &green);
679 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
680 ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_BLUE, &blue);
681 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
682
683 uint8_t max_color = MAX(MAX(red, green), blue);
684 uint8_t change_value = brightness * 255 / 100 - max_color;
685 fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 255;
686 } else {
687 fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * MAX(MAX(red, green), blue) / 255;
688 red = 0;
689 }
690
691 g_light_status.value = brightness;
692 light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
693
694 ret = iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
695 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
696
697 ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
698 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
699
700 ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
701 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
702
703 } else if (g_light_status.mode == MODE_CTB) {
704 uint8_t warm_tmp = 0;
705 uint8_t cold_tmp = 0;
706 fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * g_light_status.brightness / 100;
707
708 if (brightness != 0) {
709 uint8_t change_value = brightness - g_light_status.brightness;
710 warm_tmp = g_light_status.color_temperature;
711 cold_tmp = (brightness - g_light_status.color_temperature);
712 fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 100;
713 }
714
715 ret = iot_led_set_channel(CHANNEL_ID_COLD,
716 cold_tmp * 255 / 100, fade_period_ms);
717 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
718
719 ret = iot_led_set_channel(CHANNEL_ID_WARM,
720 warm_tmp * 255 / 100, fade_period_ms);
721 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
722
723 g_light_status.brightness = brightness;
724 }
725
726 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
727 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
728
729 return ESP_OK;
730 }
731
light_fade_timer_stop(void)732 static void light_fade_timer_stop(void)
733 {
734 if (!g_fade_timer) {
735 return ;
736 }
737
738 if (!xTimerStop(g_fade_timer, portMAX_DELAY)) {
739 ESP_LOGW(TAG, "xTimerStop timer: %p", g_fade_timer);
740 }
741
742 if (!xTimerDelete(g_fade_timer, portMAX_DELAY)) {
743 ESP_LOGW(TAG, "xTimerDelete timer: %p", g_fade_timer);
744 }
745
746 g_fade_timer = NULL;
747 }
748
light_fade_timer_cb(void * timer)749 static void light_fade_timer_cb(void *timer)
750 {
751 uint8_t red = 0;
752 uint8_t green = 0;
753 uint8_t blue = 0;
754 uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
755 int variety = (g_fade_hue > 180) ? 60 : -60;
756
757 if (g_light_status.hue >= 360 || g_light_status.hue <= 0) {
758 light_fade_timer_stop();
759 }
760
761 g_light_status.hue = g_light_status.hue >= 360 ? 360 : g_light_status.hue + variety;
762 g_light_status.hue = g_light_status.hue <= 60 ? 0 : g_light_status.hue + variety;
763
764 light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
765
766 iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
767 iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
768 iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
769 }
770
light_driver_fade_hue(uint16_t hue)771 esp_err_t light_driver_fade_hue(uint16_t hue)
772 {
773 esp_err_t ret = ESP_OK;
774 g_fade_mode = MODE_HSV;
775 g_fade_hue = hue;
776
777 light_fade_timer_stop();
778
779 if (g_light_status.mode != MODE_HSV) {
780 ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
781 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
782
783 ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
784 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
785 }
786
787 g_light_status.mode = MODE_HSV;
788 g_light_status.value = (g_light_status.value == 0) ? 100 : g_light_status.value;
789 uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
790
791 light_fade_timer_cb(NULL);
792
793 g_fade_timer = xTimerCreate("light_timer", fade_period_ms,
794 true, NULL, light_fade_timer_cb);
795 xTimerStart(g_fade_timer, 0);
796
797 return ESP_OK;
798 }
799
light_driver_fade_warm(uint8_t color_temperature)800 esp_err_t light_driver_fade_warm(uint8_t color_temperature)
801 {
802 esp_err_t ret = ESP_OK;
803 g_fade_mode = MODE_CTB;
804
805 if (g_light_status.mode != MODE_CTB) {
806 ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
807 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
808
809 ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
810 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
811
812 ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
813 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
814 }
815
816 uint8_t warm_tmp = color_temperature * g_light_status.brightness / 100;
817 uint8_t cold_tmp = (100 - color_temperature) * g_light_status.brightness / 100;
818
819 ret = iot_led_set_channel(CHANNEL_ID_COLD, cold_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
820 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
821
822 ret = iot_led_set_channel(CHANNEL_ID_WARM, warm_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
823 LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
824
825 g_light_status.mode = MODE_CTB;
826 g_light_status.color_temperature = color_temperature;
827 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
828 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
829
830 return ESP_OK;
831 }
832
light_driver_fade_stop(void)833 esp_err_t light_driver_fade_stop(void)
834 {
835 esp_err_t ret = ESP_OK;
836
837 light_fade_timer_stop();
838
839 if (g_light_status.mode != MODE_CTB) {
840 uint16_t hue = 0;
841 uint8_t saturation = 0;
842 uint8_t value = 0;
843
844 ret = iot_led_stop_blink(CHANNEL_ID_RED);
845 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
846
847 ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
848 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
849
850 ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
851 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
852
853 uint8_t red, green, blue;
854
855 ret = iot_led_get_channel(CHANNEL_ID_RED, &red);
856 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
857 ret = iot_led_get_channel(CHANNEL_ID_GREEN, &green);
858 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
859 ret = iot_led_get_channel(CHANNEL_ID_BLUE, &blue);
860 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
861
862 light_driver_rgb2hsv(red, green, blue, &hue, &saturation, &value);
863
864 g_light_status.hue = (g_fade_mode == MODE_HSV) ? hue : g_light_status.hue;
865 g_light_status.value = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? value : g_light_status.value;
866 } else {
867 uint8_t color_temperature = 0;
868 uint8_t brightness = 0;
869
870 ret = iot_led_stop_blink(CHANNEL_ID_COLD);
871 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
872
873 ret = iot_led_stop_blink(CHANNEL_ID_WARM);
874 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
875
876 uint8_t warm_tmp, cold_tmp;
877 uint8_t tmp;
878
879 ret = iot_led_get_channel(CHANNEL_ID_WARM, &tmp);
880 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
881 warm_tmp = (int32_t)tmp * 100 / 255;
882
883 ret = iot_led_get_channel(CHANNEL_ID_COLD, &tmp);
884 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
885 cold_tmp = (int32_t)tmp * 100 / 255;
886
887 color_temperature = (!warm_tmp) ? 0 : 100 / (cold_tmp / warm_tmp + 1);
888 brightness = (!color_temperature) ? cold_tmp : warm_tmp * 100 / color_temperature;
889
890 g_light_status.brightness = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? brightness : g_light_status.brightness;
891 g_light_status.color_temperature = (g_fade_mode == MODE_CTB) ? color_temperature : g_light_status.color_temperature;
892 }
893
894 ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
895 LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
896
897 g_fade_mode = MODE_NONE;
898 return ESP_OK;
899 }
900