Explorar el Código

Add door and closed-locked group sensors with per-lock attributes

Groups now publish a Door sensor (open if any lock is open, closed if all
are closed) and expose per-lock states as attributes on both the Door and
Closed-Locked group sensors.
ZiB hace 4 meses
padre
commit
6a69668003
Se han modificado 1 ficheros con 51 adiciones y 7 borrados
  1. 51 7
      custom_components/zlock_slots/sensor.py

+ 51 - 7
custom_components/zlock_slots/sensor.py

@@ -47,6 +47,9 @@ async def async_setup_entry(
     entities.append(ZLockGroupLastActionSensor(coordinator, entry, group_name))
     entities.append(ZLockGroupLastUserSensor(coordinator, entry, group_name))
     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(
         ZLockGroupCombinedStateSensor(coordinator, entry, group_name, group_lock_ids)
       )
@@ -280,6 +283,36 @@ class ZLockGroupLastUserSensor(_ZLockGroupBaseSensor):
     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):
   _attr_name = "Closed-Locked"
 
@@ -288,15 +321,19 @@ class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
     self._group_lock_ids = group_lock_ids
     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:
       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:
       return None
     if DoorLockState.JAMMED in contributing:
@@ -306,3 +343,10 @@ class ZLockGroupCombinedStateSensor(_ZLockGroupBaseSensor):
     if all(s == DoorLockState.LOCKED for s in contributing):
       return DoorLockState.LOCKED.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()
+    }