|
@@ -47,6 +47,9 @@ async def async_setup_entry(
|
|
|
entities.append(ZLockGroupLastActionSensor(coordinator, entry, group_name))
|
|
entities.append(ZLockGroupLastActionSensor(coordinator, entry, group_name))
|
|
|
entities.append(ZLockGroupLastUserSensor(coordinator, entry, group_name))
|
|
entities.append(ZLockGroupLastUserSensor(coordinator, entry, group_name))
|
|
|
if any(lid in door_sensor_map for lid in group_lock_ids):
|
|
if any(lid in door_sensor_map for lid in group_lock_ids):
|
|
|
|
|
+ entities.append(
|
|
|
|
|
+ ZLockGroupDoorSensor(coordinator, entry, group_name, group_lock_ids)
|
|
|
|
|
+ )
|
|
|
entities.append(
|
|
entities.append(
|
|
|
ZLockGroupCombinedStateSensor(coordinator, entry, group_name, group_lock_ids)
|
|
ZLockGroupCombinedStateSensor(coordinator, entry, group_name, group_lock_ids)
|
|
|
)
|
|
)
|
|
@@ -280,6 +283,36 @@ class ZLockGroupLastUserSensor(_ZLockGroupBaseSensor):
|
|
|
return state.last_user if state else None
|
|
return state.last_user if state else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+class ZLockGroupDoorSensor(_ZLockGroupBaseSensor):
|
|
|
|
|
+ _attr_name = "Door"
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, coordinator, entry, group_name, group_lock_ids: list[str]):
|
|
|
|
|
+ super().__init__(coordinator, entry, group_name)
|
|
|
|
|
+ self._group_lock_ids = group_lock_ids
|
|
|
|
|
+ self._attr_unique_id = f"{entry.entry_id}_group_{group_name}_door"
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def native_value(self) -> str | None:
|
|
|
|
|
+ known = [
|
|
|
|
|
+ self.coordinator.data[lid].door_open
|
|
|
|
|
+ for lid in self._group_lock_ids
|
|
|
|
|
+ if lid in self.coordinator.data and self.coordinator.data[lid].door_open is not None
|
|
|
|
|
+ ]
|
|
|
|
|
+ if not known:
|
|
|
|
|
+ return None
|
|
|
|
|
+ return "Open" if any(known) else "Closed"
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def extra_state_attributes(self) -> dict:
|
|
|
|
|
+ return {
|
|
|
|
|
+ lid: (
|
|
|
|
|
+ None if (s := self.coordinator.data.get(lid)) is None or s.door_open is None
|
|
|
|
|
+ else ("Open" if s.door_open else "Closed")
|
|
|
|
|
+ )
|
|
|
|
|
+ for lid in self._group_lock_ids
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
|
|
class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
|
|
|
_attr_name = "Closed-Locked"
|
|
_attr_name = "Closed-Locked"
|
|
|
|
|
|
|
@@ -288,15 +321,19 @@ class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
|
|
|
self._group_lock_ids = group_lock_ids
|
|
self._group_lock_ids = group_lock_ids
|
|
|
self._attr_unique_id = f"{entry.entry_id}_group_{group_name}_closed_locked"
|
|
self._attr_unique_id = f"{entry.entry_id}_group_{group_name}_closed_locked"
|
|
|
|
|
|
|
|
- @property
|
|
|
|
|
- def native_value(self) -> str | None:
|
|
|
|
|
- contributing: list[DoorLockState] = []
|
|
|
|
|
|
|
+ def _per_lock_states(self) -> dict[str, DoorLockState | None]:
|
|
|
|
|
+ result = {}
|
|
|
for lid in self._group_lock_ids:
|
|
for lid in self._group_lock_ids:
|
|
|
lock_state = self.coordinator.data.get(lid)
|
|
lock_state = self.coordinator.data.get(lid)
|
|
|
- if lock_state and lock_state.last_action is not None and lock_state.door_open is not None:
|
|
|
|
|
- cs = compute_combined_state(lock_state.last_action, lock_state.door_open)
|
|
|
|
|
- if cs:
|
|
|
|
|
- contributing.append(cs)
|
|
|
|
|
|
|
+ if lock_state is None or lock_state.last_action is None or lock_state.door_open is None:
|
|
|
|
|
+ result[lid] = None
|
|
|
|
|
+ else:
|
|
|
|
|
+ result[lid] = compute_combined_state(lock_state.last_action, lock_state.door_open)
|
|
|
|
|
+ return result
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def native_value(self) -> str | None:
|
|
|
|
|
+ contributing = [s for s in self._per_lock_states().values() if s is not None]
|
|
|
if not contributing:
|
|
if not contributing:
|
|
|
return None
|
|
return None
|
|
|
if DoorLockState.JAMMED in contributing:
|
|
if DoorLockState.JAMMED in contributing:
|
|
@@ -306,3 +343,10 @@ class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
|
|
|
if all(s == DoorLockState.LOCKED for s in contributing):
|
|
if all(s == DoorLockState.LOCKED for s in contributing):
|
|
|
return DoorLockState.LOCKED.value
|
|
return DoorLockState.LOCKED.value
|
|
|
return DoorLockState.CLOSED.value
|
|
return DoorLockState.CLOSED.value
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def extra_state_attributes(self) -> dict:
|
|
|
|
|
+ return {
|
|
|
|
|
+ lid: (s.value if s is not None else None)
|
|
|
|
|
+ for lid, s in self._per_lock_states().items()
|
|
|
|
|
+ }
|