Simplify ESPHome bluetooth disconnected during operation wrapper (#96459)

pull/96520/head
J. Nick Koston 2023-07-13 16:45:45 -10:00 committed by GitHub
parent bbc420bc90
commit c44c7bba84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 28 additions and 24 deletions

View File

@ -62,29 +62,32 @@ def verify_connected(func: _WrapFuncType) -> _WrapFuncType:
async def _async_wrap_bluetooth_connected_operation(
self: ESPHomeClient, *args: Any, **kwargs: Any
) -> Any:
disconnected_event = (
self._disconnected_event # pylint: disable=protected-access
loop = self._loop # pylint: disable=protected-access
disconnected_futures = (
self._disconnected_futures # pylint: disable=protected-access
)
if not disconnected_event:
raise BleakError("Not connected")
action_task = asyncio.create_task(func(self, *args, **kwargs))
disconnect_task = asyncio.create_task(disconnected_event.wait())
await asyncio.wait(
(action_task, disconnect_task),
return_when=asyncio.FIRST_COMPLETED,
)
if disconnect_task.done():
action_task.cancel()
with contextlib.suppress(asyncio.CancelledError):
await action_task
disconnected_future = loop.create_future()
disconnected_futures.add(disconnected_future)
task = asyncio.current_task(loop)
def _on_disconnected(fut: asyncio.Future[None]) -> None:
if task and not task.done():
task.cancel()
disconnected_future.add_done_callback(_on_disconnected)
try:
return await func(self, *args, **kwargs)
except asyncio.CancelledError as ex:
source_name = self._source_name # pylint: disable=protected-access
ble_device = self._ble_device # pylint: disable=protected-access
raise BleakError(
f"{self._source_name}: " # pylint: disable=protected-access
f"{self._ble_device.name} - " # pylint: disable=protected-access
f" {self._ble_device.address}: " # pylint: disable=protected-access
f"{source_name}: {ble_device.name} - {ble_device.address}: "
"Disconnected during operation"
)
return action_task.result()
) from ex
finally:
disconnected_futures.discard(disconnected_future)
disconnected_future.remove_done_callback(_on_disconnected)
return cast(_WrapFuncType, _async_wrap_bluetooth_connected_operation)
@ -152,7 +155,8 @@ class ESPHomeClient(BaseBleakClient):
self._notify_cancels: dict[
int, tuple[Callable[[], Coroutine[Any, Any, None]], Callable[[], None]]
] = {}
self._disconnected_event: asyncio.Event | None = None
self._loop = asyncio.get_running_loop()
self._disconnected_futures: set[asyncio.Future[None]] = set()
device_info = self.entry_data.device_info
assert device_info is not None
self._device_info = device_info
@ -192,9 +196,10 @@ class ESPHomeClient(BaseBleakClient):
for _, notify_abort in self._notify_cancels.values():
notify_abort()
self._notify_cancels.clear()
if self._disconnected_event:
self._disconnected_event.set()
self._disconnected_event = None
for future in self._disconnected_futures:
if not future.done():
future.set_result(None)
self._disconnected_futures.clear()
self._unsubscribe_connection_state()
def _async_ble_device_disconnected(self) -> None:
@ -359,7 +364,6 @@ class ESPHomeClient(BaseBleakClient):
await self.disconnect()
raise
self._disconnected_event = asyncio.Event()
return True
@api_error_as_bleak_error