mirror of
https://github.com/esphome/esphome.git
synced 2026-08-24 07:06:20 +00:00
Carry the address as uint64 in RawAdvertisement and unify the proxy setup
This commit is contained in:
@@ -159,7 +159,7 @@ void BK72xxBLETracker::dump_config() {
|
||||
void BK72xxBLETracker::on_scan_report(const bk72xx_ble::BLEScanReport &report) {
|
||||
// Raw callback (the raw-advertisement path).
|
||||
if (this->raw_advertisement_callback_.is_set()) {
|
||||
const ble_device_base::RawAdvertisement adv{.mac = report.mac,
|
||||
const ble_device_base::RawAdvertisement adv{.address = ble_device_base::mac_lsb_first_to_uint64(report.mac),
|
||||
.data = report.data,
|
||||
.data_len = report.data_len,
|
||||
.rssi = report.rssi,
|
||||
|
||||
@@ -23,8 +23,9 @@ namespace esphome::ble_device_base {
|
||||
/// One raw advertisement as delivered by the controller — a borrowed view,
|
||||
/// valid only for the duration of the invoke() callback.
|
||||
struct RawAdvertisement {
|
||||
/// Least-significant octet first (BLE controller convention).
|
||||
const uint8_t *mac;
|
||||
/// Producers convert their native byte order at the emit site, so no
|
||||
/// byte-order convention crosses this contract.
|
||||
uint64_t address;
|
||||
const uint8_t *data;
|
||||
uint16_t data_len;
|
||||
int8_t rssi; // signed dBm
|
||||
|
||||
@@ -26,18 +26,6 @@ BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
void BluetoothProxy::setup() {
|
||||
this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
|
||||
// Capture the configured scan mode from YAML before any API changes
|
||||
this->configured_scan_active_ = this->parent_->get_scan_active();
|
||||
|
||||
this->hub_->set_raw_advertisement_callback({this, [](void *self, const ble_device_base::RawAdvertisement &adv) {
|
||||
static_cast<BluetoothProxy *>(self)->on_raw_advertisement_(adv);
|
||||
}});
|
||||
}
|
||||
|
||||
void BluetoothProxy::on_scanner_state(esp32_ble_tracker::ScannerState state) {
|
||||
if (this->api_connection_ != nullptr) {
|
||||
this->send_bluetooth_scanner_state_(state);
|
||||
@@ -47,8 +35,8 @@ void BluetoothProxy::on_scanner_state(esp32_ble_tracker::ScannerState state) {
|
||||
void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state) {
|
||||
api::BluetoothScannerStateResponse resp;
|
||||
resp.state = static_cast<api::enums::BluetoothScannerState>(state);
|
||||
resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
||||
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
||||
resp.mode = this->hub_->scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
||||
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
||||
resp.configured_mode = this->configured_scan_active_
|
||||
? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
||||
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
||||
@@ -57,21 +45,6 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta
|
||||
|
||||
#else // !USE_ESP32
|
||||
|
||||
void BluetoothProxy::setup() {
|
||||
// BLUETOOTH_PROXY_MAX_CONNECTIONS is 0 on an advertisement-only proxy.
|
||||
this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
|
||||
// Capture the configured scan mode from YAML before any API changes
|
||||
this->configured_scan_active_ = this->hub_->scan_active();
|
||||
|
||||
// The hub delivers raw advertisements on the ESPHome main loop:
|
||||
// mac is least-significant octet first (BLE controller convention).
|
||||
this->hub_->set_raw_advertisement_callback({this, [](void *self, const ble_device_base::RawAdvertisement &adv) {
|
||||
static_cast<BluetoothProxy *>(self)->on_raw_advertisement_(adv);
|
||||
}});
|
||||
}
|
||||
|
||||
void BluetoothProxy::send_bluetooth_scanner_state_() {
|
||||
// One read feeds both the frame and the change detector; the detector only
|
||||
// advances if the frame was accepted, so a dropped send (WOULD_BLOCK on a
|
||||
@@ -92,15 +65,26 @@ void BluetoothProxy::send_bluetooth_scanner_state_() {
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
// The hub delivers raw advertisements on the ESPHome main loop; raw.mac is
|
||||
// least-significant octet first (BLE controller convention).
|
||||
void BluetoothProxy::setup() {
|
||||
// BLUETOOTH_PROXY_MAX_CONNECTIONS is 0 on an advertisement-only proxy.
|
||||
this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
|
||||
// Capture the configured scan mode from YAML before any API changes
|
||||
this->configured_scan_active_ = this->hub_->scan_active();
|
||||
|
||||
this->hub_->set_raw_advertisement_callback({this, [](void *self, const ble_device_base::RawAdvertisement &adv) {
|
||||
static_cast<BluetoothProxy *>(self)->on_raw_advertisement_(adv);
|
||||
}});
|
||||
}
|
||||
|
||||
// The hub delivers raw advertisements on the ESPHome main loop.
|
||||
void BluetoothProxy::on_raw_advertisement_(const ble_device_base::RawAdvertisement &raw) {
|
||||
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr)
|
||||
return;
|
||||
|
||||
auto &adv = this->response_.advertisements[this->response_.advertisements_len];
|
||||
// raw.mac is LSB-first; this matches ble_addr_to_uint64 on esp32.
|
||||
adv.address = ble_device_base::mac_lsb_first_to_uint64(raw.mac);
|
||||
adv.address = raw.address;
|
||||
adv.rssi = raw.rssi;
|
||||
adv.address_type = raw.addr_type;
|
||||
uint8_t length = raw.data_len > sizeof(adv.data) ? sizeof(adv.data) : static_cast<uint8_t>(raw.data_len);
|
||||
@@ -109,8 +93,7 @@ void BluetoothProxy::on_raw_advertisement_(const ble_device_base::RawAdvertiseme
|
||||
|
||||
this->response_.advertisements_len++;
|
||||
|
||||
ESP_LOGV(TAG, "Queuing raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", raw.mac[5], raw.mac[4],
|
||||
raw.mac[3], raw.mac[2], raw.mac[1], raw.mac[0], length, raw.rssi);
|
||||
ESP_LOGV(TAG, "Queuing raw packet from %012llX, length %d. RSSI: %d dB", raw.address, length, raw.rssi);
|
||||
|
||||
// Flush if we have reached BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE
|
||||
if (this->response_.advertisements_len >= BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE) {
|
||||
@@ -139,10 +122,6 @@ void BluetoothProxy::handle_gatt_not_connected_(uint64_t address, uint16_t handl
|
||||
this->send_gatt_error(address, handle, GATT_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
void BluetoothProxy::log_advertisement_flush_() {
|
||||
ESP_LOGV(TAG, "Sent batch of %u BLE advertisements", this->response_.advertisements_len);
|
||||
}
|
||||
|
||||
@@ -374,20 +374,6 @@ async def register_client(var: cg.SafeExpType, config: ConfigType) -> cg.SafeExp
|
||||
return var
|
||||
|
||||
|
||||
async def register_raw_ble_device(
|
||||
var: cg.SafeExpType, config: ConfigType
|
||||
) -> cg.SafeExpType:
|
||||
"""Register a BLE device listener that only needs raw advertisement data.
|
||||
|
||||
This does NOT register the ESP_BT_DEVICE feature, meaning ESPBTDevice
|
||||
will not be compiled in if this is the only registration method used.
|
||||
"""
|
||||
_request_listener_slot()
|
||||
paren = await cg.get_variable(config[CONF_ESP32_BLE_ID])
|
||||
cg.add(paren.register_listener(var))
|
||||
return var
|
||||
|
||||
|
||||
async def register_raw_client(
|
||||
var: cg.SafeExpType, config: ConfigType
|
||||
) -> cg.SafeExpType:
|
||||
|
||||
@@ -464,12 +464,8 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {
|
||||
void ESP32BLETracker::process_scan_result_(const BLEScanResult &scan_result) {
|
||||
// Neutral raw-advertisement subscriber (the bluetooth_proxy path).
|
||||
if (this->raw_advertisement_callback_.is_set()) {
|
||||
uint8_t mac_lsb[6];
|
||||
// bda is MSB-first; the neutral convention is LSB-first.
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
mac_lsb[i] = scan_result.bda[5 - i];
|
||||
ble_device_base::RawAdvertisement adv;
|
||||
adv.mac = mac_lsb;
|
||||
adv.address = esp32_ble::ble_addr_to_uint64(scan_result.bda);
|
||||
adv.data = scan_result.ble_adv;
|
||||
adv.data_len = static_cast<uint16_t>(scan_result.adv_data_len) + scan_result.scan_rsp_len;
|
||||
adv.rssi = scan_result.rssi;
|
||||
|
||||
@@ -240,8 +240,11 @@ void LN882HBLETracker::process_adv_(const uint8_t *mac, int8_t rssi, uint8_t add
|
||||
// Raw callback (the raw-advertisement path). Both full advertisements and
|
||||
// unmatched scan responses (raw_only) are forwarded.
|
||||
if (this->raw_advertisement_callback_.is_set()) {
|
||||
const ble_device_base::RawAdvertisement adv{
|
||||
.mac = mac, .data = data, .data_len = data_len, .rssi = rssi, .addr_type = addr_type};
|
||||
const ble_device_base::RawAdvertisement adv{.address = ble_device_base::mac_lsb_first_to_uint64(mac),
|
||||
.data = data,
|
||||
.data_len = data_len,
|
||||
.rssi = rssi,
|
||||
.addr_type = addr_type};
|
||||
this->raw_advertisement_callback_.invoke(adv);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ void RP2BLETracker::dump_config() {
|
||||
void RP2BLETracker::on_scan_report(const rp2040_ble::BLEScanReport &report) {
|
||||
// Raw callback (the raw-advertisement path).
|
||||
if (this->raw_advertisement_callback_.is_set()) {
|
||||
const ble_device_base::RawAdvertisement adv{.mac = report.mac,
|
||||
const ble_device_base::RawAdvertisement adv{.address = ble_device_base::mac_lsb_first_to_uint64(report.mac),
|
||||
.data = report.data,
|
||||
.data_len = report.data_len,
|
||||
.rssi = report.rssi,
|
||||
|
||||
@@ -47,12 +47,12 @@ struct CapturingSubscriber {
|
||||
};
|
||||
|
||||
// Device AA:BB:CC:DD:EE:FF — controller order delivers FF first.
|
||||
const uint8_t MAC_LSB_FIRST[6] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa};
|
||||
constexpr uint64_t TEST_ADDRESS = 0xAABBCCDDEEFFULL;
|
||||
const uint8_t ADV_DATA[4] = {0x02, 0x01, 0x06, 0x00};
|
||||
|
||||
RawAdvertisement make_test_adv() {
|
||||
return RawAdvertisement{
|
||||
.mac = MAC_LSB_FIRST, .data = ADV_DATA, .data_len = sizeof(ADV_DATA), .rssi = -63, .addr_type = 1};
|
||||
.address = TEST_ADDRESS, .data = ADV_DATA, .data_len = sizeof(ADV_DATA), .rssi = -63, .addr_type = 1};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -70,7 +70,7 @@ TEST(RawAdvertisementCallback, SubscriberSeesFieldsUnchanged) {
|
||||
hub.emit(make_test_adv());
|
||||
|
||||
ASSERT_EQ(subscriber.calls, 1);
|
||||
EXPECT_EQ(subscriber.last.mac, MAC_LSB_FIRST);
|
||||
EXPECT_EQ(subscriber.last.address, TEST_ADDRESS);
|
||||
EXPECT_EQ(subscriber.last.data, ADV_DATA);
|
||||
EXPECT_EQ(subscriber.last.data_len, sizeof(ADV_DATA));
|
||||
EXPECT_EQ(subscriber.last.rssi, -63);
|
||||
|
||||
Reference in New Issue
Block a user