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)
if address == resp.address:
on_bluetooth_connection_state(resp.connected, resp.mtu, resp.error)
if resp.connected:
event.set()
# Resolve on ANY connection state since we do not want
# to wait the whole timeout if the device disconnects
# or we get an error.
event.set()
assert self._connection is not None
if has_cache:
@ -570,26 +572,27 @@ class APIClient:
# Disconnect before raising the exception to ensure
# the slot is recovered before the timeout is raised
# 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)
_LOGGER.debug("%s: Connecting timed out, waiting for disconnect", addr)
disconnect_timed_out = False
try:
async with async_timeout.timeout(disconnect_timeout):
await event.wait()
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,
await self.bluetooth_device_disconnect(
address, timeout=disconnect_timeout
)
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(
f"Timeout waiting for connect response while connecting to {addr} "
f"after {timeout}s, disconnect timed out: {disconnect_timed_out}, "
@ -693,15 +696,24 @@ class APIClient:
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()
def predicate_func(msg: BluetoothDeviceConnectionResponse) -> bool:
return bool(msg.address == address and not msg.connected)
assert self._connection is not None
self._connection.send_message(
await self._connection.send_message_await_response_complex(
BluetoothDeviceRequest(
address=address,
request_type=BluetoothDeviceRequestType.DISCONNECT,
)
),
predicate_func,
predicate_func,
(BluetoothDeviceConnectionResponse,),
timeout=timeout,
)
async def bluetooth_gatt_get_services(