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.

125 lines
3.9 KiB

  1. #pragma once
  2. #include <array>
  3. #include <stdexcept>
  4. #include "common.h"
  5. #include "gpio_outputs.h"
  6. namespace esphome {
  7. namespace yeelight {
  8. namespace bs2 {
  9. /**
  10. * The minimum color temperature in mired. Same as supported by
  11. * the original Yeelight firmware.
  12. */
  13. static const int MIRED_MIN = 153;
  14. /**
  15. * The maximum color temperature in mired. Same as supported by
  16. * the original Yeelight firmware.
  17. */
  18. static const int MIRED_MAX = 588;
  19. struct RGBWLevelsByTemperature {
  20. float from_temperature;
  21. float red;
  22. float green;
  23. float blue;
  24. float white;
  25. };
  26. using RGBWLevelsTable = std::array<RGBWLevelsByTemperature, 15>;
  27. static const RGBWLevelsTable rgbw_levels_1_ {{
  28. { 501.0f, 0.873f, 0.907f, 1.000f, 0.063f },
  29. { 455.0f, 0.873f, 0.896f, 1.000f, 0.063f },
  30. { 417.0f, 0.873f, 0.891f, 1.000f, 0.068f },
  31. { 371.0f, 0.873f, 0.880f, 1.000f, 0.070f },
  32. { 334.0f, 0.873f, 0.887f, 1.000f, 0.088f },
  33. { 313.0f, 0.882f, 0.904f, 1.000f, 0.128f },
  34. { 295.0f, 0.947f, 1.000f, 0.968f, 0.145f },
  35. { 251.0f, 0.999f, 1.000f, 1.000f, 0.155f },
  36. { 223.0f, 1.000f, 0.899f, 0.921f, 0.130f },
  37. { 201.0f, 1.000f, 0.873f, 0.908f, 0.115f },
  38. { 182.0f, 1.000f, 0.873f, 0.901f, 0.103f },
  39. { 173.0f, 1.000f, 0.873f, 0.904f, 0.094f },
  40. { 167.0f, 1.000f, 0.873f, 0.891f, 0.098f },
  41. { 154.0f, 1.000f, 0.873f, 0.894f, 0.090f },
  42. { 153.0f, 1.000f, 0.873f, 0.892f, 0.088f }
  43. }};
  44. static const RGBWLevelsTable rgbw_levels_100_ {{
  45. { 501.0f, 0.000f, 0.344f, 1.000f, 0.068f },
  46. { 455.0f, 0.000f, 0.237f, 1.000f, 0.093f },
  47. { 417.0f, 0.000f, 0.186f, 1.000f, 0.120f },
  48. { 371.0f, 0.000f, 0.149f, 1.000f, 0.167f },
  49. { 334.0f, 0.000f, 0.135f, 1.000f, 0.325f },
  50. { 313.0f, 0.097f, 0.314f, 1.000f, 0.740f },
  51. { 295.0f, 0.745f, 1.000f, 0.953f, 0.905f },
  52. { 251.0f, 1.000f, 1.000f, 1.000f, 1.000f },
  53. { 223.0f, 1.000f, 0.267f, 0.485f, 0.765f },
  54. { 201.0f, 1.000f, 0.000f, 0.355f, 0.609f },
  55. { 182.0f, 1.000f, 0.000f, 0.282f, 0.489f },
  56. { 173.0f, 1.000f, 0.000f, 0.313f, 0.392f },
  57. { 167.0f, 1.000f, 0.000f, 0.180f, 0.422f },
  58. { 154.0f, 1.000f, 0.000f, 0.218f, 0.368f },
  59. { 153.0f, 1.000f, 0.000f, 0.187f, 0.335f }
  60. }};
  61. /**
  62. * This class can handle the GPIO outputs for the white light mode,
  63. * based on color temperature + brightness.
  64. */
  65. class ColorWhiteLight : public GPIOOutputs {
  66. protected:
  67. bool set_light_color_values(light::LightColorValues v) {
  68. if (v.get_white() == 0.0f) {
  69. return false;
  70. }
  71. auto temperature = clamp_temperature_(v.get_color_temperature());
  72. auto brightness = clamp_brightness_(v.get_brightness());
  73. auto levels_1 = lookup_in_table_(rgbw_levels_1_, temperature);
  74. auto levels_100 = lookup_in_table_(rgbw_levels_100_, temperature);
  75. red = esphome::lerp(brightness, levels_1.red, levels_100.red);
  76. green = esphome::lerp(brightness, levels_1.green, levels_100.green);
  77. blue = esphome::lerp(brightness, levels_1.blue, levels_100.blue);
  78. white = esphome::lerp(brightness, levels_1.white, levels_100.white);
  79. return true;
  80. }
  81. float clamp_temperature_(float temperature)
  82. {
  83. if (temperature > MIRED_MAX)
  84. temperature = MIRED_MAX;
  85. else if (temperature < MIRED_MIN)
  86. temperature = MIRED_MIN;
  87. return temperature;
  88. }
  89. float clamp_brightness_(float brightness)
  90. {
  91. if (brightness < 0.01f)
  92. brightness = 0.01f;
  93. else if (brightness > 1.00f)
  94. brightness = 1.00f;
  95. return brightness;
  96. }
  97. RGBWLevelsByTemperature lookup_in_table_(RGBWLevelsTable table, float temperature)
  98. {
  99. for (RGBWLevelsByTemperature& item : table)
  100. if (temperature >= item.from_temperature)
  101. return item;
  102. throw std::invalid_argument("received too low temperature");
  103. }
  104. };
  105. } // namespace bs2
  106. } // namespace yeelight
  107. } // namespace esphome