From d144228272deff59e86b34418d67cc964a956771 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Mon, 20 Apr 2020 06:44:55 -0700 Subject: [PATCH] Add support for Lutron Keypad LEDs (#30452) * Add support for Lutron Keypad LEDs * Removed unneeded attribute definitions * Pull initial state from Lutron on startup * Format updates per code review * Altered caching code to only fetch state if needed * Update homeassistant/components/lutron/switch.py Co-Authored-By: Martin Hjelmare * Cloud pylint is also offended by this ;) Co-authored-by: Martin Hjelmare --- homeassistant/components/lutron/__init__.py | 16 ++++-- homeassistant/components/lutron/switch.py | 57 +++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/lutron/__init__.py b/homeassistant/components/lutron/__init__.py index ac6ffa46b27..2eeebac4c96 100644 --- a/homeassistant/components/lutron/__init__.py +++ b/homeassistant/components/lutron/__init__.py @@ -20,6 +20,7 @@ LUTRON_DEVICES = "lutron_devices" # Attribute on events that indicates what action was taken with the button. ATTR_ACTION = "action" +ATTR_FULL_ID = "full_id" CONFIG_SCHEMA = vol.Schema( { @@ -37,7 +38,6 @@ CONFIG_SCHEMA = vol.Schema( 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 +84,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 +135,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 +143,17 @@ class LutronButton: 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 +167,5 @@ class LutronButton: 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 604f19fc2ae..64ca5e6f216 100644 --- a/homeassistant/components/lutron/switch.py +++ b/homeassistant/components/lutron/switch.py @@ -11,10 +11,21 @@ _LOGGER = logging.getLogger(__name__) 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,49 @@ class LutronSwitch(LutronDevice, SwitchDevice): """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._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 = { + "keypad": self._keypad_name, + "scene": self._scene_name, + "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 f"{self._area_name} {self._keypad_name}: {self._scene_name} LED" + + def update(self): + """Call when forcing a refresh of the device.""" + if self._lutron_device.last_state is not None: + return + + # The following property getter actually triggers an update in Lutron + self._lutron_device.state # pylint: disable=pointless-statement