diff --git a/.coveragerc b/.coveragerc index 38b74601214..07e31e07961 100644 --- a/.coveragerc +++ b/.coveragerc @@ -475,6 +475,7 @@ omit = homeassistant/components/guardian/__init__.py homeassistant/components/guardian/binary_sensor.py homeassistant/components/guardian/button.py + homeassistant/components/guardian/coordinator.py homeassistant/components/guardian/sensor.py homeassistant/components/guardian/switch.py homeassistant/components/guardian/util.py diff --git a/homeassistant/components/guardian/__init__.py b/homeassistant/components/guardian/__init__.py index 90504f3213e..8a3ac265618 100644 --- a/homeassistant/components/guardian/__init__.py +++ b/homeassistant/components/guardian/__init__.py @@ -40,7 +40,7 @@ from .const import ( LOGGER, SIGNAL_PAIRED_SENSOR_COORDINATOR_ADDED, ) -from .util import GuardianDataUpdateCoordinator +from .coordinator import GuardianDataUpdateCoordinator DATA_PAIRED_SENSOR_MANAGER = "paired_sensor_manager" diff --git a/homeassistant/components/guardian/binary_sensor.py b/homeassistant/components/guardian/binary_sensor.py index 6b58e70e45d..c7094cf624c 100644 --- a/homeassistant/components/guardian/binary_sensor.py +++ b/homeassistant/components/guardian/binary_sensor.py @@ -29,9 +29,9 @@ from .const import ( DOMAIN, SIGNAL_PAIRED_SENSOR_COORDINATOR_ADDED, ) +from .coordinator import GuardianDataUpdateCoordinator from .util import ( EntityDomainReplacementStrategy, - GuardianDataUpdateCoordinator, async_finish_entity_domain_replacements, ) diff --git a/homeassistant/components/guardian/coordinator.py b/homeassistant/components/guardian/coordinator.py new file mode 100644 index 00000000000..dda0a20be69 --- /dev/null +++ b/homeassistant/components/guardian/coordinator.py @@ -0,0 +1,79 @@ +"""Define Guardian-specific utilities.""" +from __future__ import annotations + +import asyncio +from collections.abc import Callable, Coroutine +from datetime import timedelta +from typing import Any, cast + +from aioguardian import Client +from aioguardian.errors import GuardianError + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import LOGGER + +DEFAULT_UPDATE_INTERVAL = timedelta(seconds=30) + +SIGNAL_REBOOT_REQUESTED = "guardian_reboot_requested_{0}" + + +class GuardianDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]): + """Define an extended DataUpdateCoordinator with some Guardian goodies.""" + + config_entry: ConfigEntry + + def __init__( + self, + hass: HomeAssistant, + *, + entry: ConfigEntry, + client: Client, + api_name: str, + api_coro: Callable[..., Coroutine[Any, Any, dict[str, Any]]], + api_lock: asyncio.Lock, + valve_controller_uid: str, + ) -> None: + """Initialize.""" + super().__init__( + hass, + LOGGER, + name=f"{valve_controller_uid}_{api_name}", + update_interval=DEFAULT_UPDATE_INTERVAL, + ) + + self._api_coro = api_coro + self._api_lock = api_lock + self._client = client + + self.config_entry = entry + self.signal_reboot_requested = SIGNAL_REBOOT_REQUESTED.format( + self.config_entry.entry_id + ) + + async def _async_update_data(self) -> dict[str, Any]: + """Execute a "locked" API request against the valve controller.""" + async with self._api_lock, self._client: + try: + resp = await self._api_coro() + except GuardianError as err: + raise UpdateFailed(err) from err + return cast(dict[str, Any], resp["data"]) + + async def async_initialize(self) -> None: + """Initialize the coordinator.""" + + @callback + def async_reboot_requested() -> None: + """Respond to a reboot request.""" + self.last_update_success = False + self.async_update_listeners() + + self.config_entry.async_on_unload( + async_dispatcher_connect( + self.hass, self.signal_reboot_requested, async_reboot_requested + ) + ) diff --git a/homeassistant/components/guardian/util.py b/homeassistant/components/guardian/util.py index 048f3750d32..ffa57322551 100644 --- a/homeassistant/components/guardian/util.py +++ b/homeassistant/components/guardian/util.py @@ -1,22 +1,18 @@ """Define Guardian-specific utilities.""" from __future__ import annotations -import asyncio from collections.abc import Callable, Coroutine, Iterable from dataclasses import dataclass from datetime import timedelta from functools import wraps -from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar, cast +from typing import TYPE_CHECKING, Any, Concatenate, ParamSpec, TypeVar -from aioguardian import Client from aioguardian.errors import GuardianError from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import LOGGER @@ -29,6 +25,8 @@ DEFAULT_UPDATE_INTERVAL = timedelta(seconds=30) SIGNAL_REBOOT_REQUESTED = "guardian_reboot_requested_{0}" +_P = ParamSpec("_P") + @dataclass class EntityDomainReplacementStrategy: @@ -63,67 +61,6 @@ def async_finish_entity_domain_replacements( ent_reg.async_remove(old_entity_id) -class GuardianDataUpdateCoordinator(DataUpdateCoordinator[dict]): - """Define an extended DataUpdateCoordinator with some Guardian goodies.""" - - config_entry: ConfigEntry - - def __init__( - self, - hass: HomeAssistant, - *, - entry: ConfigEntry, - client: Client, - api_name: str, - api_coro: Callable[..., Coroutine[Any, Any, dict[str, Any]]], - api_lock: asyncio.Lock, - valve_controller_uid: str, - ) -> None: - """Initialize.""" - super().__init__( - hass, - LOGGER, - name=f"{valve_controller_uid}_{api_name}", - update_interval=DEFAULT_UPDATE_INTERVAL, - ) - - self._api_coro = api_coro - self._api_lock = api_lock - self._client = client - - self.config_entry = entry - self.signal_reboot_requested = SIGNAL_REBOOT_REQUESTED.format( - self.config_entry.entry_id - ) - - async def _async_update_data(self) -> dict[str, Any]: - """Execute a "locked" API request against the valve controller.""" - async with self._api_lock, self._client: - try: - resp = await self._api_coro() - except GuardianError as err: - raise UpdateFailed(err) from err - return cast(dict[str, Any], resp["data"]) - - async def async_initialize(self) -> None: - """Initialize the coordinator.""" - - @callback - def async_reboot_requested() -> None: - """Respond to a reboot request.""" - self.last_update_success = False - self.async_update_listeners() - - self.config_entry.async_on_unload( - async_dispatcher_connect( - self.hass, self.signal_reboot_requested, async_reboot_requested - ) - ) - - -_P = ParamSpec("_P") - - @callback def convert_exceptions_to_homeassistant_error( func: Callable[Concatenate[_GuardianEntityT, _P], Coroutine[Any, Any, Any]],