mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2025-01-11 20:01:14 +01:00
Cleanup bluetooth connection failure code (#495)
This commit is contained in:
parent
821735e3a3
commit
2d89b9e267
@ -588,7 +588,7 @@ class APIClient:
|
|||||||
"""Handle a timeout."""
|
"""Handle a timeout."""
|
||||||
if fut.done():
|
if fut.done():
|
||||||
return
|
return
|
||||||
fut.set_exception(asyncio.TimeoutError())
|
fut.set_exception(asyncio.TimeoutError)
|
||||||
|
|
||||||
def _on_bluetooth_device_connection_response(
|
def _on_bluetooth_device_connection_response(
|
||||||
self,
|
self,
|
||||||
@ -653,47 +653,33 @@ class APIClient:
|
|||||||
msg_types,
|
msg_types,
|
||||||
)
|
)
|
||||||
|
|
||||||
timeout_handle = self._loop.call_later(
|
loop = self._loop
|
||||||
timeout, self._handle_timeout, connect_future
|
timeout_handle = loop.call_later(timeout, self._handle_timeout, connect_future)
|
||||||
)
|
timeout_expired = False
|
||||||
try:
|
connect_ok = False
|
||||||
try:
|
try:
|
||||||
await connect_future
|
await connect_future
|
||||||
|
connect_ok = True
|
||||||
except asyncio.TimeoutError as err:
|
except asyncio.TimeoutError as err:
|
||||||
|
timeout_expired = True
|
||||||
# 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.
|
||||||
addr = to_human_readable_address(address)
|
addr = to_human_readable_address(address)
|
||||||
if debug:
|
if debug:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug("%s: Connecting timed out, waiting for disconnect", addr)
|
||||||
"%s: Connecting timed out, waiting for disconnect", addr
|
disconnect_timed_out = (
|
||||||
|
not await self._bluetooth_device_disconnect_guard_timeout(
|
||||||
|
address, disconnect_timeout
|
||||||
)
|
)
|
||||||
disconnect_timed_out = False
|
|
||||||
try:
|
|
||||||
await self.bluetooth_device_disconnect(
|
|
||||||
address, timeout=disconnect_timeout
|
|
||||||
)
|
|
||||||
except TimeoutAPIError:
|
|
||||||
disconnect_timed_out = True
|
|
||||||
if debug:
|
|
||||||
_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}, "
|
||||||
f" after {disconnect_timeout}s"
|
f" after {disconnect_timeout}s"
|
||||||
) from err
|
) from err
|
||||||
except asyncio.CancelledError:
|
finally:
|
||||||
|
if not connect_ok:
|
||||||
try:
|
try:
|
||||||
unsub()
|
unsub()
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
@ -701,12 +687,30 @@ class APIClient:
|
|||||||
"%s: Bluetooth device connection canceled but already unsubscribed",
|
"%s: Bluetooth device connection canceled but already unsubscribed",
|
||||||
addr,
|
addr,
|
||||||
)
|
)
|
||||||
raise
|
if not timeout_expired:
|
||||||
finally:
|
|
||||||
timeout_handle.cancel()
|
timeout_handle.cancel()
|
||||||
|
|
||||||
return unsub
|
return unsub
|
||||||
|
|
||||||
|
async def _bluetooth_device_disconnect_guard_timeout(
|
||||||
|
self, address: int, timeout: float
|
||||||
|
) -> bool:
|
||||||
|
"""Disconnect from a Bluetooth device and guard against timeout.
|
||||||
|
|
||||||
|
Return true if the disconnect was successful, false if it timed out.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
await self.bluetooth_device_disconnect(address, timeout=timeout)
|
||||||
|
except TimeoutAPIError:
|
||||||
|
if _LOGGER.isEnabledFor(logging.DEBUG):
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s: Disconnect timed out: %s",
|
||||||
|
to_human_readable_address(address),
|
||||||
|
timeout,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def bluetooth_device_pair(
|
async def bluetooth_device_pair(
|
||||||
self, address: int, timeout: float = DEFAULT_BLE_TIMEOUT
|
self, address: int, timeout: float = DEFAULT_BLE_TIMEOUT
|
||||||
) -> BluetoothDevicePairing:
|
) -> BluetoothDevicePairing:
|
||||||
|
@ -599,7 +599,7 @@ class APIConnection:
|
|||||||
"""Handle a timeout."""
|
"""Handle a timeout."""
|
||||||
if fut.done():
|
if fut.done():
|
||||||
return
|
return
|
||||||
fut.set_exception(asyncio.TimeoutError())
|
fut.set_exception(asyncio.TimeoutError)
|
||||||
|
|
||||||
def _handle_complex_message(
|
def _handle_complex_message(
|
||||||
self,
|
self,
|
||||||
@ -658,13 +658,16 @@ class APIConnection:
|
|||||||
# the message could fail to be removed if the
|
# the message could fail to be removed if the
|
||||||
# the await is cancelled
|
# the await is cancelled
|
||||||
timeout_handle = self._loop.call_later(timeout, self._handle_timeout, fut)
|
timeout_handle = self._loop.call_later(timeout, self._handle_timeout, fut)
|
||||||
|
timeout_expired = False
|
||||||
try:
|
try:
|
||||||
await fut
|
await fut
|
||||||
except asyncio.TimeoutError as err:
|
except asyncio.TimeoutError as err:
|
||||||
|
timeout_expired = True
|
||||||
raise TimeoutAPIError(
|
raise TimeoutAPIError(
|
||||||
f"Timeout waiting for response for {type(send_msg)} after {timeout}s"
|
f"Timeout waiting for response for {type(send_msg)} after {timeout}s"
|
||||||
) from err
|
) from err
|
||||||
finally:
|
finally:
|
||||||
|
if not timeout_expired:
|
||||||
timeout_handle.cancel()
|
timeout_handle.cancel()
|
||||||
for msg_type in msg_types:
|
for msg_type in msg_types:
|
||||||
message_handlers[msg_type].discard(on_message)
|
message_handlers[msg_type].discard(on_message)
|
||||||
|
Loading…
Reference in New Issue
Block a user