Skip to content

Commit c141b03

Browse files
fix(lightbulb): Adjust the power calculation algorithm
1 parent 4aca00f commit c141b03

File tree

7 files changed

+616
-45
lines changed

7 files changed

+616
-45
lines changed

components/led/lightbulb_driver/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# ChangeLog
22

3+
## v1.8.2 - 2025-04-17
4+
5+
### Bug Fix:
6+
7+
- Adjust the power calculation algorithm
8+
39
## v1.8.1 - 2025-04-17
410

511
### Bug Fix:

components/led/lightbulb_driver/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.8.1"
1+
version: "1.8.2"
22
description: Provide multiple dimming driver solutions to easily build lightbulb applications
33
url: https://github.com/espressif/esp-iot-solution/tree/master/components/led/lightbulb_driver
44
dependencies:

components/led/lightbulb_driver/src/hal_driver.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static const char *TAG = "hal_manage";
2828
#define PROBE_GPIO 4
2929
#define FADE_DEBUG_LOG_OUTPUT 0
3030

31-
static void create_gpio_probe(int gpio_num, int level)
31+
void create_gpio_probe(int gpio_num, int level)
3232
{
3333
gpio_config_t io_conf;
3434
io_conf.intr_type = GPIO_INTR_DISABLE;
@@ -40,7 +40,7 @@ static void create_gpio_probe(int gpio_num, int level)
4040
gpio_set_level(gpio_num, level);
4141
}
4242

43-
static void gpio_reverse(int gpio_num)
43+
void gpio_reverse(int gpio_num)
4444
{
4545
static int level = 0;
4646
gpio_set_level(gpio_num, (level++) % 2);
@@ -102,6 +102,7 @@ typedef struct {
102102
bool use_hw_fade;
103103
bool enable_multi_ch_write;
104104
uint16_t *table_group;
105+
uint16_t table_size;
105106
// R G B C W
106107
float balance_coefficient[5];
107108
SemaphoreHandle_t fade_mutex;
@@ -530,12 +531,13 @@ esp_err_t hal_output_init(hal_config_t *config, lightbulb_gamma_config_t *gamma,
530531
s_hal_obj->enable_multi_ch_write = true;
531532
}
532533

533-
s_hal_obj->table_group = calloc(table_size, sizeof(uint16_t));
534+
s_hal_obj->table_size = table_size;
535+
s_hal_obj->table_group = calloc(s_hal_obj->table_size, sizeof(uint16_t));
534536
LIGHTBULB_CHECK(s_hal_obj->table_group, "curve table buffer alloc fail", goto EXIT);
535537

536538
//Currently only used as a mapping table, it will be used for fade to achieve curve sliding changes in the future
537539
float curve_coe = DEFAULT_CURVE_COE;
538-
hal_gamma_table_create(s_hal_obj->table_group, table_size, curve_coe, s_hal_obj->interface->hardware_allow_max_input_value);
540+
hal_gamma_table_create(s_hal_obj->table_group, s_hal_obj->table_size, curve_coe, s_hal_obj->interface->hardware_allow_max_input_value);
539541

540542
for (int i = 0; i < 5; i++) {
541543
float balance = gamma ? gamma->balance_coefficient[i] : 1.0;

components/led/lightbulb_driver/src/lightbulb.c

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static uint8_t precise_kelvin_convert_to_percentage(uint16_t kelvin)
304304
* @param brightness Brightness value in the range 0-100
305305
* @param white_value Array to store the calculated cold and warm values for white output
306306
*/
307-
static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_t led_beads, float multiple, uint8_t cct, uint8_t brightness, uint16_t white_value[])
307+
static esp_err_t cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_t led_beads, float multiple, uint8_t cct, uint8_t brightness, uint16_t white_value[])
308308
{
309309
uint16_t max_value = 0;
310310
hal_get_driver_feature(QUERY_MAX_INPUT_VALUE, &max_value);
@@ -353,6 +353,18 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
353353
hal_get_curve_table_value((uint16_t)value, &white_value[i]);
354354
}
355355
}
356+
357+
#if CONFIG_ENABLE_LIGHTBULB_DEBUG
358+
uint16_t test_power = white_value[0] + white_value[1] + white_value[2] + white_value[3] + white_value[4];
359+
uint16_t limit_power = max_value * multiple * (brightness / 100.0);
360+
361+
if (test_power > limit_power) {
362+
ESP_LOGE(TAG, "Power exceeds expected, current: %d, expected:%d", test_power, limit_power);
363+
return ESP_FAIL;
364+
}
365+
#endif
366+
367+
return ESP_OK;
356368
}
357369

