From 2c328a7849ceed0732898158ae1f805c80062e55 Mon Sep 17 00:00:00 2001 From: Chris Heiser <10488026+cdheiser@users.noreply.github.com> Date: Fri, 9 Nov 2018 00:32:44 -0800 Subject: [PATCH 1/5] 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. --- homeassistant/components/lutron.py | 33 ++++++++++--- homeassistant/components/scene/lutron.py | 60 +++++++++++++++++++++++ homeassistant/components/switch/lutron.py | 54 ++++++++++++++++++++ requirements_all.txt | 2 +- 4 files changed, 140 insertions(+), 9 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..78a15f3b174fe9 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 @@ -71,11 +87,12 @@ 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._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..6d2d963adf13c2 --- /dev/null +++ b/homeassistant/components/scene/lutron.py @@ -0,0 +1,60 @@ +""" +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 +from homeassistant.const import (STATE_ON, STATE_OFF) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['lutron'] + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the Lutron lights.""" + 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) + return True + + +class LutronScene(LutronDevice, Scene): + """Representation of a Lutron Switch.""" + + def __init__(self, + area_name, + keypad_name, + lutron_device, + lutron_led, + controller): + """Initialize the scene/button.""" + LutronDevice.__init__(self, 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 state(self): + """Return the state of the scene.""" + return STATE_ON if self._led.state else STATE_OFF + + @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..a3f4255c4124bd --- /dev/null +++ b/homeassistant/components/switch/lutron.py @@ -0,0 +1,54 @@ +""" +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) + return True + + +class LutronSwitch(LutronDevice, SwitchDevice): + """Representation of a Lutron Switch.""" + + def __init__(self, area_name, lutron_device, controller): + """Initialize the switch.""" + LutronDevice.__init__(self, area_name, lutron_device, controller) + + 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 d8a41643e60076..896d0bb9f9335a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1011,7 +1011,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 From 2bead09ab7c7cb13e3891fd8361e0d8c13110707 Mon Sep 17 00:00:00 2001 From: Chris Heiser <10488026+cdheiser@users.noreply.github.com> Date: Mon, 19 Nov 2018 11:50:10 -0800 Subject: [PATCH 2/5] Fixes for comments in pull request home-assistant/home-assistant#18330 --- homeassistant/components/lutron.py | 2 +- homeassistant/components/switch/lutron.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/components/lutron.py b/homeassistant/components/lutron.py index 78a15f3b174fe9..48ad95da415a79 100644 --- a/homeassistant/components/lutron.py +++ b/homeassistant/components/lutron.py @@ -86,7 +86,7 @@ def __init__(self, area_name, lutron_device, controller): async def async_added_to_hass(self): """Register callbacks.""" - self.hass.async_add_job( + self.hass.async_add_executor_job( self._lutron_device.subscribe, self._update_callback, None diff --git a/homeassistant/components/switch/lutron.py b/homeassistant/components/switch/lutron.py index a3f4255c4124bd..742ecdb1ddb90c 100644 --- a/homeassistant/components/switch/lutron.py +++ b/homeassistant/components/switch/lutron.py @@ -29,10 +29,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class LutronSwitch(LutronDevice, SwitchDevice): """Representation of a Lutron Switch.""" - def __init__(self, area_name, lutron_device, controller): - """Initialize the switch.""" - LutronDevice.__init__(self, area_name, lutron_device, controller) - def turn_on(self, **kwargs): """Turn the switch on.""" self._lutron_device.level = 100 From ec85dbf79dcef66f1ddcc5e67d050fd66d68b3e1 Mon Sep 17 00:00:00 2001 From: Chris Heiser <10488026+cdheiser@users.noreply.github.com> Date: Wed, 21 Nov 2018 23:14:10 -0800 Subject: [PATCH 3/5] More fixes for comments in pull request #18330 --- homeassistant/components/scene/lutron.py | 8 +------- homeassistant/components/switch/lutron.py | 3 +-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/scene/lutron.py b/homeassistant/components/scene/lutron.py index 6d2d963adf13c2..4aace5b52774fd 100644 --- a/homeassistant/components/scene/lutron.py +++ b/homeassistant/components/scene/lutron.py @@ -26,7 +26,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devs.append(dev) add_entities(devs, True) - return True class LutronScene(LutronDevice, Scene): @@ -39,7 +38,7 @@ def __init__(self, lutron_led, controller): """Initialize the scene/button.""" - LutronDevice.__init__(self, area_name, lutron_device, controller) + super().__init__(area_name, lutron_device, controller) self._keypad_name = keypad_name self._led = lutron_led @@ -47,11 +46,6 @@ def activate(self): """Activate the scene.""" self._lutron_device.press() - @property - def state(self): - """Return the state of the scene.""" - return STATE_ON if self._led.state else STATE_OFF - @property def name(self): """Return the name of the device.""" diff --git a/homeassistant/components/switch/lutron.py b/homeassistant/components/switch/lutron.py index 742ecdb1ddb90c..4146ba5a43b0a8 100644 --- a/homeassistant/components/switch/lutron.py +++ b/homeassistant/components/switch/lutron.py @@ -23,7 +23,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devs.append(dev) add_entities(devs, True) - return True class LutronSwitch(LutronDevice, SwitchDevice): @@ -41,7 +40,7 @@ def turn_off(self, **kwargs): def device_state_attributes(self): """Return the state attributes.""" attr = {} - attr['Lutron Integration ID'] = self._lutron_device.id + attr['lutron_integration_id'] = self._lutron_device.id return attr @property From 24de54ec5bf2c0c90d52cc3b7a0787367573cc4f Mon Sep 17 00:00:00 2001 From: Chris Heiser <10488026+cdheiser@users.noreply.github.com> Date: Wed, 21 Nov 2018 23:19:02 -0800 Subject: [PATCH 4/5] Remove unused imports --- homeassistant/components/scene/lutron.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/scene/lutron.py b/homeassistant/components/scene/lutron.py index 4aace5b52774fd..673dc0e7c6bde8 100644 --- a/homeassistant/components/scene/lutron.py +++ b/homeassistant/components/scene/lutron.py @@ -9,7 +9,6 @@ from homeassistant.components.lutron import ( LutronDevice, LUTRON_DEVICES, LUTRON_CONTROLLER) from homeassistant.components.scene import Scene -from homeassistant.const import (STATE_ON, STATE_OFF) _LOGGER = logging.getLogger(__name__) From 34c2b12efb6cd52d7691d0ee454ab9116f16ffe0 Mon Sep 17 00:00:00 2001 From: Chris Heiser <10488026+cdheiser@users.noreply.github.com> Date: Mon, 24 Dec 2018 21:56:41 -0800 Subject: [PATCH 5/5] Cleanup in docstrings for Lutron scene support. --- homeassistant/components/scene/lutron.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/scene/lutron.py b/homeassistant/components/scene/lutron.py index 673dc0e7c6bde8..bdb8bc344fec62 100644 --- a/homeassistant/components/scene/lutron.py +++ b/homeassistant/components/scene/lutron.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the Lutron lights.""" + """Set up the Lutron scenes.""" devs = [] for scene_data in hass.data[LUTRON_DEVICES]['scene']: (area_name, keypad_name, device, led) = scene_data @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class LutronScene(LutronDevice, Scene): - """Representation of a Lutron Switch.""" + """Representation of a Lutron Scene.""" def __init__(self, area_name,