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.

119 lines
3.7 KiB

  1. #pragma once
  2. #include <array>
  3. #include <stdexcept>
  4. namespace esphome {
  5. namespace rgbww {
  6. namespace yeelight_bs2 {
  7. // Same range as supported by the original Yeelight firmware.
  8. static const int MIRED_MAX = 153;
  9. static const int MIRED_MIN = 588;
  10. struct RgbwLevelsByTemperature {
  11. float from_temperature;
  12. float red;
  13. float green;
  14. float blue;
  15. float white;
  16. };
  17. using RgbwLevelsTable = std::array<RgbwLevelsByTemperature, 15>;
  18. static const RgbwLevelsTable rgbw_levels_1_ {{
  19. { 501.0f, 87.3f, 90.7f, 100.0f, 6.3f },
  20. { 455.0f, 87.3f, 89.6f, 100.0f, 6.3f },
  21. { 417.0f, 87.3f, 89.1f, 100.0f, 6.8f },
  22. { 371.0f, 87.3f, 88.0f, 100.0f, 7.0f },
  23. { 334.0f, 87.3f, 88.7f, 100.0f, 8.8f },
  24. { 313.0f, 88.2f, 90.4f, 100.0f, 12.8f },
  25. { 295.0f, 94.7f, 100.0f, 96.8f, 14.5f },
  26. { 251.0f, 99.9f, 100.0f, 100.0f, 15.5f },
  27. { 223.0f, 100.0f, 89.9f, 92.1f, 13.0f },
  28. { 201.0f, 100.0f, 87.3f, 90.8f, 11.5f },
  29. { 182.0f, 100.0f, 87.3f, 90.1f, 10.3f },
  30. { 173.0f, 100.0f, 87.3f, 90.4f, 9.4f },
  31. { 167.0f, 100.0f, 87.3f, 89.1f, 9.8f },
  32. { 154.0f, 100.0f, 87.3f, 89.4f, 9.0f },
  33. { 153.0f, 100.0f, 87.3f, 89.2f, 8.8f }
  34. }};
  35. static const RgbwLevelsTable rgbw_levels_100_ {{
  36. { 501.0f, 0.0f, 34.4f, 100.0f, 6.8f },
  37. { 455.0f, 0.0f, 23.7f, 100.0f, 9.3f },
  38. { 417.0f, 0.0f, 18.6f, 100.0f, 12.0f },
  39. { 371.0f, 0.0f, 14.9f, 100.0f, 16.7f },
  40. { 334.0f, 0.0f, 13.5f, 100.0f, 32.5f },
  41. { 313.0f, 9.7f, 31.4f, 100.0f, 74.0f },
  42. { 295.0f, 74.5f, 100.0f, 95.3f, 90.5f },
  43. { 251.0f, 100.0f, 100.0f, 100.0f, 100.0f },
  44. { 223.0f, 100.0f, 26.7f, 48.5f, 76.5f },
  45. { 201.0f, 100.0f, 0.0f, 35.5f, 60.9f },
  46. { 182.0f, 100.0f, 0.0f, 28.2f, 48.9f },
  47. { 173.0f, 100.0f, 0.0f, 31.3f, 39.2f },
  48. { 167.0f, 100.0f, 0.0f, 18.0f, 42.2f },
  49. { 154.0f, 100.0f, 0.0f, 21.8f, 36.8f },
  50. { 153.0f, 100.0f, 0.0f, 18.7f, 33.5f }
  51. }};
  52. class WhiteLight
  53. {
  54. public:
  55. float red = 0;
  56. float green = 0;
  57. float blue = 0;
  58. float white = 0;
  59. void set_color(float temperature, float brightness)
  60. {
  61. temperature = clamp_temperature_(temperature);
  62. brightness = clamp_brightness_(brightness);
  63. auto levels_1 = lookup_in_table_(rgbw_levels_1_, temperature);
  64. auto levels_100 = lookup_in_table_(rgbw_levels_100_, temperature);
  65. red = interpolate_(levels_1.red, levels_100.red, brightness);
  66. green = interpolate_(levels_1.green, levels_100.green, brightness);
  67. blue = interpolate_(levels_1.blue, levels_100.blue, brightness);
  68. white = interpolate_(levels_1.white, levels_100.white, brightness);
  69. }
  70. protected:
  71. float clamp_temperature_(float temperature)
  72. {
  73. if (temperature < MIRED_MAX)
  74. temperature = MIRED_MAX;
  75. else if (temperature > MIRED_MIN)
  76. temperature = MIRED_MIN;
  77. return temperature;
  78. }
  79. float clamp_brightness_(float brightness)
  80. {
  81. if (brightness < 0.01f)
  82. brightness = 0.01f;
  83. else if (brightness > 1.00f)
  84. brightness = 1.00f;
  85. return brightness;
  86. }
  87. RgbwLevelsByTemperature lookup_in_table_(RgbwLevelsTable table, float temperature)
  88. {
  89. for (RgbwLevelsByTemperature& item : table)
  90. if (temperature >= item.from_temperature)
  91. return item;
  92. throw std::invalid_argument("received too low temperature");
  93. }
  94. float interpolate_(float level_1, float level_100, float brightness)
  95. {
  96. auto coefficient = (level_100 - level_1) / 0.99f;
  97. auto level = level_1 + (brightness - 0.01f) * coefficient;
  98. return level;
  99. }
  100. };
  101. } // namespace yeelight_bs2
  102. } // namespace rgbww
  103. } // namespace esphome