Centralize wemo exception handling (#46705)

This commit is contained in:
Eric Severance 2021-02-17 14:36:39 -08:00 committed by GitHub
parent b2df9aaaf1
commit 8bee3cda37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 92 deletions

View file

@ -2,8 +2,6 @@
import asyncio
import logging
from pywemo.ouimeaux_device.api.service import ActionException
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -35,12 +33,5 @@ class WemoBinarySensor(WemoSubscriptionEntity, BinarySensorEntity):
def _update(self, force_update=True):
"""Update the sensor state."""
try:
with self._wemo_exception_handler("update status"):
self._state = self.wemo.get_state(force_update)
if not self._available:
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
except ActionException as err:
_LOGGER.warning("Could not update status for %s (%s)", self.name, err)
self._available = False

View file

@ -1,10 +1,12 @@
"""Classes shared among Wemo entities."""
import asyncio
import contextlib
import logging
from typing import Any, Dict, Optional
from typing import Any, Dict, Generator, Optional
import async_timeout
from pywemo import WeMoDevice
from pywemo.ouimeaux_device.api.service import ActionException
from homeassistant.helpers.entity import Entity
@ -13,6 +15,18 @@ from .const import DOMAIN as WEMO_DOMAIN
_LOGGER = logging.getLogger(__name__)
class ExceptionHandlerStatus:
"""Exit status from the _wemo_exception_handler context manager."""
# An exception if one was raised in the _wemo_exception_handler.
exception: Optional[Exception] = None
@property
def success(self) -> bool:
"""Return True if the handler completed with no exception."""
return self.exception is None
class WemoEntity(Entity):
"""Common methods for Wemo entities.
@ -36,6 +50,23 @@ class WemoEntity(Entity):
"""Return true if switch is available."""
return self._available
@contextlib.contextmanager
def _wemo_exception_handler(
self, message: str
) -> Generator[ExceptionHandlerStatus, None, None]:
"""Wrap device calls to set `_available` when wemo exceptions happen."""
status = ExceptionHandlerStatus()
try:
yield status
except ActionException as err:
status.exception = err
_LOGGER.warning("Could not %s for %s (%s)", message, self.name, err)
self._available = False
else:
if not self._available:
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
def _update(self, force_update: Optional[bool] = True):
"""Update the device state."""
raise NotImplementedError()

View file

@ -4,7 +4,6 @@ from datetime import timedelta
import logging
import math
from pywemo.ouimeaux_device.api.service import ActionException
import voluptuous as vol
from homeassistant.components.fan import SUPPORT_SET_SPEED, FanEntity
@ -138,7 +137,7 @@ class WemoHumidifier(WemoSubscriptionEntity, FanEntity):
def _update(self, force_update=True):
"""Update the device state."""
try:
with self._wemo_exception_handler("update status"):
self._state = self.wemo.get_state(force_update)
self._fan_mode = self.wemo.fan_mode
@ -152,13 +151,6 @@ class WemoHumidifier(WemoSubscriptionEntity, FanEntity):
if self.wemo.fan_mode != WEMO_FAN_OFF:
self._last_fan_on_mode = self.wemo.fan_mode
if not self._available:
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
except ActionException as err:
_LOGGER.warning("Could not update status for %s (%s)", self.name, err)
self._available = False
def turn_on(
self,
speed: str = None,
@ -171,11 +163,8 @@ class WemoHumidifier(WemoSubscriptionEntity, FanEntity):
def turn_off(self, **kwargs) -> None:
"""Turn the switch off."""
try:
with self._wemo_exception_handler("turn off"):
self.wemo.set_state(WEMO_FAN_OFF)
except ActionException as err:
_LOGGER.warning("Error while turning off device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
@ -188,13 +177,8 @@ class WemoHumidifier(WemoSubscriptionEntity, FanEntity):
else:
named_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
try:
with self._wemo_exception_handler("set speed"):
self.wemo.set_state(named_speed)
except ActionException as err:
_LOGGER.warning(
"Error while setting speed of device %s (%s)", self.name, err
)
self._available = False
self.schedule_update_ha_state()
@ -211,24 +195,14 @@ class WemoHumidifier(WemoSubscriptionEntity, FanEntity):
elif target_humidity >= 100:
pywemo_humidity = WEMO_HUMIDITY_100
try:
with self._wemo_exception_handler("set humidity"):
self.wemo.set_humidity(pywemo_humidity)
except ActionException as err:
_LOGGER.warning(
"Error while setting humidity of device: %s (%s)", self.name, err
)
self._available = False
self.schedule_update_ha_state()
def reset_filter_life(self) -> None:
"""Reset the filter life to 100%."""
try:
with self._wemo_exception_handler("reset filter life"):
self.wemo.reset_filter_life()
except ActionException as err:
_LOGGER.warning(
"Error while resetting filter life on device: %s (%s)", self.name, err
)
self._available = False
self.schedule_update_ha_state()

View file

@ -3,8 +3,6 @@ import asyncio
from datetime import timedelta
import logging
from pywemo.ouimeaux_device.api.service import ActionException
from homeassistant import util
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
@ -158,7 +156,7 @@ class WemoLight(WemoEntity, LightEntity):
"force_update": False,
}
try:
with self._wemo_exception_handler("turn on"):
if xy_color is not None:
self.wemo.set_color(xy_color, transition=transition_time)
@ -167,9 +165,6 @@ class WemoLight(WemoEntity, LightEntity):
if self.wemo.turn_on(**turn_on_kwargs):
self._state["onoff"] = WEMO_ON
except ActionException as err:
_LOGGER.warning("Error while turning on device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
@ -177,28 +172,21 @@ class WemoLight(WemoEntity, LightEntity):
"""Turn the light off."""
transition_time = int(kwargs.get(ATTR_TRANSITION, 0))
try:
with self._wemo_exception_handler("turn off"):
if self.wemo.turn_off(transition=transition_time):
self._state["onoff"] = WEMO_OFF
except ActionException as err:
_LOGGER.warning("Error while turning off device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
def _update(self, force_update=True):
"""Synchronize state with bridge."""
try:
with self._wemo_exception_handler("update status") as handler:
self._update_lights(no_throttle=force_update)
self._state = self.wemo.state
except ActionException as err:
_LOGGER.warning("Could not update status for %s (%s)", self.name, err)
self._available = False
else:
if handler.success:
self._is_on = self._state.get("onoff") != WEMO_OFF
self._brightness = self._state.get("level", 255)
self._color_temp = self._state.get("temperature_mireds")
self._available = True
xy_color = self._state.get("color_xy")
@ -228,19 +216,12 @@ class WemoDimmer(WemoSubscriptionEntity, LightEntity):
def _update(self, force_update=True):
"""Update the device state."""
try:
with self._wemo_exception_handler("update status"):
self._state = self.wemo.get_state(force_update)
wemobrightness = int(self.wemo.get_brightness(force_update))
self._brightness = int((wemobrightness * 255) / 100)
if not self._available:
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
except ActionException as err:
_LOGGER.warning("Could not update status for %s (%s)", self.name, err)
self._available = False
def turn_on(self, **kwargs):
"""Turn the dimmer on."""
# Wemo dimmer switches use a range of [0, 100] to control
@ -251,24 +232,18 @@ class WemoDimmer(WemoSubscriptionEntity, LightEntity):
else:
brightness = 255
try:
with self._wemo_exception_handler("turn on"):
if self.wemo.on():
self._state = WEMO_ON
self.wemo.set_brightness(brightness)
except ActionException as err:
_LOGGER.warning("Error while turning on device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
def turn_off(self, **kwargs):
"""Turn the dimmer off."""
try:
with self._wemo_exception_handler("turn off"):
if self.wemo.off():
self._state = WEMO_OFF
except ActionException as err:
_LOGGER.warning("Error while turning on device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()

View file

@ -3,8 +3,6 @@ import asyncio
from datetime import datetime, timedelta
import logging
from pywemo.ouimeaux_device.api.service import ActionException
from homeassistant.components.switch import SwitchEntity
from homeassistant.const import STATE_OFF, STATE_ON, STATE_STANDBY, STATE_UNKNOWN
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -140,29 +138,23 @@ class WemoSwitch(WemoSubscriptionEntity, SwitchEntity):
def turn_on(self, **kwargs):
"""Turn the switch on."""
try:
with self._wemo_exception_handler("turn on"):
if self.wemo.on():
self._state = WEMO_ON
except ActionException as err:
_LOGGER.warning("Error while turning on device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
def turn_off(self, **kwargs):
"""Turn the switch off."""
try:
with self._wemo_exception_handler("turn off"):
if self.wemo.off():
self._state = WEMO_OFF
except ActionException as err:
_LOGGER.warning("Error while turning off device %s (%s)", self.name, err)
self._available = False
self.schedule_update_ha_state()
def _update(self, force_update=True):
"""Update the device state."""
try:
with self._wemo_exception_handler("update status"):
self._state = self.wemo.get_state(force_update)
if self.wemo.model_name == "Insight":
@ -173,10 +165,3 @@ class WemoSwitch(WemoSubscriptionEntity, SwitchEntity):
elif self.wemo.model_name == "CoffeeMaker":
self.coffeemaker_mode = self.wemo.mode
self._mode_string = self.wemo.mode_string
if not self._available:
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
except ActionException as err:
_LOGGER.warning("Could not update status for %s (%s)", self.name, err)
self._available = False