From e133813227c589742b0aab11a3ce25ab63af99b4 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Sun, 1 Jan 2023 22:29:45 +0100 Subject: [PATCH 01/11] Nuki: add battery percentage + add to device registry --- homeassistant/components/nuki/__init__.py | 15 ++++- homeassistant/components/nuki/sensor.py | 76 +++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/nuki/sensor.py diff --git a/homeassistant/components/nuki/__init__.py b/homeassistant/components/nuki/__init__.py index dcb359f32d23a..59cf09c5ccab9 100644 --- a/homeassistant/components/nuki/__init__.py +++ b/homeassistant/components/nuki/__init__.py @@ -19,6 +19,7 @@ DataUpdateCoordinator, UpdateFailed, ) +from homeassistant.helpers.entity import DeviceInfo from .const import ( DATA_BRIDGE, @@ -33,7 +34,7 @@ _LOGGER = logging.getLogger(__name__) -PLATFORMS = [Platform.BINARY_SENSOR, Platform.LOCK] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR] UPDATE_INTERVAL = timedelta(seconds=30) @@ -178,3 +179,15 @@ def __init__( """Pass coordinator to CoordinatorEntity.""" super().__init__(coordinator) self._nuki_device = nuki_device + + @property + def device_info(self) -> DeviceInfo: + """Return the device information.""" + + return DeviceInfo( + identifiers={(DOMAIN, self._nuki_device.nuki_id)}, + manufacturer="Nuki Home Solutions GmbH", + name=self._nuki_device.name, + sw_version=self._nuki_device.firmware_version, + hw_version=self._nuki_device.device_type_str, + ) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py new file mode 100644 index 0000000000000..112e14dc12909 --- /dev/null +++ b/homeassistant/components/nuki/sensor.py @@ -0,0 +1,76 @@ +"""Battery sensor for the Nuki Lock.""" + +from pynuki.constants import STATE_DOORSENSOR_OPENED + +from homeassistant.components.sensor import ( + SensorEntity, + SensorDeviceClass, +) + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity import EntityCategory +from homeassistant.const import ( + PERCENTAGE, +) + +from . import NukiEntity +from .const import ATTR_NUKI_ID, DATA_COORDINATOR, DATA_LOCKS, DOMAIN as NUKI_DOMAIN + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the Nuki lock sensor.""" + data = hass.data[NUKI_DOMAIN][entry.entry_id] + coordinator = data[DATA_COORDINATOR] + + entities = [] + + for lock in data[DATA_LOCKS]: + entities.append(NukiBatterySensor(coordinator, lock)) + + async_add_entities(entities) + + +class NukiBatterySensor(NukiEntity, SensorEntity): + """Representation of a Nuki Lock Battery sensor.""" + + @property + def name(self): + """Return the name of the lock.""" + return f"{self._nuki_device.name} Battery level" + + @property + def unique_id(self) -> str: + """Return a unique ID.""" + return f"{self._nuki_device.nuki_id}_battery_level" + + @property + def device_class(self) -> str: + """Return the device class.""" + return SensorDeviceClass.BATTERY + + @property + def extra_state_attributes(self): + """Return the device specific state attributes.""" + data = { + ATTR_NUKI_ID: self._nuki_device.nuki_id, + } + return data + + @property + def entity_category(self) -> str: + """Device entity category.""" + return EntityCategory.DIAGNOSTIC + + @property + def native_value(self) -> float | None: + """Return the state of the sensor.""" + return self._nuki_device.battery_charge + + @property + def native_unit_of_measurement(self) -> str: + """Return the unit the value is expressed in.""" + return PERCENTAGE From 2a3dcf56bc9ff57f690f1224b2bee3cc4bb0372a Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 08:17:43 +0100 Subject: [PATCH 02/11] Remove unused import --- homeassistant/components/nuki/sensor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 112e14dc12909..85b847214e383 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -1,7 +1,5 @@ """Battery sensor for the Nuki Lock.""" -from pynuki.constants import STATE_DOORSENSOR_OPENED - from homeassistant.components.sensor import ( SensorEntity, SensorDeviceClass, From 0e64324b6c59e05a68e0a67d0e25e81745ffd527 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 08:33:20 +0100 Subject: [PATCH 03/11] Fixing linting and sorting issues --- homeassistant/components/nuki/__init__.py | 2 +- homeassistant/components/nuki/sensor.py | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/nuki/__init__.py b/homeassistant/components/nuki/__init__.py index 59cf09c5ccab9..d9694ff635048 100644 --- a/homeassistant/components/nuki/__init__.py +++ b/homeassistant/components/nuki/__init__.py @@ -14,12 +14,12 @@ from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TOKEN, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, UpdateFailed, ) -from homeassistant.helpers.entity import DeviceInfo from .const import ( DATA_BRIDGE, diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 85b847214e383..ef33ba772f6f6 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -1,17 +1,11 @@ """Battery sensor for the Nuki Lock.""" -from homeassistant.components.sensor import ( - SensorEntity, - SensorDeviceClass, -) - +from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.config_entries import ConfigEntry +from homeassistant.const import PERCENTAGE from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity import EntityCategory -from homeassistant.const import ( - PERCENTAGE, -) +from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import NukiEntity from .const import ATTR_NUKI_ID, DATA_COORDINATOR, DATA_LOCKS, DOMAIN as NUKI_DOMAIN @@ -46,7 +40,7 @@ def unique_id(self) -> str: return f"{self._nuki_device.nuki_id}_battery_level" @property - def device_class(self) -> str: + def device_class(self): """Return the device class.""" return SensorDeviceClass.BATTERY @@ -59,12 +53,12 @@ def extra_state_attributes(self): return data @property - def entity_category(self) -> str: + def entity_category(self): """Device entity category.""" return EntityCategory.DIAGNOSTIC @property - def native_value(self) -> float | None: + def native_value(self) -> float: """Return the state of the sensor.""" return self._nuki_device.battery_charge From c5792182f62a2215c4183f7dc49a4dc9f171f1db Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 12:17:23 +0100 Subject: [PATCH 04/11] Update homeassistant/components/nuki/sensor.py Co-authored-by: Robert Svensson --- homeassistant/components/nuki/sensor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index ef33ba772f6f6..59c877c572c88 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -18,12 +18,12 @@ async def async_setup_entry( data = hass.data[NUKI_DOMAIN][entry.entry_id] coordinator = data[DATA_COORDINATOR] - entities = [] - - for lock in data[DATA_LOCKS]: - entities.append(NukiBatterySensor(coordinator, lock)) - - async_add_entities(entities) + async_add_entities( + [ + entities.append(NukiBatterySensor(coordinator, lock)) + for lock in data[DATA_LOCKS] + ] + ) class NukiBatterySensor(NukiEntity, SensorEntity): From f52008fb9c3b13944439efbdc0f657d82249efec Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 12:20:59 +0100 Subject: [PATCH 05/11] Shorthand for adding entities --- homeassistant/components/nuki/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 59c877c572c88..9a950598d5379 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -20,7 +20,7 @@ async def async_setup_entry( async_add_entities( [ - entities.append(NukiBatterySensor(coordinator, lock)) + NukiBatterySensor(coordinator, lock) for lock in data[DATA_LOCKS] ] ) From f77e64ca5227bd4538756a621337ae48263f7ed3 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 12:34:05 +0100 Subject: [PATCH 06/11] Use _attr_has_entity_name for battery sensor --- homeassistant/components/nuki/sensor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 9a950598d5379..ff06cc3e1b082 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -29,10 +29,12 @@ async def async_setup_entry( class NukiBatterySensor(NukiEntity, SensorEntity): """Representation of a Nuki Lock Battery sensor.""" + _attr_has_entity_name = True + @property def name(self): """Return the name of the lock.""" - return f"{self._nuki_device.name} Battery level" + return "Battery" @property def unique_id(self) -> str: From 49a4fb1ecb40d62b64ae8dac6dd945576dc26cc3 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Mon, 2 Jan 2023 12:37:43 +0100 Subject: [PATCH 07/11] Fix linting issue --- homeassistant/components/nuki/sensor.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index ff06cc3e1b082..3193542e27236 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -19,10 +19,7 @@ async def async_setup_entry( coordinator = data[DATA_COORDINATOR] async_add_entities( - [ - NukiBatterySensor(coordinator, lock) - for lock in data[DATA_LOCKS] - ] + [NukiBatterySensor(coordinator, lock) for lock in data[DATA_LOCKS]] ) From b0312136ded9cf08c6285f6f1faec3139936b8b7 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Sat, 7 Jan 2023 13:50:31 +0100 Subject: [PATCH 08/11] Remove device registry changes --- homeassistant/components/nuki/__init__.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/homeassistant/components/nuki/__init__.py b/homeassistant/components/nuki/__init__.py index d9694ff635048..4ff683318f983 100644 --- a/homeassistant/components/nuki/__init__.py +++ b/homeassistant/components/nuki/__init__.py @@ -14,7 +14,6 @@ from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TOKEN, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -179,15 +178,3 @@ def __init__( """Pass coordinator to CoordinatorEntity.""" super().__init__(coordinator) self._nuki_device = nuki_device - - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - - return DeviceInfo( - identifiers={(DOMAIN, self._nuki_device.nuki_id)}, - manufacturer="Nuki Home Solutions GmbH", - name=self._nuki_device.name, - sw_version=self._nuki_device.firmware_version, - hw_version=self._nuki_device.device_type_str, - ) From a7efbe93d980d9db1329f53297d55b4b7ad74b41 Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Sat, 7 Jan 2023 14:11:48 +0100 Subject: [PATCH 09/11] Exclude from coverage --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 42b43b93d4332..865dc70060369 100644 --- a/.coveragerc +++ b/.coveragerc @@ -870,6 +870,7 @@ omit = homeassistant/components/nuki/binary_sensor.py homeassistant/components/nuki/const.py homeassistant/components/nuki/lock.py + homeassistant/components/nuki/sensor.py homeassistant/components/nut/diagnostics.py homeassistant/components/nx584/alarm_control_panel.py homeassistant/components/nzbget/coordinator.py From c2ce5e4db76b518e144f436d60b8e17415820b0a Mon Sep 17 00:00:00 2001 From: Xavier Decuyper Date: Sat, 7 Jan 2023 17:07:29 +0100 Subject: [PATCH 10/11] Use _attr_ instead of properties --- homeassistant/components/nuki/sensor.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 3193542e27236..9394c08d07f3a 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -28,21 +28,16 @@ class NukiBatterySensor(NukiEntity, SensorEntity): _attr_has_entity_name = True - @property - def name(self): - """Return the name of the lock.""" - return "Battery" + _attr_name = "Battery" + _attr_native_unit_of_measurement = PERCENTAGE + _attr_device_class = SensorDeviceClass.BATTERY + _attr_entity_category = EntityCategory.DIAGNOSTIC @property def unique_id(self) -> str: """Return a unique ID.""" return f"{self._nuki_device.nuki_id}_battery_level" - @property - def device_class(self): - """Return the device class.""" - return SensorDeviceClass.BATTERY - @property def extra_state_attributes(self): """Return the device specific state attributes.""" @@ -51,17 +46,7 @@ def extra_state_attributes(self): } return data - @property - def entity_category(self): - """Device entity category.""" - return EntityCategory.DIAGNOSTIC - @property def native_value(self) -> float: """Return the state of the sensor.""" return self._nuki_device.battery_charge - - @property - def native_unit_of_measurement(self) -> str: - """Return the unit the value is expressed in.""" - return PERCENTAGE From 1f38e1bf1a8f1f6a3360759feef3b054369a9aa3 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sat, 7 Jan 2023 20:03:42 +0100 Subject: [PATCH 11/11] Clean up --- homeassistant/components/nuki/sensor.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/nuki/sensor.py b/homeassistant/components/nuki/sensor.py index 9394c08d07f3a..f4a9103eecba7 100644 --- a/homeassistant/components/nuki/sensor.py +++ b/homeassistant/components/nuki/sensor.py @@ -19,7 +19,7 @@ async def async_setup_entry( coordinator = data[DATA_COORDINATOR] async_add_entities( - [NukiBatterySensor(coordinator, lock) for lock in data[DATA_LOCKS]] + NukiBatterySensor(coordinator, lock) for lock in data[DATA_LOCKS] ) @@ -27,7 +27,6 @@ class NukiBatterySensor(NukiEntity, SensorEntity): """Representation of a Nuki Lock Battery sensor.""" _attr_has_entity_name = True - _attr_name = "Battery" _attr_native_unit_of_measurement = PERCENTAGE _attr_device_class = SensorDeviceClass.BATTERY @@ -41,10 +40,7 @@ def unique_id(self) -> str: @property def extra_state_attributes(self): """Return the device specific state attributes.""" - data = { - ATTR_NUKI_ID: self._nuki_device.nuki_id, - } - return data + return {ATTR_NUKI_ID: self._nuki_device.nuki_id} @property def native_value(self) -> float: