From b4d2e41a688b45dc2012a4213bcb6f4258fc4233 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Sun, 26 Dec 2021 16:53:11 +0100 Subject: [PATCH 1/6] Add YLKG07YL support --- .clang-format | 137 ++++++++++++ components/xiaomi_ble/xiaomi_ble.cpp | 11 +- components/xiaomi_ble/xiaomi_ble.h | 6 +- components/xiaomi_ylkg07yl/__init__.py | 91 ++++++++ .../xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp | 199 ++++++++++++++++++ components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h | 56 +++++ yeedimmer_ylkg07yl.yaml | 42 ++++ 7 files changed, 539 insertions(+), 3 deletions(-) create mode 100644 .clang-format create mode 100644 components/xiaomi_ylkg07yl/__init__.py create mode 100644 components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp create mode 100644 components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h create mode 100644 yeedimmer_ylkg07yl.yaml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e0f5ddc --- /dev/null +++ b/.clang-format @@ -0,0 +1,137 @@ +Language: Cpp +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: DontAlign +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: "^<.*" + Priority: 2 + - Regex: ".*" + Priority: 3 +IncludeIsMainRegex: "([-_](test|unittest))?$" +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 2000 +PointerAlignment: Right +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - "c++" + - "C++" + CanonicalDelimiter: "" + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: "" + BasedOnStyle: google +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 2 +UseTab: Never diff --git a/components/xiaomi_ble/xiaomi_ble.cpp b/components/xiaomi_ble/xiaomi_ble.cpp index 417c3ce..da0963e 100644 --- a/components/xiaomi_ble/xiaomi_ble.cpp +++ b/components/xiaomi_ble/xiaomi_ble.cpp @@ -16,7 +16,12 @@ bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_l // remote control key code, 3 bytes if ((value_type == 0x01) && (value_length == 3)) { result.keycode = data[0]; - result.is_long_press = data[2] == 2; + result.dimmer = data[1]; + result.press_type = data[2]; + ESP_LOGD(TAG, "Key code: %d", data[0]); // button + ESP_LOGD(TAG, "Dimmer: %d", data[1]); // value + ESP_LOGD(TAG, "Press type: %d", data[2]); // 0: single press, 1: double press, 2: long press, 3: ???, + // 4: dimmer <= 127 = rotate right / else: rotate left } // motion detection, 1 byte, 8-bit unsigned integer else if ((value_type == 0x03) && (value_length == 1)) { @@ -214,6 +219,9 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service } else if ((raw[2] == 0x53) && (raw[3] == 0x01)) { // Yeelight Remote Control YLYK01YL result.type = XiaomiParseResult::TYPE_YLYK01YL; result.name = "YLYK01YL"; + } else if ((raw[2] == 0xB6) && (raw[3] == 0x03)) { // Yeelight Wireless Smart Dimmer YLKG07YL/YLKG08YL + result.type = XiaomiParseResult::TYPE_YLKG07YL; + result.name = "YLKG07YL"; } else { ESP_LOGVV(TAG, "parse_xiaomi_header(): unknown device, no magic bytes."); return {}; @@ -222,6 +230,7 @@ optional parse_xiaomi_header(const esp32_ble_tracker::Service return result; } +// Decrypt MiBeacon V4/V5 payload bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, const uint64_t &address) { if (!((raw.size() == 19) || ((raw.size() >= 22) && (raw.size() <= 24)))) { ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): data packet has wrong size (%d)!", raw.size()); diff --git a/components/xiaomi_ble/xiaomi_ble.h b/components/xiaomi_ble/xiaomi_ble.h index 77edf73..f32b69b 100644 --- a/components/xiaomi_ble/xiaomi_ble.h +++ b/components/xiaomi_ble/xiaomi_ble.h @@ -25,10 +25,13 @@ struct XiaomiParseResult { TYPE_MJYD02YLA, TYPE_MHOC401, TYPE_CGPR1, - TYPE_YLYK01YL + TYPE_YLYK01YL, + TYPE_YLKG07YL, } type; std::string name; optional keycode; + optional dimmer; + optional press_type; optional temperature; optional humidity; optional moisture; @@ -41,7 +44,6 @@ struct XiaomiParseResult { optional is_active; optional has_motion; optional is_light; - optional is_long_press; bool has_data; // 0x40 bool has_capability; // 0x20 bool has_encryption; // 0x08 diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py new file mode 100644 index 0000000..11f274a --- /dev/null +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -0,0 +1,91 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, esp32_ble_tracker +from esphome import automation +from esphome.const import ( + CONF_MAC_ADDRESS, + CONF_BINDKEY, + UNIT_EMPTY, + ICON_EMPTY, + DEVICE_CLASS_EMPTY, + CONF_ID, + CONF_TRIGGER_ID, +) + +AUTO_LOAD = ["xiaomi_ble", "sensor"] +CODEOWNERS = ["@syssi"] +DEPENDENCIES = ["esp32_ble_tracker"] +MULTI_CONF = True + +CONF_LAST_BUTTON_PRESSED = "last_button_pressed" +CONF_ON_BUTTON_ON = "on_button_on" + +ON_PRESS_ACTIONS = [ + CONF_ON_BUTTON_ON, +] + +xiaomi_ylkg07yl_ns = cg.esphome_ns.namespace("xiaomi_ylkg07yl") +XiaomiYLKG07YL = xiaomi_ylkg07yl_ns.class_( + "XiaomiYLKG07YL", esp32_ble_tracker.ESPBTDeviceListener, cg.Component +) + +OnButtonOnTrigger = xiaomi_ylkg07yl_ns.class_( + "OnButtonOnTrigger", automation.Trigger.template() +) + + +def validate_short_bind_key(value): + value = cv.string_strict(value) + parts = [value[i : i + 2] for i in range(0, len(value), 2)] + if len(parts) != 12: + raise cv.Invalid("Bind key must consist of 12 hexadecimal numbers") + parts_int = [] + if any(len(part) != 2 for part in parts): + raise cv.Invalid("Bind key must be format XX") + for part in parts: + try: + parts_int.append(int(part, 16)) + except ValueError: + # pylint: disable=raise-missing-from + raise cv.Invalid("Bind key must be hex values from 00 to FF") + + return "".join(f"{part:02X}" for part in parts_int) + + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XiaomiYLKG07YL), + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Required(CONF_BINDKEY): validate_short_bind_key, + cv.Optional(CONF_LAST_BUTTON_PRESSED): sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_ON_BUTTON_ON): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnButtonOnTrigger), + } + ), + } + ) + .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) + .extend(cv.COMPONENT_SCHEMA) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await esp32_ble_tracker.register_ble_device(var, config) + + cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) + cg.add(var.set_bindkey(config[CONF_BINDKEY])) + + if CONF_LAST_BUTTON_PRESSED in config: + sens = await sensor.new_sensor(config[CONF_LAST_BUTTON_PRESSED]) + cg.add(var.set_keycode(sens)) + + for action in ON_PRESS_ACTIONS: + for conf in config.get(action, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp new file mode 100644 index 0000000..a60a3e8 --- /dev/null +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp @@ -0,0 +1,199 @@ +#include "xiaomi_ylkg07yl.h" +#include "esphome/core/log.h" + +#include "mbedtls/ccm.h" +#include + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_ylkg07yl { + +static const char *const TAG = "xiaomi_ylkg07yl"; + +void XiaomiYLKG07YL::dump_config() { + ESP_LOGCONFIG(TAG, "Xiaomi YLKG07YL"); + ESP_LOGCONFIG(TAG, " Bindkey: %s", hexencode(this->bindkey_, 12).c_str()); + LOG_SENSOR(" ", "Keycode", this->keycode_); +} + +bool XiaomiYLKG07YL::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { + if (device.address_uint64() != this->address_) { + ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); + return false; + } + ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); + + bool success = false; + for (auto &service_data : device.get_service_datas()) { + auto res = xiaomi_ble::parse_xiaomi_header(service_data); + if (!res.has_value()) { + continue; + } + if (res->is_duplicate) { + continue; + } + if (res->has_encryption && (!(this->decrypt_mibeacon_v23_(const_cast &>(service_data.data), + this->bindkey_, this->address_)))) { + continue; + } + if (!(xiaomi_ble::parse_xiaomi_message(service_data.data, *res))) { + continue; + } + if (!(xiaomi_ble::report_xiaomi_results(res, device.address_str()))) { + continue; + } + if (res->keycode.has_value()) { + if (this->keycode_ != nullptr) + this->keycode_->publish_state(*res->keycode); + + this->receive_callback_.call(*res->keycode); + } + success = true; + } + + return success; +} + +void XiaomiYLKG07YL::set_bindkey(const std::string &bindkey) { + memset(bindkey_, 0, 12); + if (bindkey.size() != 24) { + return; + } + char temp[3] = {0}; + for (int i = 0; i < 12; i++) { + strncpy(temp, &(bindkey.c_str()[i * 2]), 2); + bindkey_[i] = std::strtoul(temp, nullptr, 16); + } +} + +void XiaomiYLKG07YL::add_on_receive_callback(std::function &&callback) { + this->receive_callback_.add(std::move(callback)); +} + +// Decrypt MiBeacon V2/V3 payload +bool XiaomiYLKG07YL::decrypt_mibeacon_v23_(std::vector &raw, const uint8_t *bindkey, const uint64_t &address) { + if (raw.size() != 21) { + ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): data packet has wrong size (%d)!", raw.size()); + ESP_LOGVV(TAG, " Packet : %s", hexencode(raw.data(), raw.size()).c_str()); + return false; + } + + uint8_t mac_reverse[6] = {0}; + mac_reverse[5] = (uint8_t)(address >> 40); + mac_reverse[4] = (uint8_t)(address >> 32); + mac_reverse[3] = (uint8_t)(address >> 24); + mac_reverse[2] = (uint8_t)(address >> 16); + mac_reverse[1] = (uint8_t)(address >> 8); + mac_reverse[0] = (uint8_t)(address >> 0); + + xiaomi_ble::XiaomiAESVector vector{.key = {0}, + .plaintext = {0}, + .ciphertext = {0}, + .authdata = {0x11}, + .iv = {0}, + .tag = {0}, + .keysize = 16, + .authsize = 1, + .datasize = 0, + .tagsize = 4, + .ivsize = 13}; + + vector.datasize = raw.size() - 15; + int cipher_pos = 11; + + const uint8_t *v = raw.data(); + + // key format is: bindkey[:6] "8d3d3c97" bindkey[6:] + uint8_t key[16] = {0, 0, 0, 0, 0, 0, 0x8d, 0x3d, 0x3c, 0x97, 0, 0, 0, 0, 0, 0}; + memcpy(key + 0x0, bindkey + 0, 6); + memcpy(key + 0xA, bindkey + 6, 6); + + memcpy(vector.key, key, vector.keysize); + memcpy(vector.ciphertext, v + cipher_pos, vector.datasize); + + // 58.30.B6.03.01.BC.7B.C4.41.24.F8.5A.B8.4A.60.93.B8.01.00.00.21 (21) + // ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // + // 58.30. Frame control + // B6.03. Device type + // 01. Frame count + // BC.7B.C4.41.24.F8. MAC address + // 5A.B8.4A.60.93.B8. Cipher + // 01.00.00. Ext. count + // 21 + + // nonce = b"".join( + // [ + // self.framectrl_data, + // self.device_type, + // payload_counter, + // self.xiaomi_mac_reversed[:-1] + // ] + // ) + + // 58.30.B6.03.01.BC.7B.C4.41.24.F8.5A.B8.4A.60.93.B8.01.00.00.21 (21) + // ^^^^^^^^^^^^^^ + memcpy(vector.iv, v, 5); // frame control (2 bytes) + device type (2 bytes) + + // frame count (1 byte) + + // 58.30.B6.03.01.BC.7B.C4.41.24.F8.5A.B8.4A.60.93.B8.01.00.00.21 (21) + // ^^^^^^^^ + memcpy(vector.iv + 5, v + raw.size() - 4, 3); // ext. count + + // 58.30.B6.03.01.BC.7B.C4.41.24.F8.5A.B8.4A.60.93.B8.01.00.00.21 (21) + // ^^^^^^^^^^^^^^ + memcpy(vector.iv + 8, mac_reverse, 5); // 5 bytes of the reversed MAC address + + mbedtls_ccm_context ctx; + mbedtls_ccm_init(&ctx); + + int ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, vector.key, vector.keysize * 8); + if (ret) { + ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): mbedtls_ccm_setkey() failed."); + mbedtls_ccm_free(&ctx); + return false; + } + + ret = mbedtls_ccm_star_auth_decrypt(&ctx, vector.datasize, vector.iv, vector.ivsize, vector.authdata, vector.authsize, + vector.ciphertext, vector.plaintext, nullptr, 0); + if (ret) { + uint8_t mac_address[6] = {0}; + memcpy(mac_address, mac_reverse + 5, 1); + memcpy(mac_address + 1, mac_reverse + 4, 1); + memcpy(mac_address + 2, mac_reverse + 3, 1); + memcpy(mac_address + 3, mac_reverse + 2, 1); + memcpy(mac_address + 4, mac_reverse + 1, 1); + memcpy(mac_address + 5, mac_reverse, 1); + ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): mbedtls_ccm_star_auth_decrypt failed."); + ESP_LOGVV(TAG, " MAC address : %s", hexencode(mac_address, 6).c_str()); + ESP_LOGVV(TAG, " Packet : %s", hexencode(raw.data(), raw.size()).c_str()); + ESP_LOGVV(TAG, " Key : %s", hexencode(vector.key, vector.keysize).c_str()); + ESP_LOGVV(TAG, " Iv : %s", hexencode(vector.iv, vector.ivsize).c_str()); + ESP_LOGVV(TAG, " Cipher : %s", hexencode(vector.ciphertext, vector.datasize).c_str()); + mbedtls_ccm_free(&ctx); + return false; + } + + // replace encrypted payload with plaintext + uint8_t *p = vector.plaintext; + for (std::vector::iterator it = raw.begin() + cipher_pos; it != raw.begin() + cipher_pos + vector.datasize; + ++it) { + *it = *(p++); + } + + // clear encrypted flag + raw[0] &= ~0x08; + + ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption passed."); + ESP_LOGVV(TAG, " Plaintext : %s, Packet : %d", hexencode(raw.data() + cipher_pos, vector.datasize).c_str(), + static_cast(raw[4])); + + mbedtls_ccm_free(&ctx); + return true; +} + +} // namespace xiaomi_ylkg07yl +} // namespace esphome + +#endif diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h new file mode 100644 index 0000000..8bed957 --- /dev/null +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h @@ -0,0 +1,56 @@ +#pragma once + +#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/xiaomi_ble/xiaomi_ble.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" + +#ifdef USE_ESP32 + +namespace esphome { +namespace xiaomi_ylkg07yl { + +static const uint8_t BUTTON_ON = 0; +static const uint8_t BUTTON_OFF = 1; +static const uint8_t BUTTON_SUN = 2; +static const uint8_t BUTTON_M = 4; +static const uint8_t BUTTON_PLUS = 3; +static const uint8_t BUTTON_MINUS = 5; + +class XiaomiYLKG07YL : public Component, public esp32_ble_tracker::ESPBTDeviceListener { + public: + void set_address(uint64_t address) { address_ = address; } + void set_bindkey(const std::string &bindkey); + + bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; + + void dump_config() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_keycode(sensor::Sensor *keycode) { keycode_ = keycode; } + void add_on_receive_callback(std::function &&callback); + + protected: + uint64_t address_; + uint8_t bindkey_[12]; + sensor::Sensor *keycode_{nullptr}; + CallbackManager receive_callback_{}; + + bool decrypt_mibeacon_v23_(std::vector &raw, const uint8_t *bindkey, const uint64_t &address); +}; + +class OnButtonOnTrigger : public Trigger<> { + public: + OnButtonOnTrigger(XiaomiYLKG07YL *a_remote) { + a_remote->add_on_receive_callback([this](int keycode) { + if (keycode == BUTTON_ON) { + this->trigger(); + } + }); + } +}; + +} // namespace xiaomi_ylkg07yl +} // namespace esphome + +#endif diff --git a/yeedimmer_ylkg07yl.yaml b/yeedimmer_ylkg07yl.yaml new file mode 100644 index 0000000..6382db2 --- /dev/null +++ b/yeedimmer_ylkg07yl.yaml @@ -0,0 +1,42 @@ +substitutions: + name: yeedimmer + +esphome: + name: ${name} + +esp32: + board: esp32doit-devkit-v1 + framework: + type: esp-idf + +external_components: + - source: components +# - source: github://syssi/esphome-yeelight-ceiling-light@main +# refresh: 0s + +wifi: + ssid: !secret wifi_ssid_back + password: !secret wifi_password_back + fast_connect: true + +ota: +api: + +logger: + level: DEBUG + +esp32_ble_tracker: + scan_parameters: + interval: 250ms + window: 250ms + duration: 1min + active: false + +xiaomi_ylkg07yl: + mac_address: "F8:24:41:C4:7B:BC" + bindkey: "ef3afd53f5c7853a080a3d52" + last_button_pressed: + name: "last button pressed" + on_button_on: + then: + - logger.log: "Button on pressed" From 6dd619e05a01c59a1da8b387b98f7753880d9612 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Sun, 26 Dec 2021 21:55:05 +0100 Subject: [PATCH 2/6] Drop last button pressed sensor --- components/xiaomi_ylkg07yl/__init__.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py index 11f274a..03c4a52 100644 --- a/components/xiaomi_ylkg07yl/__init__.py +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -17,7 +17,6 @@ DEPENDENCIES = ["esp32_ble_tracker"] MULTI_CONF = True -CONF_LAST_BUTTON_PRESSED = "last_button_pressed" CONF_ON_BUTTON_ON = "on_button_on" ON_PRESS_ACTIONS = [ @@ -58,9 +57,6 @@ def validate_short_bind_key(value): cv.GenerateID(): cv.declare_id(XiaomiYLKG07YL), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Required(CONF_BINDKEY): validate_short_bind_key, - cv.Optional(CONF_LAST_BUTTON_PRESSED): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY - ), cv.Optional(CONF_ON_BUTTON_ON): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnButtonOnTrigger), @@ -81,10 +77,6 @@ async def to_code(config): cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) - if CONF_LAST_BUTTON_PRESSED in config: - sens = await sensor.new_sensor(config[CONF_LAST_BUTTON_PRESSED]) - cg.add(var.set_keycode(sens)) - for action in ON_PRESS_ACTIONS: for conf in config.get(action, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) From 25c3e504e7a22dd00bbfbf9193ec4c4e4a9e825c Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Tue, 28 Dec 2021 14:10:02 +0100 Subject: [PATCH 3/6] Revert "Drop last button pressed sensor" This reverts commit 6dd619e05a01c59a1da8b387b98f7753880d9612. --- components/xiaomi_ylkg07yl/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py index 03c4a52..11f274a 100644 --- a/components/xiaomi_ylkg07yl/__init__.py +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -17,6 +17,7 @@ DEPENDENCIES = ["esp32_ble_tracker"] MULTI_CONF = True +CONF_LAST_BUTTON_PRESSED = "last_button_pressed" CONF_ON_BUTTON_ON = "on_button_on" ON_PRESS_ACTIONS = [ @@ -57,6 +58,9 @@ def validate_short_bind_key(value): cv.GenerateID(): cv.declare_id(XiaomiYLKG07YL), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Required(CONF_BINDKEY): validate_short_bind_key, + cv.Optional(CONF_LAST_BUTTON_PRESSED): sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + ), cv.Optional(CONF_ON_BUTTON_ON): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnButtonOnTrigger), @@ -77,6 +81,10 @@ async def to_code(config): cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) + if CONF_LAST_BUTTON_PRESSED in config: + sens = await sensor.new_sensor(config[CONF_LAST_BUTTON_PRESSED]) + cg.add(var.set_keycode(sens)) + for action in ON_PRESS_ACTIONS: for conf in config.get(action, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) From a61c9c78f9e5dd9ace0a386db72c006bd6f14291 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Tue, 28 Dec 2021 18:14:42 +0100 Subject: [PATCH 4/6] Add trigger --- components/xiaomi_ble/xiaomi_ble.cpp | 12 ++--- components/xiaomi_ble/xiaomi_ble.h | 4 +- components/xiaomi_ylkg07yl/__init__.py | 36 +++++++++++--- .../xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp | 4 +- components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h | 48 +++++++++++++------ yeedimmer_ylkg07yl.yaml | 10 +++- 6 files changed, 82 insertions(+), 32 deletions(-) diff --git a/components/xiaomi_ble/xiaomi_ble.cpp b/components/xiaomi_ble/xiaomi_ble.cpp index da0963e..b9f2757 100644 --- a/components/xiaomi_ble/xiaomi_ble.cpp +++ b/components/xiaomi_ble/xiaomi_ble.cpp @@ -16,12 +16,12 @@ bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_l // remote control key code, 3 bytes if ((value_type == 0x01) && (value_length == 3)) { result.keycode = data[0]; - result.dimmer = data[1]; - result.press_type = data[2]; - ESP_LOGD(TAG, "Key code: %d", data[0]); // button - ESP_LOGD(TAG, "Dimmer: %d", data[1]); // value - ESP_LOGD(TAG, "Press type: %d", data[2]); // 0: single press, 1: double press, 2: long press, 3: ???, - // 4: dimmer <= 127 = rotate right / else: rotate left + result.encoder_value = data[1]; + result.action_type = data[2]; + ESP_LOGD(TAG, "Key code: %d", data[0]); + ESP_LOGD(TAG, "Encoder value: %d", data[1]); + ESP_LOGD(TAG, "Action type: %d", data[2]); // 0: single press, 1: double press, 2: long press, 3: ???, + // 4: dimmer <= 127 = rotate right / else: rotate left } // motion detection, 1 byte, 8-bit unsigned integer else if ((value_type == 0x03) && (value_length == 1)) { diff --git a/components/xiaomi_ble/xiaomi_ble.h b/components/xiaomi_ble/xiaomi_ble.h index f32b69b..5242489 100644 --- a/components/xiaomi_ble/xiaomi_ble.h +++ b/components/xiaomi_ble/xiaomi_ble.h @@ -30,8 +30,8 @@ struct XiaomiParseResult { } type; std::string name; optional keycode; - optional dimmer; - optional press_type; + optional encoder_value; + optional action_type; optional temperature; optional humidity; optional moisture; diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py index 11f274a..216fac8 100644 --- a/components/xiaomi_ylkg07yl/__init__.py +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -18,10 +18,14 @@ MULTI_CONF = True CONF_LAST_BUTTON_PRESSED = "last_button_pressed" -CONF_ON_BUTTON_ON = "on_button_on" +CONF_ON_PRESS = "on_press" +CONF_ON_PRESS_AND_ROTATE = "on_press_and_rotate" +CONF_ON_ROTATE = "on_rotate" ON_PRESS_ACTIONS = [ - CONF_ON_BUTTON_ON, + CONF_ON_PRESS, + CONF_ON_PRESS_AND_ROTATE, + CONF_ON_ROTATE, ] xiaomi_ylkg07yl_ns = cg.esphome_ns.namespace("xiaomi_ylkg07yl") @@ -29,8 +33,16 @@ "XiaomiYLKG07YL", esp32_ble_tracker.ESPBTDeviceListener, cg.Component ) -OnButtonOnTrigger = xiaomi_ylkg07yl_ns.class_( - "OnButtonOnTrigger", automation.Trigger.template() +OnPressTrigger = xiaomi_ylkg07yl_ns.class_( + "OnPressTrigger", automation.Trigger.template() +) + +OnPressAndRotateTrigger = xiaomi_ylkg07yl_ns.class_( + "OnPressAndRotateTrigger", automation.Trigger.template() +) + +OnRotateTrigger = xiaomi_ylkg07yl_ns.class_( + "OnRotateTrigger", automation.Trigger.template() ) @@ -61,9 +73,21 @@ def validate_short_bind_key(value): cv.Optional(CONF_LAST_BUTTON_PRESSED): sensor.sensor_schema( UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY ), - cv.Optional(CONF_ON_BUTTON_ON): automation.validate_automation( + cv.Optional(CONF_ON_PRESS): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnPressTrigger), + } + ), + cv.Optional(CONF_ON_PRESS_AND_ROTATE): automation.validate_automation( + { + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( + OnPressAndRotateTrigger + ), + } + ), + cv.Optional(CONF_ON_ROTATE): automation.validate_automation( { - cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnButtonOnTrigger), + cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnRotateTrigger), } ), } diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp index a60a3e8..231bb53 100644 --- a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp @@ -47,7 +47,7 @@ bool XiaomiYLKG07YL::parse_device(const esp32_ble_tracker::ESPBTDevice &device) if (this->keycode_ != nullptr) this->keycode_->publish_state(*res->keycode); - this->receive_callback_.call(*res->keycode); + this->receive_callback_.call(*res->keycode, *res->encoder_value, *res->action_type); } success = true; } @@ -67,7 +67,7 @@ void XiaomiYLKG07YL::set_bindkey(const std::string &bindkey) { } } -void XiaomiYLKG07YL::add_on_receive_callback(std::function &&callback) { +void XiaomiYLKG07YL::add_on_receive_callback(std::function &&callback) { this->receive_callback_.add(std::move(callback)); } diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h index 8bed957..2967c40 100644 --- a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once> #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" #include "esphome/components/sensor/sensor.h" @@ -8,16 +8,14 @@ #ifdef USE_ESP32 +static const uint8_t KEY_CODE_BUTTON = 0; + +static const uint8_t ACTION_TYPE_PRESS = 3; +static const uint8_t ACTION_TYPE_ROTATE = 4; + namespace esphome { namespace xiaomi_ylkg07yl { -static const uint8_t BUTTON_ON = 0; -static const uint8_t BUTTON_OFF = 1; -static const uint8_t BUTTON_SUN = 2; -static const uint8_t BUTTON_M = 4; -static const uint8_t BUTTON_PLUS = 3; -static const uint8_t BUTTON_MINUS = 5; - class XiaomiYLKG07YL : public Component, public esp32_ble_tracker::ESPBTDeviceListener { public: void set_address(uint64_t address) { address_ = address; } @@ -28,22 +26,44 @@ class XiaomiYLKG07YL : public Component, public esp32_ble_tracker::ESPBTDeviceLi void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } void set_keycode(sensor::Sensor *keycode) { keycode_ = keycode; } - void add_on_receive_callback(std::function &&callback); + void add_on_receive_callback(std::function &&callback); protected: uint64_t address_; uint8_t bindkey_[12]; sensor::Sensor *keycode_{nullptr}; - CallbackManager receive_callback_{}; + CallbackManager receive_callback_{}; bool decrypt_mibeacon_v23_(std::vector &raw, const uint8_t *bindkey, const uint64_t &address); }; -class OnButtonOnTrigger : public Trigger<> { +class OnPressTrigger : public Trigger<> { + public: + OnPressTrigger(XiaomiYLKG07YL *a_remote) { + a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { + if (action_type == ACTION_TYPE_PRESS && keycode == KEY_CODE_BUTTON) { + this->trigger(); + } + }); + } +}; + +class OnRotateTrigger : public Trigger<> { + public: + OnRotateTrigger(XiaomiYLKG07YL *a_remote) { + a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { + if (action_type == ACTION_TYPE_ROTATE && keycode == KEY_CODE_BUTTON) { + this->trigger(); + } + }); + } +}; + +class OnPressAndRotateTrigger : public Trigger<> { public: - OnButtonOnTrigger(XiaomiYLKG07YL *a_remote) { - a_remote->add_on_receive_callback([this](int keycode) { - if (keycode == BUTTON_ON) { + OnPressAndRotateTrigger(XiaomiYLKG07YL *a_remote) { + a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { + if (action_type == ACTION_TYPE_ROTATE && keycode != KEY_CODE_BUTTON) { this->trigger(); } }); diff --git a/yeedimmer_ylkg07yl.yaml b/yeedimmer_ylkg07yl.yaml index 6382db2..4813877 100644 --- a/yeedimmer_ylkg07yl.yaml +++ b/yeedimmer_ylkg07yl.yaml @@ -37,6 +37,12 @@ xiaomi_ylkg07yl: bindkey: "ef3afd53f5c7853a080a3d52" last_button_pressed: name: "last button pressed" - on_button_on: + on_press: then: - - logger.log: "Button on pressed" + - logger.log: "Button press" + on_press_and_rotate: + then: + - logger.log: "Button press and rotate" + on_rotate: + then: + - logger.log: "Button rotate" From 62aa72b5dde90f1de5e7e4e943ad86c5dcdf9667 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Tue, 28 Dec 2021 18:35:19 +0100 Subject: [PATCH 5/6] Introduce sensors --- components/xiaomi_ble/xiaomi_ble.cpp | 4 --- components/xiaomi_ylkg07yl/__init__.py | 27 +++++++++++++++---- .../xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp | 14 +++++++--- components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h | 16 ++++++----- yeedimmer_ylkg07yl.yaml | 11 ++++++-- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/components/xiaomi_ble/xiaomi_ble.cpp b/components/xiaomi_ble/xiaomi_ble.cpp index b9f2757..7fa64f1 100644 --- a/components/xiaomi_ble/xiaomi_ble.cpp +++ b/components/xiaomi_ble/xiaomi_ble.cpp @@ -18,10 +18,6 @@ bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_l result.keycode = data[0]; result.encoder_value = data[1]; result.action_type = data[2]; - ESP_LOGD(TAG, "Key code: %d", data[0]); - ESP_LOGD(TAG, "Encoder value: %d", data[1]); - ESP_LOGD(TAG, "Action type: %d", data[2]); // 0: single press, 1: double press, 2: long press, 3: ???, - // 4: dimmer <= 127 = rotate right / else: rotate left } // motion detection, 1 byte, 8-bit unsigned integer else if ((value_type == 0x03) && (value_length == 1)) { diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py index 216fac8..5f7b429 100644 --- a/components/xiaomi_ylkg07yl/__init__.py +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -17,7 +17,16 @@ DEPENDENCIES = ["esp32_ble_tracker"] MULTI_CONF = True -CONF_LAST_BUTTON_PRESSED = "last_button_pressed" +CONF_KEYCODE = "keycode" +CONF_ENCODER_VALUE = "encoder_value" +CONF_ACTION_TYPE = "action_type" + +SENSORS = [ + CONF_KEYCODE, + CONF_ENCODER_VALUE, + CONF_ACTION_TYPE, +] + CONF_ON_PRESS = "on_press" CONF_ON_PRESS_AND_ROTATE = "on_press_and_rotate" CONF_ON_ROTATE = "on_rotate" @@ -70,7 +79,13 @@ def validate_short_bind_key(value): cv.GenerateID(): cv.declare_id(XiaomiYLKG07YL), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Required(CONF_BINDKEY): validate_short_bind_key, - cv.Optional(CONF_LAST_BUTTON_PRESSED): sensor.sensor_schema( + cv.Optional(CONF_KEYCODE): sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_ENCODER_VALUE): sensor.sensor_schema( + UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + ), + cv.Optional(CONF_ACTION_TYPE): sensor.sensor_schema( UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY ), cv.Optional(CONF_ON_PRESS): automation.validate_automation( @@ -105,9 +120,11 @@ async def to_code(config): cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex)) cg.add(var.set_bindkey(config[CONF_BINDKEY])) - if CONF_LAST_BUTTON_PRESSED in config: - sens = await sensor.new_sensor(config[CONF_LAST_BUTTON_PRESSED]) - cg.add(var.set_keycode(sens)) + for key in SENSORS: + if key in config: + conf = config[key] + sens = await sensor.new_sensor(conf) + cg.add(getattr(var, f"set_{key}_sensor")(sens)) for action in ON_PRESS_ACTIONS: for conf in config.get(action, []): diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp index 231bb53..ca7a781 100644 --- a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.cpp @@ -14,7 +14,9 @@ static const char *const TAG = "xiaomi_ylkg07yl"; void XiaomiYLKG07YL::dump_config() { ESP_LOGCONFIG(TAG, "Xiaomi YLKG07YL"); ESP_LOGCONFIG(TAG, " Bindkey: %s", hexencode(this->bindkey_, 12).c_str()); - LOG_SENSOR(" ", "Keycode", this->keycode_); + LOG_SENSOR(" ", "Keycode", this->keycode_sensor_); + LOG_SENSOR(" ", "Encoder value", this->encoder_value_sensor_); + LOG_SENSOR(" ", "Action type", this->action_type_sensor_); } bool XiaomiYLKG07YL::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { @@ -44,8 +46,14 @@ bool XiaomiYLKG07YL::parse_device(const esp32_ble_tracker::ESPBTDevice &device) continue; } if (res->keycode.has_value()) { - if (this->keycode_ != nullptr) - this->keycode_->publish_state(*res->keycode); + if (this->keycode_sensor_ != nullptr) + this->keycode_sensor_->publish_state(*res->keycode); + + if (this->encoder_value_sensor_ != nullptr) + this->encoder_value_sensor_->publish_state(*res->encoder_value); + + if (this->action_type_sensor_ != nullptr) + this->action_type_sensor_->publish_state(*res->action_type); this->receive_callback_.call(*res->keycode, *res->encoder_value, *res->action_type); } diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h index 2967c40..a966f5d 100644 --- a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h @@ -8,7 +8,7 @@ #ifdef USE_ESP32 -static const uint8_t KEY_CODE_BUTTON = 0; +static const uint8_t KEYCODE_BUTTON = 0; static const uint8_t ACTION_TYPE_PRESS = 3; static const uint8_t ACTION_TYPE_ROTATE = 4; @@ -25,13 +25,17 @@ class XiaomiYLKG07YL : public Component, public esp32_ble_tracker::ESPBTDeviceLi void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } - void set_keycode(sensor::Sensor *keycode) { keycode_ = keycode; } + void set_keycode_sensor(sensor::Sensor *keycode_sensor) { keycode_sensor_ = keycode_sensor; } + void set_encoder_value_sensor(sensor::Sensor *encoder_value_sensor) { encoder_value_sensor_ = encoder_value_sensor; } + void set_action_type_sensor(sensor::Sensor *action_type_sensor) { action_type_sensor_ = action_type_sensor; } void add_on_receive_callback(std::function &&callback); protected: uint64_t address_; uint8_t bindkey_[12]; - sensor::Sensor *keycode_{nullptr}; + sensor::Sensor *keycode_sensor_{nullptr}; + sensor::Sensor *encoder_value_sensor_{nullptr}; + sensor::Sensor *action_type_sensor_{nullptr}; CallbackManager receive_callback_{}; bool decrypt_mibeacon_v23_(std::vector &raw, const uint8_t *bindkey, const uint64_t &address); @@ -41,7 +45,7 @@ class OnPressTrigger : public Trigger<> { public: OnPressTrigger(XiaomiYLKG07YL *a_remote) { a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { - if (action_type == ACTION_TYPE_PRESS && keycode == KEY_CODE_BUTTON) { + if (action_type == ACTION_TYPE_PRESS && keycode == KEYCODE_BUTTON) { this->trigger(); } }); @@ -52,7 +56,7 @@ class OnRotateTrigger : public Trigger<> { public: OnRotateTrigger(XiaomiYLKG07YL *a_remote) { a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { - if (action_type == ACTION_TYPE_ROTATE && keycode == KEY_CODE_BUTTON) { + if (action_type == ACTION_TYPE_ROTATE && keycode == KEYCODE_BUTTON) { this->trigger(); } }); @@ -63,7 +67,7 @@ class OnPressAndRotateTrigger : public Trigger<> { public: OnPressAndRotateTrigger(XiaomiYLKG07YL *a_remote) { a_remote->add_on_receive_callback([this](int keycode, int encoder_value, int action_type) { - if (action_type == ACTION_TYPE_ROTATE && keycode != KEY_CODE_BUTTON) { + if (action_type == ACTION_TYPE_ROTATE && keycode != KEYCODE_BUTTON) { this->trigger(); } }); diff --git a/yeedimmer_ylkg07yl.yaml b/yeedimmer_ylkg07yl.yaml index 4813877..d248ba0 100644 --- a/yeedimmer_ylkg07yl.yaml +++ b/yeedimmer_ylkg07yl.yaml @@ -35,8 +35,15 @@ esp32_ble_tracker: xiaomi_ylkg07yl: mac_address: "F8:24:41:C4:7B:BC" bindkey: "ef3afd53f5c7853a080a3d52" - last_button_pressed: - name: "last button pressed" + keycode: + name: "last keycode" + id: keycode + encoder_value: + name: "last encoder value" + id: encoder_value + action_type: + name: "last action type" + id: action_type on_press: then: - logger.log: "Button press" From 6b1cf4ef0887422303e8256f819e3926a8c85832 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Fri, 31 Dec 2021 10:23:38 +0100 Subject: [PATCH 6/6] Add some lambda functions --- components/xiaomi_ylkg07yl/__init__.py | 6 ++-- components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h | 2 +- yeedimmer_ylkg07yl.yaml | 37 +++++++++++++++++--- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/components/xiaomi_ylkg07yl/__init__.py b/components/xiaomi_ylkg07yl/__init__.py index 5f7b429..0aee1c4 100644 --- a/components/xiaomi_ylkg07yl/__init__.py +++ b/components/xiaomi_ylkg07yl/__init__.py @@ -80,13 +80,13 @@ def validate_short_bind_key(value): cv.Required(CONF_MAC_ADDRESS): cv.mac_address, cv.Required(CONF_BINDKEY): validate_short_bind_key, cv.Optional(CONF_KEYCODE): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY ), cv.Optional(CONF_ENCODER_VALUE): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY ), cv.Optional(CONF_ACTION_TYPE): sensor.sensor_schema( - UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY + UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY ), cv.Optional(CONF_ON_PRESS): automation.validate_automation( { diff --git a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h index a966f5d..b15e585 100644 --- a/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h +++ b/components/xiaomi_ylkg07yl/xiaomi_ylkg07yl.h @@ -1,4 +1,4 @@ -#pragma once> +#pragma once #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" #include "esphome/components/sensor/sensor.h" diff --git a/yeedimmer_ylkg07yl.yaml b/yeedimmer_ylkg07yl.yaml index d248ba0..6157e9a 100644 --- a/yeedimmer_ylkg07yl.yaml +++ b/yeedimmer_ylkg07yl.yaml @@ -1,5 +1,6 @@ substitutions: name: yeedimmer + light_entity: light.office_desk esphome: name: ${name} @@ -21,9 +22,14 @@ wifi: ota: api: + password: !secret api_password logger: - level: DEBUG + level: VERY_VERBOSE + logs: + esp32_ble_tracker: WARN + xiaomi_ylkg07yl: DEBUG + api.service: WARN esp32_ble_tracker: scan_parameters: @@ -38,18 +44,39 @@ xiaomi_ylkg07yl: keycode: name: "last keycode" id: keycode +# internal: true encoder_value: name: "last encoder value" id: encoder_value +# internal: true action_type: name: "last action type" id: action_type +# internal: true on_press: then: - - logger.log: "Button press" + - logger.log: "Press event" + - homeassistant.service: + service: light.toggle + data: + entity_id: ${light_entity} + on_rotate: + then: + - logger.log: "Rotate event" + - homeassistant.service: + service: light.turn_on + data: + entity_id: ${light_entity} + data_template: + brightness_step_pct: "{{ step }}" + variables: + step: |- + if (id(encoder_value).state <= 127) { + return id(encoder_value).state * 2.5; + } else { + return (256 - id(encoder_value).state) * 2.5 * -1; + } + on_press_and_rotate: then: - logger.log: "Button press and rotate" - on_rotate: - then: - - logger.log: "Button rotate"