Use bleak-retry-connector and write-only move loop for BLE proxy reliability#41
Use bleak-retry-connector and write-only move loop for BLE proxy reliability#41pedropombeiro wants to merge 2 commits into
Conversation
6f5087c to
715bfc0
Compare
Replace the raw BleakClient.connect() path with bleak_retry_connector.establish_connection(), building on the wakeup ordering fix from abmantis#40. - add bleak-retry-connector as a dependency - use establish_connection() with BleakClientWithServiceCache for proper connection caching - introduce ManagedIdasenDesk subclass to avoid creating an unused BleakClient in __init__ and cleanly adopt the externally-established client - accept the current BLEDevice in ConnectionManager.connect() so device-swap and reconnect paths stay aligned
Rewrite ManagedIdasenDesk.move_to_target to eliminate GATT reads during movement. Send target height writes every 200ms with acknowledged delivery and detect arrival via BLE notifications from the monitor() subscription instead of polling get_height_and_speed(). The previous implementation interleaved GATT reads with writes. BLE has a single ATT channel per connection -- reads block the channel until the response arrives. Over Bluetooth proxies, read latency can spike to seconds on timeout/retry, creating unpredictable gaps between reference input writes that cause the desk to stop moving. Send explicit stop commands (COMMAND_STOP + REFERENCE_INPUT_STOP) when the move loop exits to cleanly terminate desk movement. Add a 30-second safety timeout to prevent infinite move loops. Ref: abmantis#38 (comment)
715bfc0 to
a0e00f3
Compare
|
Hey! This is doing too much for a single PR. |
Thanks for the review! I've split the move-loop change off and proposed it upstream in newAM/idasen#489 — that's a small, self-contained fix that makes That leaves this PR scoped to the BLE connection path:
I'll trim this PR down to just the connection-path changes once we agree. |
I just don't like this part very much 😄 . Can we open another PR to upstream, adding an argument |
|
Good call — that's a cleaner design. I'll open a follow-up upstream PR on Once that lands and is released, I'll:
Will update here once the upstream PR is filed. |
Summary
Replace the raw
BleakClient.connect()path withbleak_retry_connector.establish_connection()and rewritemove_to_targetto eliminate GATT reads during movement, building on the wakeup ordering fix from #40.Connection improvements
bleak-retry-connectoras a dependencyestablish_connection()withBleakClientWithServiceCachefor proper connection cachingManagedIdasenDesksubclass to avoid creating an unusedBleakClientin__init__and cleanly adopt the externally-established clientBLEDeviceinConnectionManager.connect()so device-swap and reconnect paths stay alignedWrite-only move loop
response=False(fire-and-forget)monitor()instead of pollingget_height_and_speed()Why
The upstream
move_to_targetinterleaves GATT reads with writes during movement. BLE has a single ATT channel per connection — reads block the channel until the response arrives. Over Bluetooth proxies (HA → WiFi → ESP32 → BLE → desk), read latency is 50–200ms normally but can spike to seconds on timeout/retry, creating unpredictable gaps between reference input writes. The desk interprets these gaps as "stop commanding movement" and decelerates or stops.By removing reads from the loop, the write cadence becomes deterministic and the ATT channel stays free for outgoing commands. Height data is already pushed to us via the existing
monitor()BLE notification subscription.Ref: #38 (comment: #38 (comment))
Validation
BleakClient.connect() called without bleak-retry-connectorwarning is goneConnecting v3 with cacheSupersedes #39. Related to home-assistant/core#155912.