ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
bk72xx_ble_tracker.h
Go to the documentation of this file.
1// bk72xx_ble_tracker.h
2//
3// ESPHome BLE scanner for the BK72xx BLE-5.x chips (LibreTiny beken-72xx family).
4// Implements the platform-neutral ble_device_base::BLEHub contract on top of the
5// bk72xx_ble controller component: parsed ESPBTDevice objects go to registered
6// listeners (bthome_mithermometer, ble_presence, …) and every raw frame to the
7// hub's raw-advertisement callback.
8//
9// This component contains no Beken SDK calls and no cross-task state: the
10// controller (stack bring-up, BLE address, scan primitives, and the BLE-task →
11// main-task report queue) is owned by bk72xx_ble, which delivers every scan
12// report on the ESPHome main task. The tracker owns scan policy — parameters,
13// duration/period timers and the rate-limited start retry.
14//
15// YAML config (values shown are the defaults; interval/window are a 30 % duty
16// cycle, the BK reference scan rate):
17//
18// bk72xx_ble_tracker:
19// scan_parameters:
20// interval: 100ms
21// window: 30ms
22// duration: 5min
23// continuous: true
24// active: true
25
26#pragma once
27
28#ifdef USE_LIBRETINY
29
36
37#include <cstdint>
38
39#ifdef USE_OTA_STATE_LISTENER
41#endif
42
44
45// ---------------------------------------------------------------------------
46// BK72xxBLETracker
47// ---------------------------------------------------------------------------
48
51 public Parented<bk72xx_ble::BK72xxBLE>
52#ifdef USE_OTA_STATE_LISTENER
53 ,
55#endif
56{
57 public:
58 // ---- ESPHome Component ----
59 void setup() override;
60 void loop() override;
61 void dump_config() override;
62 float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
63
64#ifdef USE_OTA_STATE_LISTENER
65 // Pause scanning while an OTA update runs (single-core WiFi/BLE/flash contention);
66 // mirrors esp32_ble_tracker.
67 void on_ota_global_state(ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) override;
68#endif
69
70 // ---- YAML configuration setters ----
71 void set_scan_interval(uint32_t scan_interval) { this->scan_interval_ = scan_interval; }
72 void set_scan_window(uint32_t scan_window) { this->scan_window_ = scan_window; }
73 void set_scan_duration(uint32_t scan_duration) { this->scan_duration_ = scan_duration; }
90 bool scan_continuous() const { return this->scan_continuous_; }
96
97 // ---- Public scan control ----
98 // Mirrors esp32_ble_tracker: set_scan_continuous() + start_scan() / stop_scan().
99 void start_scan();
100 void stop_scan();
101
102 // ---- ble_device_base::BLEHub contract ----
110 // Active scanning is driven through bk72xx_ble's reconciler because the BDK
111 // API itself is passive-only. The controller delivers scan responses as
112 // separate reports; this tracker merges the pair before delivery (shared
113 // ScanResponseMerger, Bluedroid semantics). No GATT client.
114 return {.active_scan = true, .merges_scan_response = true, .gatt = false, .scan_mode_switch = true};
115 }
116 bool request_scan_mode(bool active);
117 // The controller stores the address LSB-first (BLE convention); the contract
118 // wants printable (MSB-first) order.
119 void get_adapter_mac(uint8_t out[MAC_ADDRESS_SIZE]) {
120 uint8_t mac[MAC_ADDRESS_SIZE];
121 this->parent_->get_mac_lsb_first(mac);
122 for (int i = 0; i < 6; i++)
123 out[i] = mac[5 - i];
124 }
125 bool scan_running() { return this->scan_running_; }
126 bool scan_active() { return this->scan_active_; }
127
128 // ---- bk72xx_ble::BLEScanListener ----
129 // Delivered by the controller's loop() on the ESPHome main task — the
130 // BLE-task → main-task handoff already happened in the controller's queue.
131 void on_scan_report(const bk72xx_ble::BLEScanReport &report) override;
132
133 protected:
134 void start_scan_();
135 void stop_scan_();
136 void fire_scan_end_();
137 void mark_scan_ended_(uint32_t now);
144 bool try_start_with_backoff_(uint32_t now, bool force = false);
145 void count_failed_start_();
146
147 bool scan_running_{false};
148 bool scan_requested_{false}; // latched start_scan() request not yet running; loop() retries with backoff
149 bool start_attempt_open_{false}; // charge a later FAILED observation to the backoff exactly once
150 // Defaults: the BK reference — 30 % duty cycle
151 // (interval 100 ms / window 30 ms), in 0.625 ms BLE units.
152 uint32_t scan_interval_{160}; // 160 × 0.625 ms = 100 ms
153 uint32_t scan_window_{48}; // 48 × 0.625 ms = 30 ms (30/100 = 30 %)
156 bool scan_continuous_configured_{true}; // YAML value; stop_scan() must not lose it
157 bool scan_active_{true}; // resolved mode; see scan_parameters.active
158 bool scan_active_configured_{true}; // YAML value; runtime requests must not lose it
159#ifdef USE_OTA_STATE_LISTENER
160 bool scan_continuous_before_ota_{false}; // continuous mode saved at OTA start, restored on OTA failure
161 bool scan_requested_before_ota_{false}; // pending one-shot latch saved at OTA start, re-latched on OTA failure
162#endif
164
165 uint32_t last_scan_start_attempt_{0}; // last controller start attempt, any caller; rate-limits retries
166 uint8_t failed_start_count_{0}; // failed starts AND drops; backoff shift, cleared after a stable run (loop())
167 uint32_t scan_period_start_{0}; // loop-clock start of the scan period; rate-limits on_scan_end()
168 bool scan_started_once_{false}; // true after first successful scan start; gates the period timer
169
170 // Shared adv + scan-response merge and frame dispatch (ble_device_base).
171 // All calls run on the main task (the controller queue already crossed
172 // tasks). Merger clock: stash_adv() reads the PARENT's cached loop time
173 // (on_scan_report runs inside bk72xx_ble's queue drain), sweep() this
174 // component's — same App.loop() pass, so the delta stays non-negative and
175 // the 300 ms timeout holds.
178};
179
180} // namespace esphome::bk72xx_ble_tracker
181
182#endif // USE_LIBRETINY
Helper class to easily give an object a parent of type T.
Definition helpers.h:1907
void get_mac_lsb_first(uint8_t out[MAC_ADDRESS_SIZE]) const
Controller BLE address, least-significant octet first (BLE convention).
Consumer interface for controller scan reports.
Definition bk72xx_ble.h:61
void set_configured_continuous(bool scan_continuous)
Set from YAML (scan_parameters.continuous); also the value configured_continuous() reports and a bare...
void on_ota_global_state(ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) override
bool try_start_with_backoff_(uint32_t now, bool force=false)
Rate-limited (re)start; true when the scan is running (the caller must not reuse a now older than the...
void on_scan_report(const bk72xx_ble::BLEScanReport &report) override
void register_listener(ble_device_base::ESPBTDeviceListener *listener)
void set_scan_continuous(bool scan_continuous)
Runtime control (esp32_ble_tracker lambda parity): does not change the configured value,...
void restart_scan_duration()
Re-anchor the one-shot duration clock of a running scan to now — used when an action changes the scan...
void set_scan_active(bool scan_active)
Set from YAML (scan_parameters.active); runtime mode requests change only the resolved mode.
void get_adapter_mac(uint8_t out[MAC_ADDRESS_SIZE])
ble_device_base::ScanResponseMerger merger_
bk72xx_ble::ScanOpResult controller_scan_start_()
Stamp-and-start for every controller scan attempt, so the retry rate limit covers all callers.
static constexpr ble_device_base::HubCapabilities get_capabilities()
void set_raw_advertisement_callback(ble_device_base::RawAdvertisementCallback callback)
The delivery half of a split-report tracker, shared so the dispatch contract (raw-callback ordering,...
void set_raw_advertisement_callback(RawAdvertisementCallback callback)
void register_listener(ESPBTDeviceListener *listener)
Listener interface for global OTA state changes (includes OTA component pointer).
bool state
Definition fan.h:2
ScanOpResult
Outcome of one reconciliation step.
Definition bk72xx_ble.h:25
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.h:55
static void uint32_t
One advertisement report from the controller.
Definition bk72xx_ble.h:42
What a tracker's controller/SDK can do — consumers branch on data, not #ifdefs.
Definition ble_hub.h:73
Subscriber slot for the raw-advertisement stream (the bluetooth_proxy path).
Definition ble_hub.h:43