From 91be0a34f70a62e14dffb0574ea0ea8ddf23c2e7 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Fri, 3 Jan 2020 13:23:26 -0800 Subject: [PATCH 1/7] Add support for Lutron Keypad LEDs --- homeassistant/components/lutron/__init__.py | 21 ++++++-- homeassistant/components/lutron/switch.py | 56 +++++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/lutron/__init__.py b/homeassistant/components/lutron/__init__.py index ac6ffa46b27c8..6e0098504b8c3 100644 --- a/homeassistant/components/lutron/__init__.py +++ b/homeassistant/components/lutron/__init__.py @@ -20,6 +20,12 @@ # Attribute on events that indicates what action was taken with the button. ATTR_ACTION = "action" +ATTR_AREA_NAME = "area_name" +ATTR_KEYPAD_NAME = "keypad_name" +ATTR_BUTTON_NAME = "button_name" +ATTR_BUTTON_ID = "button_id" +ATTR_KEYPAD_ID = "keypad_id" +ATTR_FULL_ID = "full_id" CONFIG_SCHEMA = vol.Schema( { @@ -37,7 +43,6 @@ def setup(hass, base_config): """Set up the Lutron component.""" - hass.data[LUTRON_BUTTONS] = [] hass.data[LUTRON_CONTROLLER] = None hass.data[LUTRON_DEVICES] = { @@ -84,7 +89,9 @@ def setup(hass, base_config): (area.name, keypad.name, button, led) ) - hass.data[LUTRON_BUTTONS].append(LutronButton(hass, keypad, button)) + hass.data[LUTRON_BUTTONS].append( + LutronButton(hass, area.name, keypad, button) + ) if area.occupancy_group is not None: hass.data[LUTRON_DEVICES]["binary_sensor"].append( (area.name, area.occupancy_group) @@ -133,7 +140,7 @@ class LutronButton: represented as an entity; it simply fires events. """ - def __init__(self, hass, keypad, button): + def __init__(self, hass, area_name, keypad, button): """Register callback for activity on the button.""" name = f"{keypad.name}: {button.name}" self._hass = hass @@ -141,13 +148,17 @@ def __init__(self, hass, keypad, button): button.button_type is not None and "RaiseLower" in button.button_type ) self._id = slugify(name) + self._keypad = keypad + self._area_name = area_name + self._button_name = button.name + self._button = button self._event = "lutron_event" + self._full_id = slugify(f"{area_name} {keypad.name}: {button.name}") button.subscribe(self.button_callback, None) def button_callback(self, button, context, event, params): """Fire an event about a button being pressed or released.""" - # Events per button type: # RaiseLower -> pressed/released # SingleAction -> single @@ -161,5 +172,5 @@ def button_callback(self, button, context, event, params): action = "single" if action: - data = {ATTR_ID: self._id, ATTR_ACTION: action} + data = {ATTR_ID: self._id, ATTR_ACTION: action, ATTR_FULL_ID: self._full_id} self._hass.bus.fire(self._event, data) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 604f19fc2ae7a..7847131096371 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -11,10 +11,21 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Lutron switches.""" devs = [] + + # Add Lutron Switches for (area_name, device) in hass.data[LUTRON_DEVICES]["switch"]: dev = LutronSwitch(area_name, device, hass.data[LUTRON_CONTROLLER]) devs.append(dev) + # Add the indicator LEDs for scenes (keypad buttons) + for scene_data in hass.data[LUTRON_DEVICES]["scene"]: + (area_name, keypad_name, scene, led) = scene_data + if led is not None: + led = LutronLed( + area_name, keypad_name, scene, led, hass.data[LUTRON_CONTROLLER] + ) + devs.append(led) + add_entities(devs, True) @@ -50,3 +61,48 @@ def update(self): """Call when forcing a refresh of the device.""" if self._prev_state is None: self._prev_state = self._lutron_device.level > 0 + + +class LutronLed(LutronDevice, SwitchDevice): + """Representation of a Lutron Keypad LED.""" + + def __init__(self, area_name, keypad_name, scene_device, led_device, controller): + """Initialize the switch.""" + self._prev_state = None + self._keypad_name = keypad_name + self._scene_name = scene_device.name + super().__init__(area_name, led_device, controller) + + def turn_on(self, **kwargs): + """Turn the LED on.""" + self._lutron_device.state = 1 + + def turn_off(self, **kwargs): + """Turn the LED off.""" + self._lutron_device.state = 0 + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attr = {} + attr["keypad"] = self._keypad_name + attr["scene"] = self._scene_name + attr["led"] = self._lutron_device.name + return attr + + @property + def is_on(self): + """Return true if device is on.""" + return self._lutron_device.last_state + + @property + def name(self): + """Return the name of the LED.""" + return "{} {}: {} LED".format( + self._area_name, self._keypad_name, self._scene_name + ) + + def update(self): + """Call when forcing a refresh of the device.""" + if self._prev_state is None: + self._prev_state = self.state From c13b73549f5fc901aead8236b27c206b232d1694 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Fri, 3 Jan 2020 13:32:40 -0800 Subject: [PATCH 2/7] Removed unneeded attribute definitions --- homeassistant/components/lutron/__init__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/homeassistant/components/lutron/__init__.py b/homeassistant/components/lutron/__init__.py index 6e0098504b8c3..2eeebac4c96ce 100644 --- a/homeassistant/components/lutron/__init__.py +++ b/homeassistant/components/lutron/__init__.py @@ -20,11 +20,6 @@ # Attribute on events that indicates what action was taken with the button. ATTR_ACTION = "action" -ATTR_AREA_NAME = "area_name" -ATTR_KEYPAD_NAME = "keypad_name" -ATTR_BUTTON_NAME = "button_name" -ATTR_BUTTON_ID = "button_id" -ATTR_KEYPAD_ID = "keypad_id" ATTR_FULL_ID = "full_id" CONFIG_SCHEMA = vol.Schema( From 719cdac7cf7cfdd72161fbdd795c571d1960f9c8 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Sun, 15 Mar 2020 09:09:14 -0700 Subject: [PATCH 3/7] Pull initial state from Lutron on startup --- homeassistant/components/lutron/switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 7847131096371..1ef1ef7ffc304 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -105,4 +105,4 @@ def name(self): def update(self): """Call when forcing a refresh of the device.""" if self._prev_state is None: - self._prev_state = self.state + self._prev_state = self._lutron_device.state From 7e95dc8fcd5684f83a26a096b03795e99a2695fe Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Sun, 19 Apr 2020 09:53:51 -0700 Subject: [PATCH 4/7] Format updates per code review --- homeassistant/components/lutron/switch.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 1ef1ef7ffc304..06948e9b0f3a7 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -68,7 +68,6 @@ class LutronLed(LutronDevice, SwitchDevice): def __init__(self, area_name, keypad_name, scene_device, led_device, controller): """Initialize the switch.""" - self._prev_state = None self._keypad_name = keypad_name self._scene_name = scene_device.name super().__init__(area_name, led_device, controller) @@ -84,10 +83,11 @@ def turn_off(self, **kwargs): @property def device_state_attributes(self): """Return the state attributes.""" - attr = {} - attr["keypad"] = self._keypad_name - attr["scene"] = self._scene_name - attr["led"] = self._lutron_device.name + attr = { + "keypad": self._keypad_name, + "scene": self._scene_name, + "led": self._lutron_device.name, + } return attr @property @@ -98,11 +98,8 @@ def is_on(self): @property def name(self): """Return the name of the LED.""" - return "{} {}: {} LED".format( - self._area_name, self._keypad_name, self._scene_name - ) + return f"{self._area_name} {self._keypad_name}: {self._scene_name} LED" def update(self): """Call when forcing a refresh of the device.""" - if self._prev_state is None: - self._prev_state = self._lutron_device.state + self._lutron_device.state From c3cfbaf58a40a1562dd5982b2792330055d70914 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Sun, 19 Apr 2020 15:25:05 -0700 Subject: [PATCH 5/7] Altered caching code to only fetch state if needed --- homeassistant/components/lutron/switch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 06948e9b0f3a7..fa87720c73234 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -102,4 +102,6 @@ def name(self): def update(self): """Call when forcing a refresh of the device.""" - self._lutron_device.state + if self._lutron_device.last_state is not None: + return self._lutron_device.last_state + return self._lutron_device.state From 14812206193d497448903c258776f94a9212af51 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Sun, 19 Apr 2020 15:45:24 -0700 Subject: [PATCH 6/7] Update homeassistant/components/lutron/switch.py Co-Authored-By: Martin Hjelmare --- homeassistant/components/lutron/switch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index fa87720c73234..7715491419bbb 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -103,5 +103,5 @@ def name(self): def update(self): """Call when forcing a refresh of the device.""" if self._lutron_device.last_state is not None: - return self._lutron_device.last_state - return self._lutron_device.state + return + self._lutron_device.state From f757346bf35f7e3f34539f14a024c29c803cd9be Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Sun, 19 Apr 2020 16:31:38 -0700 Subject: [PATCH 7/7] Cloud pylint is also offended by this ;) --- homeassistant/components/lutron/switch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/lutron/switch.py b/homeassistant/components/lutron/switch.py index 7715491419bbb..64ca5e6f21658 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -104,4 +104,6 @@ def update(self): """Call when forcing a refresh of the device.""" if self._lutron_device.last_state is not None: return - self._lutron_device.state + + # The following property getter actually triggers an update in Lutron + self._lutron_device.state # pylint: disable=pointless-statement