diff --git a/homeassistant/components/light/avion.py b/homeassistant/components/light/avion.py index 9b717c64c86900be03bde58967e061a21bdba5f2..100ad860faafb9b150d17c02d12a9d0cf0ad5ed2 100644 --- a/homeassistant/components/light/avion.py +++ b/homeassistant/components/light/avion.py @@ -5,16 +5,23 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.avion/ """ import logging +import time import voluptuous as vol -from homeassistant.const import CONF_API_KEY, CONF_DEVICES, CONF_NAME +from homeassistant.const import CONF_API_KEY, CONF_DEVICES, CONF_NAME, \ + CONF_USERNAME, CONF_PASSWORD + from homeassistant.components.light import ( ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light, PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['avion==0.6'] +# pylint: disable=import-error + +AVION_EXCEPTION = None + +REQUIREMENTS = ['avion==0.7'] _LOGGER = logging.getLogger(__name__) @@ -27,20 +34,40 @@ DEVICE_SCHEMA = vol.Schema({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA}, + vol.Optional(CONF_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD): cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): """Set up an Avion switch.""" + global AVION_EXCEPTION + + import avion + + AVION_EXCEPTION = avion.avionException + lights = [] + if CONF_USERNAME in config and CONF_PASSWORD in config: + data = avion.avion_info(config[CONF_USERNAME], config[CONF_PASSWORD]) + for location in data['locations']: + for avion_device in location['location']['devices']: + device = {} + mac = avion_device['device']['mac_address'] + device['name'] = avion_device['device']['name'] + device['key'] = location['location']['passphrase'] + device['address'] = '%s%s:%s%s:%s%s:%s%s:%s%s:%s%s' % \ + (mac[8], mac[9], mac[10], mac[11], mac[4], + mac[5], mac[6], mac[7], mac[0], mac[1], + mac[2], mac[3]) + lights.append(AvionLight(device)) + for address, device_config in config[CONF_DEVICES].items(): device = {} device['name'] = device_config[CONF_NAME] device['key'] = device_config[CONF_API_KEY] device['address'] = address - light = AvionLight(device) - if light.is_valid: - lights.append(light) + lights.append(AvionLight(device)) add_devices(lights) @@ -50,7 +77,6 @@ class AvionLight(Light): def __init__(self, device): """Initialize the light.""" - # pylint: disable=import-error import avion self._name = device['name'] @@ -59,8 +85,6 @@ class AvionLight(Light): self._brightness = 255 self._state = False self._switch = avion.avion(self._address, self._key) - self._switch.connect() - self.is_valid = True @property def unique_id(self): @@ -99,7 +123,17 @@ class AvionLight(Light): def set_state(self, brightness): """Set the state of this lamp to the provided brightness.""" - self._switch.set_brightness(brightness) + # Bluetooth LE is unreliable, and the connection may drop at any + # time. Make an effort to re-establish the link. + initial = time.monotonic() + while True: + if time.monotonic() - initial >= 10: + return False + try: + self._switch.set_brightness(brightness) + break + except AVION_EXCEPTION: + self._switch.connect() return True def turn_on(self, **kwargs): diff --git a/homeassistant/components/light/decora.py b/homeassistant/components/light/decora.py index c653f4b1ed4c0a9680bcdb07986e3c7f28527043..26c7368b6487c99a3d4f86d849b2d2477dd2eda1 100644 --- a/homeassistant/components/light/decora.py +++ b/homeassistant/components/light/decora.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.decora/ """ import logging +import time import voluptuous as vol @@ -14,6 +15,10 @@ from homeassistant.components.light import ( PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv +# pylint: disable=import-error + +DECORA_EXCEPTION = None + REQUIREMENTS = ['decora==0.6'] _LOGGER = logging.getLogger(__name__) @@ -32,6 +37,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up an Decora switch.""" + global DECORA_EXCEPTION + + import decora + + DECORA_EXCEPTION = decora.decoraException + lights = [] for address, device_config in config[CONF_DEVICES].items(): device = {} @@ -39,8 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device['key'] = device_config[CONF_API_KEY] device['address'] = address light = DecoraLight(device) - if light.is_valid: - lights.append(light) + lights.append(light) add_devices(lights) @@ -50,17 +60,14 @@ class DecoraLight(Light): def __init__(self, device): """Initialize the light.""" - # pylint: disable=import-error import decora self._name = device['name'] self._address = device['address'] self._key = device["key"] self._switch = decora.decora(self._address, self._key) - self._switch.connect() - self._state = self._switch.get_on() - self._brightness = self._switch.get_brightness() * 2.55 - self.is_valid = True + self._brightness = 0 + self._state = False @property def unique_id(self): @@ -75,11 +82,13 @@ class DecoraLight(Light): @property def is_on(self): """Return true if device is on.""" + self.update() return self._state @property def brightness(self): """Return the brightness of this light between 0..255.""" + self.update() return self._brightness @property @@ -99,7 +108,16 @@ class DecoraLight(Light): def set_state(self, brightness): """Set the state of this lamp to the provided brightness.""" - self._switch.set_brightness(int(brightness / 2.55)) + initial = time.monotonic() + while True: + if time.monotonic() - initial >= 10: + return None + try: + self._switch.set_brightness(brightness / 2.55) + break + except (DECORA_EXCEPTION, AttributeError): + self._switch.connect() + self._brightness = brightness return True @@ -107,18 +125,42 @@ class DecoraLight(Light): """Turn the specified or all lights on.""" brightness = kwargs.get(ATTR_BRIGHTNESS) - self._switch.on() + initial = time.monotonic() + while True: + if time.monotonic() - initial >= 10: + return None + try: + self._switch.on() + self._state = True + break + except (DECORA_EXCEPTION, AttributeError): + self._switch.connect() + if brightness is not None: self.set_state(brightness) - self._state = True - def turn_off(self, **kwargs): """Turn the specified or all lights off.""" - self._switch.off() - self._state = False + initial = time.monotonic() + while True: + if time.monotonic() - initial >= 10: + return None + try: + self._switch.off() + self._state = False + break + except (DECORA_EXCEPTION, AttributeError): + self._switch.connect() def update(self): """Synchronise internal state with the actual light state.""" - self._brightness = self._switch.get_brightness() * 2.55 - self._state = self._switch.get_on() + initial = time.monotonic() + while True: + if time.monotonic() - initial >= 10: + return None + try: + self._brightness = self._switch.get_brightness() * 2.55 + self._state = self._switch.get_on() + break + except (DECORA_EXCEPTION, AttributeError): + self._switch.connect() diff --git a/requirements_all.txt b/requirements_all.txt index fe0cea803da0db86b89be3501954447e6d2151f9..fc71a3ab3ffb2bcb1ae0257d3c7f3e0615169bb6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -74,7 +74,7 @@ apcaccess==0.0.13 apns2==0.1.1 # homeassistant.components.light.avion -# avion==0.6 +# avion==0.7 # homeassistant.components.axis axis==8