mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
[ble_device_base] Scan-mode request contract on BLEHub (#18061)
This commit is contained in:
@@ -93,6 +93,11 @@ class BK72xxBLETracker : public Component,
|
||||
// receiver merges per address (Home Assistant does). No GATT client either.
|
||||
return {.active_scan = false, .merges_scan_response = false, .gatt = false};
|
||||
}
|
||||
bool request_scan_mode(bool active) override {
|
||||
// Passive-only controller: a passive request is already honored, an active
|
||||
// one cannot be.
|
||||
return !active;
|
||||
}
|
||||
// The controller stores the address LSB-first (BLE convention); the contract
|
||||
// wants printable (MSB-first) order.
|
||||
void get_adapter_mac(uint8_t out[6]) override {
|
||||
|
||||
@@ -79,6 +79,17 @@ class BLEHub {
|
||||
virtual bool scan_running() = 0;
|
||||
/// True when the current/configured scan mode is active (scan requests sent).
|
||||
virtual bool scan_active() = 0;
|
||||
/// Request a scan-mode change (active = send scan requests). Returns false
|
||||
/// when the hub cannot honor the request; the caller reports the real state
|
||||
/// back to its subscriber. A hub that returns true applies the mode
|
||||
/// immediately: a running scan is restarted with the new mode, an idle one
|
||||
/// picks it up on its next start. The default cannot-change keeps hubs
|
||||
/// without a mode switch (and out-of-tree trackers) building unchanged.
|
||||
/// Independent of HubCapabilities::active_scan: that bit describes what the
|
||||
/// CONTROLLER can do, this method describes whether the hub exposes a
|
||||
/// runtime switch — a hub may support active scanning and still refuse
|
||||
/// (esp32_ble_tracker drives its mode through its own tracker API).
|
||||
virtual bool request_scan_mode(bool active) { return false; }
|
||||
};
|
||||
|
||||
} // namespace esphome::ble_device_base
|
||||
|
||||
@@ -152,6 +152,31 @@ void RP2BLETracker::start_scan() {
|
||||
this->start_scan_();
|
||||
}
|
||||
|
||||
bool RP2BLETracker::request_scan_mode(bool active) {
|
||||
if (this->scan_active_ == active)
|
||||
return true;
|
||||
this->scan_active_ = active;
|
||||
ESP_LOGD(TAG, "Scan mode %s", active ? "active" : "passive");
|
||||
// Apply to a running scan by restarting the CONTROLLER scan with the new
|
||||
// mode, bypassing the tracker's stop/start bookkeeping: no on_scan_end (the
|
||||
// scan logically continues, only the request mode changes), no period reset.
|
||||
// An idle scanner picks the mode up on its next start.
|
||||
if (this->scan_running_) {
|
||||
this->parent_->scan_stop();
|
||||
// Stamp the attempt so the SCAN_START_RETRY_MS floor covers this start
|
||||
// like every other one.
|
||||
this->last_scan_start_attempt_ = App.get_loop_component_start_time();
|
||||
if (!this->parent_->scan_start(static_cast<uint16_t>(this->scan_interval_),
|
||||
static_cast<uint16_t>(this->scan_window_), this->scan_active_)) {
|
||||
// The controller really stopped: behave exactly like loop()'s
|
||||
// reconciliation branch - notify listeners and let its retry recover.
|
||||
this->scan_running_ = false;
|
||||
this->fire_scan_end_();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RP2BLETracker::stop_scan() {
|
||||
this->scan_continuous_ = false;
|
||||
this->stop_scan_();
|
||||
|
||||
@@ -71,6 +71,7 @@ class RP2BLETracker : public Component,
|
||||
void get_adapter_mac(uint8_t out[6]) override { this->parent_->get_mac_msb_first(out); }
|
||||
bool scan_running() override { return this->scan_running_; }
|
||||
bool scan_active() override { return this->scan_active_; }
|
||||
bool request_scan_mode(bool active) override;
|
||||
|
||||
// ---- rp2040_ble::BLEScanListener ----
|
||||
// Delivered by the controller's loop() on the ESPHome main loop — the
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "esphome/components/ble_device_base/ble_hub.h"
|
||||
|
||||
namespace esphome::ble_device_base::testing {
|
||||
|
||||
// Pins the request_scan_mode() contract: the base default refuses (so hubs
|
||||
// without a mode switch — and out-of-tree trackers — keep building and
|
||||
// callers report the real state), while an overriding hub both honors the
|
||||
// request and applies it.
|
||||
namespace {
|
||||
|
||||
class DefaultHub : public BLEHub {
|
||||
public:
|
||||
void register_listener(ESPBTDeviceListener *listener) override {}
|
||||
void set_raw_advertisement_callback(RawAdvertisementCallback callback) override {}
|
||||
HubCapabilities get_capabilities() const override { return {false, false, false}; }
|
||||
void get_adapter_mac(uint8_t out[6]) override {}
|
||||
bool scan_running() override { return false; }
|
||||
// Backed by real state so "changes nothing" is observable: a base default
|
||||
// that silently mutated the hub would flip this and fail the assertion.
|
||||
bool scan_active() override { return this->active_; }
|
||||
|
||||
protected:
|
||||
bool active_{true};
|
||||
};
|
||||
|
||||
class SwitchingHub : public DefaultHub {
|
||||
public:
|
||||
HubCapabilities get_capabilities() const override { return {true, false, false}; }
|
||||
bool request_scan_mode(bool active) override {
|
||||
this->active_ = active;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BLEHubScanModeRequest, DefaultRefusesAndChangesNothing) {
|
||||
DefaultHub hub;
|
||||
EXPECT_TRUE(hub.scan_active());
|
||||
EXPECT_FALSE(hub.request_scan_mode(false));
|
||||
// Refused, not applied-and-reported-false: the state is untouched.
|
||||
EXPECT_TRUE(hub.scan_active());
|
||||
EXPECT_FALSE(hub.request_scan_mode(true));
|
||||
EXPECT_TRUE(hub.scan_active());
|
||||
}
|
||||
|
||||
TEST(BLEHubScanModeRequest, OverrideHonorsAndApplies) {
|
||||
SwitchingHub hub;
|
||||
EXPECT_TRUE(hub.request_scan_mode(true));
|
||||
EXPECT_TRUE(hub.scan_active());
|
||||
EXPECT_TRUE(hub.request_scan_mode(false));
|
||||
EXPECT_FALSE(hub.scan_active());
|
||||
}
|
||||
|
||||
} // namespace esphome::ble_device_base::testing
|
||||
Reference in New Issue
Block a user