From b4d39d517f945e85bf886cdd629ba320dffb4e54 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Fri, 26 Mar 2021 04:06:40 +0100 Subject: [PATCH] Update in 1 minute on unavailable Motion blinds (#47800) * if unavailable request update in 1 minute * fix styling * improve changing update interval * remove unused import * try to fix * remove unused pass * add const * fix missing timedelta * update to motionblinds 0.4.10 * improve update coordinator * fix linting errors * remove unused import * move update functions within the DataUpdateCoordinator * fix white space --- .../components/motion_blinds/__init__.py | 89 +++++++++++++++---- .../components/motion_blinds/const.py | 4 + .../components/motion_blinds/cover.py | 9 +- .../components/motion_blinds/manifest.json | 2 +- .../components/motion_blinds/sensor.py | 18 +++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 7 files changed, 103 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/motion_blinds/__init__.py b/homeassistant/components/motion_blinds/__init__.py index f57d31b47d3..d4a5dd1f79b 100644 --- a/homeassistant/components/motion_blinds/__init__.py +++ b/homeassistant/components/motion_blinds/__init__.py @@ -1,11 +1,11 @@ """The motion_blinds component.""" import asyncio -from contextlib import suppress from datetime import timedelta import logging from socket import timeout from motionblinds import MotionMulticast +from motionblinds.motion_blinds import ParseException from homeassistant import config_entries, core from homeassistant.const import CONF_API_KEY, CONF_HOST, EVENT_HOMEASSISTANT_STOP @@ -14,18 +14,87 @@ from homeassistant.helpers import device_registry as dr from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import ( + ATTR_AVAILABLE, DOMAIN, KEY_COORDINATOR, KEY_GATEWAY, KEY_MULTICAST_LISTENER, MANUFACTURER, PLATFORMS, + UPDATE_INTERVAL, + UPDATE_INTERVAL_FAST, ) from .gateway import ConnectMotionGateway _LOGGER = logging.getLogger(__name__) +class DataUpdateCoordinatorMotionBlinds(DataUpdateCoordinator): + """Class to manage fetching data from single endpoint.""" + + def __init__( + self, + hass, + logger, + gateway, + *, + name, + update_interval=None, + update_method=None, + ): + """Initialize global data updater.""" + super().__init__( + hass, + logger, + name=name, + update_method=update_method, + update_interval=update_interval, + ) + + self._gateway = gateway + + def update_gateway(self): + """Call all updates using one async_add_executor_job.""" + data = {} + + try: + self._gateway.Update() + except (timeout, ParseException): + # let the error be logged and handled by the motionblinds library + data[KEY_GATEWAY] = {ATTR_AVAILABLE: False} + return data + else: + data[KEY_GATEWAY] = {ATTR_AVAILABLE: True} + + for blind in self._gateway.device_list.values(): + try: + blind.Update() + except (timeout, ParseException): + # let the error be logged and handled by the motionblinds library + data[blind.mac] = {ATTR_AVAILABLE: False} + else: + data[blind.mac] = {ATTR_AVAILABLE: True} + + return data + + async def _async_update_data(self): + """Fetch the latest data from the gateway and blinds.""" + data = await self.hass.async_add_executor_job(self.update_gateway) + + all_available = True + for device in data.values(): + if not device[ATTR_AVAILABLE]: + all_available = False + break + + if all_available: + self.update_interval = timedelta(seconds=UPDATE_INTERVAL) + else: + self.update_interval = timedelta(seconds=UPDATE_INTERVAL_FAST) + + return data + + def setup(hass: core.HomeAssistant, config: dict): """Set up the Motion Blinds component.""" return True @@ -61,26 +130,14 @@ async def async_setup_entry( raise ConfigEntryNotReady motion_gateway = connect_gateway_class.gateway_device - def update_gateway(): - """Call all updates using one async_add_executor_job.""" - motion_gateway.Update() - for blind in motion_gateway.device_list.values(): - with suppress(timeout): - blind.Update() - - async def async_update_data(): - """Fetch data from the gateway and blinds.""" - with suppress(timeout): # Let the error be handled by the motionblinds - await hass.async_add_executor_job(update_gateway) - - coordinator = DataUpdateCoordinator( + coordinator = DataUpdateCoordinatorMotionBlinds( hass, _LOGGER, + motion_gateway, # Name of the data. For logging purposes. name=entry.title, - update_method=async_update_data, # Polling interval. Will only be polled if there are subscribers. - update_interval=timedelta(seconds=600), + update_interval=timedelta(seconds=UPDATE_INTERVAL), ) # Fetch initial data so we have data when entities subscribe diff --git a/homeassistant/components/motion_blinds/const.py b/homeassistant/components/motion_blinds/const.py index 4b1f0ee0527..52c6e39b096 100644 --- a/homeassistant/components/motion_blinds/const.py +++ b/homeassistant/components/motion_blinds/const.py @@ -11,5 +11,9 @@ KEY_MULTICAST_LISTENER = "multicast_listener" ATTR_WIDTH = "width" ATTR_ABSOLUTE_POSITION = "absolute_position" +ATTR_AVAILABLE = "available" SERVICE_SET_ABSOLUTE_POSITION = "set_absolute_position" + +UPDATE_INTERVAL = 600 +UPDATE_INTERVAL_FAST = 60 diff --git a/homeassistant/components/motion_blinds/cover.py b/homeassistant/components/motion_blinds/cover.py index 4ac09a5fd11..2c4fee5f8aa 100644 --- a/homeassistant/components/motion_blinds/cover.py +++ b/homeassistant/components/motion_blinds/cover.py @@ -21,6 +21,7 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( ATTR_ABSOLUTE_POSITION, + ATTR_AVAILABLE, ATTR_WIDTH, DOMAIN, KEY_COORDINATOR, @@ -160,7 +161,13 @@ class MotionPositionDevice(CoordinatorEntity, CoverEntity): @property def available(self): """Return True if entity is available.""" - return self._blind.available + if self.coordinator.data is None: + return False + + if not self.coordinator.data[KEY_GATEWAY][ATTR_AVAILABLE]: + return False + + return self.coordinator.data[self._blind.mac][ATTR_AVAILABLE] @property def current_cover_position(self): diff --git a/homeassistant/components/motion_blinds/manifest.json b/homeassistant/components/motion_blinds/manifest.json index ec2823dbd2e..c144dc99bc5 100644 --- a/homeassistant/components/motion_blinds/manifest.json +++ b/homeassistant/components/motion_blinds/manifest.json @@ -3,6 +3,6 @@ "name": "Motion Blinds", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/motion_blinds", - "requirements": ["motionblinds==0.4.8"], + "requirements": ["motionblinds==0.4.10"], "codeowners": ["@starkillerOG"] } diff --git a/homeassistant/components/motion_blinds/sensor.py b/homeassistant/components/motion_blinds/sensor.py index 5d7a29bf9da..d7f40337cec 100644 --- a/homeassistant/components/motion_blinds/sensor.py +++ b/homeassistant/components/motion_blinds/sensor.py @@ -10,7 +10,7 @@ from homeassistant.const import ( ) from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN, KEY_COORDINATOR, KEY_GATEWAY +from .const import ATTR_AVAILABLE, DOMAIN, KEY_COORDINATOR, KEY_GATEWAY ATTR_BATTERY_VOLTAGE = "battery_voltage" TYPE_BLIND = "blind" @@ -70,7 +70,13 @@ class MotionBatterySensor(CoordinatorEntity, SensorEntity): @property def available(self): """Return True if entity is available.""" - return self._blind.available + if self.coordinator.data is None: + return False + + if not self.coordinator.data[KEY_GATEWAY][ATTR_AVAILABLE]: + return False + + return self.coordinator.data[self._blind.mac][ATTR_AVAILABLE] @property def unit_of_measurement(self): @@ -174,7 +180,13 @@ class MotionSignalStrengthSensor(CoordinatorEntity, SensorEntity): @property def available(self): """Return True if entity is available.""" - return self._device.available + if self.coordinator.data is None: + return False + + if not self.coordinator.data[KEY_GATEWAY][ATTR_AVAILABLE]: + return False + + return self.coordinator.data[self._device.mac][ATTR_AVAILABLE] @property def unit_of_measurement(self): diff --git a/requirements_all.txt b/requirements_all.txt index d40244074a9..db05a88e9f7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -946,7 +946,7 @@ minio==4.0.9 mitemp_bt==0.0.3 # homeassistant.components.motion_blinds -motionblinds==0.4.8 +motionblinds==0.4.10 # homeassistant.components.mullvad mullvad-api==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 149c156f4cc..e641de25fb8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -491,7 +491,7 @@ millheater==0.4.0 minio==4.0.9 # homeassistant.components.motion_blinds -motionblinds==0.4.8 +motionblinds==0.4.10 # homeassistant.components.mullvad mullvad-api==1.0.0