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 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/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/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/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 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() 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( 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) 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