Catch all Ring timeout errors (#30960)

* Catch more Ring errors

* Fix comment & Disable wifi entities by default
This commit is contained in:
Paulus Schoutsen 2020-01-19 13:39:16 -08:00 committed by GitHub
parent 8fcd0e9a79
commit ecef0f6e93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 11 deletions

View File

@ -7,6 +7,7 @@ from pathlib import Path
from typing import Optional from typing import Optional
from oauthlib.oauth2 import AccessDeniedError from oauthlib.oauth2 import AccessDeniedError
import requests
from ring_doorbell import Auth, Ring from ring_doorbell import Auth, Ring
import voluptuous as vol import voluptuous as vol
@ -95,13 +96,19 @@ async def async_setup_entry(hass, entry):
"api": ring, "api": ring,
"devices": ring.devices(), "devices": ring.devices(),
"device_data": GlobalDataUpdater( "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( "dings_data": GlobalDataUpdater(
hass, entry.entry_id, ring, "update_dings", timedelta(seconds=5) hass,
"active dings",
entry.entry_id,
ring,
"update_dings",
timedelta(seconds=5),
), ),
"history_data": DeviceDataUpdater( "history_data": DeviceDataUpdater(
hass, hass,
"history",
entry.entry_id, entry.entry_id,
ring, ring,
lambda device: device.history(limit=10), lambda device: device.history(limit=10),
@ -109,6 +116,7 @@ async def async_setup_entry(hass, entry):
), ),
"health_data": DeviceDataUpdater( "health_data": DeviceDataUpdater(
hass, hass,
"health",
entry.entry_id, entry.entry_id,
ring, ring,
lambda device: device.update_health_data(), lambda device: device.update_health_data(),
@ -168,6 +176,7 @@ class GlobalDataUpdater:
def __init__( def __init__(
self, self,
hass: HomeAssistant, hass: HomeAssistant,
data_type: str,
config_entry_id: str, config_entry_id: str,
ring: Ring, ring: Ring,
update_method: str, update_method: str,
@ -175,6 +184,7 @@ class GlobalDataUpdater:
): ):
"""Initialize global data updater.""" """Initialize global data updater."""
self.hass = hass self.hass = hass
self.data_type = data_type
self.config_entry_id = config_entry_id self.config_entry_id = config_entry_id
self.ring = ring self.ring = ring
self.update_method = update_method self.update_method = update_method
@ -215,6 +225,11 @@ class GlobalDataUpdater:
_LOGGER.error("Ring access token is no longer valid. Set up Ring again") _LOGGER.error("Ring access token is no longer valid. Set up Ring again")
await self.hass.config_entries.async_unload(self.config_entry_id) await self.hass.config_entries.async_unload(self.config_entry_id)
return return
except requests.Timeout:
_LOGGER.warning(
"Time out fetching Ring %s data", self.data_type,
)
return
for update_callback in self.listeners: for update_callback in self.listeners:
update_callback() update_callback()
@ -226,12 +241,14 @@ class DeviceDataUpdater:
def __init__( def __init__(
self, self,
hass: HomeAssistant, hass: HomeAssistant,
data_type: str,
config_entry_id: str, config_entry_id: str,
ring: Ring, ring: Ring,
update_method: str, update_method: str,
update_interval: timedelta, update_interval: timedelta,
): ):
"""Initialize device data updater.""" """Initialize device data updater."""
self.data_type = data_type
self.hass = hass self.hass = hass
self.config_entry_id = config_entry_id self.config_entry_id = config_entry_id
self.ring = ring self.ring = ring
@ -282,7 +299,7 @@ class DeviceDataUpdater:
def refresh_all(self, _=None): def refresh_all(self, _=None):
"""Refresh all registered devices.""" """Refresh all registered devices."""
for info in self.devices.values(): for device_id, info in self.devices.items():
try: try:
data = info["data"] = self.update_method(info["device"]) data = info["data"] = self.update_method(info["device"])
except AccessDeniedError: except AccessDeniedError:
@ -291,6 +308,13 @@ class DeviceDataUpdater:
self.hass.config_entries.async_unload(self.config_entry_id) self.hass.config_entries.async_unload(self.config_entry_id)
) )
return 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"]: for update_callback in info["update_callbacks"]:
self.hass.loop.call_soon_threadsafe(update_callback, data) self.hass.loop.call_soon_threadsafe(update_callback, data)

View File

@ -2,6 +2,8 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
import requests
from homeassistant.components.light import Light from homeassistant.components.light import Light
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -72,7 +74,12 @@ class RingLight(RingEntityMixin, Light):
def _set_light(self, new_state): def _set_light(self, new_state):
"""Update light state, and causes Home Assistant to correctly update.""" """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._light_on = new_state == ON_STATE
self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()

View File

@ -15,9 +15,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a sensor for a Ring device.""" """Set up a sensor for a Ring device."""
devices = hass.data[DOMAIN][config_entry.entry_id]["devices"] 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 = [] sensors = []
for device_type in ("chimes", "doorbots", "authorized_doorbots", "stickup_cams"): 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]: if device_type not in SENSOR_TYPES[sensor_type][1]:
continue continue
if not wifi_enabled and sensor_type.startswith("wifi_"):
continue
for device in devices[device_type]: for device in devices[device_type]:
if device_type == "battery" and device.battery_life is None: if device_type == "battery" and device.battery_life is None:
continue continue
@ -124,6 +118,12 @@ class HealthDataRingSensor(RingSensor):
"""Call update method.""" """Call update method."""
self.async_write_ha_state() 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 @property
def state(self): def state(self):
"""Return the state of the sensor.""" """Return the state of the sensor."""

View File

@ -2,6 +2,8 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
import requests
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -74,7 +76,12 @@ class SirenSwitch(BaseRingSwitch):
def _set_switch(self, new_state): def _set_switch(self, new_state):
"""Update switch state, and causes Home Assistant to correctly update.""" """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._siren_on = new_state > 0
self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY self._no_updates_until = dt_util.utcnow() + SKIP_UPDATES_DELAY
self.schedule_update_ha_state() self.schedule_update_ha_state()