From ec8205d32e1e4df4026d9762da6d654687948a5a Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Tue, 13 Apr 2021 02:15:05 +0200 Subject: [PATCH] Added a binary sensor component, which can be used to handle touch/release events for the parts of the front panel (power button, color button and slider). Note that for the slider, this binary_sensor only detects the touch events. This cannot be used for detecting the actual slider level that was touch. For that purpose, a separate sensor will be created. --- binary_sensor/__init__.py | 43 ++++++++++++++++++++++++++++++++ binary_sensor/button.h | 52 +++++++++++++++++++++++++++++++++++++++ front_panel_hal.h | 7 ++++-- 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 binary_sensor/__init__.py create mode 100644 binary_sensor/button.h diff --git a/binary_sensor/__init__.py b/binary_sensor/__init__.py new file mode 100644 index 0000000..91924d0 --- /dev/null +++ b/binary_sensor/__init__.py @@ -0,0 +1,43 @@ +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 .. import ( + bs2_ns, CODEOWNERS, + CONF_FRONT_PANEL_HAL_ID, FrontPanelHAL +) + +AUTO_LOAD = ["yeelight_bs2"] + +CONF_PART = "part" + +PARTS = { + "ANY" : 0, + "POWER_BUTTON" : 1, + "COLOR_BUTTON" : 2, + "SLIDER" : 3. +} + +def validate_part(value): + value = cv.string(value) + return cv.enum(PARTS, upper=True)(value) + +YeelightBS2Button = bs2_ns.class_("YeelightBS2Button", binary_sensor.BinarySensor, cg.Component) + +CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(YeelightBS2Button), + cv.GenerateID(CONF_FRONT_PANEL_HAL_ID): cv.use_id(FrontPanelHAL), + cv.Optional(CONF_PART, default="ANY"): validate_part, + } +).extend(cv.COMPONENT_SCHEMA) + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + yield cg.register_component(var, 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_part(config[CONF_PART])) diff --git a/binary_sensor/button.h b/binary_sensor/button.h new file mode 100644 index 0000000..0545aaa --- /dev/null +++ b/binary_sensor/button.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../common.h" +#include "../front_panel_hal.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace yeelight { +namespace bs2 { + +/** + * This class implements a binary sensor for the buttons on the + * Yeelight Bedside Lamp 2. + */ +class YeelightBS2Button : public binary_sensor::BinarySensor, public Component { +public: + void set_front_panel_hal(FrontPanelHAL *front_panel) { + front_panel_ = front_panel; + } + + void set_part(int part) { + part_ = part; + } + + void setup() { + ESP_LOGCONFIG(TAG, "Setting up binary_sensor ..."); + ESP_LOGCONFIG(TAG, " Part id: %d", 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; + } + } + // Publish the new state, based on the touch/release status.. + auto on_or_off = (ev & FLAG_TYPE_MASK) == FLAG_TYPE_TOUCH; + this->publish_state(on_or_off); + } + ); + } + +protected: + FrontPanelHAL *front_panel_; + EVENT part_; +}; + +} // namespace bs2 +} // namespace yeelight +} // namespace esphome diff --git a/front_panel_hal.h b/front_panel_hal.h index 7d105e6..445bb89 100644 --- a/front_panel_hal.h +++ b/front_panel_hal.h @@ -54,17 +54,20 @@ static const EVENT FLAG_INIT = 0b0000000000; static const EVENT FLAG_ERR = 0b0000000000; static const EVENT FLAG_OK = 0b0000000001; +static const EVENT FLAG_PART_SHIFT = 1; static const EVENT FLAG_PART_MASK = 0b0000000110; static const EVENT FLAG_PART_UNKNOWN = 0b0000000000; static const EVENT FLAG_PART_POWER = 0b0000000010; static const EVENT FLAG_PART_COLOR = 0b0000000100; static const EVENT FLAG_PART_SLIDER = 0b0000000110; +static const EVENT FLAG_TYPE_SHIFT = 3; static const EVENT FLAG_TYPE_MASK = 0b0000011000; static const EVENT FLAG_TYPE_UNKNOWN = 0b0000000000; static const EVENT FLAG_TYPE_TOUCH = 0b0000001000; static const EVENT FLAG_TYPE_RELEASE = 0b0000010000; +static const EVENT FLAG_LEVEL_SHIFT = 5; static const EVENT FLAG_LEVEL_MASK = 0b1111100000; static const EVENT FLAG_LEVEL_UNKNOWN = 0b0000000000; @@ -110,7 +113,7 @@ public: return error_(ev, m, "out of bounds slider value"); } else { auto level = 0x17 - m[5]; - ev |= (level << 5); + ev |= (level << FLAG_LEVEL_SHIFT); } break; default: @@ -143,7 +146,7 @@ protected: (has_(ev, FLAG_TYPE_MASK, FLAG_TYPE_TOUCH) ? "touch" : has_(ev, FLAG_TYPE_MASK, FLAG_TYPE_RELEASE) ? "release" : "n/a")); if (has_(ev, FLAG_PART_MASK, FLAG_PART_SLIDER)) { - auto level = (ev & FLAG_LEVEL_MASK) >> 5; + auto level = (ev & FLAG_LEVEL_MASK) >> FLAG_LEVEL_SHIFT; if (level > 0) { ESP_LOGE(TAG, " Parsed slider level: %d", level); }