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.

149 lines
5.3 KiB

3 years ago
  1. #pragma once
  2. #include "common.h"
  3. #include "color_instant_handler.h"
  4. #include "color_transition_handler.h"
  5. namespace esphome {
  6. namespace yeelight {
  7. namespace bs2 {
  8. /**
  9. * A LightOutput class for the Yeelight Bedside Lamp 2.
  10. *
  11. * The function of this class is to translate a required light state
  12. * into actual physicial GPIO output signals to drive the device's LED
  13. * circuitry. It forms the glue between the physical device and the
  14. * logical light color input.
  15. */
  16. class YeelightBS2LightOutput : public Component, public light::LightOutput {
  17. public:
  18. /** Sets the LEDC output for the red LED circuitry channel. */
  19. void set_red_output(ledc::LEDCOutput *red) { red_ = red; }
  20. /** Sets the LEDC output for the green LED circuitry channel. */
  21. void set_green_output(ledc::LEDCOutput *green) { green_ = green; }
  22. /** Sets the LEDC output for the blue LED circuitry channel. */
  23. void set_blue_output(ledc::LEDCOutput *blue) { blue_ = blue; }
  24. /** Sets the LEDC output for the white LED circuitry channel. */
  25. void set_white_output(ledc::LEDCOutput *white) { white_ = white; }
  26. /**
  27. * Sets the first GPIO binary output, used as internal master switch for
  28. * the LED light circuitry.
  29. */
  30. void set_master1_output(gpio::GPIOBinaryOutput *master1) { master1_ = master1; }
  31. /**
  32. * Set the second GPIO binary output, used as internal master switch for
  33. * the LED light circuitry.
  34. */
  35. void set_master2_output(gpio::GPIOBinaryOutput *master2) { master2_ = master2; }
  36. /**
  37. * Returns a LightTraits object, which is used to explain to the outside
  38. * world (e.g. Home Assistant) what features are supported by this device.
  39. */
  40. light::LightTraits get_traits() override
  41. {
  42. auto traits = light::LightTraits();
  43. traits.set_supports_rgb(true);
  44. traits.set_supports_color_temperature(true);
  45. traits.set_supports_brightness(true);
  46. traits.set_supports_rgb_white_value(false);
  47. traits.set_supports_color_interlock(true);
  48. traits.set_min_mireds(MIRED_MIN);
  49. traits.set_max_mireds(MIRED_MAX);
  50. return traits;
  51. }
  52. /**
  53. * Applies a requested light state to the physicial GPIO outputs.
  54. */
  55. void write_state(light::LightState *state)
  56. {
  57. auto values = state->current_values;
  58. // The color must either be set instantly, or the color is
  59. // transitioning to an end color. The transition handler will do its
  60. // own inspection to see if a transition is currently active or not.
  61. // Based on the outcome, use either the instant or transition handler.
  62. GPIOOutputs *delegate;
  63. if (transition_handler_->set_light_color_values(values)) {
  64. delegate = transition_handler_;
  65. } else {
  66. instant_handler_->set_light_color_values(values);
  67. delegate = instant_handler_;
  68. }
  69. // Note: one might think that it is more logical to turn on the LED
  70. // circuitry master switch after setting the individual channels,
  71. // but this is the order that was used by the original firmware. I
  72. // tried to stay as close as possible to the original behavior, so
  73. // that's why these GPIOs are turned on at this point.
  74. if (values.get_state() != 0)
  75. {
  76. master2_->turn_on();
  77. master1_->turn_on();
  78. }
  79. // Apply the current GPIO output levels from the selected handler.
  80. red_->set_level(delegate->red);
  81. green_->set_level(delegate->green);
  82. blue_->set_level(delegate->blue);
  83. white_->set_level(delegate->white);
  84. if (values.get_state() == 0)
  85. {
  86. master2_->turn_off();
  87. master1_->turn_off();
  88. }
  89. }
  90. protected:
  91. ledc::LEDCOutput *red_;
  92. ledc::LEDCOutput *green_;
  93. ledc::LEDCOutput *blue_;
  94. ledc::LEDCOutput *white_;
  95. esphome::gpio::GPIOBinaryOutput *master1_;
  96. esphome::gpio::GPIOBinaryOutput *master2_;
  97. GPIOOutputs *transition_handler_;
  98. GPIOOutputs *instant_handler_ = new ColorInstantHandler();
  99. friend class YeelightBS2LightState;
  100. /**
  101. * Called by the YeelightBS2LightState class, to set the object that can be
  102. * used to access the protected LightTransformer data from the LightState
  103. * object.
  104. */
  105. void set_transformer_inspector(LightStateTransformerInspector *exposer) {
  106. transition_handler_ = new ColorTransitionHandler(exposer);
  107. }
  108. };
  109. /**
  110. * This custom LightState class is used to provide access to the protected
  111. * LightTranformer information in the LightState class.
  112. *
  113. * This class is used by the ColorTransitionHandler class to inspect if
  114. * an ongoing light color transition is active in a LightState object.
  115. */
  116. class YeelightBS2LightState : public light::LightState, public LightStateTransformerInspector
  117. {
  118. public:
  119. YeelightBS2LightState(const std::string &name, YeelightBS2LightOutput *output) : light::LightState(name, output) {
  120. output->set_transformer_inspector(this);
  121. }
  122. bool is_active() { return this->transformer_ != nullptr; }
  123. bool is_transition() { return this->transformer_->is_transition(); }
  124. light::LightColorValues get_end_values() { return this->transformer_->get_end_values(); }
  125. float get_progress() { return this->transformer_->get_progress(); }
  126. };
  127. } // namespace bs2
  128. } // namespace yeelight
  129. } // namespace esphome