1010import async_timeout
1111
1212from bleak import BleakError
13+ from bleak .exc import BleakDBusError
1314from bleak .backends .device import BLEDevice
1415from bleak .backends .service import BleakGATTCharacteristic , BleakGATTServiceCollection
1516from bleak_retry_connector import (
@@ -164,7 +165,7 @@ async def _ensure_connected(self):
164165 self .name ,
165166 self ._disconnected ,
166167 cached_services = self ._cached_services ,
167- ble_device_callback = lambda : self ._device
168+ ble_device_callback = lambda : self ._device ,
168169 )
169170 self ._cached_services = client .services
170171 _LOGGER .debug ("%s: Connected; RSSI: %s" , self .name , self .rssi )
@@ -199,15 +200,19 @@ def _disconnected(self, client: BleakClientWithServiceCache) -> None:
199200 def _disconnect (self ):
200201 """Disconnect from device."""
201202 self ._disconnect_timer = None
202- asyncio .create_task (self ._execute_disconnect ())
203+ asyncio .create_task (self ._execute_timed_disconnect ())
203204
204- async def _execute_disconnect (self ):
205- """Execute disconnection."""
205+ async def _execute_timed_disconnect (self ):
206+ """Execute timed disconnection."""
206207 _LOGGER .debug (
207208 "%s: Disconnecting after timeout of %s" ,
208209 self .name ,
209210 DISCONNECT_DELAY ,
210211 )
212+ await self ._execute_disconnect ()
213+
214+ async def _execute_disconnect (self ):
215+ """Execute disconnection."""
211216 async with self ._connect_lock :
212217 if not self ._client or not self ._client .is_connected :
213218 return
@@ -220,6 +225,29 @@ async def _execute_disconnect(self):
220225 async def _send_command_locked (self , key : str , command : bytes ) -> bytes :
221226 """Send command to device and read response."""
222227 await self ._ensure_connected ()
228+ try :
229+ return await self ._execute_command_locked (key , command )
230+ except BleakDBusError as ex :
231+ # Disconnect so we can reset state and try again
232+ await asyncio .sleep (0.25 )
233+ _LOGGER .debug (
234+ "%s: RSSI: %s; Backing off %ss; Disconnecting due to error: %s" ,
235+ self .name ,
236+ self .rssi ,
237+ 0.25 ,
238+ ex ,
239+ )
240+ await self ._execute_disconnect ()
241+ except BleakError as ex :
242+ # Disconnect so we can reset state and try again
243+ _LOGGER .debug (
244+ "%s: RSSI: %s; Disconnecting due to error: %s" , self .name , self .rssi , ex
245+ )
246+ await self ._execute_disconnect ()
247+ raise
248+
249+ async def _execute_command_locked (self , key : str , command : bytes ) -> bytes :
250+ """Execute command and read response."""
223251 assert self ._client is not None
224252 assert self ._read_char is not None
225253 assert self ._write_char is not None
0 commit comments