From e9d601a688966758554dd1dfa2c4f9cd18d11d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hjelseth=20H=C3=B8yer?= Date: Sun, 17 Oct 2021 19:48:45 +0200 Subject: [PATCH] Opengarage dataupdater (#56931) --- .../components/opengarage/__init__.py | 43 ++++++++++++++++- homeassistant/components/opengarage/cover.py | 46 ++++++++++--------- 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/opengarage/__init__.py b/homeassistant/components/opengarage/__init__.py index 5ea3af79ae4..d64a608a3ef 100644 --- a/homeassistant/components/opengarage/__init__.py +++ b/homeassistant/components/opengarage/__init__.py @@ -1,15 +1,21 @@ """The OpenGarage integration.""" from __future__ import annotations +from datetime import timedelta +import logging + import opengarage from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PORT, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant +from homeassistant.helpers import update_coordinator from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import CONF_DEVICE_KEY, DOMAIN +_LOGGER = logging.getLogger(__name__) + PLATFORMS = ["cover"] @@ -17,12 +23,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up OpenGarage from a config entry.""" hass.data.setdefault(DOMAIN, {}) - hass.data[DOMAIN][entry.entry_id] = opengarage.OpenGarage( + open_garage_connection = opengarage.OpenGarage( f"{entry.data[CONF_HOST]}:{entry.data[CONF_PORT]}", entry.data[CONF_DEVICE_KEY], entry.data[CONF_VERIFY_SSL], async_get_clientsession(hass), ) + open_garage_data_coordinator = OpenGarageDataUpdateCoordinator( + hass, + open_garage_connection=open_garage_connection, + ) + await open_garage_data_coordinator.async_config_entry_first_refresh() + hass.data[DOMAIN][entry.entry_id] = open_garage_data_coordinator hass.config_entries.async_setup_platforms(entry, PLATFORMS) @@ -36,3 +48,32 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok + + +class OpenGarageDataUpdateCoordinator(update_coordinator.DataUpdateCoordinator): + """Class to manage fetching Opengarage data.""" + + def __init__( + self, + hass: HomeAssistant, + *, + open_garage_connection: opengarage.OpenGarage, + ) -> None: + """Initialize global Opengarage data updater.""" + self.open_garage_connection = open_garage_connection + + super().__init__( + hass, + _LOGGER, + name=DOMAIN, + update_interval=timedelta(seconds=30), + ) + + async def _async_update_data(self) -> None: + """Fetch data.""" + data = await self.open_garage_connection.update_state() + if data is None: + raise update_coordinator.UpdateFailed( + "Unable to connect to OpenGarage device" + ) + return data diff --git a/homeassistant/components/opengarage/cover.py b/homeassistant/components/opengarage/cover.py index ad3b2a4f74f..b80e1c82079 100644 --- a/homeassistant/components/opengarage/cover.py +++ b/homeassistant/components/opengarage/cover.py @@ -23,8 +23,10 @@ from homeassistant.const import ( STATE_OPEN, STATE_OPENING, ) +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( ATTR_DISTANCE_SENSOR, @@ -75,28 +77,26 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= async def async_setup_entry(hass, entry, async_add_entities): """Set up the OpenGarage covers.""" async_add_entities( - [OpenGarageCover(hass.data[DOMAIN][entry.entry_id], entry.unique_id)], True + [OpenGarageCover(hass.data[DOMAIN][entry.entry_id], entry.unique_id)] ) -class OpenGarageCover(CoverEntity): +class OpenGarageCover(CoordinatorEntity, CoverEntity): """Representation of a OpenGarage cover.""" _attr_device_class = DEVICE_CLASS_GARAGE _attr_supported_features = SUPPORT_OPEN | SUPPORT_CLOSE - def __init__(self, open_garage, device_id): + def __init__(self, open_garage_data_coordinator, device_id): """Initialize the cover.""" - self._open_garage = open_garage + super().__init__(open_garage_data_coordinator) + self._state = None self._state_before_move = None - self._extra_state_attributes = {} + self._attr_extra_state_attributes = {} self._attr_unique_id = self._device_id = device_id - - @property - def extra_state_attributes(self): - """Return the device state attributes.""" - return self._extra_state_attributes + self._device_name = None + self._update_attr() @property def is_closed(self): @@ -135,16 +135,16 @@ class OpenGarageCover(CoverEntity): self._state = STATE_OPENING await self._push_button() - async def async_update(self): - """Get updated status from API.""" - status = await self._open_garage.update_state() + @callback + def _update_attr(self) -> None: + """Update the state and attributes.""" + status = self.coordinator.data if status is None: _LOGGER.error("Unable to connect to OpenGarage device") self._attr_available = False return - if self.name is None and status["name"] is not None: - self._attr_name = status["name"] + self._device_name = self._attr_name = status["name"] state = STATES_MAP.get(status.get("door")) if self._state_before_move is not None: if self._state_before_move != state: @@ -155,17 +155,21 @@ class OpenGarageCover(CoverEntity): _LOGGER.debug("%s status: %s", self.name, self._state) if status.get("rssi") is not None: - self._extra_state_attributes[ATTR_SIGNAL_STRENGTH] = status.get("rssi") + self._attr_extra_state_attributes[ATTR_SIGNAL_STRENGTH] = status.get("rssi") if status.get("dist") is not None: - self._extra_state_attributes[ATTR_DISTANCE_SENSOR] = status.get("dist") + self._attr_extra_state_attributes[ATTR_DISTANCE_SENSOR] = status.get("dist") if self._state is not None: - self._extra_state_attributes[ATTR_DOOR_STATE] = self._state + self._attr_extra_state_attributes[ATTR_DOOR_STATE] = self._state - self._attr_available = True + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self._update_attr() + self.async_write_ha_state() async def _push_button(self): """Send commands to API.""" - result = await self._open_garage.push_button() + result = await self.coordinator.open_garage_connection.push_button() if result is None: _LOGGER.error("Unable to connect to OpenGarage device") if result == 1: @@ -184,7 +188,7 @@ class OpenGarageCover(CoverEntity): """Return the device_info of the device.""" device_info = DeviceInfo( identifiers={(DOMAIN, self._device_id)}, - name=self.name, + name=self._device_name, manufacturer="Open Garage", ) return device_info