From 914cab301f66e51ba23a4d17f0f2c349b3eb4a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Filistovi=C4=8D?= Date: Tue, 4 Aug 2026 21:20:57 +0300 Subject: [PATCH] [rp2_ble_tracker] Extract stamp-and-start helper; pin capability/switch independence (#18072) --- .../rp2_ble_tracker/rp2_ble_tracker.cpp | 21 +++++++++---------- .../rp2_ble_tracker/rp2_ble_tracker.h | 1 + .../test_scan_mode_request.cpp | 14 +++++++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/esphome/components/rp2_ble_tracker/rp2_ble_tracker.cpp b/esphome/components/rp2_ble_tracker/rp2_ble_tracker.cpp index 08a954239f..ed036328ae 100644 --- a/esphome/components/rp2_ble_tracker/rp2_ble_tracker.cpp +++ b/esphome/components/rp2_ble_tracker/rp2_ble_tracker.cpp @@ -163,11 +163,7 @@ bool RP2BLETracker::request_scan_mode(bool active) { // 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(this->scan_interval_), - static_cast(this->scan_window_), this->scan_active_)) { + if (!this->controller_scan_start_()) { // The controller really stopped: behave exactly like loop()'s // reconciliation branch - notify listeners and let its retry recover. this->scan_running_ = false; @@ -186,16 +182,19 @@ void RP2BLETracker::stop_scan() { this->disable_loop(); } +// Stamp-and-start for every controller scan attempt: the stamp keeps the +// SCAN_START_RETRY_MS floor covering all callers, not only loop()'s retry. +bool RP2BLETracker::controller_scan_start_() { + this->last_scan_start_attempt_ = App.get_loop_component_start_time(); + return this->parent_->scan_start(static_cast(this->scan_interval_), + static_cast(this->scan_window_), this->scan_active_); +} + void RP2BLETracker::start_scan_() { if (this->scan_running_) return; - // Stamp every attempt regardless of caller so the loop's rate limit also - // covers a failed start that came through the public start_scan(). - this->last_scan_start_attempt_ = App.get_loop_component_start_time(); - - if (!this->parent_->scan_start(static_cast(this->scan_interval_), static_cast(this->scan_window_), - this->scan_active_)) + if (!this->controller_scan_start_()) return; this->scan_running_ = true; diff --git a/esphome/components/rp2_ble_tracker/rp2_ble_tracker.h b/esphome/components/rp2_ble_tracker/rp2_ble_tracker.h index dd000645c5..4806f599bd 100644 --- a/esphome/components/rp2_ble_tracker/rp2_ble_tracker.h +++ b/esphome/components/rp2_ble_tracker/rp2_ble_tracker.h @@ -80,6 +80,7 @@ class RP2BLETracker : public Component, protected: void start_scan_(); + bool controller_scan_start_(); void stop_scan_(); void fire_scan_end_(); diff --git a/tests/components/ble_device_base/test_scan_mode_request.cpp b/tests/components/ble_device_base/test_scan_mode_request.cpp index e98f25b10d..2eeb602999 100644 --- a/tests/components/ble_device_base/test_scan_mode_request.cpp +++ b/tests/components/ble_device_base/test_scan_mode_request.cpp @@ -36,6 +36,13 @@ class SwitchingHub : public DefaultHub { } }; +// The esp32 shape: the controller supports active scanning but the hub keeps +// the refusing default (mode is driven through its own tracker API). +class CapableRefusingHub : public DefaultHub { + public: + HubCapabilities get_capabilities() const override { return {true, false, false}; } +}; + } // namespace TEST(BLEHubScanModeRequest, DefaultRefusesAndChangesNothing) { @@ -56,4 +63,11 @@ TEST(BLEHubScanModeRequest, OverrideHonorsAndApplies) { EXPECT_FALSE(hub.scan_active()); } +TEST(BLEHubScanModeRequest, CapabilityAndSwitchAreIndependent) { + CapableRefusingHub hub; + EXPECT_TRUE(hub.get_capabilities().active_scan); + EXPECT_FALSE(hub.request_scan_mode(false)); + EXPECT_TRUE(hub.scan_active()); +} + } // namespace esphome::ble_device_base::testing