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.
 
 

132 lines
5.4 KiB

import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components.ledc.output import LEDCOutput
from esphome.components.gpio.output import GPIOBinaryOutput
from esphome.components.i2c import I2CComponent, I2CDevice
from esphome.core import coroutine
from esphome.core import CORE
from esphome.const import (
CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, CONF_TRIGGER_PIN,
CONF_SDA, CONF_SCL, CONF_ADDRESS, CONF_PLATFORM
)
CODEOWNERS = ["@mmakaay"]
CONF_HUB_ID = "yeelight_bs2_hub_id"
CONF_RED_ID = "red_id"
CONF_GREEN_ID = "green_id"
CONF_BLUE_ID = "blue_id"
CONF_WHITE_ID = "white_id"
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_LIGHT_HAL_ID = "light_hal"
CONF_FRONT_PANEL_HAL_ID = "front_panel_hal_id"
CONF_ON_BRIGHTNESS = "on_brightness"
AUTO_LOAD = ["ledc", "output", "i2c"]
yeelight_ns = cg.esphome_ns.namespace("yeelight")
bs2_ns = yeelight_ns.namespace("bs2")
LightHAL = bs2_ns.class_("LightHAL", cg.Component)
FrontPanelHAL = bs2_ns.class_("FrontPanelHAL", cg.Component, I2CDevice)
def make_config_schema():
schema = cv.COMPONENT_SCHEMA.extend({
# RGBWW Light
cv.GenerateID(CONF_LIGHT_HAL_ID): cv.declare_id(LightHAL),
cv.GenerateID(CONF_RED_ID): cv.declare_id(LEDCOutput),
cv.Optional(CONF_RED, default="GPIO13"): pins.validate_gpio_pin,
cv.GenerateID(CONF_GREEN_ID): cv.declare_id(LEDCOutput),
cv.Optional(CONF_GREEN, default="GPIO14"): pins.validate_gpio_pin,
cv.GenerateID(CONF_BLUE_ID): cv.declare_id(LEDCOutput),
cv.Optional(CONF_BLUE, default="GPIO5"): pins.validate_gpio_pin,
cv.GenerateID(CONF_WHITE_ID): cv.declare_id(LEDCOutput),
cv.Optional(CONF_WHITE, default="GPIO12"): pins.validate_gpio_pin,
cv.GenerateID(CONF_MASTER1_ID): cv.declare_id(GPIOBinaryOutput),
cv.Optional(CONF_MASTER1, default="GPIO33"): pins.validate_gpio_pin,
cv.GenerateID(CONF_MASTER2_ID): cv.declare_id(GPIOBinaryOutput),
cv.Optional(CONF_MASTER2, default="GPIO4"): pins.validate_gpio_pin,
# Front panel I2C
cv.GenerateID(CONF_FRONT_PANEL_HAL_ID): cv.declare_id(FrontPanelHAL),
cv.GenerateID(CONF_FP_I2C_ID): cv.use_id(I2CComponent),
cv.Optional(CONF_SDA, default="GPIO21"): pins.validate_gpio_pin,
cv.Optional(CONF_SCL, default="GPIO19"): pins.validate_gpio_pin,
cv.Optional(CONF_ADDRESS, default="0x2C"): cv.i2c_address,
cv.Optional(CONF_TRIGGER_PIN, default="GPIO16"): cv.All(
pins.validate_gpio_pin,
pins.validate_has_interrupt
),
})
return schema;
CONFIG_SCHEMA = make_config_schema()
@coroutine
def make_gpio(number, mode="OUTPUT"):
yield from cg.gpio_pin_expression({ "number": number, "mode": mode });
@coroutine
def make_gpio_binary_output(id_, number):
gpio_var = yield make_gpio(number)
output_var = cg.new_Pvariable(id_)
cg.add(output_var.set_pin(gpio_var))
yield from cg.register_component(output_var, {})
@coroutine
def make_ledc_output(id_, number, frequency, channel):
gpio_var = yield make_gpio(number)
ledc_var = cg.new_Pvariable(id_, gpio_var)
cg.add(ledc_var.set_frequency(frequency));
cg.add(ledc_var.set_channel(channel));
yield from cg.register_component(ledc_var, {})
@coroutine
def make_light_hal(config):
r_var = yield make_ledc_output(config[CONF_RED_ID], config[CONF_RED], 3000, 0)
g_var = yield make_ledc_output(config[CONF_GREEN_ID], config[CONF_GREEN], 3000, 1)
b_var = yield make_ledc_output(config[CONF_BLUE_ID], config[CONF_BLUE], 3000, 2)
w_var = yield make_ledc_output(config[CONF_WHITE_ID], config[CONF_WHITE], 10000, 4)
m1_var = yield make_gpio_binary_output(config[CONF_MASTER1_ID], config[CONF_MASTER1])
m2_var = yield make_gpio_binary_output(config[CONF_MASTER2_ID], config[CONF_MASTER2])
light_hal = cg.new_Pvariable(config[CONF_LIGHT_HAL_ID])
yield cg.register_component(light_hal, config)
cg.add(light_hal.set_red_pin(r_var))
cg.add(light_hal.set_green_pin(g_var))
cg.add(light_hal.set_blue_pin(b_var))
cg.add(light_hal.set_white_pin(w_var))
cg.add(light_hal.set_master1_pin(m1_var))
cg.add(light_hal.set_master2_pin(m2_var))
@coroutine
def make_front_panel_hal(config):
trigger_pin = yield make_gpio(config[CONF_TRIGGER_PIN], "INPUT")
fp_hal = cg.new_Pvariable(config[CONF_FRONT_PANEL_HAL_ID])
yield cg.register_component(fp_hal, config)
cg.add(fp_hal.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(fp_hal.set_i2c_parent(fp_i2c_var))
cg.add(fp_hal.set_i2c_address(config[CONF_ADDRESS]))
def to_code(config):
# Dirty little hack to make the ESPHome component loader inlcude
# the code for the "gpio" platform for the "output" domain.
# Loading specific platform components is not possible using
# the AUTO_LOAD feature unfortunately.
CORE.config["output"].append({ CONF_PLATFORM: "gpio" })
yield make_light_hal(config)
yield make_front_panel_hal(config)