From b2081c579b81893e9f2b71f3ba29af0fc1517518 Mon Sep 17 00:00:00 2001 From: cdheiser <10488026+cdheiser@users.noreply.github.com> Date: Tue, 25 Dec 2018 00:33:03 -0800 Subject: [PATCH] Improve Lutron RadioRA2 support, adding switches and scenes (#18330) * Improve Lutron RadioRA2 support, adding switch and scene support. - Update the version of pylutron to 0.2 which has various bug fixes. - Switch to pylutron's per-device subscribe - Add switch support, and configure any non-dimmable output as a switch. - Add scene support, using any configured keypad button with a corresponding LED as a scene. * Fixes for comments in pull request home-assistant/home-assistant#18330 * More fixes for comments in pull request #18330 * Remove unused imports * Cleanup in docstrings for Lutron scene support. --- homeassistant/components/lutron.py | 35 +++++++++++---- homeassistant/components/scene/lutron.py | 53 +++++++++++++++++++++++ homeassistant/components/switch/lutron.py | 49 +++++++++++++++++++++ requirements_all.txt | 2 +- 4 files changed, 129 insertions(+), 10 deletions(-) create mode 100644 homeassistant/components/scene/lutron.py create mode 100644 homeassistant/components/switch/lutron.py diff --git a/homeassistant/components/lutron.py b/homeassistant/components/lutron.py index 2e49d7ce69005b..48ad95da415a79 100644 --- a/homeassistant/components/lutron.py +++ b/homeassistant/components/lutron.py @@ -13,7 +13,7 @@ from homeassistant.helpers import discovery from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pylutron==0.1.0'] +REQUIREMENTS = ['pylutron==0.2.0'] DOMAIN = 'lutron' @@ -36,7 +36,10 @@ def setup(hass, base_config): from pylutron import Lutron hass.data[LUTRON_CONTROLLER] = None - hass.data[LUTRON_DEVICES] = {'light': [], 'cover': []} + hass.data[LUTRON_DEVICES] = {'light': [], + 'cover': [], + 'switch': [], + 'scene': []} config = base_config.get(DOMAIN) hass.data[LUTRON_CONTROLLER] = Lutron( @@ -51,10 +54,23 @@ def setup(hass, base_config): for output in area.outputs: if output.type == 'SYSTEM_SHADE': hass.data[LUTRON_DEVICES]['cover'].append((area.name, output)) - else: + elif output.is_dimmable: hass.data[LUTRON_DEVICES]['light'].append((area.name, output)) - - for component in ('light', 'cover'): + else: + hass.data[LUTRON_DEVICES]['switch'].append((area.name, output)) + for keypad in area.keypads: + for button in keypad.buttons: + # This is the best way to determine if a button does anything + # useful until pylutron is updated to provide information on + # which buttons actually control scenes. + for led in keypad.leds: + if (led.number == button.number and + button.name != 'Unknown Button' and + button.button_type in ('SingleAction', 'Toggle')): + hass.data[LUTRON_DEVICES]['scene'].append( + (area.name, button, led)) + + for component in ('light', 'cover', 'switch', 'scene'): discovery.load_platform(hass, component, DOMAIN, None, base_config) return True @@ -70,12 +86,13 @@ def __init__(self, area_name, lutron_device, controller): async def async_added_to_hass(self): """Register callbacks.""" - self.hass.async_add_job( - self._controller.subscribe, self._lutron_device, - self._update_callback + self.hass.async_add_executor_job( + self._lutron_device.subscribe, + self._update_callback, + None ) - def _update_callback(self, _device): + def _update_callback(self, _device, _context, _event, _params): """Run when invoked by pylutron when the device state changes.""" self.schedule_update_ha_state() diff --git a/homeassistant/components/scene/lutron.py b/homeassistant/components/scene/lutron.py new file mode 100644 index 00000000000000..bdb8bc344fec62 --- /dev/null +++ b/homeassistant/components/scene/lutron.py @@ -0,0 +1,53 @@ +""" +Support for Lutron scenes. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/scene.lutron/ +""" +import logging + +from homeassistant.components.lutron import ( + LutronDevice, LUTRON_DEVICES, LUTRON_CONTROLLER) +from homeassistant.components.scene import Scene + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['lutron'] + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the Lutron scenes.""" + devs = [] + for scene_data in hass.data[LUTRON_DEVICES]['scene']: + (area_name, keypad_name, device, led) = scene_data + dev = LutronScene(area_name, keypad_name, device, led, + hass.data[LUTRON_CONTROLLER]) + devs.append(dev) + + add_entities(devs, True) + + +class LutronScene(LutronDevice, Scene): + """Representation of a Lutron Scene.""" + + def __init__(self, + area_name, + keypad_name, + lutron_device, + lutron_led, + controller): + """Initialize the scene/button.""" + super().__init__(area_name, lutron_device, controller) + self._keypad_name = keypad_name + self._led = lutron_led + + def activate(self): + """Activate the scene.""" + self._lutron_device.press() + + @property + def name(self): + """Return the name of the device.""" + return "{} {}: {}".format(self._area_name, + self._keypad_name, + self._lutron_device.name) diff --git a/homeassistant/components/switch/lutron.py b/homeassistant/components/switch/lutron.py new file mode 100644 index 00000000000000..4146ba5a43b0a8 --- /dev/null +++ b/homeassistant/components/switch/lutron.py @@ -0,0 +1,49 @@ +""" +Support for Lutron switches. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.lutron/ +""" +import logging + +from homeassistant.components.switch import SwitchDevice +from homeassistant.components.lutron import ( + LutronDevice, LUTRON_DEVICES, LUTRON_CONTROLLER) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['lutron'] + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the Lutron switches.""" + devs = [] + for (area_name, device) in hass.data[LUTRON_DEVICES]['switch']: + dev = LutronSwitch(area_name, device, hass.data[LUTRON_CONTROLLER]) + devs.append(dev) + + add_entities(devs, True) + + +class LutronSwitch(LutronDevice, SwitchDevice): + """Representation of a Lutron Switch.""" + + def turn_on(self, **kwargs): + """Turn the switch on.""" + self._lutron_device.level = 100 + + def turn_off(self, **kwargs): + """Turn the switch off.""" + self._lutron_device.level = 0 + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attr = {} + attr['lutron_integration_id'] = self._lutron_device.id + return attr + + @property + def is_on(self): + """Return true if device is on.""" + return self._lutron_device.last_level() > 0 diff --git a/requirements_all.txt b/requirements_all.txt index 2c389ede713a77..18d7bd30d60329 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1068,7 +1068,7 @@ pyloopenergy==0.0.18 pylutron-caseta==0.5.0 # homeassistant.components.lutron -pylutron==0.1.0 +pylutron==0.2.0 # homeassistant.components.notify.mailgun pymailgunner==1.4