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
4.0 KiB

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