Suppress both restart on_scan_end sweeps; scope the window error path; test the no-effect warning

This commit is contained in:
J. Nick Koston
2026-08-21 17:54:12 -05:00
parent 90e25f2349
commit 256853210b
5 changed files with 45 additions and 7 deletions
@@ -203,7 +203,8 @@ def _raise_defaulted_scan_window(config: ConfigType) -> ConfigType:
# A larger value would widen the scan during connections.
raise cv.Invalid(
f"{CONF_CONNECTION_SCAN_WINDOW} ({connection_window}) needs to be "
f"smaller than the scan window ({params[CONF_WINDOW]})"
f"smaller than the scan window ({params[CONF_WINDOW]})",
path=[CONF_SCAN_PARAMETERS, CONF_CONNECTION_SCAN_WINDOW],
)
return config
@@ -154,7 +154,8 @@ void ESP32BLETracker::loop() {
// scan would not restart); !disconnecting matches the restart gate below.
if (this->using_connection_window_ && !counts.active && !counts.disconnecting && this->scan_continuous_ &&
this->scanner_state_ == ScannerState::RUNNING) {
// Same logical scan period continues: no extra on_scan_end for listeners.
// Same logical scan period continues: cleanup_scan_state_ and start_scan_
// both skip their on_scan_end sweep.
this->skip_next_scan_end_ = true;
this->stop_scan_();
}
@@ -528,14 +529,22 @@ void ESP32BLETracker::cleanup_scan_state_(bool is_stop_complete) {
// Reset timeout state machine instead of cancelling scheduler timeout
this->scan_timeout_state_ = ScanTimeoutState::INACTIVE;
bool notify_scan_end = true;
#ifdef ESPHOME_ESP32_BLE_TRACKER_CLIENT_COUNT
// Window-change restart continues the scan period: no on_scan_end here.
// The flag stays set so start_scan_ skips its sweep too.
notify_scan_end = !this->skip_next_scan_end_;
#endif
if (notify_scan_end) {
#ifdef ESPHOME_ESP32_BLE_TRACKER_LISTENER_COUNT
for (auto *listener : this->listeners_)
listener->on_scan_end();
for (auto *listener : this->listeners_)
listener->on_scan_end();
#endif
#ifdef ESPHOME_BLE_DEVICE_BASE_LISTENER_COUNT
for (auto *listener : this->neutral_listeners_)
listener->on_scan_end();
for (auto *listener : this->neutral_listeners_)
listener->on_scan_end();
#endif
}
this->set_scanner_state_(ScannerState::IDLE);
}
@@ -350,7 +350,7 @@ class ESP32BLETracker final : public Component,
/// The running scan was started with connection_scan_window_; lets loop()
/// restart the scan at the configured window when the last connection drops.
bool using_connection_window_ : 1 {false};
/// Skip one on_scan_end sweep: the window-change restart continues the period.
/// Suppress the window-change restart's on_scan_end sweeps (stop and start).
bool skip_next_scan_end_ : 1 {false};
#endif
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
@@ -0,0 +1,14 @@
esphome:
name: scan-window-user-scan-only
esp32:
board: esp32dev
framework:
type: esp-idf
wifi:
ssid: MySSID
esp32_ble_tracker:
scan_parameters:
connection_scan_window: 20ms
@@ -222,3 +222,17 @@ def test_codegen_no_connection_window_without_gatt_clients(
main_cpp = generate_main(component_config_path("scan_window_scan_only.yaml"))
assert "set_scan_window(512)" in main_cpp
assert "set_connection_scan_window" not in main_cpp
def test_user_set_connection_window_warns_without_gatt_clients(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
caplog: pytest.LogCaptureFixture,
) -> None:
"""A user-set value that cannot take effect warns; the injected default
(previous test) is dropped silently."""
main_cpp = generate_main(
component_config_path("scan_window_user_set_scan_only.yaml")
)
assert "set_connection_scan_window" not in main_cpp
assert "'connection_scan_window' has no effect" in caplog.text