Fix BLE connection timing out on failure instead of raising (#429)

This commit is contained in:
J. Nick Koston 2023-05-07 09:05:51 -05:00 committed by GitHub
parent 85e19020fa
commit 7b8ed9fd03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -529,8 +529,10 @@ class APIClient:
resp = BluetoothDeviceConnection.from_pb(msg) resp = BluetoothDeviceConnection.from_pb(msg)
if address == resp.address: if address == resp.address:
on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error) on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error)
if resp.connected: # Resolve on ANY connection state since we do not want
event.set() # to wait the whole timeout if the device disconnects
# or we get an error.
event.set()
assert self._connection is not None assert self._connection is not None
if has_cache: if has_cache:
@ -570,26 +572,27 @@ class APIClient:
# Disconnect before raising the exception to ensure # Disconnect before raising the exception to ensure
# the slot is recovered before the timeout is raised # the slot is recovered before the timeout is raised
# to avoid race were we run out even though we have a slot. # to avoid race were we run out even though we have a slot.
await self.bluetooth_device_disconnect(address)
addr = to_human_readable_address(address) addr = to_human_readable_address(address)
_LOGGER.debug("%s: Connecting timed out, waiting for disconnect", addr) _LOGGER.debug("%s: Connecting timed out, waiting for disconnect", addr)
disconnect_timed_out = False
try: try:
async with async_timeout.timeout(disconnect_timeout): await self.bluetooth_device_disconnect(
await event.wait() address, timeout=disconnect_timeout
disconnect_timed_out = False
except asyncio.TimeoutError:
disconnect_timed_out = True
_LOGGER.debug(
"%s: Disconnect timed out: %s", addr, disconnect_timed_out
)
try:
unsub()
except (KeyError, ValueError):
_LOGGER.warning(
"%s: Bluetooth device connection timed out but already unsubscribed "
"(likely due to unexpected disconnect)",
addr,
) )
except TimeoutAPIError:
disconnect_timed_out = True
_LOGGER.debug(
"%s: Disconnect timed out: %s", addr, disconnect_timed_out
)
finally:
try:
unsub()
except (KeyError, ValueError):
_LOGGER.warning(
"%s: Bluetooth device connection timed out but already unsubscribed "
"(likely due to unexpected disconnect)",
addr,
)
raise TimeoutAPIError( raise TimeoutAPIError(
f"Timeout waiting for connect response while connecting to {addr} " f"Timeout waiting for connect response while connecting to {addr} "
f"after {timeout}s, disconnect timed out: {disconnect_timed_out}, " f"after {timeout}s, disconnect timed out: {disconnect_timed_out}, "
@ -693,15 +696,24 @@ class APIClient:
return BluetoothDeviceClearCache.from_pb(response) return BluetoothDeviceClearCache.from_pb(response)
async def bluetooth_device_disconnect(self, address: int) -> None: async def bluetooth_device_disconnect(
self, address: int, timeout: float = DEFAULT_BLE_DISCONNECT_TIMEOUT
) -> None:
self._check_authenticated() self._check_authenticated()
def predicate_func(msg: BluetoothDeviceConnectionResponse) -> bool:
return bool(msg.address == address and not msg.connected)
assert self._connection is not None assert self._connection is not None
self._connection.send_message( await self._connection.send_message_await_response_complex(
BluetoothDeviceRequest( BluetoothDeviceRequest(
address=address, address=address,
request_type=BluetoothDeviceRequestType.DISCONNECT, request_type=BluetoothDeviceRequestType.DISCONNECT,
) ),
predicate_func,
predicate_func,
(BluetoothDeviceConnectionResponse,),
timeout=timeout,
) )
async def bluetooth_gatt_get_services( async def bluetooth_gatt_get_services(