Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert somfy to use DataUpdateCoordinator #42434

Merged
merged 1 commit into from Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 37 additions & 34 deletions homeassistant/components/somfy/__init__.py
Expand Up @@ -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
Expand All @@ -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"

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -127,18 +140,24 @@ 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."""
return self.device.id
return self._id

@property
def name(self):
Expand All @@ -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
Expand All @@ -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)
3 changes: 3 additions & 0 deletions homeassistant/components/somfy/const.py
@@ -1,3 +1,6 @@
"""Define constants for the Somfy component."""

DOMAIN = "somfy"
COORDINATOR = "coordinator"
API = "api"
CONF_OPTIMISTIC = "optimistic"
42 changes: 21 additions & 21 deletions homeassistant/components/somfy/cover.py
Expand Up @@ -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}
Expand All @@ -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))
Expand All @@ -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)
bdraco marked this conversation as resolved.
Show resolved Hide resolved
self.categories = set(device.categories)
self.categories = set(self.device.categories)
self.optimistic = optimistic
self._closed = None
self._is_opening = None
Expand Down Expand Up @@ -163,14 +164,13 @@ def stop_cover_tilt(self, **kwargs):
async def async_added_to_hass(self):
"""Complete the initialization."""
await super().async_added_to_hass()
if self.optimistic:
# Restore the last state if we use optimistic
last_state = await self.async_get_last_state()

if last_state is not None and last_state.state in (
STATE_OPEN,
STATE_CLOSED,
):
self._closed = last_state.state == STATE_CLOSED

await self.async_update()
if not self.optimistic:
return
# Restore the last state if we use optimistic
last_state = await self.async_get_last_state()

if last_state is not None and last_state.state in (
STATE_OPEN,
STATE_CLOSED,
):
self._closed = last_state.state == STATE_CLOSED
15 changes: 9 additions & 6 deletions homeassistant/components/somfy/switch.py
Expand Up @@ -4,19 +4,22 @@

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):
"""Set up the Somfy switch platform."""

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
]

Expand All @@ -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)
bdraco marked this conversation as resolved.
Show resolved Hide resolved

async def async_update(self):
Expand Down