#pragma once #include #include namespace esphome { namespace rgbww { namespace yeelight_bs2 { class RGBLight { public: float red = 0; float green = 0; float blue = 0; float white = 0; void set_color(float red, float green, float blue, float brightness, float state) { // Overall, the RGB colors are very usable when simply scaling the // RGB channels with the brightness, but around the white point, // the color is a bit on the red side of the spectrum. The following // scaling was created to fix that. // These functions were created, based on actual measurements while // using the original firmware. auto b = brightness * 100.0f; auto red_w = 1.00f - (-0.0000121426 * b * b - 0.147576 * b + 93.2335) / 100.0f; auto green_w = 1.00f - (-0.0000242425 * b * b - 0.340449 * b + 88.4423) / 100.0f; auto blue_w = 1.00f - (-0.0000085869 * b * b - 0.109649 * b + 94.2026) / 100.0f; // For colors that are not around the white point, we can scale the // RGB channels with the requested brightness, resulting in a very // usable color. Not 100% the same as the original firmware, but // sometimes even better IMO. auto red_c = red * brightness; auto green_c = green * brightness; auto blue_c = blue * brightness; // The actual RGB values are a weighed mix of the above two. // The closer to the white point, the more the white point // value applies. auto level_red = (red_w * ((green+blue)/2)) + (red_c * (1-(green+blue)/2)); auto level_green = (green_w * ((red+blue)/2)) + (green_c * (1-(red+blue)/2)); auto level_blue = (blue_w * ((red+green)/2)) + (blue_c * (1-(red+green)/2)); if (red == 1 && green == 1 && blue == 1) { level_red = red_w; level_green = green_w; level_blue = blue_w; } // Invert the signal. The LEDs in the lamp's circuit are brighter // when the pwm levels on the GPIO pins are lower. this->red = 1.0f - level_red; this->green = 1.0f - level_green; this->blue = 1.0f - level_blue; } }; } // namespace yeelight_bs2 } // namespace rgbww } // namespace esphome