#pragma once #include "common.h" #include "esphome/core/component.h" #include "esphome/core/esphal.h" #include "esphome/components/ledc/ledc_output.h" #include "esphome/components/gpio/output/gpio_binary_output.h" #include "esphome/components/i2c/i2c.h" namespace esphome { namespace yeelight { namespace bs2 { struct TriggerPinStore { volatile int queue_length = 0; static void isr(TriggerPinStore *store); }; /** * This ISR is used to handle IRQ triggers from the front panel. * * The front panel pulls the trigger pin low when a new event * is available. All we do here to handle the interrupt, is * increment a simple queue length counter. Reading the event * from the I2C bus will be handled in the main loop, based * on this counter. */ void ICACHE_RAM_ATTR HOT TriggerPinStore::isr(TriggerPinStore *store) { store->queue_length++; } class LightHAL { public: virtual void light_turn_on() = 0; virtual void light_turn_off() = 0; virtual void light_set_rgbw(float r, float g, float b, float w) = 0; }; class YeelightBS2Hub : public Component, public LightHAL { public: void set_trigger_pin(GPIOPin *pin) { i2c_trigger_pin_ = pin; } void set_red_pin(ledc::LEDCOutput *pin) { red_ = pin; } void set_green_pin(ledc::LEDCOutput *pin) { green_ = pin; } void set_blue_pin(ledc::LEDCOutput *pin) { blue_ = pin; } void set_white_pin(ledc::LEDCOutput *pin) { white_ = pin; } void set_master1_pin(gpio::GPIOBinaryOutput *pin) { master1_ = pin; } void set_master2_pin(gpio::GPIOBinaryOutput *pin) { master2_ = pin; } void set_front_panel_i2c(i2c::I2CComponent *fp_i2c) { fp_i2c_ = fp_i2c; } void setup() { ESP_LOGCONFIG(TAG, "Setting up I2C trigger pin interrupt..."); this->i2c_trigger_pin_->setup(); this->i2c_trigger_pin_->attach_interrupt( TriggerPinStore::isr, &this->trigger_pin_store_, FALLING); } void dump_config() { ESP_LOGCONFIG(TAG, "I2C"); LOG_PIN(" Interrupt pin: ", this->i2c_trigger_pin_); } void loop() { if (this->trigger_pin_store_.queue_length > 0) { this->counter_++; ESP_LOGD(TAG, "Front Panel interrupt queue=%d, counter=%d", this->trigger_pin_store_.queue_length, this->counter_); this->trigger_pin_store_.queue_length--; } } void light_turn_on() { master1_->turn_on(); master2_->turn_on(); } void light_turn_off() { master1_->turn_off(); master2_->turn_off(); } void light_set_rgbw(float r, float g, float b, float w) { red_->set_level(r); green_->set_level(g); blue_->set_level(b); white_->set_level(w); } protected: // Pins that are used for the RGBWW LEDs. ledc::LEDCOutput *red_; ledc::LEDCOutput *green_; ledc::LEDCOutput *blue_; ledc::LEDCOutput *white_; gpio::GPIOBinaryOutput *master1_; gpio::GPIOBinaryOutput *master2_; // Pin that is used by the front panel to notify the ESP that // a touch/release event can be read using I2C. GPIOPin *i2c_trigger_pin_; // The I2C bus that is connected to the front panel. i2c::I2CComponent *fp_i2c_; // Fields that are used for trigger pin interrupt handling. int counter_ = 0; TriggerPinStore trigger_pin_store_{}; friend class LightHAL; }; } // namespace bs2 } // namespace yeelight } // namespace esphome