From af608792da1cda0c2b13c474853a416e5e65ab78 Mon Sep 17 00:00:00 2001 From: Jannis Christiani Date: Sat, 11 Apr 2026 20:02:31 +0200 Subject: [PATCH] Fix dirty client state after failed BLE connection Previously a failed connect() / start_notify() left self._client pointing at a broken BleakClient. On the next poll is_connected returned False but the stale object caused confusing errors. Now the client is only assigned after both steps succeed; on any exception we try a clean disconnect and reset to None so the next attempt starts completely fresh. Co-Authored-By: Claude Sonnet 4.6 --- .../xiaoxiang_bms/bluetooth_handler.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/custom_components/xiaoxiang_bms/bluetooth_handler.py b/custom_components/xiaoxiang_bms/bluetooth_handler.py index a148e4f..daf00a9 100644 --- a/custom_components/xiaoxiang_bms/bluetooth_handler.py +++ b/custom_components/xiaoxiang_bms/bluetooth_handler.py @@ -52,14 +52,25 @@ class BmsBluetoothHandler: if self.is_connected: return _LOGGER.debug("Connecting to BMS at %s (via %s)", self._address, ble_device.name) - self._client = BleakClient( + client = BleakClient( ble_device, disconnected_callback=self._on_disconnect, ) - await self._client.connect() - await self._client.start_notify(RX_CHAR_UUID, self._on_notify) + try: + await client.connect() + await client.start_notify(RX_CHAR_UUID, self._on_notify) + except Exception: + # Ensure a failed connect never leaves a broken client behind — + # next poll will start fresh + try: + await client.disconnect() + except Exception: + pass + self._client = None + raise # Give the BMS a moment to register the notification subscription # before we start sending commands — avoids dropped first response + self._client = client await asyncio.sleep(0.5) _LOGGER.debug("Connected to BMS at %s", self._address)