diff --git a/homeassistant/components/somfy/__init__.py b/homeassistant/components/somfy/__init__.py index 0a683a75374a..89cd65719e1b 100644 --- a/homeassistant/components/somfy/__init__.py +++ b/homeassistant/components/somfy/__init__.py @@ -4,7 +4,6 @@ import logging from pymfy.api.devices.category import Category -from requests import HTTPError import voluptuous as vol from homeassistant.components.somfy import config_flow @@ -17,22 +16,19 @@ ) from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType -from homeassistant.util import Throttle +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) from . import api -from .const import DOMAIN - -API = "api" - -DEVICES = "devices" +from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(minutes=1) -CONF_OPTIMISTIC = "optimistic" - SOMFY_AUTH_CALLBACK_PATH = "/auth/somfy/callback" SOMFY_AUTH_START = "/auth/somfy" @@ -88,15 +84,32 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): ) ) - hass.data[DOMAIN][API] = api.ConfigEntrySomfyApi(hass, entry, implementation) - hass.data[DOMAIN][DEVICES] = [] + data = hass.data[DOMAIN] + data[API] = api.ConfigEntrySomfyApi(hass, entry, implementation) + + async def _update_all_devices(): + """Update all the devices.""" + devices = await hass.async_add_executor_job(data[API].get_devices) + return {dev.id: dev for dev in devices} + + coordinator = DataUpdateCoordinator( + hass, + _LOGGER, + name="somfy device update", + update_method=_update_all_devices, + update_interval=SCAN_INTERVAL, + ) + data[COORDINATOR] = coordinator - await update_all_devices(hass) + await coordinator.async_refresh() device_registry = await dr.async_get_registry(hass) - devices = hass.data[DOMAIN][DEVICES] - hubs = [device for device in devices if Category.HUB.value in device.categories] + hubs = [ + device + for device in coordinator.data.values() + if Category.HUB.value in device.categories + ] for hub in hubs: device_registry.async_get_or_create( @@ -127,14 +140,20 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry): return True -class SomfyEntity(Entity): +class SomfyEntity(CoordinatorEntity, Entity): """Representation of a generic Somfy device.""" - def __init__(self, device, somfy_api): + def __init__(self, coordinator, device_id, somfy_api): """Initialize the Somfy device.""" - self.device = device + super().__init__(coordinator) + self._id = device_id self.api = somfy_api + @property + def device(self): + """Return data for the device id.""" + return self.coordinator.data[self._id] + @property def unique_id(self): """Return the unique id base on the id returned by Somfy.""" @@ -160,12 +179,6 @@ def device_info(self): "manufacturer": "Somfy", } - async def async_update(self): - """Update the device with the latest data.""" - await update_all_devices(self.hass) - devices = self.hass.data[DOMAIN][DEVICES] - self.device = next((d for d in devices if d.id == self.device.id), self.device) - def has_capability(self, capability): """Test if device has a capability.""" capabilities = self.device.capabilities @@ -175,13 +188,3 @@ def has_capability(self, capability): def assumed_state(self): """Return if the device has an assumed state.""" return not bool(self.device.states) - - -@Throttle(SCAN_INTERVAL) -async def update_all_devices(hass): - """Update all the devices.""" - try: - data = hass.data[DOMAIN] - data[DEVICES] = await hass.async_add_executor_job(data[API].get_devices) - except HTTPError as err: - _LOGGER.warning("Cannot update devices: %s", err.response.status_code) diff --git a/homeassistant/components/somfy/const.py b/homeassistant/components/somfy/const.py index 8765e37e6d68..aca93be66cb1 100644 --- a/homeassistant/components/somfy/const.py +++ b/homeassistant/components/somfy/const.py @@ -1,3 +1,6 @@ """Define constants for the Somfy component.""" DOMAIN = "somfy" +COORDINATOR = "coordinator" +API = "api" +CONF_OPTIMISTIC = "optimistic" diff --git a/homeassistant/components/somfy/cover.py b/homeassistant/components/somfy/cover.py index c577ecdc4844..2105f1ffe280 100644 --- a/homeassistant/components/somfy/cover.py +++ b/homeassistant/components/somfy/cover.py @@ -13,7 +13,8 @@ from homeassistant.const import STATE_CLOSED, STATE_OPEN from homeassistant.helpers.restore_state import RestoreEntity -from . import API, CONF_OPTIMISTIC, DEVICES, DOMAIN, SomfyEntity +from . import SomfyEntity +from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN BLIND_DEVICE_CATEGORIES = {Category.INTERIOR_BLIND.value, Category.EXTERIOR_BLIND.value} SHUTTER_DEVICE_CATEGORIES = {Category.EXTERIOR_BLIND.value} @@ -29,14 +30,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities): def get_covers(): """Retrieve covers.""" - devices = hass.data[DOMAIN][DEVICES] + domain_data = hass.data[DOMAIN] + coordinator = domain_data[COORDINATOR] + api = domain_data[API] return [ - SomfyCover( - cover, hass.data[DOMAIN][API], hass.data[DOMAIN][CONF_OPTIMISTIC] - ) - for cover in devices - if SUPPORTED_CATEGORIES & set(cover.categories) + SomfyCover(coordinator, device_id, api, domain_data[CONF_OPTIMISTIC]) + for device_id, device in coordinator.data.items() + if SUPPORTED_CATEGORIES & set(device.categories) ] async_add_entities(await hass.async_add_executor_job(get_covers)) @@ -45,11 +46,11 @@ def get_covers(): class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity): """Representation of a Somfy cover device.""" - def __init__(self, device, api, optimistic): + def __init__(self, coordinator, device_id, api, optimistic): """Initialize the Somfy device.""" - super().__init__(device, api) + super().__init__(coordinator, device_id, api) self.cover = Blind(self.device, self.api) - self.categories = set(device.categories) + self.categories = set(self.device.categories) self.optimistic = optimistic self._closed = None self._is_opening = None diff --git a/homeassistant/components/somfy/switch.py b/homeassistant/components/somfy/switch.py index e96c91ecaea0..2a81775cc22a 100644 --- a/homeassistant/components/somfy/switch.py +++ b/homeassistant/components/somfy/switch.py @@ -4,7 +4,8 @@ from homeassistant.components.switch import SwitchEntity -from . import API, DEVICES, DOMAIN, SomfyEntity +from . import SomfyEntity +from .const import API, COORDINATOR, DOMAIN async def async_setup_entry(hass, config_entry, async_add_entities): @@ -12,11 +13,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): def get_shutters(): """Retrieve switches.""" - devices = hass.data[DOMAIN][DEVICES] + domain_data = hass.data[DOMAIN] + coordinator = domain_data[COORDINATOR] + api = domain_data[API] return [ - SomfyCameraShutter(device, hass.data[DOMAIN][API]) - for device in devices + SomfyCameraShutter(coordinator, device_id, api) + for device_id, device in coordinator.data.items() if Category.CAMERA.value in device.categories ] @@ -26,9 +29,9 @@ def get_shutters(): class SomfyCameraShutter(SomfyEntity, SwitchEntity): """Representation of a Somfy Camera Shutter device.""" - def __init__(self, device, api): + def __init__(self, coordinator, device_id, api): """Initialize the Somfy device.""" - super().__init__(device, api) + super().__init__(coordinator, device_id, api) self.shutter = CameraProtect(self.device, self.api) async def async_update(self):