Skip to content

Commit 676dfd5

Browse files
authored
Fix disconnect race (#110)
1 parent 4792b97 commit 676dfd5

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

switchbot/devices/device.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def name(self) -> str:
205205
@property
206206
def rssi(self) -> int:
207207
"""Return RSSI of device."""
208-
return self._get_adv_value("rssi")
208+
return self._get_adv_value("rssi") or self._device.rssi
209209

210210
async def _ensure_connected(self):
211211
"""Ensure connection to device is established."""
@@ -249,8 +249,7 @@ def _resolve_characteristics(self, services: BleakGATTServiceCollection) -> bool
249249

250250
def _reset_disconnect_timer(self):
251251
"""Reset disconnect timer."""
252-
if self._disconnect_timer:
253-
self._disconnect_timer.cancel()
252+
self._cancel_disconnect_timer()
254253
self._expected_disconnect = False
255254
self._disconnect_timer = self.loop.call_later(
256255
DISCONNECT_DELAY, self._disconnect
@@ -271,28 +270,47 @@ def _disconnected(self, client: BleakClientWithServiceCache) -> None:
271270

272271
def _disconnect(self):
273272
"""Disconnect from device."""
274-
self._disconnect_timer = None
273+
self._cancel_disconnect_timer()
275274
asyncio.create_task(self._execute_timed_disconnect())
276275

277-
async def _execute_timed_disconnect(self):
276+
def _cancel_disconnect_timer(self):
277+
"""Cancel disconnect timer."""
278+
if self._disconnect_timer:
279+
self._disconnect_timer.cancel()
280+
self._disconnect_timer = None
281+
282+
async def _execute_forced_disconnect(self) -> None:
283+
"""Execute forced disconnection."""
284+
self._cancel_disconnect_timer()
285+
_LOGGER.debug(
286+
"%s: Executing forced disconnect",
287+
self.name,
288+
)
289+
await self._execute_disconnect()
290+
291+
async def _execute_timed_disconnect(self) -> None:
278292
"""Execute timed disconnection."""
279293
_LOGGER.debug(
280-
"%s: Disconnecting after timeout of %s",
294+
"%s: Executing timed disconnect after timeout of %s",
281295
self.name,
282296
DISCONNECT_DELAY,
283297
)
284298
await self._execute_disconnect()
285299

286-
async def _execute_disconnect(self):
300+
async def _execute_disconnect(self) -> None:
287301
"""Execute disconnection."""
288302
async with self._connect_lock:
303+
if self._disconnect_timer: # If the timer was reset, don't disconnect
304+
return
289305
client = self._client
290306
self._expected_disconnect = True
291307
self._client = None
292308
self._read_char = None
293309
self._write_char = None
294310
if client and client.is_connected:
311+
_LOGGER.debug("%s: Disconnecting", self.name)
295312
await client.disconnect()
313+
_LOGGER.debug("%s: Disconnect completed", self.name)
296314

297315
async def _send_command_locked(self, key: str, command: bytes) -> bytes:
298316
"""Send command to device and read response."""
@@ -309,14 +327,14 @@ async def _send_command_locked(self, key: str, command: bytes) -> bytes:
309327
0.25,
310328
ex,
311329
)
312-
await self._execute_disconnect()
330+
await self._execute_forced_disconnect()
313331
raise
314332
except BleakError as ex:
315333
# Disconnect so we can reset state and try again
316334
_LOGGER.debug(
317335
"%s: RSSI: %s; Disconnecting due to error: %s", self.name, self.rssi, ex
318336
)
319-
await self._execute_disconnect()
337+
await self._execute_forced_disconnect()
320338
raise
321339

322340
async def _execute_command_locked(self, key: str, command: bytes) -> bytes:

0 commit comments

Comments
 (0)