Centralize wemo exception handling (#46705)
This commit is contained in:
parent
b2df9aaaf1
commit
8bee3cda37
5 changed files with 48 additions and 92 deletions
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue