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.

127 lines
4.4 KiB

3 years ago
Introduced a HUB component + front panel IRQ handling A HUB component was introduced. This HUB component has all the knowledge about the Yeelight Bedside Lamp 2 hardware. It known what pins are used, that PWM frequencies to use, what pins to switch in binary mode, etc. etc. No configuration is required for this HUB component. It's automatically loaded when the light component is loaded. The light component will use the HUB component to access the pins that are required for driving the LED circuitry. Note that this simplifies the configuration by A LOT. There's no need anymore to configure the pinouts in the YAML file. This is a logical route to take, since we're talking about a factory-produced PCB with a soldered on ESP32 chip, which uses the same GPIO's and settings on all produced devices (I presume). It would be quite redundant to force every user into configuring these pinouts themselves. ** Beware to update your device yaml configuration ** There are a few pinouts left to move into the HUB. I will do that in the next commit. Your device yaml configuration can be simplified along with these changes. Some of the keys in the existing light configuration block will no longer work and will have to be removed (red, green, blue, white). ** Further development ** The HUB will be extended make it the central component that also handles the I2C communication. This way, there is a central place to regulate the traffic to and from the front panel. We will be able to build upon this by implementing extra, fully separated components that handle for example the front panel light level, the power button, the color button and the slider. ** Interrupt handler for the I2C IRQ trigger pin ** One requirement for the I2C communication has already been implemented: an interrupt handler for the GPIO that is used by the front panel to signal the ESP that a new touch or release event is avilable to be read. It doens't do anything functionally right now, but if you watch the log file, you will see that touch events are detected and that they trigger some log messages.
3 years ago
Introduced a HUB component + front panel IRQ handling A HUB component was introduced. This HUB component has all the knowledge about the Yeelight Bedside Lamp 2 hardware. It known what pins are used, that PWM frequencies to use, what pins to switch in binary mode, etc. etc. No configuration is required for this HUB component. It's automatically loaded when the light component is loaded. The light component will use the HUB component to access the pins that are required for driving the LED circuitry. Note that this simplifies the configuration by A LOT. There's no need anymore to configure the pinouts in the YAML file. This is a logical route to take, since we're talking about a factory-produced PCB with a soldered on ESP32 chip, which uses the same GPIO's and settings on all produced devices (I presume). It would be quite redundant to force every user into configuring these pinouts themselves. ** Beware to update your device yaml configuration ** There are a few pinouts left to move into the HUB. I will do that in the next commit. Your device yaml configuration can be simplified along with these changes. Some of the keys in the existing light configuration block will no longer work and will have to be removed (red, green, blue, white). ** Further development ** The HUB will be extended make it the central component that also handles the I2C communication. This way, there is a central place to regulate the traffic to and from the front panel. We will be able to build upon this by implementing extra, fully separated components that handle for example the front panel light level, the power button, the color button and the slider. ** Interrupt handler for the I2C IRQ trigger pin ** One requirement for the I2C communication has already been implemented: an interrupt handler for the GPIO that is used by the front panel to signal the ESP that a new touch or release event is avilable to be read. It doens't do anything functionally right now, but if you watch the log file, you will see that touch events are detected and that they trigger some log messages.
3 years ago
  1. #pragma once
  2. #include "../common.h"
  3. #include "../light_hal.h"
  4. #include "color_instant_handler.h"
  5. #include "color_transition_handler.h"
  6. #include "esphome/components/ledc/ledc_output.h"
  7. namespace esphome {
  8. namespace yeelight {
  9. namespace bs2 {
  10. /**
  11. * A LightOutput class for the Yeelight Bedside Lamp 2.
  12. *
  13. * The function of this class is to translate a required light state
  14. * into actual physicial GPIO output signals to drive the device's LED
  15. * circuitry. It forms the glue between the physical device and the
  16. * logical light color input.
  17. */
  18. class YeelightBS2LightOutput : public Component, public light::LightOutput {
  19. public:
  20. void set_parent(LightHAL *light) { light_ = light; }
  21. /**
  22. * Returns a LightTraits object, which is used to explain to the outside
  23. * world (e.g. Home Assistant) what features are supported by this device.
  24. */
  25. light::LightTraits get_traits() override
  26. {
  27. auto traits = light::LightTraits();
  28. traits.set_supports_rgb(true);
  29. traits.set_supports_color_temperature(true);
  30. traits.set_supports_brightness(true);
  31. traits.set_supports_rgb_white_value(false);
  32. traits.set_supports_color_interlock(true);
  33. traits.set_min_mireds(MIRED_MIN);
  34. traits.set_max_mireds(MIRED_MAX);
  35. return traits;
  36. }
  37. void add_on_state_callback(std::function<void(light::LightColorValues)> &&callback) {
  38. state_callback_.add(std::move(callback));
  39. }
  40. /**
  41. * Applies a requested light state to the physicial GPIO outputs.
  42. */
  43. void write_state(light::LightState *state)
  44. {
  45. auto values = state->current_values;
  46. // The color must either be set instantly, or the color is
  47. // transitioning to an end color. The transition handler will do its
  48. // own inspection to see if a transition is currently active or not.
  49. // Based on the outcome, use either the instant or transition handler.
  50. GPIOOutputs *delegate;
  51. if (transition_handler_->set_light_color_values(values)) {
  52. delegate = transition_handler_;
  53. } else {
  54. instant_handler_->set_light_color_values(values);
  55. delegate = instant_handler_;
  56. }
  57. // Note: one might think that it is more logical to turn on the LED
  58. // circuitry master switch after setting the individual channels,
  59. // but this is the order that was used by the original firmware. I
  60. // tried to stay as close as possible to the original behavior, so
  61. // that's why these GPIOs are turned on at this point.
  62. if (values.get_state() != 0)
  63. light_->turn_on();
  64. // Apply the current GPIO output levels from the selected handler.
  65. light_->set_rgbw(
  66. delegate->red,
  67. delegate->green,
  68. delegate->blue,
  69. delegate->white
  70. );
  71. if (values.get_state() == 0)
  72. light_->turn_off();
  73. state_callback_.call(values);
  74. }
  75. protected:
  76. LightHAL *light_;
  77. GPIOOutputs *transition_handler_;
  78. GPIOOutputs *instant_handler_ = new ColorInstantHandler();
  79. CallbackManager<void(light::LightColorValues)> state_callback_{};
  80. friend class YeelightBS2LightState;
  81. /**
  82. * Called by the YeelightBS2LightState class, to set the object that can be
  83. * used to access the protected LightTransformer data from the LightState
  84. * object.
  85. */
  86. void set_transformer_inspector(LightStateTransformerInspector *exposer) {
  87. transition_handler_ = new ColorTransitionHandler(exposer);
  88. }
  89. };
  90. /**
  91. * This custom LightState class is used to provide access to the protected
  92. * LightTranformer information in the LightState class.
  93. *
  94. * This class is used by the ColorTransitionHandler class to inspect if
  95. * an ongoing light color transition is active in a LightState object.
  96. */
  97. class YeelightBS2LightState : public light::LightState, public LightStateTransformerInspector
  98. {
  99. public:
  100. YeelightBS2LightState(const std::string &name, YeelightBS2LightOutput *output) : light::LightState(name, output) {
  101. output->set_transformer_inspector(this);
  102. }
  103. bool is_active() { return transformer_ != nullptr; }
  104. bool is_transition() { return transformer_->is_transition(); }
  105. light::LightColorValues get_end_values() { return transformer_->get_end_values(); }
  106. float get_progress() { return transformer_->get_progress(); }
  107. };
  108. } // namespace bs2
  109. } // namespace yeelight
  110. } // namespace esphome