Simplify ESPHome bluetooth disconnected during operation wrapper (#96459)
parent
bbc420bc90
commit
c44c7bba84
|
@ -62,29 +62,32 @@ def verify_connected(func: _WrapFuncType) -> _WrapFuncType:
|
||||||
async def _async_wrap_bluetooth_connected_operation(
|
async def _async_wrap_bluetooth_connected_operation(
|
||||||
self: ESPHomeClient, *args: Any, **kwargs: Any
|
self: ESPHomeClient, *args: Any, **kwargs: Any
|
||||||
) -> Any:
|
) -> Any:
|
||||||
disconnected_event = (
|
loop = self._loop # pylint: disable=protected-access
|
||||||
self._disconnected_event # pylint: disable=protected-access
|
disconnected_futures = (
|
||||||
|
self._disconnected_futures # pylint: disable=protected-access
|
||||||
)
|
)
|
||||||
if not disconnected_event:
|
disconnected_future = loop.create_future()
|
||||||
raise BleakError("Not connected")
|
disconnected_futures.add(disconnected_future)
|
||||||
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
|
|
||||||
|
|
||||||
|
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(
|
raise BleakError(
|
||||||
f"{self._source_name}: " # pylint: disable=protected-access
|
f"{source_name}: {ble_device.name} - {ble_device.address}: "
|
||||||
f"{self._ble_device.name} - " # pylint: disable=protected-access
|
|
||||||
f" {self._ble_device.address}: " # pylint: disable=protected-access
|
|
||||||
"Disconnected during operation"
|
"Disconnected during operation"
|
||||||
)
|
) from ex
|
||||||
return action_task.result()
|
finally:
|
||||||
|
disconnected_futures.discard(disconnected_future)
|
||||||
|
disconnected_future.remove_done_callback(_on_disconnected)
|
||||||
|
|
||||||
return cast(_WrapFuncType, _async_wrap_bluetooth_connected_operation)
|
return cast(_WrapFuncType, _async_wrap_bluetooth_connected_operation)
|
||||||
|
|
||||||
|
@ -152,7 +155,8 @@ class ESPHomeClient(BaseBleakClient):
|
||||||
self._notify_cancels: dict[
|
self._notify_cancels: dict[
|
||||||
int, tuple[Callable[[], Coroutine[Any, Any, None]], Callable[[], None]]
|
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
|
device_info = self.entry_data.device_info
|
||||||
assert device_info is not None
|
assert device_info is not None
|
||||||
self._device_info = device_info
|
self._device_info = device_info
|
||||||
|
@ -192,9 +196,10 @@ class ESPHomeClient(BaseBleakClient):
|
||||||
for _, notify_abort in self._notify_cancels.values():
|
for _, notify_abort in self._notify_cancels.values():
|
||||||
notify_abort()
|
notify_abort()
|
||||||
self._notify_cancels.clear()
|
self._notify_cancels.clear()
|
||||||
if self._disconnected_event:
|
for future in self._disconnected_futures:
|
||||||
self._disconnected_event.set()
|
if not future.done():
|
||||||
self._disconnected_event = None
|
future.set_result(None)
|
||||||
|
self._disconnected_futures.clear()
|
||||||
self._unsubscribe_connection_state()
|
self._unsubscribe_connection_state()
|
||||||
|
|
||||||
def _async_ble_device_disconnected(self) -> None:
|
def _async_ble_device_disconnected(self) -> None:
|
||||||
|
@ -359,7 +364,6 @@ class ESPHomeClient(BaseBleakClient):
|
||||||
await self.disconnect()
|
await self.disconnect()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
self._disconnected_event = asyncio.Event()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api_error_as_bleak_error
|
@api_error_as_bleak_error
|
||||||
|
|
Loading…
Reference in New Issue