feat(ble): replace blocking scan with advertisement observation

The one-shot scan kept only the top six devices by RSSI and dropped the
advertisement payload, so a distant beacon lost its slot to nearby phones
and its data was unreachable -- wrong on every axis for reading sensors
that broadcast in their adverts.

Replace it with a continuous observer: observe(filter)/observed()/
unobserve()/isObserving(). BleObservation carries the raw advertisement
bytes for Lua to parse, and BleFilter keeps only adverts matching a
service-data UUID or manufacturer id.
This commit is contained in:
2026-08-06 23:03:05 -04:00
parent eac4084f80
commit a09bcfaf06
5 changed files with 135 additions and 31 deletions
+23 -6
View File
@@ -2,10 +2,16 @@
-- Generated from native/src/bindings/core/ble.cpp. Do not edit.
---@class BleDevice
---@field name string
---@class BleObservation
---@field address string
---@field name string
---@field rssi integer
---@field payload string Raw advertisement bytes.
---@field lastSeenMs integer sys.getMillis() at last sighting.
---@class BleFilter
---@field services? string[] Service-data UUIDs to keep.
---@field manufacturers? integer[] Manufacturer ids to keep.
---@class BleLib
ble = {}
@@ -23,11 +29,22 @@ function ble.deinit() end
---@return boolean
function ble.isInitialized() end
---Scans for advertising devices.
---@param durationMs? integer Defaults to 3000.
---@return BleDevice[]? devices
---Starts passively observing advertisements, coalesced per device.
---@param filter? BleFilter Keep only matching adverts; nil keeps all.
---@return true? ok
---@return string? error
function ble.scan(durationMs) end
function ble.observe(filter) end
---Stops observing and clears the snapshot.
function ble.unobserve() end
---Whether advertisement observation is running.
---@return boolean
function ble.isObserving() end
---The current snapshot of observed devices.
---@return BleObservation[] devices
function ble.observed() end
---Connects to a peripheral.
---@param address string