[ble_device_base] Migrate BLE sensor platforms to the neutral layer (batch 1: ble_presence, ble_rssi, ble_scanner) (#17716)

This commit is contained in:
Edvard Filistovič
2026-08-07 16:19:08 +00:00
committed by GitHub
parent b802740997
commit 5f483b11b6
22 changed files with 150 additions and 87 deletions
@@ -1,5 +1,5 @@
import esphome.codegen as cg
from esphome.components import binary_sensor, esp32_ble_tracker
from esphome.components import binary_sensor, ble_device_base
import esphome.config_validation as cv
from esphome.const import (
CONF_IBEACON_MAJOR,
@@ -13,14 +13,14 @@ from esphome.const import (
CONF_IRK = "irk"
DEPENDENCIES = ["esp32_ble_tracker"]
AUTO_LOAD = ["ble_device_base"]
ble_presence_ns = cg.esphome_ns.namespace("ble_presence")
BLEPresenceDevice = ble_presence_ns.class_(
"BLEPresenceDevice",
binary_sensor.BinarySensor,
cg.Component,
esp32_ble_tracker.ESPBTDeviceListener,
ble_device_base.ESPBTDeviceListener,
)
@@ -33,23 +33,24 @@ def _validate(config):
CONFIG_SCHEMA = cv.All(
ble_device_base.rename_legacy_hub_id("ble_presence"),
binary_sensor.binary_sensor_schema(BLEPresenceDevice)
.extend(
{
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_IRK): cv.uuid,
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_SERVICE_UUID): ble_device_base.bt_uuid,
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_UUID): ble_device_base.bt_uuid,
cv.Optional(CONF_TIMEOUT, default="5min"): cv.positive_time_period,
cv.Optional(CONF_MIN_RSSI): cv.All(
cv.decibel, cv.int_range(min=-100, max=-30)
),
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA),
.extend(cv.COMPONENT_SCHEMA)
.extend(ble_device_base.BLE_DEVICE_SCHEMA),
cv.has_exactly_one_key(
CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID
),
@@ -60,7 +61,7 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
await esp32_ble_tracker.register_ble_device(var, config)
await ble_device_base.register_ble_device(var, config)
cg.add(var.set_timeout(config[CONF_TIMEOUT].total_milliseconds))
if min_rssi := config.get(CONF_MIN_RSSI):
@@ -70,20 +71,15 @@ async def to_code(config):
cg.add(var.set_address(mac_address.as_hex))
if irk := config.get(CONF_IRK):
irk = esp32_ble_tracker.as_hex_array(str(irk))
ble_device_base.request_irk_support()
irk = ble_device_base.as_hex_array(str(irk))
cg.add(var.set_irk(irk))
if service_uuid := config.get(CONF_SERVICE_UUID):
if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))
elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid32_format):
cg.add(var.set_service_uuid32(esp32_ble_tracker.as_hex(service_uuid)))
elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid128_format):
uuid128 = esp32_ble_tracker.as_reversed_hex_array(service_uuid)
cg.add(var.set_service_uuid128(uuid128))
ble_device_base.add_service_uuid(var, service_uuid)
if ibeacon_uuid := config.get(CONF_IBEACON_UUID):
ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid)
ibeacon_uuid = ble_device_base.as_reversed_hex_array(ibeacon_uuid)
cg.add(var.set_ibeacon_uuid(ibeacon_uuid))
if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None:
@@ -1,8 +1,6 @@
#include "ble_presence_device.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome::ble_presence {
static const char *const TAG = "ble_presence";
@@ -10,5 +8,3 @@ static const char *const TAG = "ble_presence";
void BLEPresenceDevice::dump_config() { LOG_BINARY_SENSOR("", "BLE Presence", this); }
} // namespace esphome::ble_presence
#endif
@@ -1,15 +1,17 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/components/ble_device_base/ble_device.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#ifdef USE_ESP32
// No platform #ifdef: ble_device_base provides the BLE types on every platform,
// and this component is only compiled when configured — which requires a BLE
// hub — so it builds on any platform with a BLEHub tracker without a per-chip
// guard.
namespace esphome::ble_presence {
class BLEPresenceDevice final : public binary_sensor::BinarySensorInitiallyOff,
public esp32_ble_tracker::ESPBTDeviceListener,
public ble_device_base::ESPBTDeviceListener,
public Component {
public:
void set_address(uint64_t address) {
@@ -22,19 +24,19 @@ class BLEPresenceDevice final : public binary_sensor::BinarySensorInitiallyOff,
}
void set_service_uuid16(uint16_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_uint16(uuid);
}
void set_service_uuid32(uint32_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint32(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_uint32(uuid);
}
void set_service_uuid128(uint8_t *uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_raw(uuid);
}
void set_ibeacon_uuid(uint8_t *uuid) {
this->match_by_ = MATCH_BY_IBEACON_UUID;
this->ibeacon_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(uuid);
this->ibeacon_uuid_ = ble_device_base::ESPBTUUID::from_raw(uuid);
}
void set_ibeacon_major(uint16_t major) {
this->check_ibeacon_major_ = true;
@@ -49,7 +51,7 @@ class BLEPresenceDevice final : public binary_sensor::BinarySensorInitiallyOff,
this->minimum_rssi_ = rssi;
}
void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
bool parse_device(const ble_device_base::ESPBTDevice &device) override {
if (this->check_minimum_rssi_ && this->minimum_rssi_ > device.get_rssi()) {
return false;
}
@@ -119,9 +121,9 @@ class BLEPresenceDevice final : public binary_sensor::BinarySensorInitiallyOff,
uint64_t address_;
uint8_t *irk_;
esp32_ble_tracker::ESPBTUUID uuid_;
ble_device_base::ESPBTUUID uuid_;
esp32_ble_tracker::ESPBTUUID ibeacon_uuid_;
ble_device_base::ESPBTUUID ibeacon_uuid_;
uint16_t ibeacon_major_{0};
uint16_t ibeacon_minor_{0};
@@ -137,5 +139,3 @@ class BLEPresenceDevice final : public binary_sensor::BinarySensorInitiallyOff,
};
} // namespace esphome::ble_presence
#endif
@@ -1,8 +1,6 @@
#include "ble_rssi_sensor.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome::ble_rssi {
static const char *const TAG = "ble_rssi";
@@ -10,5 +8,3 @@ static const char *const TAG = "ble_rssi";
void BLERSSISensor::dump_config() { LOG_SENSOR("", "BLE RSSI Sensor", this); }
} // namespace esphome::ble_rssi
#endif
+13 -13
View File
@@ -1,14 +1,16 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/components/ble_device_base/ble_device.h"
#include "esphome/components/sensor/sensor.h"
#ifdef USE_ESP32
// No platform #ifdef: ble_device_base provides the BLE types on every platform,
// and this component is only compiled when configured — which requires a BLE
// hub — so it builds on any platform with a BLEHub tracker without a per-chip
// guard.
namespace esphome::ble_rssi {
class BLERSSISensor final : public sensor::Sensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component {
class BLERSSISensor final : public sensor::Sensor, public ble_device_base::ESPBTDeviceListener, public Component {
public:
void set_address(uint64_t address) {
this->match_by_ = MATCH_BY_MAC_ADDRESS;
@@ -20,19 +22,19 @@ class BLERSSISensor final : public sensor::Sensor, public esp32_ble_tracker::ESP
}
void set_service_uuid16(uint16_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_uint16(uuid);
}
void set_service_uuid32(uint32_t uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint32(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_uint32(uuid);
}
void set_service_uuid128(uint8_t *uuid) {
this->match_by_ = MATCH_BY_SERVICE_UUID;
this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(uuid);
this->uuid_ = ble_device_base::ESPBTUUID::from_raw(uuid);
}
void set_ibeacon_uuid(uint8_t *uuid) {
this->match_by_ = MATCH_BY_IBEACON_UUID;
this->ibeacon_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(uuid);
this->ibeacon_uuid_ = ble_device_base::ESPBTUUID::from_raw(uuid);
}
void set_ibeacon_major(uint16_t major) {
this->check_ibeacon_major_ = true;
@@ -47,7 +49,7 @@ class BLERSSISensor final : public sensor::Sensor, public esp32_ble_tracker::ESP
this->publish_state(NAN);
this->found_ = false;
}
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
bool parse_device(const ble_device_base::ESPBTDevice &device) override {
switch (this->match_by_) {
case MATCH_BY_MAC_ADDRESS:
if (device.address_uint64() == this->address_) {
@@ -109,9 +111,9 @@ class BLERSSISensor final : public sensor::Sensor, public esp32_ble_tracker::ESP
uint64_t address_;
uint8_t *irk_;
esp32_ble_tracker::ESPBTUUID uuid_;
ble_device_base::ESPBTUUID uuid_;
esp32_ble_tracker::ESPBTUUID ibeacon_uuid_;
ble_device_base::ESPBTUUID ibeacon_uuid_;
uint16_t ibeacon_major_;
uint16_t ibeacon_minor_;
@@ -120,5 +122,3 @@ class BLERSSISensor final : public sensor::Sensor, public esp32_ble_tracker::ESP
};
} // namespace esphome::ble_rssi
#endif
+13 -17
View File
@@ -1,5 +1,5 @@
import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, sensor
from esphome.components import ble_device_base, sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_IBEACON_MAJOR,
@@ -14,11 +14,11 @@ from esphome.const import (
CONF_IRK = "irk"
DEPENDENCIES = ["esp32_ble_tracker"]
AUTO_LOAD = ["ble_device_base"]
ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi")
BLERSSISensor = ble_rssi_ns.class_(
"BLERSSISensor", sensor.Sensor, cg.Component, esp32_ble_tracker.ESPBTDeviceListener
"BLERSSISensor", sensor.Sensor, cg.Component, ble_device_base.ESPBTDeviceListener
)
@@ -31,6 +31,7 @@ def _validate(config):
CONFIG_SCHEMA = cv.All(
ble_device_base.rename_legacy_hub_id("ble_rssi"),
sensor.sensor_schema(
BLERSSISensor,
unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
@@ -42,14 +43,14 @@ CONFIG_SCHEMA = cv.All(
{
cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_IRK): cv.uuid,
cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_SERVICE_UUID): ble_device_base.bt_uuid,
cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
cv.Optional(CONF_IBEACON_UUID): esp32_ble_tracker.bt_uuid,
cv.Optional(CONF_IBEACON_UUID): ble_device_base.bt_uuid,
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA),
.extend(cv.COMPONENT_SCHEMA)
.extend(ble_device_base.BLE_DEVICE_SCHEMA),
cv.has_exactly_one_key(
CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID
),
@@ -60,26 +61,21 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
await esp32_ble_tracker.register_ble_device(var, config)
await ble_device_base.register_ble_device(var, config)
if mac_address := config.get(CONF_MAC_ADDRESS):
cg.add(var.set_address(mac_address.as_hex))
if irk := config.get(CONF_IRK):
irk = esp32_ble_tracker.as_hex_array(str(irk))
ble_device_base.request_irk_support()
irk = ble_device_base.as_hex_array(str(irk))
cg.add(var.set_irk(irk))
if service_uuid := config.get(CONF_SERVICE_UUID):
if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))
elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid32_format):
cg.add(var.set_service_uuid32(esp32_ble_tracker.as_hex(service_uuid)))
elif len(service_uuid) == len(esp32_ble_tracker.bt_uuid128_format):
uuid128 = esp32_ble_tracker.as_reversed_hex_array(service_uuid)
cg.add(var.set_service_uuid128(uuid128))
ble_device_base.add_service_uuid(var, service_uuid)
if ibeacon_uuid := config.get(CONF_IBEACON_UUID):
ibeacon_uuid = esp32_ble_tracker.as_reversed_hex_array(ibeacon_uuid)
ibeacon_uuid = ble_device_base.as_reversed_hex_array(ibeacon_uuid)
cg.add(var.set_ibeacon_uuid(ibeacon_uuid))
if (ibeacon_major := config.get(CONF_IBEACON_MAJOR)) is not None:
@@ -1,8 +1,6 @@
#include "ble_scanner.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome::ble_scanner {
static const char *const TAG = "ble_scanner";
@@ -10,5 +8,3 @@ static const char *const TAG = "ble_scanner";
void BLEScanner::dump_config() { LOG_TEXT_SENSOR("", "BLE Scanner", this); }
} // namespace esphome::ble_scanner
#endif
+7 -9
View File
@@ -7,18 +7,18 @@
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/string_ref.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/components/ble_device_base/ble_device.h"
#include "esphome/components/text_sensor/text_sensor.h"
#ifdef USE_ESP32
// No platform #ifdef: ble_device_base provides the BLE types on every platform,
// and this component is only compiled when configured — which requires a BLE
// hub — so it builds on any platform with a BLEHub tracker without a per-chip
// guard.
namespace esphome::ble_scanner {
class BLEScanner final : public text_sensor::TextSensor,
public esp32_ble_tracker::ESPBTDeviceListener,
public Component {
class BLEScanner final : public text_sensor::TextSensor, public ble_device_base::ESPBTDeviceListener, public Component {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
bool parse_device(const ble_device_base::ESPBTDevice &device) override {
char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
// Escape special characters in the device name for valid JSON. Control characters stay in the \u00XX form this
// sensor has always published.
@@ -35,5 +35,3 @@ class BLEScanner final : public text_sensor::TextSensor,
};
} // namespace esphome::ble_scanner
#endif
@@ -1,25 +1,26 @@
import esphome.codegen as cg
from esphome.components import esp32_ble_tracker, text_sensor
from esphome.components import ble_device_base, text_sensor
import esphome.config_validation as cv
DEPENDENCIES = ["esp32_ble_tracker"]
AUTO_LOAD = ["ble_device_base"]
ble_scanner_ns = cg.esphome_ns.namespace("ble_scanner")
BLEScanner = ble_scanner_ns.class_(
"BLEScanner",
text_sensor.TextSensor,
cg.Component,
esp32_ble_tracker.ESPBTDeviceListener,
ble_device_base.ESPBTDeviceListener,
)
CONFIG_SCHEMA = cv.All(
ble_device_base.rename_legacy_hub_id("ble_scanner"),
text_sensor.text_sensor_schema(BLEScanner)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
.extend(ble_device_base.BLE_DEVICE_SCHEMA),
)
async def to_code(config):
var = await text_sensor.new_text_sensor(config)
await cg.register_component(var, config)
await esp32_ble_tracker.register_ble_device(var, config)
await ble_device_base.register_ble_device(var, config)
@@ -0,0 +1,4 @@
binary_sensor:
- platform: ble_presence
mac_address: 11:22:33:44:55:66
name: BLE Test Presence
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: ble_presence
ble_hub_id: ble_tracker_hub
mac_address: AC:37:43:77:5F:4C
name: ESP32 BLE Tracker Google Home Mini
- platform: ble_presence
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
ble_presence: !include common-ln.yaml
@@ -0,0 +1,14 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_hub
binary_sensor:
- platform: ble_presence
ble_hub_id: ble_hub
mac_address: AC:37:43:77:5F:4C
name: BK BLE Presence
- platform: ble_presence
irk: 1234567890abcdef1234567890abcdef
name: BK BLE Presence IRK
+5
View File
@@ -0,0 +1,5 @@
sensor:
- platform: ble_rssi
# irk: is the only thing that emits USE_BLE_DEVICE_IRK off ESP32
irk: 1234567890abcdef1234567890abcdef
name: BLE Test RSSI
+6 -1
View File
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: ble_rssi
ble_hub_id: ble_tracker_hub
mac_address: AC:37:43:77:5F:4C
name: BLE Google Home Mini RSSI value
- platform: ble_rssi
@@ -14,7 +17,9 @@ sensor:
service_uuid: 11223344-5566-7788-99aa-bbccddeeff00
name: BLE Test Service 128
- platform: ble_rssi
service_uuid: 11223344-5566-7788-99aa-bbccddeeff00
ibeacon_uuid: 11223344-5566-7788-99aa-bbccddeeff00
ibeacon_major: 100
ibeacon_minor: 1
name: BLE Test iBeacon UUID
- platform: ble_rssi
irk: 1234567890abcdef1234567890abcdef
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
ble_rssi: !include common-ln.yaml
@@ -0,0 +1,11 @@
# Config-only: pins the esp32_ble_id: -> ble_hub_id: deprecation alias — the
# legacy key must keep validating (with a rename warning) until its removal
# release (2027.2.0).
esp32_ble_tracker:
id: legacy_tracker
sensor:
- platform: ble_rssi
esp32_ble_id: legacy_tracker
mac_address: AC:37:43:77:5F:4C
name: Legacy Key RSSI
@@ -0,0 +1,14 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_hub
sensor:
- platform: ble_rssi
ble_hub_id: ble_hub
mac_address: AC:37:43:77:5F:4C
name: BK BLE RSSI
- platform: ble_rssi
irk: 1234567890abcdef1234567890abcdef
name: BK BLE RSSI IRK
@@ -0,0 +1,3 @@
text_sensor:
- platform: ble_scanner
name: BLE Test Scanner
+3
View File
@@ -1,5 +1,8 @@
esp32_ble_tracker:
id: ble_tracker_hub
text_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: ble_scanner
ble_hub_id: ble_tracker_hub
name: Scanner
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
ble_scanner: !include common-ln.yaml
@@ -0,0 +1,13 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_hub
text_sensor:
- platform: ble_scanner
ble_hub_id: ble_hub
name: BK Scanner
# No ble_hub_id: exercises the generated binding _require_hub guards.
- platform: ble_scanner
name: BK Scanner Implicit