From faaeadaa8c69d2502bf8838bb51ca82f45bd602b Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 00:53:25 -0400 Subject: [PATCH 01/14] Add support for Lutron Caseta occupancy/vacancy sensors This follows updates to pylutron-caseta to add support for these devices. This code works for me as a custom component in Home Assistant Core with pylutron-caseta 0.6.0 (currently unreleased). --- .../components/lutron_caseta/__init__.py | 22 ++++++- .../components/lutron_caseta/binary_sensor.py | 65 +++++++++++++++++++ .../components/lutron_caseta/manifest.json | 2 +- 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 homeassistant/components/lutron_caseta/binary_sensor.py diff --git a/homeassistant/components/lutron_caseta/__init__.py b/homeassistant/components/lutron_caseta/__init__.py index a3e384fd77bca..3ae58b22bd1a2 100644 --- a/homeassistant/components/lutron_caseta/__init__.py +++ b/homeassistant/components/lutron_caseta/__init__.py @@ -33,7 +33,8 @@ extra=vol.ALLOW_EXTRA, ) -LUTRON_CASETA_COMPONENTS = ["light", "switch", "cover", "scene", "fan"] +LUTRON_CASETA_COMPONENTS = ["light", "switch", "cover", "scene", "fan", + "binary_sensor"] async def async_setup(hass, base_config): @@ -79,6 +80,20 @@ def __init__(self, device, bridge): self._device = device self._smartbridge = bridge + @property + def device_info(self): + """Unique device identification""" + try: + return { + "identifiers": {(DOMAIN, self.serial)}, + "name": self.name, + "model": self.model, + "manufacturer": "Lutron", + } + except Exception: + _LOGGER.exception("Failed generating device info for %s and device %s", + self, self._device) + async def async_added_to_hass(self): """Register callbacks.""" self._smartbridge.add_subscriber(self.device_id, self.async_write_ha_state) @@ -98,6 +113,11 @@ def serial(self): """Return the serial number of the device.""" return self._device["serial"] + @property + def model(self): + """Return the model number of the device.""" + return self._device['model'] + @property def unique_id(self): """Return the unique ID of the device (serial).""" diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py new file mode 100644 index 0000000000000..84d3a72da91dd --- /dev/null +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -0,0 +1,65 @@ +"""Support for Lutron Caseta Occupancy/Vacancy Sensors.""" +import logging + +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_OCCUPANCY, + DOMAIN, + BinarySensorDevice, +) +from pylutron_caseta import (OCCUPANCY_GROUP_OCCUPIED, + OCCUPANCY_GROUP_UNOCCUPIED) +from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Set up the Lutron Caseta lights.""" + devs = [] + bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] + occupancy_groups = bridge.occupancy_groups + for occupancy_group in occupancy_groups.values(): + dev = LutronOccupancySensor(occupancy_group, bridge) + devs.append(dev) + + async_add_entities(devs, True) + + +class LutronOccupancySensor(LutronCasetaDevice, BinarySensorDevice): + """Representation of a Lutron occupancy group.""" + + @property + def device_class(self): + """Flag supported features.""" + return DEVICE_CLASS_OCCUPANCY + + @property + def is_on(self): + """Return the brightness of the light.""" + return self._device['status'] == OCCUPANCY_GROUP_OCCUPIED + + async def async_added_to_hass(self): + """Register callbacks.""" + self._smartbridge.add_occupancy_subscriber( + self.device_id, self.async_schedule_update_ha_state + ) + + @property + def device_id(self): + """Return the device ID used for calling pylutron_caseta.""" + return self._device["occupancy_group_id"] + + @property + def serial(self): + """Return a unique identifier.""" + return f"caseta_occupancygroup_{self.device_id}" + + @property + def model(self): + """Return a model number""" + return "PD-OSENS-WH" + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return {"Device ID": self.device_id} diff --git a/homeassistant/components/lutron_caseta/manifest.json b/homeassistant/components/lutron_caseta/manifest.json index 3dd8c8fac2e15..09f74e2b19c20 100644 --- a/homeassistant/components/lutron_caseta/manifest.json +++ b/homeassistant/components/lutron_caseta/manifest.json @@ -2,7 +2,7 @@ "domain": "lutron_caseta", "name": "Lutron Caseta", "documentation": "https://www.home-assistant.io/integrations/lutron_caseta", - "requirements": ["pylutron-caseta==0.5.1"], + "requirements": ["pylutron-caseta==0.6.0"], "dependencies": [], "codeowners": [] } From 9d2087a0769062316869e5869a4e290dc4daa36d Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 00:54:54 -0400 Subject: [PATCH 02/14] black formatting --- homeassistant/components/lutron_caseta/binary_sensor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index 84d3a72da91dd..23195f9775698 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -6,8 +6,7 @@ DOMAIN, BinarySensorDevice, ) -from pylutron_caseta import (OCCUPANCY_GROUP_OCCUPIED, - OCCUPANCY_GROUP_UNOCCUPIED) +from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED, OCCUPANCY_GROUP_UNOCCUPIED from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice _LOGGER = logging.getLogger(__name__) @@ -36,7 +35,7 @@ def device_class(self): @property def is_on(self): """Return the brightness of the light.""" - return self._device['status'] == OCCUPANCY_GROUP_OCCUPIED + return self._device["status"] == OCCUPANCY_GROUP_OCCUPIED async def async_added_to_hass(self): """Register callbacks.""" From d95ed1ff2f08c7ae006efe8e7725d84591011035 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 00:55:35 -0400 Subject: [PATCH 03/14] Update requirements_all.txt --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 927c8d35c13bb..e2f81dbcf202b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1364,7 +1364,7 @@ pylitejet==0.1 pyloopenergy==0.1.3 # homeassistant.components.lutron_caseta -pylutron-caseta==0.5.1 +pylutron-caseta==0.6.0 # homeassistant.components.lutron pylutron==0.2.5 From 44596d199e4b20f36e4b1bd2182de8e2a9ea4774 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 08:39:05 -0400 Subject: [PATCH 04/14] Apply black formatting --- homeassistant/components/lutron_caseta/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/lutron_caseta/__init__.py b/homeassistant/components/lutron_caseta/__init__.py index 3ae58b22bd1a2..0fddb6d3bd5fc 100644 --- a/homeassistant/components/lutron_caseta/__init__.py +++ b/homeassistant/components/lutron_caseta/__init__.py @@ -33,8 +33,7 @@ extra=vol.ALLOW_EXTRA, ) -LUTRON_CASETA_COMPONENTS = ["light", "switch", "cover", "scene", "fan", - "binary_sensor"] +LUTRON_CASETA_COMPONENTS = ["light", "switch", "cover", "scene", "fan", "binary_sensor"] async def async_setup(hass, base_config): @@ -91,8 +90,9 @@ def device_info(self): "manufacturer": "Lutron", } except Exception: - _LOGGER.exception("Failed generating device info for %s and device %s", - self, self._device) + _LOGGER.exception( + "Failed generating device info for %s and device %s", self, self._device + ) async def async_added_to_hass(self): """Register callbacks.""" @@ -116,7 +116,7 @@ def serial(self): @property def model(self): """Return the model number of the device.""" - return self._device['model'] + return self._device["model"] @property def unique_id(self): From 7e7627b6274abf2f7b9521ec19f01ae2e2894246 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 21:26:41 -0400 Subject: [PATCH 05/14] Resolve some review comments --- .../components/lutron_caseta/__init__.py | 19 +++---------------- .../components/lutron_caseta/binary_sensor.py | 12 +++++------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/lutron_caseta/__init__.py b/homeassistant/components/lutron_caseta/__init__.py index 0fddb6d3bd5fc..09a067d863113 100644 --- a/homeassistant/components/lutron_caseta/__init__.py +++ b/homeassistant/components/lutron_caseta/__init__.py @@ -79,24 +79,11 @@ def __init__(self, device, bridge): self._device = device self._smartbridge = bridge - @property - def device_info(self): - """Unique device identification""" - try: - return { - "identifiers": {(DOMAIN, self.serial)}, - "name": self.name, - "model": self.model, - "manufacturer": "Lutron", - } - except Exception: - _LOGGER.exception( - "Failed generating device info for %s and device %s", self, self._device - ) - async def async_added_to_hass(self): """Register callbacks.""" - self._smartbridge.add_subscriber(self.device_id, self.async_write_ha_state) + self._smartbridge.add_subscriber( + self.device_id, self.async_write_ha_state + ) @property def device_id(self): diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index 23195f9775698..7067ca97b27d0 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -9,19 +9,17 @@ from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED, OCCUPANCY_GROUP_UNOCCUPIED from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice -_LOGGER = logging.getLogger(__name__) - async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Lutron Caseta lights.""" - devs = [] + entities = [] bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] occupancy_groups = bridge.occupancy_groups for occupancy_group in occupancy_groups.values(): - dev = LutronOccupancySensor(occupancy_group, bridge) - devs.append(dev) + entity = LutronOccupancySensor(occupancy_group, bridge) + entities.append(entity) - async_add_entities(devs, True) + async_add_entities(entities, True) class LutronOccupancySensor(LutronCasetaDevice, BinarySensorDevice): @@ -40,7 +38,7 @@ def is_on(self): async def async_added_to_hass(self): """Register callbacks.""" self._smartbridge.add_occupancy_subscriber( - self.device_id, self.async_schedule_update_ha_state + self.device_id, self.async_write_ha_state ) @property From c0da06908606f96e99d38a68e6c8a9e79547a73b Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 21:32:36 -0400 Subject: [PATCH 06/14] serial -> unique_id --- homeassistant/components/lutron_caseta/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index 7067ca97b27d0..ff423f773be95 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -47,7 +47,7 @@ def device_id(self): return self._device["occupancy_group_id"] @property - def serial(self): + def unique_id(self): """Return a unique identifier.""" return f"caseta_occupancygroup_{self.device_id}" From 4f6e5a08bcf51939482721dac35ae0932f3e741d Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 23:09:55 -0400 Subject: [PATCH 07/14] Black formatting --- homeassistant/components/lutron_caseta/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homeassistant/components/lutron_caseta/__init__.py b/homeassistant/components/lutron_caseta/__init__.py index 09a067d863113..0167b147a2d59 100644 --- a/homeassistant/components/lutron_caseta/__init__.py +++ b/homeassistant/components/lutron_caseta/__init__.py @@ -81,9 +81,7 @@ def __init__(self, device, bridge): async def async_added_to_hass(self): """Register callbacks.""" - self._smartbridge.add_subscriber( - self.device_id, self.async_write_ha_state - ) + self._smartbridge.add_subscriber(self.device_id, self.async_write_ha_state) @property def device_id(self): From a9a88fa06b4e52eb88d90b3ea92d767232e55af1 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 23:12:43 -0400 Subject: [PATCH 08/14] Resolve linting errors --- homeassistant/components/lutron_caseta/binary_sensor.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index ff423f773be95..fc40cd0790986 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -1,12 +1,9 @@ """Support for Lutron Caseta Occupancy/Vacancy Sensors.""" -import logging - from homeassistant.components.binary_sensor import ( DEVICE_CLASS_OCCUPANCY, - DOMAIN, BinarySensorDevice, ) -from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED, OCCUPANCY_GROUP_UNOCCUPIED +from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice @@ -53,7 +50,7 @@ def unique_id(self): @property def model(self): - """Return a model number""" + """Return a model number.""" return "PD-OSENS-WH" @property From e326a964da1adc58ac7e870c238d9be1f4a2ed3b Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 23:19:45 -0400 Subject: [PATCH 09/14] Add code owner... --- homeassistant/components/lutron_caseta/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lutron_caseta/manifest.json b/homeassistant/components/lutron_caseta/manifest.json index 09f74e2b19c20..856bf285a1633 100644 --- a/homeassistant/components/lutron_caseta/manifest.json +++ b/homeassistant/components/lutron_caseta/manifest.json @@ -4,5 +4,5 @@ "documentation": "https://www.home-assistant.io/integrations/lutron_caseta", "requirements": ["pylutron-caseta==0.6.0"], "dependencies": [], - "codeowners": [] + "codeowners": ["@swails"] } From 4cc75f5dcbcdefcbc97e45824c6f54204a486d55 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Fri, 20 Mar 2020 23:20:56 -0400 Subject: [PATCH 10/14] Fix isort complaint --- homeassistant/components/lutron_caseta/binary_sensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index fc40cd0790986..8513051150e75 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -4,6 +4,7 @@ BinarySensorDevice, ) from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED + from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice From eb868592cff407cab86023d05339a96c4d9f7b60 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Sat, 21 Mar 2020 08:33:56 -0400 Subject: [PATCH 11/14] Fix remaining isort complaints --- homeassistant/components/lutron_caseta/binary_sensor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index 8513051150e75..3c4dfdfa7246f 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -1,9 +1,10 @@ """Support for Lutron Caseta Occupancy/Vacancy Sensors.""" +from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED + from homeassistant.components.binary_sensor import ( DEVICE_CLASS_OCCUPANCY, BinarySensorDevice, ) -from pylutron_caseta import OCCUPANCY_GROUP_OCCUPIED from . import LUTRON_CASETA_SMARTBRIDGE, LutronCasetaDevice From f9d1ead414b9f61aec1a938aac789f5030941985 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Sat, 21 Mar 2020 14:53:47 -0400 Subject: [PATCH 12/14] Update codeowners --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index f185059c999ed..fdf9906fccfc2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -211,6 +211,7 @@ homeassistant/components/luci/* @fbradyirl @mzdrale homeassistant/components/luftdaten/* @fabaff homeassistant/components/lupusec/* @majuss homeassistant/components/lutron/* @JonGilmore +homeassistant/components/lutron_caseta/* @swails homeassistant/components/mastodon/* @fabaff homeassistant/components/matrix/* @tinloaf homeassistant/components/mcp23017/* @jardiamj From 83e39dc78e7c7ca8060c4140eebe85bbe8b118dd Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Sat, 21 Mar 2020 15:13:17 -0400 Subject: [PATCH 13/14] Resolve outstanding review comments --- homeassistant/components/lutron_caseta/__init__.py | 5 ----- homeassistant/components/lutron_caseta/binary_sensor.py | 7 +------ 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/homeassistant/components/lutron_caseta/__init__.py b/homeassistant/components/lutron_caseta/__init__.py index 0167b147a2d59..47df6a221dde9 100644 --- a/homeassistant/components/lutron_caseta/__init__.py +++ b/homeassistant/components/lutron_caseta/__init__.py @@ -98,11 +98,6 @@ def serial(self): """Return the serial number of the device.""" return self._device["serial"] - @property - def model(self): - """Return the model number of the device.""" - return self._device["model"] - @property def unique_id(self): """Return the unique ID of the device (serial).""" diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index 3c4dfdfa7246f..c7c169511d267 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -50,12 +50,7 @@ def unique_id(self): """Return a unique identifier.""" return f"caseta_occupancygroup_{self.device_id}" - @property - def model(self): - """Return a model number.""" - return "PD-OSENS-WH" - @property def device_state_attributes(self): """Return the state attributes.""" - return {"Device ID": self.device_id} + return {"device_id": self.device_id} From d670353928995c9f52be843c2efbdddd45b0aeb6 Mon Sep 17 00:00:00 2001 From: Jason Swails Date: Sat, 21 Mar 2020 15:19:45 -0400 Subject: [PATCH 14/14] Remove caseta_ --- homeassistant/components/lutron_caseta/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lutron_caseta/binary_sensor.py b/homeassistant/components/lutron_caseta/binary_sensor.py index c7c169511d267..871f3c28664fc 100644 --- a/homeassistant/components/lutron_caseta/binary_sensor.py +++ b/homeassistant/components/lutron_caseta/binary_sensor.py @@ -48,7 +48,7 @@ def device_id(self): @property def unique_id(self): """Return a unique identifier.""" - return f"caseta_occupancygroup_{self.device_id}" + return f"occupancygroup_{self.device_id}" @property def device_state_attributes(self):