From 2992cd35be85c482cdadf6f49721c3e3d20478e9 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Sat, 21 Jan 2017 14:14:08 -0800 Subject: [PATCH] Add support for Leviton Decora Bluetooth dimmer switches (#5434) * Add support for Leviton Decora Bluetooth dimmer switches Add support for the Decora Bluetooth smart dimmer switches from Leviton. * Update decora.py --- .coveragerc | 1 + homeassistant/components/light/decora.py | 124 +++++++++++++++++++++++ requirements_all.txt | 3 + script/gen_requirements_all.py | 3 +- 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/light/decora.py diff --git a/.coveragerc b/.coveragerc index ea0530aa8f7..47f602072c0 100644 --- a/.coveragerc +++ b/.coveragerc @@ -191,6 +191,7 @@ omit = homeassistant/components/keyboard_remote.py homeassistant/components/light/avion.py homeassistant/components/light/blinksticklight.py + homeassistant/components/light/decora.py homeassistant/components/light/flux_led.py homeassistant/components/light/hue.py homeassistant/components/light/hyperion.py diff --git a/homeassistant/components/light/decora.py b/homeassistant/components/light/decora.py new file mode 100644 index 00000000000..eaae90f486e --- /dev/null +++ b/homeassistant/components/light/decora.py @@ -0,0 +1,124 @@ +""" +Support for Decora dimmers. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/light.decora/ +""" +import logging + +import voluptuous as vol + +from homeassistant.const import CONF_API_KEY, CONF_DEVICES, CONF_NAME +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light, + PLATFORM_SCHEMA) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['decora==0.3'] + +_LOGGER = logging.getLogger(__name__) + +SUPPORT_DECORA_LED = (SUPPORT_BRIGHTNESS) + +DEVICE_SCHEMA = vol.Schema({ + vol.Optional(CONF_NAME): cv.string, + vol.Required(CONF_API_KEY): cv.string, +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA}, +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up an Decora switch.""" + lights = [] + 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 = DecoraLight(device) + if light.is_valid: + lights.append(light) + + add_devices(lights) + + +class DecoraLight(Light): + """Representation of an Decora 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() + self.is_valid = True + + @property + def unique_id(self): + """Return the ID of this light.""" + return "{}.{}".format(self.__class__, self._address) + + @property + def name(self): + """Return the name of the device if any.""" + return self._name + + @property + def is_on(self): + """Return true if device is on.""" + return self._state + + @property + def brightness(self): + """Return the brightness of this light between 0..255.""" + return self._brightness + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_DECORA_LED + + @property + def should_poll(self): + """We can read the device state, so poll.""" + return True + + @property + def assumed_state(self): + """We can read the actual state.""" + return False + + def set_state(self, brightness): + """Set the state of this lamp to the provided brightness.""" + self._switch.set_brightness(brightness) + self._brightness = brightness + return True + + def turn_on(self, **kwargs): + """Turn the specified or all lights on.""" + brightness = kwargs.get(ATTR_BRIGHTNESS) + + self._switch.on() + 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 + + def update(self): + """Synchronise internal state with the actual light state.""" + self._brightness = self._switch.get_brightness() + self._state = self._switch.get_on() diff --git a/requirements_all.txt b/requirements_all.txt index 1b92e6b81c4..68326dbd1b4 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -87,6 +87,9 @@ colorlog>2.1,<3 # homeassistant.components.binary_sensor.concord232 concord232==0.14 +# homeassistant.components.light.decora +# decora==0.3 + # homeassistant.components.media_player.denonavr denonavr==0.3.1 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index e23c8d09fea..f5b0a271d84 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -20,7 +20,8 @@ COMMENT_REQUIREMENTS = ( 'evdev', 'pycups', 'python-eq3bt', - 'avion' + 'avion', + 'decora' ) IGNORE_PACKAGES = (