Skip to content

Commit 5f1c0a0

Browse files
committed
Wrap repeating functions into a single entity
1 parent 5e31e0b commit 5f1c0a0

File tree

4 files changed

+46
-110
lines changed

4 files changed

+46
-110
lines changed

custom_components/nuki_web/binary_sensor.py

Lines changed: 7 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from .const import DOMAIN
1111
from .coordinator import NukiWebCoordinator
12+
from .entity import NukiEntity
1213

1314
_LOGGER = logging.getLogger(__name__)
1415

@@ -38,37 +39,17 @@ async def async_setup_entry(
3839

3940
async_add_entities(entities)
4041

41-
class NukiBatteryCriticalSensor(CoordinatorEntity, BinarySensorEntity):
42+
class NukiBatteryCriticalSensor(NukiEntity, BinarySensorEntity):
4243
"""Representation of a Nuki Web battery critical sensor."""
4344

4445
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
4546
"""Initialize."""
46-
super().__init__(coordinator)
47-
self._smartlock_id = smartlock_id
47+
super().__init__(coordinator, smartlock_id)
4848
self._attr_has_entity_name = True
4949
self._attr_translation_key = "battery_critical"
5050
self._attr_unique_id = f"{smartlock_id}_battery_critical"
5151
self._attr_device_class = BinarySensorDeviceClass.BATTERY
5252

53-
@property
54-
def available(self) -> bool:
55-
"""Return if entity is available."""
56-
return super().available and self._smartlock_id in self.coordinator.data
57-
58-
@property
59-
def device_info(self):
60-
"""Return device info."""
61-
if not self.available:
62-
return None
63-
data = self.coordinator.data[self._smartlock_id]
64-
return {
65-
"identifiers": {(DOMAIN, str(self._smartlock_id))},
66-
"name": data["name"],
67-
"manufacturer": "Nuki",
68-
"model": f"Smart Lock Type {data.get('type')}",
69-
"sw_version": str(data.get("firmwareVersion")),
70-
}
71-
7253
@property
7354
def is_on(self) -> bool | None:
7455
"""Return true if battery is critical."""
@@ -77,37 +58,17 @@ def is_on(self) -> bool | None:
7758
data = self.coordinator.data[self._smartlock_id]
7859
return data["state"].get("batteryCritical")
7960

80-
class NukiDoorSensor(CoordinatorEntity, BinarySensorEntity):
61+
class NukiDoorSensor(NukiEntity, BinarySensorEntity):
8162
"""Representation of a Nuki Web door sensor."""
8263

8364
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
8465
"""Initialize."""
85-
super().__init__(coordinator)
86-
self._smartlock_id = smartlock_id
66+
super().__init__(coordinator, smartlock_id)
8767
self._attr_has_entity_name = True
8868
self._attr_translation_key = "door"
8969
self._attr_unique_id = f"{smartlock_id}_door"
9070
self._attr_device_class = BinarySensorDeviceClass.DOOR
9171

92-
@property
93-
def available(self) -> bool:
94-
"""Return if entity is available."""
95-
return super().available and self._smartlock_id in self.coordinator.data
96-
97-
@property
98-
def device_info(self):
99-
"""Return device info."""
100-
if not self.available:
101-
return None
102-
data = self.coordinator.data[self._smartlock_id]
103-
return {
104-
"identifiers": {(DOMAIN, str(self._smartlock_id))},
105-
"name": data["name"],
106-
"manufacturer": "Nuki",
107-
"model": f"Smart Lock Type {data.get('type')}",
108-
"sw_version": str(data.get("firmwareVersion")),
109-
}
110-
11172
@property
11273
def is_on(self) -> bool | None:
11374
"""Return true if door is open."""
@@ -121,36 +82,16 @@ def is_on(self) -> bool | None:
12182
return False
12283
return None
12384

124-
class NukiRingToOpenSensor(CoordinatorEntity, BinarySensorEntity):
85+
class NukiRingToOpenSensor(NukiEntity, BinarySensorEntity):
12586
"""Representation of a Nuki Web Ring to Open sensor."""
12687

12788
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
12889
"""Initialize."""
129-
super().__init__(coordinator)
130-
self._smartlock_id = smartlock_id
90+
super().__init__(coordinator, smartlock_id)
13191
self._attr_has_entity_name = True
13292
self._attr_translation_key = "ring_to_open"
13393
self._attr_unique_id = f"{smartlock_id}_rto"
13494
# No specific device class, maybe RUNNING?
135-
136-
@property
137-
def available(self) -> bool:
138-
"""Return if entity is available."""
139-
return super().available and self._smartlock_id in self.coordinator.data
140-
141-
@property
142-
def device_info(self):
143-
"""Return device info."""
144-
if not self.available:
145-
return None
146-
data = self.coordinator.data[self._smartlock_id]
147-
return {
148-
"identifiers": {(DOMAIN, str(self._smartlock_id))},
149-
"name": data["name"],
150-
"manufacturer": "Nuki",
151-
"model": f"Smart Lock Type {data.get('type')}",
152-
"sw_version": str(data.get("firmwareVersion")),
153-
}
15495

15596
@property
15697
def is_on(self) -> bool | None:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Base entity for Nuki Web."""
2+
from homeassistant.helpers.update_coordinator import CoordinatorEntity
3+
from homeassistant.helpers.entity import Entity
4+
5+
from .const import DOMAIN
6+
from .coordinator import NukiWebCoordinator
7+
8+
class NukiEntity(CoordinatorEntity, Entity):
9+
"""Base class for Nuki Web entities."""
10+
11+
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
12+
"""Initialize the entity."""
13+
super().__init__(coordinator)
14+
self._smartlock_id = smartlock_id
15+
16+
@property
17+
def available(self) -> bool:
18+
"""Return if entity is available."""
19+
return super().available and self._smartlock_id in self.coordinator.data
20+
21+
@property
22+
def device_info(self):
23+
"""Return device info."""
24+
if not self.available:
25+
return None
26+
data = self.coordinator.data[self._smartlock_id]
27+
return {
28+
"identifiers": {(DOMAIN, str(self._smartlock_id))},
29+
"name": data["name"],
30+
"manufacturer": "Nuki",
31+
"model": f"Smart Lock Type {data.get('type')}",
32+
"sw_version": str(data.get("firmwareVersion")),
33+
}

custom_components/nuki_web/lock.py

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from .const import DOMAIN
1212
from .coordinator import NukiWebCoordinator
13+
from .entity import NukiEntity
1314

1415
_LOGGER = logging.getLogger(__name__)
1516

@@ -50,37 +51,17 @@ async def async_setup_entry(
5051

5152
async_add_entities(entities)
5253

53-
class NukiLockEntity(CoordinatorEntity, LockEntity):
54+
class NukiLockEntity(NukiEntity, LockEntity):
5455
"""Representation of a Nuki Web lock."""
5556

5657
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
5758
"""Initialize the lock."""
58-
super().__init__(coordinator)
59-
self._smartlock_id = smartlock_id
59+
super().__init__(coordinator, smartlock_id)
6060
self._attr_has_entity_name = True
6161
self._attr_name = None
6262
self._attr_unique_id = f"{smartlock_id}_lock"
6363
self._attr_supported_features = LockEntityFeature.OPEN
6464

65-
@property
66-
def available(self) -> bool:
67-
"""Return if entity is available."""
68-
return super().available and self._smartlock_id in self.coordinator.data
69-
70-
@property
71-
def device_info(self):
72-
"""Return device info."""
73-
if not self.available:
74-
return None
75-
data = self.coordinator.data[self._smartlock_id]
76-
return {
77-
"identifiers": {(DOMAIN, str(self._smartlock_id))},
78-
"name": data["name"],
79-
"manufacturer": "Nuki",
80-
"model": f"Smart Lock Type {data.get('type')}",
81-
"sw_version": str(data.get("firmwareVersion")),
82-
}
83-
8465
@property
8566
def is_locked(self) -> bool | None:
8667
"""Return true if lock is locked."""

custom_components/nuki_web/sensor.py

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from .const import DOMAIN
1111
from .coordinator import NukiWebCoordinator
12+
from .entity import NukiEntity
1213

1314
_LOGGER = logging.getLogger(__name__)
1415

@@ -27,39 +28,19 @@ async def async_setup_entry(
2728

2829
async_add_entities(entities)
2930

30-
class NukiBatterySensor(CoordinatorEntity, SensorEntity):
31+
class NukiBatterySensor(NukiEntity, SensorEntity):
3132
"""Representation of a Nuki Web battery sensor."""
3233

3334
def __init__(self, coordinator: NukiWebCoordinator, smartlock_id: int) -> None:
3435
"""Initialize."""
35-
super().__init__(coordinator)
36-
self._smartlock_id = smartlock_id
36+
super().__init__(coordinator, smartlock_id)
3737
self._attr_has_entity_name = True
3838
self._attr_translation_key = "battery"
3939
self._attr_unique_id = f"{smartlock_id}_battery"
4040
self._attr_device_class = SensorDeviceClass.BATTERY
4141
self._attr_state_class = SensorStateClass.MEASUREMENT
4242
self._attr_native_unit_of_measurement = "%"
4343

44-
@property
45-
def available(self) -> bool:
46-
"""Return if entity is available."""
47-
return super().available and self._smartlock_id in self.coordinator.data
48-
49-
@property
50-
def device_info(self):
51-
"""Return device info."""
52-
if not self.available:
53-
return None
54-
data = self.coordinator.data[self._smartlock_id]
55-
return {
56-
"identifiers": {(DOMAIN, str(self._smartlock_id))},
57-
"name": data["name"],
58-
"manufacturer": "Nuki",
59-
"model": f"Smart Lock Type {data.get('type')}",
60-
"sw_version": str(data.get("firmwareVersion")),
61-
}
62-
6344
@property
6445
def native_value(self) -> int | None:
6546
"""Return the state of the sensor."""

0 commit comments

Comments
 (0)