diff --git a/homeassistant/components/wemo/binary_sensor.py b/homeassistant/components/wemo/binary_sensor.py index 805a730e3d9..b5ef3dc528b 100644 --- a/homeassistant/components/wemo/binary_sensor.py +++ b/homeassistant/components/wemo/binary_sensor.py @@ -3,6 +3,7 @@ import asyncio import logging import async_timeout +from pywemo.ouimeaux_device.api.service import ActionException from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -40,7 +41,7 @@ class WemoBinarySensor(BinarySensorEntity): self._update_lock = None self._model_name = self.wemo.model_name self._name = self.wemo.name - self._serialnumber = self.wemo.serialnumber + self._serial_number = self.wemo.serialnumber def _subscription_callback(self, _device, _type, _params): """Update the state by the Wemo sensor.""" @@ -98,14 +99,15 @@ class WemoBinarySensor(BinarySensorEntity): if not self._available: _LOGGER.info("Reconnected to %s", self.name) self._available = True - except AttributeError as err: + except (AttributeError, ActionException) as err: _LOGGER.warning("Could not update status for %s (%s)", self.name, err) self._available = False + self.wemo.reconnect_with_device() @property def unique_id(self): """Return the id of this WeMo sensor.""" - return self._serialnumber + return self._serial_number @property def name(self): @@ -126,8 +128,8 @@ class WemoBinarySensor(BinarySensorEntity): def device_info(self): """Return the device info.""" return { - "name": self.wemo.name, - "identifiers": {(WEMO_DOMAIN, self.wemo.serialnumber)}, - "model": self.wemo.model_name, + "name": self._name, + "identifiers": {(WEMO_DOMAIN, self._serial_number)}, + "model": self._model_name, "manufacturer": "Belkin", } diff --git a/homeassistant/components/wemo/fan.py b/homeassistant/components/wemo/fan.py index 24ed68c792d..f040a9f3845 100644 --- a/homeassistant/components/wemo/fan.py +++ b/homeassistant/components/wemo/fan.py @@ -4,6 +4,7 @@ from datetime import timedelta import logging import async_timeout +from pywemo.ouimeaux_device.api.service import ActionException import voluptuous as vol from homeassistant.components.fan import ( @@ -128,7 +129,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # Register service(s) hass.services.async_register( - WEMO_DOMAIN, SERVICE_SET_HUMIDITY, service_handle, schema=SET_HUMIDITY_SCHEMA + WEMO_DOMAIN, SERVICE_SET_HUMIDITY, service_handle, schema=SET_HUMIDITY_SCHEMA, ) hass.services.async_register( @@ -198,9 +199,9 @@ class WemoHumidifier(FanEntity): def device_info(self): """Return the device info.""" return { - "name": self.wemo.name, - "identifiers": {(WEMO_DOMAIN, self.wemo.serialnumber)}, - "model": self.wemo.model_name, + "name": self._name, + "identifiers": {(WEMO_DOMAIN, self._serialnumber)}, + "model": self._model_name, "manufacturer": "Belkin", } @@ -287,38 +288,67 @@ class WemoHumidifier(FanEntity): if not self._available: _LOGGER.info("Reconnected to %s", self.name) self._available = True - except AttributeError as err: + except (AttributeError, ActionException) as err: _LOGGER.warning("Could not update status for %s (%s)", self.name, err) self._available = False + self.wemo.reconnect_with_device() def turn_on(self, speed: str = None, **kwargs) -> None: """Turn the switch on.""" if speed is None: - self.wemo.set_state(self._last_fan_on_mode) + try: + self.wemo.set_state(self._last_fan_on_mode) + except ActionException as err: + _LOGGER.warning("Error while turning on device %s (%s)", self.name, err) + self._available = False else: self.set_speed(speed) def turn_off(self, **kwargs) -> None: """Turn the switch off.""" - self.wemo.set_state(WEMO_FAN_OFF) + try: + 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 def set_speed(self, speed: str) -> None: """Set the fan_mode of the Humidifier.""" - self.wemo.set_state(HASS_FAN_SPEED_TO_WEMO.get(speed)) + try: + self.wemo.set_state(HASS_FAN_SPEED_TO_WEMO.get(speed)) + except ActionException as err: + _LOGGER.warning( + "Error while setting speed of device %s (%s)", self.name, err + ) + self._available = False def set_humidity(self, humidity: float) -> None: """Set the target humidity level for the Humidifier.""" if humidity < 50: - self.wemo.set_humidity(WEMO_HUMIDITY_45) + target_humidity = WEMO_HUMIDITY_45 elif 50 <= humidity < 55: - self.wemo.set_humidity(WEMO_HUMIDITY_50) + target_humidity = WEMO_HUMIDITY_50 elif 55 <= humidity < 60: - self.wemo.set_humidity(WEMO_HUMIDITY_55) + target_humidity = WEMO_HUMIDITY_55 elif 60 <= humidity < 100: - self.wemo.set_humidity(WEMO_HUMIDITY_60) + target_humidity = WEMO_HUMIDITY_60 elif humidity >= 100: - self.wemo.set_humidity(WEMO_HUMIDITY_100) + target_humidity = WEMO_HUMIDITY_100 + + try: + self.wemo.set_humidity(target_humidity) + except ActionException as err: + _LOGGER.warning( + "Error while setting humidity of device: %s (%s)", self.name, err + ) + self._available = False def reset_filter_life(self) -> None: """Reset the filter life to 100%.""" - self.wemo.reset_filter_life() + try: + 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 diff --git a/homeassistant/components/wemo/light.py b/homeassistant/components/wemo/light.py index 02b5e79d1c6..2a05d42f1f7 100644 --- a/homeassistant/components/wemo/light.py +++ b/homeassistant/components/wemo/light.py @@ -4,6 +4,7 @@ from datetime import timedelta import logging import async_timeout +from pywemo.ouimeaux_device.api.service import ActionException from homeassistant import util from homeassistant.components.light import ( @@ -92,6 +93,7 @@ class WemoLight(LightEntity): self._is_on = None self._name = self.wemo.name self._unique_id = self.wemo.uniqueID + self._model_name = type(self.wemo).__name__ async def async_added_to_hass(self): """Wemo light added to Home Assistant.""" @@ -112,9 +114,9 @@ class WemoLight(LightEntity): def device_info(self): """Return the device info.""" return { - "name": self.wemo.name, - "identifiers": {(WEMO_DOMAIN, self.wemo.uniqueID)}, - "model": type(self.wemo).__name__, + "name": self._name, + "identifiers": {(WEMO_DOMAIN, self._unique_id)}, + "model": self._model_name, "manufacturer": "Belkin", } @@ -150,45 +152,65 @@ class WemoLight(LightEntity): def turn_on(self, **kwargs): """Turn the light on.""" - transitiontime = int(kwargs.get(ATTR_TRANSITION, 0)) + xy_color = None + brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness or 255) + color_temp = kwargs.get(ATTR_COLOR_TEMP) hs_color = kwargs.get(ATTR_HS_COLOR) + transition_time = int(kwargs.get(ATTR_TRANSITION, 0)) if hs_color is not None: xy_color = color_util.color_hs_to_xy(*hs_color) - self.wemo.set_color(xy_color, transition=transitiontime) - if ATTR_COLOR_TEMP in kwargs: - colortemp = kwargs[ATTR_COLOR_TEMP] - self.wemo.set_temperature(mireds=colortemp, transition=transitiontime) + turn_on_kwargs = { + "level": brightness, + "transition": transition_time, + "force_update": False, + } - if ATTR_BRIGHTNESS in kwargs: - brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness or 255) - self.wemo.turn_on(level=brightness, transition=transitiontime) - else: - self.wemo.turn_on(transition=transitiontime) + try: + if xy_color is not None: + self.wemo.set_color(xy_color, transition=transition_time) + + if color_temp is not None: + self.wemo.set_temperature(mireds=color_temp, transition=transition_time) + + self.wemo.turn_on(**turn_on_kwargs) + except ActionException as err: + _LOGGER.warning("Error while turning on device %s (%s)", self.name, err) + self._available = False def turn_off(self, **kwargs): """Turn the light off.""" - transitiontime = int(kwargs.get(ATTR_TRANSITION, 0)) - self.wemo.turn_off(transition=transitiontime) + transition_time = int(kwargs.get(ATTR_TRANSITION, 0)) + + try: + self.wemo.turn_off(transition=transition_time) + except ActionException as err: + _LOGGER.warning("Error while turning off device %s (%s)", self.name, err) + self._available = False def _update(self, force_update=True): """Synchronize state with bridge.""" - self._update_lights(no_throttle=force_update) - self._state = self.wemo.state - - self._is_on = self._state.get("onoff") != 0 - 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") - - if xy_color: - self._hs_color = color_util.color_xy_to_hs(*xy_color) + try: + self._update_lights(no_throttle=force_update) + self._state = self.wemo.state + except (AttributeError, ActionException) as err: + _LOGGER.warning("Could not update status for %s (%s)", self.name, err) + self._available = False + self.wemo.reconnect_with_device() else: - self._hs_color = None + self._is_on = self._state.get("onoff") != 0 + 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") + + if xy_color: + self._hs_color = color_util.color_xy_to_hs(*xy_color) + else: + self._hs_color = None async def async_update(self): """Synchronize state with bridge.""" @@ -265,7 +287,6 @@ class WemoDimmer(LightEntity): except asyncio.TimeoutError: _LOGGER.warning("Lost connection to %s", self.name) self._available = False - self.wemo.reconnect_with_device() async def _async_locked_update(self, force_update): """Try updating within an async lock.""" @@ -282,6 +303,16 @@ class WemoDimmer(LightEntity): """Return the name of the dimmer if any.""" return self._name + @property + def device_info(self): + """Return the device info.""" + return { + "name": self._name, + "identifiers": {(WEMO_DOMAIN, self._serialnumber)}, + "model": self._model_name, + "manufacturer": "Belkin", + } + @property def supported_features(self): """Flag supported features.""" @@ -308,14 +339,13 @@ class WemoDimmer(LightEntity): if not self._available: _LOGGER.info("Reconnected to %s", self.name) self._available = True - except AttributeError as err: + except (AttributeError, ActionException) as err: _LOGGER.warning("Could not update status for %s (%s)", self.name, err) self._available = False + self.wemo.reconnect_with_device() def turn_on(self, **kwargs): """Turn the dimmer on.""" - self.wemo.on() - # Wemo dimmer switches use a range of [0, 100] to control # brightness. Level 255 might mean to set it to previous value if ATTR_BRIGHTNESS in kwargs: @@ -323,11 +353,21 @@ class WemoDimmer(LightEntity): brightness = int((brightness / 255) * 100) else: brightness = 255 - self.wemo.set_brightness(brightness) + + try: + self.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 def turn_off(self, **kwargs): """Turn the dimmer off.""" - self.wemo.off() + try: + self.wemo.off() + except ActionException as err: + _LOGGER.warning("Error while turning on device %s (%s)", self.name, err) + self._available = False @property def available(self): diff --git a/homeassistant/components/wemo/manifest.json b/homeassistant/components/wemo/manifest.json index 0ad4574ecbc..96efb140cee 100644 --- a/homeassistant/components/wemo/manifest.json +++ b/homeassistant/components/wemo/manifest.json @@ -3,7 +3,7 @@ "name": "Belkin WeMo", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/wemo", - "requirements": ["pywemo==0.4.34"], + "requirements": ["pywemo==0.4.43"], "ssdp": [ { "manufacturer": "Belkin International Inc." diff --git a/homeassistant/components/wemo/switch.py b/homeassistant/components/wemo/switch.py index 203c495e974..836ddf0730f 100644 --- a/homeassistant/components/wemo/switch.py +++ b/homeassistant/components/wemo/switch.py @@ -4,6 +4,7 @@ from datetime import datetime, timedelta import logging import async_timeout +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 @@ -93,9 +94,9 @@ class WemoSwitch(SwitchEntity): def device_info(self): """Return the device info.""" return { - "name": self.wemo.name, - "identifiers": {(WEMO_DOMAIN, self.wemo.serialnumber)}, - "model": self.wemo.model_name, + "name": self._name, + "identifiers": {(WEMO_DOMAIN, self._serialnumber)}, + "model": self._model_name, "manufacturer": "Belkin", } @@ -189,11 +190,19 @@ class WemoSwitch(SwitchEntity): def turn_on(self, **kwargs): """Turn the switch on.""" - self.wemo.on() + try: + self.wemo.on() + except ActionException as err: + _LOGGER.warning("Error while turning on device %s (%s)", self.name, err) + self._available = False def turn_off(self, **kwargs): """Turn the switch off.""" - self.wemo.off() + try: + self.wemo.off() + except ActionException as err: + _LOGGER.warning("Error while turning off device %s (%s)", self.name, err) + self._available = False async def async_added_to_hass(self): """Wemo switch added to Home Assistant.""" @@ -245,6 +254,7 @@ class WemoSwitch(SwitchEntity): if not self._available: _LOGGER.info("Reconnected to %s", self.name) self._available = True - except AttributeError as err: + except (AttributeError, ActionException) as err: _LOGGER.warning("Could not update status for %s (%s)", self.name, err) self._available = False + self.wemo.reconnect_with_device() diff --git a/requirements_all.txt b/requirements_all.txt index ce77e2c1148..44d55995857 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1808,7 +1808,7 @@ pyvlx==0.2.14 pywebpush==1.9.2 # homeassistant.components.wemo -pywemo==0.4.34 +pywemo==0.4.43 # homeassistant.components.xeoma pyxeoma==1.4.1