358370
/**
@@ -414,33 +426,72 @@ static uint8_t process_white_brightness_limit(uint8_t brightness)
414426
/**
415427
* @brief Recalculate color power
416428
* @attention 300% = 100% + 100% + 100% : Full power output on each channel. If single channel output is 3w then total output is 9w.
417-
* @note
418-
* input output(color_max_power = 100) output(color_max_power = 200) output(color_max_power = 300)
419-
* 255,255,0 127,127,0 255,255,0 255,255,0
420-
* 127,127,0 63,63,0 127,127,0 127,127,0
421-
* 63,63,0 31,31,0 63,63,0 63,63,0
422-
* 255,255,255 85,85,85 170,170,170 255,255,255
423-
* 127,127,127 42,42,42 84,84,84 127,127,127
424-
* 63,63,63 21,21,21 42,42,42 63,63,63
425429
*
430+
* lightbulb_power_limit_t limit = {
431+
* .color_max_power = 100,
432+
* .color_max_value = 100,
433+
* .color_min_value = 10,
434+
* .white_max_power = 100,
435+
* .white_max_brightness = 100,
436+
* .white_min_brightness = 10
437+
* };
438+
*
439+
* lightbulb_gamma_config_t Gamma = {
440+
* .balance_coefficient = {1.0, 1.0, 1.0, 1.0, 1.0},
441+
* .color_curve_coefficient = 2.0,
442+
* .white_curve_coefficient = 2.0,
443+
* };
444+
*
445+
* @note
446+
* input(hsv) output(color_max_power = 100) output(color_max_power = 200) output(color_max_power = 300)
447+
* 0,100,100 255,0,0 255,0,0 255,0,0
448+
* 0,100,1 79,0,0 79,0,0 79,0,0
449+
* 60,100,100 127,127,0 255,255,0 255,255,0
450+
* 60,100,1 39,39,0 79,79,0 79,79,0
451+
* 0,50,100 127,63,63 255,127,127 255,127,127
452+
* 0,50,1 40,19,19 79,38,38 79,38,38
453+
* 60,50,100 102,102,50 204,204,101 254,254,126
454+
* 60,50,1 31,31,15 63,63,30 79,79,38
455+
* 0,0,100 85,85,85 170,170,170 255,255,255
456+
* 0,0,1 26,26,26 52,52,52 79,79,79
426457
*/
427-
static void process_color_power_limit(float multiple, float rgbcw[5], uint16_t value, uint16_t out[5])
458+
static esp_err_t process_color_power_limit(float multiple, float rgbcw[5], uint16_t value, uint16_t out[5])
428459
{
429460
uint16_t max_value;
430-
float max_power;
431461
hal_get_driver_feature(QUERY_MAX_INPUT_VALUE, &max_value);
432-
max_power = multiple * (max_value);
433-
434-
float baseline = MAX(rgbcw[0], rgbcw[1]);
435-
baseline = MAX(baseline, rgbcw[2]);
436-
baseline = MAX(baseline, rgbcw[3]);
437-
baseline = MAX(baseline, rgbcw[4]);
438-
max_power = MIN(max_power, max_value / baseline);
439-
ESP_LOGD(TAG, "%f, %d, %f", max_power, max_value, baseline);
440-
for (int i = 0; i < 5; i++) {
441-
float value = round(max_power * rgbcw[i]);
442-
hal_get_curve_table_value((uint16_t)value, &out[i]);
462+
463+
float scaled[5];
464+
float max_scale = 0.0f;
465+
float max_scale_limit = (float)max_value;
466+
467+
for (int i = 0; i < 5; ++i) {
468+
scaled[i] = rgbcw[i] * multiple;
469+
if (scaled[i] > max_scale) {
470+
max_scale = scaled[i];
471+
}
443472
}
473+
474+
float scale_factor = 1.0f;
475+
if (max_scale > 1.0f) {
476+
scale_factor = max_scale_limit / (max_scale * max_scale_limit);
477+
}
478+
479+
for (int i = 0; i < 5; ++i) {
480+
float value_f = scaled[i] * scale_factor * max_value * (value / 100.0);
481+
hal_get_curve_table_value((uint16_t)value_f, &out[i]);
482+
}
483+
484+
#if CONFIG_ENABLE_LIGHTBULB_DEBUG
485+
uint16_t test_power = out[0] + out[1] + out[2] + out[3] + out[4];
486+
uint16_t limit_power = max_value * multiple * (value / 100.0);
487+
488+
if (test_power > limit_power) {
489+
ESP_LOGE(TAG, "Power exceeds expected, current: %d, expected:%d", test_power, limit_power);
490+
return ESP_FAIL;
491+
}
492+
#endif
493+
494+
return ESP_OK;
444495
}
445496

446497
static void timercb(TimerHandle_t tmr)
@@ -1247,11 +1298,11 @@ static esp_err_t lightbulb_hsv2rgb_adjusted(uint16_t hue, uint8_t saturation, ui
12471298
}
12481299
}
12491300

1250-
*red = interpolated_rgbcw[0] * value / 100.0;
1251-
*green = interpolated_rgbcw[1] * value / 100.0;
1252-
*blue = interpolated_rgbcw[2] * value / 100.0;
1253-
*cold = interpolated_rgbcw[3] * value / 100.0;
1254-
*warm = interpolated_rgbcw[4] * value / 100.0;
1301+
*red = interpolated_rgbcw[0];
1302+
*green = interpolated_rgbcw[1];
1303+
*blue = interpolated_rgbcw[2];
1304+
*cold = interpolated_rgbcw[3];
1305+
*warm = interpolated_rgbcw[4];
12551306

12561307
return ESP_OK;
12571308
}
@@ -1265,14 +1316,21 @@ static esp_err_t _lightbulb_hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t va
12651316

12661317
ESP_LOGI(TAG, "Convert 8 bit value [r:%d g:%d b:%d]", _red, _green, _blue);
12671318

1268-
*red = _red / 255.0;
1269-
*green = _green / 255.0;
1270-
*blue = _blue / 255.0;
1319+
if (value == 0) {
1320+
*red = 0;
1321+
*green = 0;
1322+
*blue = 0;
1323+
} else {
1324+
*red = _red / 255.0;
1325+
*green = _green / 255.0;
1326+
*blue = _blue / 255.0;
1327+
float total = *red + *green + *blue;
1328+
1329+
*red = *red / total;
1330+
*green = *green / total;
1331+
*blue = *blue / total;
1332+
}
12711333

1272-
float total = *red + *green + *blue;
1273-
*red = *red / total;
1274-
*green = *green / total;
1275-
*blue = *blue / total;
12761334
*cold = 0;
12771335
*warm = 0;
12781336

@@ -1486,10 +1544,10 @@ esp_err_t lightbulb_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value)
14861544
ESP_LOGI(TAG, "Convert write value [r:%0.2f%% g:%0.2f%% b:%0.2f%% c:%0.2f%% w:%0.2f%%]", color_param[0] * 100, color_param[1] * 100, color_param[2] * 100, color_param[3] * 100, color_param[4] * 100);
14871545

14881546
// 3. Redistribute power
1489-
process_color_power_limit(s_lb_obj->power.color_max_power / 100.0, color_param, _value, color_value);
1547+
err |= process_color_power_limit(s_lb_obj->power.color_max_power / 100.0, color_param, _value, color_value);
14901548
ESP_LOGI(TAG, "hal write value [r:%d g:%d b:%d c:%d w:%d], channel_mask:%d fade_ms:%d", color_value[0], color_value[1], color_value[2], color_value[3], color_value[4], channel_mask, fade_time);
14911549

1492-
err = hal_set_channel_group(color_value, channel_mask, fade_time);
1550+
err |= hal_set_channel_group(color_value, channel_mask, fade_time);
14931551
LIGHTBULB_CHECK(err == ESP_OK, "set hal channel group fail", goto EXIT);
14941552

14951553
s_lb_obj->status.on = true;
@@ -1623,10 +1681,10 @@ esp_err_t lightbulb_set_cctb(uint16_t cct, uint8_t brightness)
16231681
_brightness = process_white_brightness_limit(_brightness);
16241682

16251683
// 2. convert to cold warm and redistribute power
1626-
cct_and_brightness_convert_and_power_limit(s_lb_obj->cap.led_beads, s_lb_obj->power.white_max_power / 100.0, cct, _brightness, white_value);
1684+
err |= cct_and_brightness_convert_and_power_limit(s_lb_obj->cap.led_beads, s_lb_obj->power.white_max_power / 100.0, cct, _brightness, white_value);
16271685
ESP_LOGI(TAG, "hal write value [r:%d g:%d b:%d c:%d w:%d], channel_mask:%d fade_ms:%d", white_value[0], white_value[1], white_value[2], white_value[3], white_value[4], channel_mask, fade_time);
16281686

1629-
err = hal_set_channel_group(white_value, channel_mask, fade_time);
1687+
err |= hal_set_channel_group(white_value, channel_mask, fade_time);
16301688
LIGHTBULB_CHECK(err == ESP_OK, "set hal channel group fail", goto EXIT);
16311689

16321690
s_lb_obj->status.on = true;

0 commit comments

Comments
 (0)