@DunkyDaMonkey,
Firstly, sorry for the rubbish code - I’m new to python. And, please excuse the hasty code. There’s no exception handling, and many places where it is quite brittle.
Yeah, the 1 minute polling was pretty arbitrary…
Ideally, the python api would handle trying harder to connect before failing. As I understand it, bleak_retry_connector does a lot of this handling somehow (as described here). It’s beyond me though; the documentation is a bit sparse.
When HA first loads the chlorinator entry on startup, in async_setup_entry
, it gets a BLEDevice
from the saved MAC address. This is passed to the instance of the chlorinator API and reused ‘forever’. If this fails, HA automatically retries (I think).
The problem occurs later in the polling event of the coordinator: _async_update_data
, which calls async_gatherdata
, which creates a BleakClient
from the saved BLEDevice
. This is where it actually tries to connect to the device, and is liable to fail to connect without any retry (I think). This needs something more resilient. I raked over lots of different repos using bleak, but struggled to find an obvious way to do it.
This characterises the most common failure mode:
2023-04-05 06:03:20.893 ERROR (MainThread) [custom_components.astralpool_chlorinator.coordinator] Unexpected error fetching astralpool_chlorinator data: [org.bluez.Error.Failed] le-connection-abort-by-local
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 239, in _async_refresh
self.data = await self._async_update_data()
File "/config/custom_components/astralpool_chlorinator/coordinator.py", line 39, in _async_update_data
data = await self.chlorinator.async_gatherdata()
File "/usr/local/lib/python3.10/site-packages/pychlorinator/chlorinator.py", line 136, in async_gatherdata
async with BleakClient(self._ble_device, timeout=3) as client:
File "/usr/local/lib/python3.10/site-packages/bleak/__init__.py", line 433, in __aenter__
await self.connect()
File "/usr/src/homeassistant/homeassistant/components/bluetooth/wrappers.py", line 249, in connect
connected = await super().connect(**kwargs)
File "/usr/local/lib/python3.10/site-packages/bleak/__init__.py", line 471, in connect
return await self._backend.connect(**kwargs)
File "/usr/local/lib/python3.10/site-packages/bleak/backends/bluezdbus/client.py", line 190, in connect
assert_reply(reply)
File "/usr/local/lib/python3.10/site-packages/bleak/backends/bluezdbus/utils.py", line 20, in assert_reply
raise BleakDBusError(reply.error_name, reply.body)
bleak.exc.BleakDBusError: [org.bluez.Error.Failed] le-connection-abort-by-local