diff --git a/.coveragerc b/.coveragerc index 980b1b31877..233acc43635 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1352,6 +1352,7 @@ omit = homeassistant/components/supla/* homeassistant/components/surepetcare/__init__.py homeassistant/components/surepetcare/binary_sensor.py + homeassistant/components/surepetcare/coordinator.py homeassistant/components/surepetcare/entity.py homeassistant/components/surepetcare/sensor.py homeassistant/components/swiss_hydrological_data/sensor.py diff --git a/homeassistant/components/surepetcare/__init__.py b/homeassistant/components/surepetcare/__init__.py index b9e2bb6a410..e1f846d63a7 100644 --- a/homeassistant/components/surepetcare/__init__.py +++ b/homeassistant/components/surepetcare/__init__.py @@ -5,18 +5,15 @@ from __future__ import annotations from datetime import timedelta import logging -from surepy import Surepy, SurepyEntity -from surepy.enums import EntityType, Location, LockState +from surepy.enums import Location from surepy.exceptions import SurePetcareAuthenticationError, SurePetcareError import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME, Platform -from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import ( ATTR_FLAP_ID, @@ -26,8 +23,8 @@ from .const import ( DOMAIN, SERVICE_SET_LOCK_STATE, SERVICE_SET_PET_LOCATION, - SURE_API_TIMEOUT, ) +from .coordinator import SurePetcareDataCoordinator _LOGGER = logging.getLogger(__name__) @@ -101,61 +98,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok - - -class SurePetcareDataCoordinator(DataUpdateCoordinator[dict[int, SurepyEntity]]): # pylint: disable=hass-enforce-coordinator-module - """Handle Surepetcare data.""" - - def __init__(self, entry: ConfigEntry, hass: HomeAssistant) -> None: - """Initialize the data handler.""" - self.surepy = Surepy( - entry.data[CONF_USERNAME], - entry.data[CONF_PASSWORD], - auth_token=entry.data[CONF_TOKEN], - api_timeout=SURE_API_TIMEOUT, - session=async_get_clientsession(hass), - ) - self.lock_states_callbacks = { - LockState.UNLOCKED.name.lower(): self.surepy.sac.unlock, - LockState.LOCKED_IN.name.lower(): self.surepy.sac.lock_in, - LockState.LOCKED_OUT.name.lower(): self.surepy.sac.lock_out, - LockState.LOCKED_ALL.name.lower(): self.surepy.sac.lock, - } - super().__init__( - hass, - _LOGGER, - name=DOMAIN, - update_interval=SCAN_INTERVAL, - ) - - async def _async_update_data(self) -> dict[int, SurepyEntity]: - """Get the latest data from Sure Petcare.""" - try: - return await self.surepy.get_entities(refresh=True) - except SurePetcareAuthenticationError as err: - raise ConfigEntryAuthFailed("Invalid username/password") from err - except SurePetcareError as err: - raise UpdateFailed(f"Unable to fetch data: {err}") from err - - async def handle_set_lock_state(self, call: ServiceCall) -> None: - """Call when setting the lock state.""" - flap_id = call.data[ATTR_FLAP_ID] - state = call.data[ATTR_LOCK_STATE] - await self.lock_states_callbacks[state](flap_id) - await self.async_request_refresh() - - def get_pets(self) -> dict[str, int]: - """Get pets.""" - pets = {} - for surepy_entity in self.data.values(): - if surepy_entity.type == EntityType.PET and surepy_entity.name: - pets[surepy_entity.name] = surepy_entity.id - return pets - - async def handle_set_pet_location(self, call: ServiceCall) -> None: - """Call when setting the pet location.""" - pet_name = call.data[ATTR_PET_NAME] - location = call.data[ATTR_LOCATION] - device_id = self.get_pets()[pet_name] - await self.surepy.sac.set_pet_location(device_id, Location[location.upper()]) - await self.async_request_refresh() diff --git a/homeassistant/components/surepetcare/binary_sensor.py b/homeassistant/components/surepetcare/binary_sensor.py index 0c99985d514..b422e40ef2d 100644 --- a/homeassistant/components/surepetcare/binary_sensor.py +++ b/homeassistant/components/surepetcare/binary_sensor.py @@ -17,8 +17,8 @@ from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import SurePetcareDataCoordinator from .const import DOMAIN +from .coordinator import SurePetcareDataCoordinator from .entity import SurePetcareEntity diff --git a/homeassistant/components/surepetcare/coordinator.py b/homeassistant/components/surepetcare/coordinator.py new file mode 100644 index 00000000000..a80e96ad185 --- /dev/null +++ b/homeassistant/components/surepetcare/coordinator.py @@ -0,0 +1,88 @@ +"""Coordinator for the surepetcare integration.""" + +from __future__ import annotations + +from datetime import timedelta +import logging + +from surepy import Surepy, SurepyEntity +from surepy.enums import EntityType, Location, LockState +from surepy.exceptions import SurePetcareAuthenticationError, SurePetcareError + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME +from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import ( + ATTR_FLAP_ID, + ATTR_LOCATION, + ATTR_LOCK_STATE, + ATTR_PET_NAME, + DOMAIN, + SURE_API_TIMEOUT, +) + +_LOGGER = logging.getLogger(__name__) + +SCAN_INTERVAL = timedelta(minutes=3) + + +class SurePetcareDataCoordinator(DataUpdateCoordinator[dict[int, SurepyEntity]]): + """Handle Surepetcare data.""" + + def __init__(self, entry: ConfigEntry, hass: HomeAssistant) -> None: + """Initialize the data handler.""" + self.surepy = Surepy( + entry.data[CONF_USERNAME], + entry.data[CONF_PASSWORD], + auth_token=entry.data[CONF_TOKEN], + api_timeout=SURE_API_TIMEOUT, + session=async_get_clientsession(hass), + ) + self.lock_states_callbacks = { + LockState.UNLOCKED.name.lower(): self.surepy.sac.unlock, + LockState.LOCKED_IN.name.lower(): self.surepy.sac.lock_in, + LockState.LOCKED_OUT.name.lower(): self.surepy.sac.lock_out, + LockState.LOCKED_ALL.name.lower(): self.surepy.sac.lock, + } + super().__init__( + hass, + _LOGGER, + name=DOMAIN, + update_interval=SCAN_INTERVAL, + ) + + async def _async_update_data(self) -> dict[int, SurepyEntity]: + """Get the latest data from Sure Petcare.""" + try: + return await self.surepy.get_entities(refresh=True) + except SurePetcareAuthenticationError as err: + raise ConfigEntryAuthFailed("Invalid username/password") from err + except SurePetcareError as err: + raise UpdateFailed(f"Unable to fetch data: {err}") from err + + async def handle_set_lock_state(self, call: ServiceCall) -> None: + """Call when setting the lock state.""" + flap_id = call.data[ATTR_FLAP_ID] + state = call.data[ATTR_LOCK_STATE] + await self.lock_states_callbacks[state](flap_id) + await self.async_request_refresh() + + def get_pets(self) -> dict[str, int]: + """Get pets.""" + pets = {} + for surepy_entity in self.data.values(): + if surepy_entity.type == EntityType.PET and surepy_entity.name: + pets[surepy_entity.name] = surepy_entity.id + return pets + + async def handle_set_pet_location(self, call: ServiceCall) -> None: + """Call when setting the pet location.""" + pet_name = call.data[ATTR_PET_NAME] + location = call.data[ATTR_LOCATION] + device_id = self.get_pets()[pet_name] + await self.surepy.sac.set_pet_location(device_id, Location[location.upper()]) + await self.async_request_refresh() diff --git a/homeassistant/components/surepetcare/entity.py b/homeassistant/components/surepetcare/entity.py index 400f6a80ac9..312ae4730b0 100644 --- a/homeassistant/components/surepetcare/entity.py +++ b/homeassistant/components/surepetcare/entity.py @@ -10,8 +10,8 @@ from homeassistant.core import callback from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity -from . import SurePetcareDataCoordinator from .const import DOMAIN +from .coordinator import SurePetcareDataCoordinator class SurePetcareEntity(CoordinatorEntity[SurePetcareDataCoordinator]): diff --git a/homeassistant/components/surepetcare/lock.py b/homeassistant/components/surepetcare/lock.py index b933cc40637..cd79e06c5c3 100644 --- a/homeassistant/components/surepetcare/lock.py +++ b/homeassistant/components/surepetcare/lock.py @@ -13,8 +13,8 @@ from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import SurePetcareDataCoordinator from .const import DOMAIN +from .coordinator import SurePetcareDataCoordinator from .entity import SurePetcareEntity diff --git a/homeassistant/components/surepetcare/sensor.py b/homeassistant/components/surepetcare/sensor.py index 3618ac7d163..b4e7c6203a3 100644 --- a/homeassistant/components/surepetcare/sensor.py +++ b/homeassistant/components/surepetcare/sensor.py @@ -14,8 +14,8 @@ from homeassistant.const import ATTR_VOLTAGE, PERCENTAGE, EntityCategory, UnitOf from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import SurePetcareDataCoordinator from .const import DOMAIN, SURE_BATT_VOLTAGE_DIFF, SURE_BATT_VOLTAGE_LOW +from .coordinator import SurePetcareDataCoordinator from .entity import SurePetcareEntity