From 0e05f95b17af1b7a1798a61cfdd6268f0d943c53 Mon Sep 17 00:00:00 2001 From: Rapsssito Date: Sat, 19 Oct 2024 13:09:41 +0200 Subject: [PATCH] Add byte_length --- .../components/esp32_ble_server/__init__.py | 100 +++++++++++------- tests/components/esp32_ble_server/common.yaml | 7 +- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index ef499ed751..0836c37a7b 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -18,6 +18,7 @@ AUTO_LOAD = ["esp32_ble"] CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"] DEPENDENCIES = ["esp32"] +CONF_BYTE_LENGTH = "byte_length" CONF_MANUFACTURER = "manufacturer" CONF_MANUFACTURER_DATA = "manufacturer_data" CONF_ADVERTISE = "advertise" @@ -30,6 +31,7 @@ CONF_INDICATE = "indicate" CONF_WRITE_NO_RESPONSE = "write_no_response" CONF_DESCRIPTORS = "descriptors" CONF_VALUE_ACTION_ID_ = "value_action_id_" +CONF_VALUE_BUFFER_ = "value_buffer_" # Core key to store the global configuration _KEY_NOTIFY_REQUIRED = "esp32_ble_server_notify_required" @@ -132,6 +134,8 @@ DESCRIPTOR_SCHEMA = cv.Schema( cv.GenerateID(): cv.declare_id(BLEDescriptor), cv.Required(CONF_UUID): bt_uuid, cv.Required(CONF_VALUE): DESCRIPTOR_VALUE_SCHEMA, + cv.Optional(CONF_BYTE_LENGTH): cv.uint16_t, + cv.GenerateID(CONF_VALUE_BUFFER_): cv.declare_id(ByteBuffer), } ) @@ -141,6 +145,8 @@ SERVICE_CHARACTERISTIC_SCHEMA = cv.Schema( cv.Required(CONF_UUID): bt_uuid, cv.Optional(CONF_WRITE_NO_RESPONSE, default=False): cv.boolean, cv.Optional(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA, + cv.Optional(CONF_BYTE_LENGTH): cv.uint16_t, + cv.GenerateID(CONF_VALUE_BUFFER_): cv.declare_id(ByteBuffer), cv.GenerateID(CONF_VALUE_ACTION_ID_): cv.declare_id( BLECharacteristicSetValueAction ), @@ -184,35 +190,65 @@ def parse_properties(char_conf): ) -def parse_descriptor_value(value): - # Compute the maximum length of the descriptor value +def _parse_value_(value, buffer_id, byte_length=None): + # Compute the maximum length of the value # Also parse the value for byte arrays - for val_method in [ - cv.boolean, - cv.float_, - cv.uint8_t, - cv.uint16_t, - cv.uint32_t, - cv.int_, - cv.string, - ]: + for val_method, put_method in zip( + ( + cv.boolean, + cv.float_, + cv.uint8_t, + cv.uint16_t, + cv.uint32_t, + cv.int_, + cv.string, + ), + ( + "put_bool", + "put_float", + "put_uint8", + "put_uint16", + "put_uint32", + "put_int", + "put_vector", + ), + ): try: val = val_method(value) - buffer = ByteBuffer_ns.wrap(val) - return buffer, buffer.get_capacity() + if byte_length is None: + # If no byte length is specified, use the default length + buffer_var = cg.variable(buffer_id, ByteBuffer_ns.wrap(val)) + else: + # Create a buffer with the specified length and add the value + buffer_var = cg.variable(buffer_id, ByteBuffer(byte_length)) + if isinstance(val, str): + # Split in characters + val = [ord(c) for c in val] + cg.add(getattr(buffer_var, put_method)(val)) + return buffer_var, buffer_var.get_capacity() except cv.Invalid: pass # Assume it's a list of bytes try: val = cv.All(cv.ensure_list(cv.uint8_t), cv.Length(min=1))(value) - buffer = ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val)) - return buffer, buffer.get_capacity() + if byte_length is None: + buffer_var = cg.variable( + buffer_id, ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val)) + ) + else: + buffer_var = cg.variable(buffer_id, ByteBuffer(byte_length)) + cg.add(buffer_var.put_vector(val)) + return buffer_var, buffer_var.get_capacity() except cv.Invalid: pass raise cv.Invalid(f"Could not find type for value: {value}") -async def parse_characteristic_value(value, args): +def parse_descriptor_value(value, buffer_id, byte_length=None): + return _parse_value_(value, buffer_id, byte_length) + + +async def parse_characteristic_value(value, buffer_id, args): if isinstance(value, cv.Lambda): return await cg.templatable( value, @@ -220,27 +256,7 @@ async def parse_characteristic_value(value, args): ByteBuffer, ByteBuffer_ns.wrap, ) - for val_method in [ - cv.boolean, - cv.float_, - cv.uint8_t, - cv.uint16_t, - cv.uint32_t, - cv.int_, - cv.string, - ]: - try: - val = val_method(value) - return ByteBuffer_ns.wrap(val) - except cv.Invalid: - pass - # Assume it's a list of bytes - try: - val = cv.All(cv.ensure_list(cv.uint8_t), cv.Length(min=1))(value) - return ByteBuffer_ns.wrap(cg.std_vector.template(cg.uint8)(val)) - except cv.Invalid: - pass - raise cv.Invalid(f"Could not find type for value: {value}") + return _parse_value_(value, buffer_id)[0] def calculate_num_handles(service_config): @@ -296,6 +312,8 @@ async def to_code(config): action_conf = { CONF_ID: char_conf[CONF_ID], CONF_VALUE: char_conf[CONF_VALUE], + CONF_BYTE_LENGTH: char_conf.get(CONF_BYTE_LENGTH, None), + CONF_VALUE_BUFFER_: char_conf[CONF_VALUE_BUFFER_], } value_action = await ble_server_characteristic_set_value( action_conf, @@ -306,7 +324,9 @@ async def to_code(config): cg.add(value_action.play()) for descriptor_conf in char_conf[CONF_DESCRIPTORS]: descriptor_value, max_length = parse_descriptor_value( - descriptor_conf[CONF_VALUE] + descriptor_conf[CONF_VALUE], + descriptor_conf[CONF_VALUE_BUFFER_], + descriptor_conf.get(CONF_BYTE_LENGTH, None), ) desc_var = cg.new_Pvariable( descriptor_conf[CONF_ID], @@ -329,13 +349,15 @@ async def to_code(config): { cv.Required(CONF_ID): cv.use_id(BLECharacteristic), cv.Required(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA, + cv.Optional(CONF_BYTE_LENGTH): cv.uint16_t, + cv.GenerateID(CONF_VALUE_BUFFER_): cv.declare_id(ByteBuffer), } ), ) async def ble_server_characteristic_set_value(config, action_id, template_arg, args): paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, paren) - value = await parse_characteristic_value(config[CONF_VALUE], args) + value = await parse_characteristic_value(config[CONF_VALUE], config[CONF_VALUE_BUFFER_], args) cg.add(var.set_buffer(value)) return var diff --git a/tests/components/esp32_ble_server/common.yaml b/tests/components/esp32_ble_server/common.yaml index c8239dc094..8e048b33b2 100644 --- a/tests/components/esp32_ble_server/common.yaml +++ b/tests/components/esp32_ble_server/common.yaml @@ -1,11 +1,10 @@ esp32_ble_server: - id: ble + id: ble_server manufacturer_data: [0x72, 0x4, 0x00, 0x23] manufacturer: ESPHome model: Test services: - uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d - num_handles: 14 advertise: false characteristics: - id: test_notify_characteristic @@ -16,6 +15,7 @@ esp32_ble_server: descriptors: - uuid: cad48e28-7fbe-41cf-bae9-d77a6c111111 value: 123.1 + byte_length: 100 - uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc42d advertise: false characteristics: @@ -23,6 +23,9 @@ esp32_ble_server: uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc11d read: true value: "Initial" + descriptors: + - uuid: cad48e28-7fbe-41cf-bae9-d77a6c111111 + value: 0x12 - uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc12d write: true on_write: