From dead2fe57655f91c3c1d35102e4abe01f5ac7f51 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Jan 2020 13:39:16 -0800 Subject: [PATCH 1/6] Catch all Ring timeout errors (#30960) * Catch more Ring errors * Fix comment & Disable wifi entities by default Signed-off-by: Franck Nijhof --- homeassistant/components/ring/__init__.py | 30 ++++++++++++++++++++--- homeassistant/components/ring/light.py | 9 ++++++- homeassistant/components/ring/sensor.py | 12 ++++----- homeassistant/components/ring/switch.py | 9 ++++++- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/ring/__init__.py b/homeassistant/components/ring/__init__.py index 7b4fbb15b30..34aa9f6b0ec 100644 --- a/homeassistant/components/ring/__init__.py +++ b/homeassistant/components/ring/__init__.py @@ -7,6 +7,7 @@ from pathlib import Path from typing import Optional from oauthlib.oauth2 import AccessDeniedError +import requests from ring_doorbell import Auth, Ring import voluptuous as vol @@ -95,13 +96,19 @@ async def async_setup_entry(hass, entry): "api": ring, "devices": ring.devices(), "device_data": GlobalDataUpdater( - hass, entry.entry_id, ring, "update_devices", timedelta(minutes=1) + hass, "device", entry.entry_id, ring, "update_devices", timedelta(minutes=1) ), "dings_data": GlobalDataUpdater( - hass, entry.entry_id, ring, "update_dings", timedelta(seconds=10) + hass, + "active dings", + entry.entry_id, + ring, + "update_dings", + timedelta(seconds=5), ), "history_data": DeviceDataUpdater( hass, + "history", entry.entry_id, ring, lambda device: device.history(limit=10), @@ -109,6 +116,7 @@ async def async_setup_entry(hass, entry): ), "health_data": DeviceDataUpdater( hass, + "health", entry.entry_id, ring, lambda device: device.update_health_data(), @@ -168,6 +176,7 @@ class GlobalDataUpdater: def __init__( self, hass: HomeAssistant, + data_type: str, config_entry_id: str, ring: Ring, update_method: str, @@ -175,6 +184,7 @@ class GlobalDataUpdater: ): """Initialize global data updater.""" self.hass = hass + self.data_type = data_type self.config_entry_id = config_entry_id self.ring = ring self.update_method = update_method @@ -215,6 +225,11 @@ class GlobalDataUpdater: _LOGGER.error("Ring access token is no longer valid. Set up Ring again") await self.hass.config_entries.async_unload(self.config_entry_id) return + except requests.Timeout: + _LOGGER.warning( + "Time out fetching Ring %s data", self.data_type, + ) + return for update_callback in self.listeners: update_callback() @@ -226,12 +241,14 @@ class DeviceDataUpdater: def __init__( self, hass: HomeAssistant, + data_type: str, config_entry_id: str, ring: Ring, update_method: str, update_interval: timedelta, ): """Initialize device data updater.""" + self.data_type = data_type self.hass = hass self.config_entry_id = config_entry_id self.ring = ring @@ -282,7 +299,7 @@ class DeviceDataUpdater: def refresh_all(self, _=None): """Refresh all registered devices.""" - for info in self.devices.values(): + for device_id, info in self.devices.items(): try: data = info["data"] = self.update_method(info["device"]) except AccessDeniedError: @@ -291,6 +308,13 @@ class DeviceDataUpdater: self.hass.config_entries.async_unload(self.config_entry_id) ) return + except requests.Timeout: + _LOGGER.warning( + "Time out fetching Ring %s data for device %s", + self.data_type, + device_id, + ) + continue for update_callback in info["update_callbacks"]: self.hass.loop.call_soon_threadsafe(update_callback, data) diff --git a/homeassistant/components/ring/light.py b/homeassistant/components/ring/light.py index 86ef55af16d..fa47ac35ee3 100644 --- a/homeassistant/components/ring/light.py +++ b/homeassistant/components/ring/light.py @@ -2,6 +2,8 @@ from datetime import timedelta import logging +import requests + from homeassistant.components.light import Light from homeassistant.core import callback import homeassistant.util.dt as dt_util @@ -72,7 +74,12 @@ class RingLight(RingEntityMixin, Light): def _set_light(self, new_state): """Update light state, and causes Home Assistant to correctly update.""" - self._device.lights = new_state + try: + self._device.lights = new_state + except requests.Timeout: + _LOGGER.error("Time out setting %s light to %s", self.entity_id, new_state) + return + self._light_on = new_state == ON_STATE self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY self.async_schedule_update_ha_state() diff --git a/homeassistant/components/ring/sensor.py b/homeassistant/components/ring/sensor.py index 2b921dddd2f..329077a18e7 100644 --- a/homeassistant/components/ring/sensor.py +++ b/homeassistant/components/ring/sensor.py @@ -15,9 +15,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): """Set up a sensor for a Ring device.""" devices = hass.data[DOMAIN][config_entry.entry_id]["devices"] - # Makes a ton of requests. We will make this a config entry option in the future - wifi_enabled = False - sensors = [] for device_type in ("chimes", "doorbots", "authorized_doorbots", "stickup_cams"): @@ -25,9 +22,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if device_type not in SENSOR_TYPES[sensor_type][1]: continue - if not wifi_enabled and sensor_type.startswith("wifi_"): - continue - for device in devices[device_type]: if device_type == "battery" and device.battery_life is None: continue @@ -124,6 +118,12 @@ class HealthDataRingSensor(RingSensor): """Call update method.""" self.async_write_ha_state() + @property + def entity_registry_enabled_default(self) -> bool: + """Return if the entity should be enabled when first added to the entity registry.""" + # These sensors are data hungry and not useful. Disable by default. + return False + @property def state(self): """Return the state of the sensor.""" diff --git a/homeassistant/components/ring/switch.py b/homeassistant/components/ring/switch.py index 65eed83d98e..e2f1882adf6 100644 --- a/homeassistant/components/ring/switch.py +++ b/homeassistant/components/ring/switch.py @@ -2,6 +2,8 @@ from datetime import timedelta import logging +import requests + from homeassistant.components.switch import SwitchDevice from homeassistant.core import callback import homeassistant.util.dt as dt_util @@ -74,7 +76,12 @@ class SirenSwitch(BaseRingSwitch): def _set_switch(self, new_state): """Update switch state, and causes Home Assistant to correctly update.""" - self._device.siren = new_state + try: + self._device.siren = new_state + except requests.Timeout: + _LOGGER.error("Time out setting %s siren to %s", self.entity_id, new_state) + return + self._siren_on = new_state > 0 self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY self.schedule_update_ha_state() From dde6220ca59f4fb2f07afc06e227279568906b82 Mon Sep 17 00:00:00 2001 From: Jan De Luyck <5451787+jdeluyck@users.noreply.github.com> Date: Sun, 19 Jan 2020 21:01:16 +0100 Subject: [PATCH 2/6] Update emulated_roku to 0.2.0 (#30974) --- homeassistant/components/emulated_roku/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/emulated_roku/manifest.json b/homeassistant/components/emulated_roku/manifest.json index 62d51d7d910..8b5925fd12f 100644 --- a/homeassistant/components/emulated_roku/manifest.json +++ b/homeassistant/components/emulated_roku/manifest.json @@ -3,7 +3,7 @@ "name": "Emulated Roku", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/emulated_roku", - "requirements": ["emulated_roku==0.1.9"], + "requirements": ["emulated_roku==0.2.0"], "dependencies": [], "codeowners": [] } diff --git a/requirements_all.txt b/requirements_all.txt index bddb1908b85..053bfbd9cf7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -477,7 +477,7 @@ eliqonline==1.2.2 elkm1-lib==0.7.15 # homeassistant.components.emulated_roku -emulated_roku==0.1.9 +emulated_roku==0.2.0 # homeassistant.components.enocean enocean==0.50 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cc9f3e97e85..f52cc125f92 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -171,7 +171,7 @@ eebrightbox==0.0.4 elgato==0.2.0 # homeassistant.components.emulated_roku -emulated_roku==0.1.9 +emulated_roku==0.2.0 # homeassistant.components.season ephem==3.7.7.0 From 6889816704817e584ccdbd98a41b7186e3d8f4ad Mon Sep 17 00:00:00 2001 From: steve-gombos <3118886+steve-gombos@users.noreply.github.com> Date: Sun, 19 Jan 2020 16:18:11 -0500 Subject: [PATCH 3/6] Ring camera fix (#30975) * Fix ring camera entities * Reverted test refresh interval * Fix black errors --- homeassistant/components/ring/camera.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/ring/camera.py b/homeassistant/components/ring/camera.py index 1526a915482..96b1a962a67 100644 --- a/homeassistant/components/ring/camera.py +++ b/homeassistant/components/ring/camera.py @@ -51,8 +51,7 @@ class RingCam(RingEntityMixin, Camera): self._last_event = None self._last_video_id = None self._video_url = None - self._utcnow = dt_util.utcnow() - self._expires_at = self._utcnow - FORCE_REFRESH_INTERVAL + self._expires_at = dt_util.utcnow() - FORCE_REFRESH_INTERVAL async def async_added_to_hass(self): """Register callbacks.""" @@ -80,7 +79,7 @@ class RingCam(RingEntityMixin, Camera): self._last_event = None self._last_video_id = None self._video_url = None - self._expires_at = self._utcnow + self._expires_at = dt_util.utcnow() self.async_write_ha_state() @property @@ -141,10 +140,8 @@ class RingCam(RingEntityMixin, Camera): if self._last_event["recording"]["status"] != "ready": return - if ( - self._last_video_id == self._last_event["id"] - and self._utcnow <= self._expires_at - ): + utcnow = dt_util.utcnow() + if self._last_video_id == self._last_event["id"] and utcnow <= self._expires_at: return try: @@ -160,4 +157,4 @@ class RingCam(RingEntityMixin, Camera): if video_url: self._last_video_id = self._last_event["id"] self._video_url = video_url - self._expires_at = FORCE_REFRESH_INTERVAL + self._utcnow + self._expires_at = FORCE_REFRESH_INTERVAL + utcnow From 392cf57750816901fa3892ef67c820f6cfe05247 Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Sun, 19 Jan 2020 23:06:35 -0800 Subject: [PATCH 4/6] Fix capability_attributes when supported_features is None (#30993) * Fix capability_attributes when supported_features is None (water_heater) * Fix capability_attributes when supported_features is None (media_player) --- homeassistant/components/media_player/__init__.py | 2 +- homeassistant/components/water_heater/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 83c117d6c05..b73208402f8 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -785,7 +785,7 @@ class MediaPlayerDevice(Entity): @property def capability_attributes(self): """Return capabilitiy attributes.""" - supported_features = self.supported_features + supported_features = self.supported_features or 0 data = {} if supported_features & SUPPORT_SELECT_SOURCE: diff --git a/homeassistant/components/water_heater/__init__.py b/homeassistant/components/water_heater/__init__.py index 8da94ff1098..ecff3105ae0 100644 --- a/homeassistant/components/water_heater/__init__.py +++ b/homeassistant/components/water_heater/__init__.py @@ -146,7 +146,7 @@ class WaterHeaterDevice(Entity): @property def capability_attributes(self): """Return capabilitiy attributes.""" - supported_features = self.supported_features + supported_features = self.supported_features or 0 data = { ATTR_MIN_TEMP: show_temp( From ccf6ce71cfbc18ea618cd5700134b86699ff18bd Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 20 Jan 2020 17:18:10 +0100 Subject: [PATCH 5/6] Fix deCONZ update entry from Hassio discovery (#31015) * Fix deCONZ update entry from Hassio discovery * Empty commit to re-trigger build --- homeassistant/components/deconz/config_flow.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index 5a9ef232e61..43c6cee9193 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -216,15 +216,15 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): This flow is triggered by the discovery component. """ self.bridge_id = normalize_bridge_id(user_input[CONF_SERIAL]) - gateway = self.hass.data.get(DOMAIN, {}).get(self.bridge_id) - if gateway: - return self._update_entry( - gateway.config_entry, - user_input[CONF_HOST], - user_input[CONF_PORT], - user_input[CONF_API_KEY], - ) + for entry in self.hass.config_entries.async_entries(DOMAIN): + if self.bridge_id == entry.unique_id: + return self._update_entry( + entry, + user_input[CONF_HOST], + user_input[CONF_PORT], + user_input[CONF_API_KEY], + ) await self.async_set_unique_id(self.bridge_id) self._hassio_discovery = user_input From cfa74039bb91288de71cf0aa1e743ddee4fd25fc Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 21 Jan 2020 12:18:07 +0100 Subject: [PATCH 6/6] Bumped version to 0.104.3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index e2dfdf5ef64..4f6d643b531 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 104 -PATCH_VERSION = "2" +PATCH_VERSION = "3" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0)