You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

79 lines
3.0 KiB

  1. #pragma once
  2. #include <array>
  3. #include <stdexcept>
  4. namespace esphome {
  5. namespace rgbww {
  6. namespace yeelight_bs2 {
  7. class RGBLight
  8. {
  9. public:
  10. float red = 0;
  11. float green = 0;
  12. float blue = 0;
  13. float white = 0;
  14. void set_color(float red, float green, float blue, float brightness, float state)
  15. {
  16. // Overall, the RGB colors are very usable when simply scaling the
  17. // RGB channels with the brightness, but around the white point,
  18. // the color is a bit on the red side of the spectrum. The following
  19. // scaling was created to fix that.
  20. // These functions were created, based on actual measurements while
  21. // using the original firmware, to generate white light
  22. // (i.e. when RGB = [1,1,1]).
  23. auto b = brightness * 100.0f;
  24. auto red_w = 1.00f - (-0.0000121426 * b * b - 0.147576 * b + 93.2335) / 100.0f;
  25. auto green_w = 1.00f - (-0.0000242425 * b * b - 0.340449 * b + 88.4423) / 100.0f;
  26. auto blue_w = 1.00f - (-0.0000085869 * b * b - 0.109649 * b + 94.2026) / 100.0f;
  27. // For colors that are not around the white point, we can scale the
  28. // RGB channels with the requested brightness, resulting in a very
  29. // usable color. Not 100% the same as the original firmware, but
  30. // sometimes even better IMO.
  31. auto red_c = red * brightness;
  32. auto green_c = green * brightness;
  33. auto blue_c = blue * brightness;
  34. auto level_red = red_c;
  35. auto level_green = green_c;
  36. auto level_blue = blue_c;
  37. //// The actual RGB values are a weighed mix of the above two.
  38. //// The closer to the white point, the more the white point
  39. //// value applies.
  40. //auto min = red;
  41. //if (blue < min) min = blue;
  42. //if (green < min) min = green;
  43. //if (min < 0.8f) min = 0.0f;
  44. //auto level_red = red_w * min + red_c * (1.0f - min);
  45. //auto level_green = green_w * min + green_c * (1.0f - min);
  46. //auto level_blue = blue_w * min + blue_c * (1.0f - min);
  47. //ESP_LOGD("rgb_light", "min=%f, red_w=%f, red_c=%f, red=%f", min, red_w, red_c, level_red);
  48. //// A tweak that I noticed in the original firmware and that
  49. //// were confirmed to be required to get the RGB mode to behave.
  50. ////if (level_red == 1.0f && level_blue > 0.1f && level_green == 0.0f) {
  51. //// level_green = 1.0f - (0.955804f - 0.00334462f * level_blue);
  52. ////}
  53. ////if (level_red == 1.0f) {
  54. //// level_red = level_blue > 0.1f ? 0.873f : 0.9f;
  55. ////}
  56. //if (level_red > 0.9f) level_red = 0.9f;
  57. //if (level_green > 0.9f) level_green = 0.9f;
  58. //if (level_blue > 0.9f) level_blue = 0.9f;
  59. // Invert the signal. The LEDs in the lamp's circuit are brighter
  60. // when the pwm levels on the GPIO pins are lower.
  61. this->red = 1.0f - level_red;
  62. this->green = 1.0f - level_green;
  63. this->blue = 1.0f - level_blue;
  64. }
  65. };
  66. } // namespace yeelight_bs2
  67. } // namespace rgbww
  68. } // namespace esphome