Convert somfy to use DataUpdateCoordinator (#42434)

This commit is contained in:
J. Nick Koston 2020-10-26 23:42:12 -05:00 committed by GitHub
parent f3a15eab6e
commit df25feab37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 60 deletions

View File

@ -4,7 +4,6 @@ from datetime import timedelta
import logging import logging
from pymfy.api.devices.category import Category from pymfy.api.devices.category import Category
from requests import HTTPError
import voluptuous as vol import voluptuous as vol
from homeassistant.components.somfy import config_flow from homeassistant.components.somfy import config_flow
@ -17,22 +16,19 @@ from homeassistant.helpers import (
) )
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import Throttle from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from . import api from . import api
from .const import DOMAIN from .const import API, CONF_OPTIMISTIC, COORDINATOR, DOMAIN
API = "api"
DEVICES = "devices"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(minutes=1) SCAN_INTERVAL = timedelta(minutes=1)
CONF_OPTIMISTIC = "optimistic"
SOMFY_AUTH_CALLBACK_PATH = "/auth/somfy/callback" SOMFY_AUTH_CALLBACK_PATH = "/auth/somfy/callback"
SOMFY_AUTH_START = "/auth/somfy" 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) data = hass.data[DOMAIN]
hass.data[DOMAIN][DEVICES] = [] data[API] = api.ConfigEntrySomfyApi(hass, entry, implementation)
await update_all_devices(hass) 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 coordinator.async_refresh()
device_registry = await dr.async_get_registry(hass) device_registry = await dr.async_get_registry(hass)
devices = hass.data[DOMAIN][DEVICES] hubs = [
hubs = [device for device in devices if Category.HUB.value in device.categories] device
for device in coordinator.data.values()
if Category.HUB.value in device.categories
]
for hub in hubs: for hub in hubs:
device_registry.async_get_or_create( device_registry.async_get_or_create(
@ -127,18 +140,24 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
return True return True
class SomfyEntity(Entity): class SomfyEntity(CoordinatorEntity, Entity):
"""Representation of a generic Somfy device.""" """Representation of a generic Somfy device."""
def __init__(self, device, somfy_api): def __init__(self, coordinator, device_id, somfy_api):
"""Initialize the Somfy device.""" """Initialize the Somfy device."""
self.device = device super().__init__(coordinator)
self._id = device_id
self.api = somfy_api self.api = somfy_api
@property
def device(self):
"""Return data for the device id."""
return self.coordinator.data[self._id]
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique id base on the id returned by Somfy.""" """Return the unique id base on the id returned by Somfy."""
return self.device.id return self._id
@property @property
def name(self): def name(self):
@ -160,12 +179,6 @@ class SomfyEntity(Entity):
"manufacturer": "Somfy", "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): def has_capability(self, capability):
"""Test if device has a capability.""" """Test if device has a capability."""
capabilities = self.device.capabilities capabilities = self.device.capabilities
@ -175,13 +188,3 @@ class SomfyEntity(Entity):
def assumed_state(self): def assumed_state(self):
"""Return if the device has an assumed state.""" """Return if the device has an assumed state."""
return not bool(self.device.states) 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)

View File

@ -1,3 +1,6 @@
"""Define constants for the Somfy component.""" """Define constants for the Somfy component."""
DOMAIN = "somfy" DOMAIN = "somfy"
COORDINATOR = "coordinator"
API = "api"
CONF_OPTIMISTIC = "optimistic"

View File

@ -13,7 +13,8 @@ from homeassistant.components.cover import (
from homeassistant.const import STATE_CLOSED, STATE_OPEN from homeassistant.const import STATE_CLOSED, STATE_OPEN
from homeassistant.helpers.restore_state import RestoreEntity 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} BLIND_DEVICE_CATEGORIES = {Category.INTERIOR_BLIND.value, Category.EXTERIOR_BLIND.value}
SHUTTER_DEVICE_CATEGORIES = {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(): def get_covers():
"""Retrieve covers.""" """Retrieve covers."""
devices = hass.data[DOMAIN][DEVICES] domain_data = hass.data[DOMAIN]
coordinator = domain_data[COORDINATOR]
api = domain_data[API]
return [ return [
SomfyCover( SomfyCover(coordinator, device_id, api, domain_data[CONF_OPTIMISTIC])
cover, hass.data[DOMAIN][API], hass.data[DOMAIN][CONF_OPTIMISTIC] for device_id, device in coordinator.data.items()
) if SUPPORTED_CATEGORIES & set(device.categories)
for cover in devices
if SUPPORTED_CATEGORIES & set(cover.categories)
] ]
async_add_entities(await hass.async_add_executor_job(get_covers)) async_add_entities(await hass.async_add_executor_job(get_covers))
@ -45,11 +46,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity): class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity):
"""Representation of a Somfy cover device.""" """Representation of a Somfy cover device."""
def __init__(self, device, api, optimistic): def __init__(self, coordinator, device_id, api, optimistic):
"""Initialize the Somfy device.""" """Initialize the Somfy device."""
super().__init__(device, api) super().__init__(coordinator, device_id, api)
self.cover = Blind(self.device, self.api) self.cover = Blind(self.device, self.api)
self.categories = set(device.categories) self.categories = set(self.device.categories)
self.optimistic = optimistic self.optimistic = optimistic
self._closed = None self._closed = None
self._is_opening = None self._is_opening = None
@ -163,7 +164,8 @@ class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Complete the initialization.""" """Complete the initialization."""
await super().async_added_to_hass() await super().async_added_to_hass()
if self.optimistic: if not self.optimistic:
return
# Restore the last state if we use optimistic # Restore the last state if we use optimistic
last_state = await self.async_get_last_state() last_state = await self.async_get_last_state()
@ -172,5 +174,3 @@ class SomfyCover(SomfyEntity, RestoreEntity, CoverEntity):
STATE_CLOSED, STATE_CLOSED,
): ):
self._closed = last_state.state == STATE_CLOSED self._closed = last_state.state == STATE_CLOSED
await self.async_update()

View File

@ -4,7 +4,8 @@ from pymfy.api.devices.category import Category
from homeassistant.components.switch import SwitchEntity 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): 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(): def get_shutters():
"""Retrieve switches.""" """Retrieve switches."""
devices = hass.data[DOMAIN][DEVICES] domain_data = hass.data[DOMAIN]
coordinator = domain_data[COORDINATOR]
api = domain_data[API]
return [ return [
SomfyCameraShutter(device, hass.data[DOMAIN][API]) SomfyCameraShutter(coordinator, device_id, api)
for device in devices for device_id, device in coordinator.data.items()
if Category.CAMERA.value in device.categories if Category.CAMERA.value in device.categories
] ]
@ -26,9 +29,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class SomfyCameraShutter(SomfyEntity, SwitchEntity): class SomfyCameraShutter(SomfyEntity, SwitchEntity):
"""Representation of a Somfy Camera Shutter device.""" """Representation of a Somfy Camera Shutter device."""
def __init__(self, device, api): def __init__(self, coordinator, device_id, api):
"""Initialize the Somfy device.""" """Initialize the Somfy device."""
super().__init__(device, api) super().__init__(coordinator, device_id, api)
self.shutter = CameraProtect(self.device, self.api) self.shutter = CameraProtect(self.device, self.api)
async def async_update(self): async def async_update(self):