diff --git a/__init__.py b/__init__.py index 615376c..5a428fb 100644 --- a/__init__.py +++ b/__init__.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome import pins from esphome.components.ledc.output import LEDCOutput, validate_frequency from esphome.components.gpio.output import GPIOBinaryOutput +from esphome.components.i2c import I2CComponent from esphome.core import coroutine from esphome.core import CORE from esphome.const import ( @@ -12,6 +13,8 @@ from esphome.const import ( CONF_BLUE, CONF_WHITE, CONF_TRIGGER_PIN, + CONF_SDA, + CONF_SCL, CONF_OUTPUT_ID, CONF_TRIGGER_ID, CONF_PIN, @@ -29,15 +32,12 @@ CONF_MASTER1 = "master1" CONF_MASTER1_ID = "master1_id" CONF_MASTER2 = "master2" CONF_MASTER2_ID = "master2_id" +CONF_FP_I2C_ID = "front_panel_i2c_id" CONF_ON_BRIGHTNESS = "on_brightness" CODEOWNERS = ["@mmakaay"] -AUTO_LOAD = ["ledc", "output"] - -yeelight_ns = cg.esphome_ns.namespace("yeelight") -bs2_ns = yeelight_ns.namespace("bs2") -YeelightBS2Hub = bs2_ns.class_("YeelightBS2Hub", cg.Component) +AUTO_LOAD = ["ledc", "output", "i2c"] PINS = { # Config key TYPE, ID GPIO, PARAMS @@ -46,13 +46,27 @@ PINS = { CONF_BLUE : ( LEDCOutput, CONF_BLUE_ID, "GPIO5", 3000, 2 ), CONF_WHITE : ( LEDCOutput, CONF_WHITE_ID, "GPIO12", 10000, 4 ), CONF_MASTER1 : ( GPIOBinaryOutput, CONF_MASTER1_ID, "GPIO33" ), - CONF_MASTER2 : ( GPIOBinaryOutput, CONF_MASTER2_ID, "GPIO4" ), + CONF_MASTER2 : ( GPIOBinaryOutput, CONF_MASTER2_ID, "GPIO4" ) } +FRONT_PANEL = { + CONF_SDA: "GPIO21", + CONF_SCL: "GPIO19", + CONF_TRIGGER_PIN: "GPIO16" +} + + +yeelight_ns = cg.esphome_ns.namespace("yeelight") +bs2_ns = yeelight_ns.namespace("bs2") +YeelightBS2Hub = bs2_ns.class_("YeelightBS2Hub", cg.Component) + def make_config_schema(): schema = cv.COMPONENT_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(YeelightBS2Hub), - cv.Optional(CONF_TRIGGER_PIN, default="GPIO16"): cv.All( + cv.GenerateID(CONF_FP_I2C_ID): cv.use_id(I2CComponent), + cv.Optional(CONF_SDA, default=FRONT_PANEL[CONF_SDA]): pins.validate_gpio_pin, + cv.Optional(CONF_SCL, default=FRONT_PANEL[CONF_SCL]): pins.validate_gpio_pin, + cv.Optional(CONF_TRIGGER_PIN, default=FRONT_PANEL[CONF_TRIGGER_PIN]): cv.All( pins.validate_gpio_pin, pins.validate_has_interrupt ), @@ -67,7 +81,6 @@ def make_config_schema(): return schema; - CONFIG_SCHEMA = make_config_schema() @coroutine @@ -120,6 +133,16 @@ def to_code(config): }) cg.add(hub_var.set_trigger_pin(trigger_pin)) + # The i2c component automatically sets up one I2C bus. + # Take that bus and update is to make it work for the + # front panel I2C communication. + fp_i2c_var = yield cg.get_variable(config[CONF_FP_I2C_ID]) + cg.add(fp_i2c_var.set_sda_pin(config[CONF_SDA])) + cg.add(fp_i2c_var.set_scl_pin(config[CONF_SCL])) + cg.add(fp_i2c_var.set_scan(True)) + cg.add(hub_var.set_front_panel_i2c(fp_i2c_var)) + for conf in config.get(CONF_ON_BRIGHTNESS, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) yield automation.build_automation(trigger, [(float, "x")], conf) + diff --git a/doc/example.yaml b/doc/example.yaml index 349a943..b4cf07f 100644 --- a/doc/example.yaml +++ b/doc/example.yaml @@ -32,6 +32,7 @@ esphome: platform_packages: |-4 framework-arduinoespressif32 @ https://github.com/pauln/arduino-esp32.git#solo-no-mac-crc/1.0.4 +# This component controls the light of the device. light: - platform: yeelight_bs2 name: ${friendly_name} RGBW Light @@ -47,22 +48,3 @@ light: transition_length: 3s update_interval: 3s -# The device uses two I2C busses. -i2c: - # This bus is very likely connected to an EEPROM that can be found - # on the lamp's board, right next to the GND, TX, RX and GPIO0 debug - # pads. The exact use of this component has not yet been reverse - # engineered. - - id: eeprom_i2c - sda: GPIO17 - scl: GPIO18 - scan: True - # This bus is connected to the front panel with the touch buttons. - # The touch panel is fully separated form the main board and ESP32, - # and communication is done strictly through I2C. The exact protocol - # has been reverse engineered and can be found in the file - # "doc/reverse_engineering/I2C protocol/i2c_commands.txt". - - id: front_panel_i2c - sda: GPIO21 - scl: GPIO19 - scan: True diff --git a/yeelight_bs2_hub.h b/yeelight_bs2_hub.h index b3f8d32..354b486 100644 --- a/yeelight_bs2_hub.h +++ b/yeelight_bs2_hub.h @@ -5,6 +5,7 @@ #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 { @@ -45,6 +46,7 @@ public: 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..."); @@ -72,6 +74,9 @@ protected: // 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_{};