From d6ee57a7b9f5263d7a02413d86beca1bb9d70cc5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Nov 2025 20:36:06 +0000 Subject: [PATCH] [bthome_ble] Refactor to list-based sensor configuration Refactored the component to use a list-based configuration structure that reduces duplication and makes it clearer that multiple sensors come from the same device. New configuration format: sensor: - platform: bthome_ble mac_address: "A4:C1:38:12:34:56" bindkey: "..." # optional sensors: - type: temperature name: "Temperature" - type: humidity name: "Humidity" binary_sensor: - platform: bthome_ble mac_address: "A4:C1:38:9A:BC:DE" binary_sensors: - type: motion name: "Motion" - type: door name: "Door" Benefits: - MAC address and bind key are specified once per device - More efficient (one BLE listener per device instead of per sensor) - Clearer relationship between sensors from the same device - Matches user expectations for multi-sensor devices Updated test configurations to demonstrate the new format. --- .../bthome_ble/binary_sensor/__init__.py | 39 ++-- .../components/bthome_ble/sensor/__init__.py | 42 +++-- .../components/bthome_ble/test.esp32-idf.yaml | 175 +++++++----------- tests/components/bthome_ble/test.esp32.yaml | 35 ++-- 4 files changed, 135 insertions(+), 156 deletions(-) diff --git a/esphome/components/bthome_ble/binary_sensor/__init__.py b/esphome/components/bthome_ble/binary_sensor/__init__.py index c9f6545b91..78aaff036f 100644 --- a/esphome/components/bthome_ble/binary_sensor/__init__.py +++ b/esphome/components/bthome_ble/binary_sensor/__init__.py @@ -2,8 +2,10 @@ import esphome.codegen as cg from esphome.components import binary_sensor, esp32_ble_tracker import esphome.config_validation as cv from esphome.const import ( + CONF_BINARY_SENSORS, CONF_BINDKEY, CONF_ID, + CONF_MAC_ADDRESS, CONF_TYPE, DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY_CHARGING, @@ -34,7 +36,7 @@ from esphome.const import ( ) CODEOWNERS = ["@esphome/core"] -DEPENDENCIES = ["bthome_ble"] +DEPENDENCIES = ["esp32_ble_tracker"] bthome_ble_ns = cg.esphome_ns.namespace("bthome_ble") BTHomeBinarySensor = bthome_ble_ns.class_( @@ -114,25 +116,36 @@ def apply_defaults(config): return config -CONFIG_SCHEMA = cv.All( - binary_sensor.binary_sensor_schema(BTHomeBinarySensor) - .extend( +# Schema for individual binary sensors in the list +BINARY_SENSOR_SCHEMA = cv.All( + binary_sensor.binary_sensor_schema(BTHomeBinarySensor).extend( { cv.Required(CONF_TYPE): cv.enum(BINARY_SENSOR_TYPES, lower=True), - cv.Optional(CONF_BINDKEY): cv.bind_key, } - ) - .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA), + ), apply_defaults, ) +# Platform schema with list of binary sensors +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(esp32_ble_tracker.ESP32BLETracker), + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_BINDKEY): cv.bind_key, + cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(BINARY_SENSOR_SCHEMA), + } +) + async def to_code(config): - var = await binary_sensor.new_binary_sensor(config) - await esp32_ble_tracker.register_ble_device(var, config) + tracker = await cg.get_variable(config[CONF_ID]) - object_id = BINARY_SENSOR_TYPES[config[CONF_TYPE]] - cg.add(var.set_object_id(object_id)) + for sensor_config in config[CONF_BINARY_SENSORS]: + var = await binary_sensor.new_binary_sensor(sensor_config) + await esp32_ble_tracker.register_ble_device(var, config) - if bindkey := config.get(CONF_BINDKEY): - cg.add(var.set_bindkey(bindkey)) + object_id = BINARY_SENSOR_TYPES[sensor_config[CONF_TYPE]] + cg.add(var.set_object_id(object_id)) + + if bindkey := config.get(CONF_BINDKEY): + cg.add(var.set_bindkey(bindkey)) diff --git a/esphome/components/bthome_ble/sensor/__init__.py b/esphome/components/bthome_ble/sensor/__init__.py index dec5ce2afa..3e0f82abc8 100644 --- a/esphome/components/bthome_ble/sensor/__init__.py +++ b/esphome/components/bthome_ble/sensor/__init__.py @@ -4,6 +4,8 @@ import esphome.config_validation as cv from esphome.const import ( CONF_BINDKEY, CONF_ID, + CONF_MAC_ADDRESS, + CONF_SENSORS, CONF_TYPE, DEVICE_CLASS_BATTERY, DEVICE_CLASS_CO2, @@ -24,14 +26,11 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_EMPTY, UNIT_KILOGRAM, - UNIT_KILOVOLT_AMPS_REACTIVE_HOURS, UNIT_KILOWATT_HOURS, UNIT_LUX, UNIT_METER, UNIT_MICROGRAMS_PER_CUBIC_METER, - UNIT_MILLIGRAM_PER_CUBIC_METER, UNIT_MILLIMETER, - UNIT_PARTS_PER_BILLION, UNIT_PARTS_PER_MILLION, UNIT_PASCAL, UNIT_PERCENT, @@ -40,7 +39,7 @@ from esphome.const import ( ) CODEOWNERS = ["@esphome/core"] -DEPENDENCIES = ["bthome_ble"] +DEPENDENCIES = ["esp32_ble_tracker"] bthome_ble_ns = cg.esphome_ns.namespace("bthome_ble") BTHomeSensor = bthome_ble_ns.class_( @@ -232,25 +231,36 @@ def apply_defaults(config): return config -CONFIG_SCHEMA = cv.All( - sensor.sensor_schema(BTHomeSensor) - .extend( +# Schema for individual sensors in the list +SENSOR_SCHEMA = cv.All( + sensor.sensor_schema(BTHomeSensor).extend( { cv.Required(CONF_TYPE): cv.enum(SENSOR_TYPES, lower=True), - cv.Optional(CONF_BINDKEY): cv.bind_key, } - ) - .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA), + ), apply_defaults, ) +# Platform schema with list of sensors +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.use_id(esp32_ble_tracker.ESP32BLETracker), + cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_BINDKEY): cv.bind_key, + cv.Required(CONF_SENSORS): cv.ensure_list(SENSOR_SCHEMA), + } +) + async def to_code(config): - var = await sensor.new_sensor(config) - await esp32_ble_tracker.register_ble_device(var, config) + tracker = await cg.get_variable(config[CONF_ID]) - object_id = SENSOR_TYPES[config[CONF_TYPE]] - cg.add(var.set_object_id(object_id)) + for sensor_config in config[CONF_SENSORS]: + var = await sensor.new_sensor(sensor_config) + await esp32_ble_tracker.register_ble_device(var, config) - if bindkey := config.get(CONF_BINDKEY): - cg.add(var.set_bindkey(bindkey)) + object_id = SENSOR_TYPES[sensor_config[CONF_TYPE]] + cg.add(var.set_object_id(object_id)) + + if bindkey := config.get(CONF_BINDKEY): + cg.add(var.set_bindkey(bindkey)) diff --git a/tests/components/bthome_ble/test.esp32-idf.yaml b/tests/components/bthome_ble/test.esp32-idf.yaml index 20111acb57..fdb075470f 100644 --- a/tests/components/bthome_ble/test.esp32-idf.yaml +++ b/tests/components/bthome_ble/test.esp32-idf.yaml @@ -5,137 +5,86 @@ esp32_ble_tracker: active: true sensor: - # Temperature sensor without encryption + # Multiple sensors from the same device without encryption - platform: bthome_ble mac_address: "A4:C1:38:12:34:56" - type: temperature - name: "BTHome Temperature" + sensors: + - type: temperature + name: "BTHome Temperature" + - type: humidity + name: "BTHome Humidity" + - type: pressure + name: "BTHome Pressure" + - type: illuminance + name: "BTHome Illuminance" - # Humidity sensor without encryption - - platform: bthome_ble - mac_address: "A4:C1:38:12:34:56" - type: humidity - name: "BTHome Humidity" - - # Battery sensor with encryption + # Sensors from encrypted device - platform: bthome_ble mac_address: "A4:C1:38:78:90:AB" bindkey: "231d39c1d7cc1ab1aee224cd096db932" - type: battery - name: "BTHome Battery Encrypted" + sensors: + - type: battery + name: "BTHome Battery Encrypted" + - type: temperature + name: "BTHome Temperature Encrypted" - # Pressure sensor - - platform: bthome_ble - mac_address: "A4:C1:38:12:34:56" - type: pressure - name: "BTHome Pressure" - - # Illuminance sensor - - platform: bthome_ble - mac_address: "A4:C1:38:12:34:56" - type: illuminance - name: "BTHome Illuminance" - - # Power sensor + # Power monitoring device - platform: bthome_ble mac_address: "A4:C1:38:CD:EF:12" - type: power - name: "BTHome Power" + sensors: + - type: power + name: "BTHome Power" + - type: energy + name: "BTHome Energy" + - type: voltage + name: "BTHome Voltage" + - type: current + name: "BTHome Current" - # Energy sensor - - platform: bthome_ble - mac_address: "A4:C1:38:CD:EF:12" - type: energy - name: "BTHome Energy" - - # Voltage sensor - - platform: bthome_ble - mac_address: "A4:C1:38:CD:EF:12" - type: voltage - name: "BTHome Voltage" - - # Current sensor - - platform: bthome_ble - mac_address: "A4:C1:38:CD:EF:12" - type: current - name: "BTHome Current" - - # PM2.5 sensor + # Air quality device - platform: bthome_ble mac_address: "A4:C1:38:34:56:78" - type: pm25 - name: "BTHome PM2.5" - - # PM10 sensor - - platform: bthome_ble - mac_address: "A4:C1:38:34:56:78" - type: pm10 - name: "BTHome PM10" - - # CO2 sensor - - platform: bthome_ble - mac_address: "A4:C1:38:34:56:78" - type: co2 - name: "BTHome CO2" - - # VOC sensor - - platform: bthome_ble - mac_address: "A4:C1:38:34:56:78" - type: voc - name: "BTHome VOC" - - # Moisture sensor - - platform: bthome_ble - mac_address: "A4:C1:38:34:56:78" - type: moisture - name: "BTHome Moisture" + sensors: + - type: pm25 + name: "BTHome PM2.5" + - type: pm10 + name: "BTHome PM10" + - type: co2 + name: "BTHome CO2" + - type: voc + name: "BTHome VOC" + - type: moisture + name: "BTHome Moisture" binary_sensor: - # Motion sensor without encryption + # Motion and occupancy sensors - platform: bthome_ble mac_address: "A4:C1:38:9A:BC:DE" - type: motion - name: "BTHome Motion" + binary_sensors: + - type: motion + name: "BTHome Motion" + - type: occupancy + name: "BTHome Occupancy" - # Door sensor with encryption + # Door and window sensors with encryption - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" + mac_address: "A4:C1:38:AB:CD:EF" bindkey: "231d39c1d7cc1ab1aee224cd096db932" - type: door - name: "BTHome Door Encrypted" + binary_sensors: + - type: door + name: "BTHome Door Encrypted" + - type: window + name: "BTHome Window Encrypted" + - type: battery_low + name: "BTHome Battery Low" - # Window sensor + # Safety sensors - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: window - name: "BTHome Window" - - # Battery low sensor - - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: battery_low - name: "BTHome Battery Low" - - # Occupancy sensor - - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: occupancy - name: "BTHome Occupancy" - - # Smoke sensor - - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: smoke - name: "BTHome Smoke" - - # Moisture binary sensor - - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: moisture - name: "BTHome Moisture Binary" - - # Opening sensor - - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" - type: opening - name: "BTHome Opening" + mac_address: "A4:C1:38:FE:DC:BA" + binary_sensors: + - type: smoke + name: "BTHome Smoke" + - type: opening + name: "BTHome Opening" + - type: moisture + name: "BTHome Moisture Binary" diff --git a/tests/components/bthome_ble/test.esp32.yaml b/tests/components/bthome_ble/test.esp32.yaml index 7821c70533..e6b26ee185 100644 --- a/tests/components/bthome_ble/test.esp32.yaml +++ b/tests/components/bthome_ble/test.esp32.yaml @@ -7,28 +7,35 @@ esp32_ble_tracker: sensor: - platform: bthome_ble mac_address: "A4:C1:38:12:34:56" - type: temperature - name: "BTHome Temperature" - - - platform: bthome_ble - mac_address: "A4:C1:38:12:34:56" - type: humidity - name: "BTHome Humidity" + sensors: + - type: temperature + name: "BTHome Temperature" + - type: humidity + name: "BTHome Humidity" - platform: bthome_ble mac_address: "A4:C1:38:78:90:AB" bindkey: "231d39c1d7cc1ab1aee224cd096db932" - type: battery - name: "BTHome Battery" + sensors: + - type: battery + name: "BTHome Battery" + - type: pressure + name: "BTHome Pressure" binary_sensor: - platform: bthome_ble mac_address: "A4:C1:38:9A:BC:DE" - type: motion - name: "BTHome Motion" + binary_sensors: + - type: motion + name: "BTHome Motion" + - type: window + name: "BTHome Window" - platform: bthome_ble - mac_address: "A4:C1:38:9A:BC:DE" + mac_address: "A4:C1:38:AB:CD:EF" bindkey: "231d39c1d7cc1ab1aee224cd096db932" - type: door - name: "BTHome Door" + binary_sensors: + - type: door + name: "BTHome Door" + - type: occupancy + name: "BTHome Occupancy"