From 5e328bef8f24d1cfbd7ad5a6389591674e7cde8a Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Tue, 13 Apr 2021 18:18:33 +0200 Subject: [PATCH] Implemented the slider sensor, which is used to publish a slider level when the slider is touched. The example yaml files now use this sensor to update the brightness of the LEDs. --- binary_sensor/__init__.py | 7 ++- binary_sensor/{button.h => binary_sensor.h} | 9 ++-- doc/example-full.yaml | 14 ++++- doc/example.yaml | 14 ++++- light/__init__.py | 2 +- light/light_output.h | 2 +- sensor/__init__.py | 29 ++++++++++ sensor/sensor.h | 60 +++++++++++++++++++++ 8 files changed, 125 insertions(+), 12 deletions(-) rename binary_sensor/{button.h => binary_sensor.h} (83%) create mode 100644 sensor/__init__.py create mode 100644 sensor/sensor.h diff --git a/binary_sensor/__init__.py b/binary_sensor/__init__.py index 91924d0..bd3ba3f 100644 --- a/binary_sensor/__init__.py +++ b/binary_sensor/__init__.py @@ -1,8 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import binary_sensor -#from esphome import automation -from esphome.const import CONF_DEVICE_CLASS, CONF_ID +from esphome.const import CONF_ID from .. import ( bs2_ns, CODEOWNERS, CONF_FRONT_PANEL_HAL_ID, FrontPanelHAL @@ -21,7 +20,7 @@ PARTS = { def validate_part(value): value = cv.string(value) - return cv.enum(PARTS, upper=True)(value) + return cv.enum(PARTS, upper=True, space='_')(value) YeelightBS2Button = bs2_ns.class_("YeelightBS2Button", binary_sensor.BinarySensor, cg.Component) @@ -39,5 +38,5 @@ def to_code(config): yield binary_sensor.register_binary_sensor(var, config) front_panel_hal_var = yield cg.get_variable(config[CONF_FRONT_PANEL_HAL_ID]) - cg.add(var.set_front_panel_hal(front_panel_hal_var)) + cg.add(var.set_parent(front_panel_hal_var)) cg.add(var.set_part(config[CONF_PART])) diff --git a/binary_sensor/button.h b/binary_sensor/binary_sensor.h similarity index 83% rename from binary_sensor/button.h rename to binary_sensor/binary_sensor.h index 0545aaa..d82c7bc 100644 --- a/binary_sensor/button.h +++ b/binary_sensor/binary_sensor.h @@ -14,7 +14,7 @@ namespace bs2 { */ class YeelightBS2Button : public binary_sensor::BinarySensor, public Component { public: - void set_front_panel_hal(FrontPanelHAL *front_panel) { + void set_parent(FrontPanelHAL *front_panel) { front_panel_ = front_panel; } @@ -24,12 +24,15 @@ public: void setup() { ESP_LOGCONFIG(TAG, "Setting up binary_sensor ..."); - ESP_LOGCONFIG(TAG, " Part id: %d", part_); + ESP_LOGCONFIG(TAG, " Part: %s (id %d)", + (part_ == 1 ? "power button" : + part_ == 2 ? "color button" : + part_ == 3 ? "slider" : "any"), + part_); front_panel_->add_on_event_callback( [this](EVENT ev) { // Filter events by part, when requested. - ESP_LOGI(TAG, "FILTER event=%d, part=%d", ev, part_); if (part_ > 0) { if ((ev & FLAG_PART_MASK) != (part_ << FLAG_PART_SHIFT)) { return; diff --git a/doc/example-full.yaml b/doc/example-full.yaml index 383a72f..0e9edf6 100644 --- a/doc/example-full.yaml +++ b/doc/example-full.yaml @@ -73,12 +73,22 @@ light: transition_length: 3s update_interval: 3s -# An implementation for the power button: touch to toggle the light. +# The binary sensor is used to handle front panel touch events. binary_sensor: - platform: yeelight_bs2 id: ${name}_power_button - part: POWER_BUTTON + part: power button on_press: then: - light.toggle: ${name} +# The sensor is used to publish a slider level when the slider is touched. +sensor: + - platform: yeelight_bs2 + id: ${name}_slider_level + on_value: + then: + - light.turn_on: + id: ${name} + brightness: !lambda return x; + diff --git a/doc/example.yaml b/doc/example.yaml index 12f37f6..76f5630 100644 --- a/doc/example.yaml +++ b/doc/example.yaml @@ -48,11 +48,23 @@ light: transition_length: 3s update_interval: 3s +# The binary sensor is used to handle front panel touch events. binary_sensor: - platform: yeelight_bs2 id: ${name}_power_button - part: POWER_BUTTON + part: power button on_press: then: - light.toggle: ${name} +# The sensor is used to publish a slider level when the slider is touched. +sensor: + - platform: yeelight_bs2 + id: ${name}_slider_level + on_value: + then: + - light.turn_on: + id: ${name} + brightness: !lambda return x; + + diff --git a/light/__init__.py b/light/__init__.py index 603ede5..8e65eee 100644 --- a/light/__init__.py +++ b/light/__init__.py @@ -36,7 +36,7 @@ def to_code(config): yield light.register_light(var, config) light_hal_var = yield cg.get_variable(config[CONF_LIGHT_HAL_ID]) - cg.add(var.set_light_hal(light_hal_var)) + cg.add(var.set_parent(light_hal_var)) for conf in config.get(CONF_ON_BRIGHTNESS, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) diff --git a/light/light_output.h b/light/light_output.h index bc4fef4..bdd85da 100644 --- a/light/light_output.h +++ b/light/light_output.h @@ -20,7 +20,7 @@ namespace bs2 { */ class YeelightBS2LightOutput : public Component, public light::LightOutput { public: - void set_light_hal(LightHAL *light) { light_ = light; } + void set_parent(LightHAL *light) { light_ = light; } /** * Returns a LightTraits object, which is used to explain to the outside diff --git a/sensor/__init__.py b/sensor/__init__.py new file mode 100644 index 0000000..88e5511 --- /dev/null +++ b/sensor/__init__.py @@ -0,0 +1,29 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import CONF_ID, CONF_FORCE_UPDATE +from .. import ( + bs2_ns, CODEOWNERS, + CONF_FRONT_PANEL_HAL_ID, FrontPanelHAL +) + +AUTO_LOAD = ["yeelight_bs2"] + +YeelightBS2SliderSensor = bs2_ns.class_( + "YeelightBS2SliderSensor", sensor.Sensor, cg.Component) + +CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(YeelightBS2SliderSensor), + cv.GenerateID(CONF_FRONT_PANEL_HAL_ID): cv.use_id(FrontPanelHAL), + cv.Optional(CONF_FORCE_UPDATE, default=True): cv.boolean, + } +).extend(cv.COMPONENT_SCHEMA) + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield cg.register_component(var, config) + yield sensor.register_sensor(var, config) + + front_panel_hal_var = yield cg.get_variable(config[CONF_FRONT_PANEL_HAL_ID]) + cg.add(var.set_parent(front_panel_hal_var)) diff --git a/sensor/sensor.h b/sensor/sensor.h new file mode 100644 index 0000000..0f1f410 --- /dev/null +++ b/sensor/sensor.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include "../common.h" +#include "../front_panel_hal.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace yeelight { +namespace bs2 { + +/** + * A sensor for the slider on the Yeelight Bedside Lamp 2. + * + * This sensor publishes the level at which the slider was touched, so it + * can be used to implement automations. Note that it does not represent + * the brightness of the LED lights (this is implemented by the light output + * component), nor the level as displayed by the slider using the front + * panel light (this is implemented by the slider light component). + */ +class YeelightBS2SliderSensor : public sensor::Sensor, public Component { +public: + void set_parent(FrontPanelHAL *front_panel) { + front_panel_ = front_panel; + } + + void setup() { + ESP_LOGCONFIG(TAG, "Setting up slider sensor ..."); + + front_panel_->add_on_event_callback( + [this](EVENT ev) { + if ((ev & FLAG_PART_MASK) == FLAG_PART_SLIDER) { + auto level = (ev & FLAG_LEVEL_MASK) >> FLAG_LEVEL_SHIFT; + + // Slider level 1 is really hard to touch. It is between + // the power button and the slider space, so it doesn't + // look like this one was ever meant to be used, or that + // the design was faulty on this. Therefore, level 1 is + // ignored here. + level = max(1.0f, level - 1.0f); + + // Convert the slider level to a float between 0.01 and + // 1.00, which is useful as a representation for a + // brightness value. The input level is now between + // 1 and 20. + auto publish_level = max(0.01f, (level-1.0f) * (1.00f / 19.0f)); + + this->publish_state(publish_level); + } + } + ); + } + +protected: + FrontPanelHAL *front_panel_; +}; + +} // namespace bs2 +} // namespace yeelight +} // namespace esphome