From 0b0766654dda1cfe392ec535ccff49af758ebb9f Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Thu, 27 Jun 2024 22:00:42 +0200 Subject: [PATCH] Add on_write callback and set_value automations --- .../components/esp32_ble_server/__init__.py | 54 ++++++++++++------- .../esp32_ble_server/ble_server.cpp | 9 ++++ .../components/esp32_ble_server/ble_server.h | 16 ++++++ tests/test5.yaml | 33 ++++++------ 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index d0634232d9..0b6a2a9069 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -1,6 +1,7 @@ +from esphome import automation import esphome.codegen as cg import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_MODEL +from esphome.const import CONF_ID, CONF_MODEL, CONF_UUID, CONF_SERVICES, CONF_VALUE, CONF_MAX_LENGTH, CONF_ON_CLIENT_CONNECTED, CONF_ON_CLIENT_DISCONNECTED from esphome.components import esp32_ble from esphome.core import CORE from esphome.components.esp32 import add_idf_sdkconfig_option @@ -12,15 +13,12 @@ DEPENDENCIES = ["esp32"] CONF_MANUFACTURER = "manufacturer" CONF_MANUFACTURER_DATA = "manufacturer_data" -CONF_SERVICES = "services" -CONF_UUID = "uuid" CONF_ADVERTISE = "advertise" CONF_NUM_HANDLES = "num_handles" +CONF_ON_WRITE = "on_write" CONF_CHARACTERISTICS = "characteristics" CONF_PROPERTIES = "properties" -CONF_VALUE = "value" CONF_DESCRIPTORS = "descriptors" -CONF_MAX_LENGTH = "max_length" esp32_ble_server_ns = cg.esphome_ns.namespace("esp32_ble_server") ESPBTUUID_ns = cg.esphome_ns.namespace("esp32_ble").namespace("ESPBTUUID") @@ -31,9 +29,11 @@ BLEServer = esp32_ble_server_ns.class_( esp32_ble.GATTsEventHandler, cg.Parented.template(esp32_ble.ESP32BLE), ) +BLEServerAutomationInterface = esp32_ble_server_ns.namespace("BLEServerAutomationInterface") BLEDescriptor = esp32_ble_server_ns.class_("BLEDescriptor") BLECharacteristic = esp32_ble_server_ns.class_("BLECharacteristic") BLEService = esp32_ble_server_ns.class_("BLEService") +BLECharacteristicSetValueAction = BLEServerAutomationInterface.class_("BLECharacteristicSetValueAction", automation.Action) def validate_uuid(value): @@ -85,6 +85,7 @@ SERVICE_CHARACTERISTIC_SCHEMA = cv.Schema( cv.Required(CONF_PROPERTIES): PROPERTIES_SCHEMA, cv.Optional(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA, cv.Optional(CONF_DESCRIPTORS, default=[]): cv.ensure_list(SERVICE_CHARACTERISTIC_DESCRIPTOR_SCHEMA), + cv.Optional(CONF_ON_WRITE): automation.validate_automation({cv.GenerateID(): cv.declare_id(BLECharacteristic)}, single=True), } ) @@ -141,9 +142,9 @@ def parse_value(value): def calculate_num_handles(service_config): total = 1 - for characteristic in service_config[CONF_CHARACTERISTICS]: - total += 2 # One for the characteristic itself and one for the value - for _ in characteristic[CONF_DESCRIPTORS]: + for char_conf in service_config[CONF_CHARACTERISTICS]: + total += 2 # One for the char_conf itself and one for the value + for _ in char_conf[CONF_DESCRIPTORS]: total += 1 return total @@ -171,22 +172,35 @@ async def to_code(config): service_config[CONF_ADVERTISE], num_handles, )) - for characteristic in service_config[CONF_CHARACTERISTICS]: - char_var = cg.Pvariable(characteristic[CONF_ID], service_var.create_characteristic( - parse_uuid(characteristic[CONF_UUID]), - parse_properties(characteristic[CONF_PROPERTIES]) + for char_conf in service_config[CONF_CHARACTERISTICS]: + char_var = cg.Pvariable(char_conf[CONF_ID], service_var.create_characteristic( + parse_uuid(char_conf[CONF_UUID]), + parse_properties(char_conf[CONF_PROPERTIES]) )) - if CONF_VALUE in characteristic: - cg.add(char_var.set_value(parse_value(characteristic[CONF_VALUE]))) - for descriptor in characteristic[CONF_DESCRIPTORS]: - max_length = descriptor[CONF_MAX_LENGTH] + if CONF_ON_WRITE in char_conf: + on_write_conf = char_conf[CONF_ON_WRITE] + if "WRITE" not in char_conf[CONF_PROPERTIES]: + raise cv.Invalid("on_write requires the WRITE property") + await automation.build_automation(BLEServerAutomationInterface.create_on_write_trigger(char_var), [(cg.std_string, "x")], on_write_conf) + if CONF_VALUE in char_conf: + cg.add(char_var.set_value(parse_value(char_conf[CONF_VALUE]))) + for descriptor_conf in char_conf[CONF_DESCRIPTORS]: + max_length = descriptor_conf[CONF_MAX_LENGTH] # If max_length is 0, calculate the optimal length based on the value if max_length == 0: - max_length = len(parse_value(descriptor[CONF_VALUE])) - desc_var = cg.new_Pvariable(descriptor[CONF_ID], parse_uuid(descriptor[CONF_UUID]), max_length) - if CONF_VALUE in descriptor: - cg.add(desc_var.set_value(parse_value(descriptor[CONF_VALUE]))) + max_length = len(parse_value(descriptor_conf[CONF_VALUE])) + desc_var = cg.new_Pvariable(descriptor_conf[CONF_ID], parse_uuid(descriptor_conf[CONF_UUID]), max_length) + if CONF_VALUE in descriptor_conf: + cg.add(desc_var.set_value(parse_value(descriptor_conf[CONF_VALUE]))) cg.add(var.enqueue_start_service(service_var)) cg.add_define("USE_ESP32_BLE_SERVER") if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) + +@automation.register_action("ble_server.characteristic_set_value", BLECharacteristicSetValueAction, cv.Schema({ + cv.Required(CONF_ID): cv.use_id(BLECharacteristic), + cv.Required(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA, +})) +async def ble_enable_to_code(config, action_id, template_arg, args): + char_var = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, char_var) diff --git a/esphome/components/esp32_ble_server/ble_server.cpp b/esphome/components/esp32_ble_server/ble_server.cpp index 72ee1d744d..41db5afb5e 100644 --- a/esphome/components/esp32_ble_server/ble_server.cpp +++ b/esphome/components/esp32_ble_server/ble_server.cpp @@ -17,6 +17,15 @@ namespace esphome { namespace esp32_ble_server { +Trigger *BLEServerAutomationInterface::create_on_write_trigger(BLECharacteristic *characteristic) { + Trigger *on_write_trigger = new Trigger(); + characteristic->on_write([on_write_trigger](const std::vector &data) { + std::string value(data.begin(), data.end()); + on_write_trigger->trigger(value); + }); + return on_write_trigger; +} + static const char *const TAG = "esp32_ble_server"; static const uint16_t DEVICE_INFORMATION_SERVICE_UUID = 0x180A; diff --git a/esphome/components/esp32_ble_server/ble_server.h b/esphome/components/esp32_ble_server/ble_server.h index fa6c8f142a..e4c6cb7cc8 100644 --- a/esphome/components/esp32_ble_server/ble_server.h +++ b/esphome/components/esp32_ble_server/ble_server.h @@ -7,6 +7,7 @@ #include "esphome/components/esp32_ble/ble_advertising.h" #include "esphome/components/esp32_ble/ble_uuid.h" #include "esphome/components/esp32_ble/queue.h" +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" @@ -25,6 +26,21 @@ namespace esp32_ble_server { using namespace esp32_ble; +class BLEServerAutomationInterface { + public: + static Trigger *create_on_write_trigger(BLECharacteristic *characteristic); + + template class BLECharacteristicSetValueAction : public Action { + public: + BLECharacteristicSetValueAction(BLECharacteristic *characteristic) : characteristic_(characteristic) {} + void play(Ts... x) override { this->characteristic_->set_value(x...); } + + protected: + BLECharacteristic *characteristic_; + }; +}; + + class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented { public: void setup() override; diff --git a/tests/test5.yaml b/tests/test5.yaml index fc1adc8ebe..30d28b13c8 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -296,27 +296,28 @@ esp32_ble_server: model: Test5 services: - uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d - advertise: true + num_handles: 14 + advertise: false characteristics: - uuid: cad48e28-7fbe-41cf-bae9-d77a6c233423 - name: "Test Characteristic" properties: - - READ - - WRITE - - NOTIFY - permissions: - - READ - - WRITE - value: "Hello World" + - read + value: [0, 1, 2] + - uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc42d + advertise: false + characteristics: + - id: test_write_characteristic + uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc12d + properties: + - read + - write on_write: then: - - logger.log: "Characteristic written" - on_read: - then: - - logger.log: "Characteristic read" - on_notify: - then: - - logger.log: "Characteristic notified" + - lambda: |- + ESP_LOGD("BLE", "Received: %s", x.c_str()); + - ble_server.characteristic_set_value: + id: test_write_characteristic + value: x esp32_improv: authorizer: io0_button