Просмотр исходного кода

Add GuestNameSensor with name-part attributes

Publishes first_name, first_abbr, last_name, last_abbr, and public on the
Guest Name sensor so display devices can format names without template logic.
last_name uses rsplit to take the final word in multi-word names.
ZiB 4 месяцев назад
Родитель
Сommit
baebb7683b
2 измененных файлов с 65 добавлено и 1 удалено
  1. 22 1
      custom_components/room_cal_ha/sensor.py
  2. 43 0
      tests/test_sensors.py

+ 22 - 1
custom_components/room_cal_ha/sensor.py

@@ -43,7 +43,7 @@ async def async_setup_entry(
       name=device_name,
       name=device_name,
     )
     )
     entities += [
     entities += [
-      ReservationStrSensor(coordinator, entry, slot, device_info, "Guest Name", "guest_name", "mdi:account-convert"),
+      GuestNameSensor(coordinator, entry, slot, device_info, "Guest Name", "guest_name", "mdi:account-convert"),
       ReservationDateTimeSensor(coordinator, entry, slot, device_info, "Arrival", "check_in_date", "check_in_time", "mdi:calendar-start"),
       ReservationDateTimeSensor(coordinator, entry, slot, device_info, "Arrival", "check_in_date", "check_in_time", "mdi:calendar-start"),
       ReservationTimeSensor(coordinator, entry, slot, device_info, "Check In", "check_in_time", "mdi:timer-check-outline"),
       ReservationTimeSensor(coordinator, entry, slot, device_info, "Check In", "check_in_time", "mdi:timer-check-outline"),
       ReservationDateTimeSensor(coordinator, entry, slot, device_info, "Departure", "check_out_date", "check_out_time", "mdi:calendar-end"),
       ReservationDateTimeSensor(coordinator, entry, slot, device_info, "Departure", "check_out_date", "check_out_time", "mdi:calendar-end"),
@@ -99,6 +99,27 @@ class ReservationStrSensor(_ReservationSensor):
     return getattr(self._reservation(), self._field)
     return getattr(self._reservation(), self._field)
 
 
 
 
+class GuestNameSensor(ReservationStrSensor):
+  @property
+  def extra_state_attributes(self) -> dict[str, str | None] | None:
+    full: str | None = self._reservation().guest_name
+    if full is None:
+      return None
+    parts = full.rsplit(" ", 1)
+    first_name = parts[0]
+    last_name = parts[1] if len(parts) > 1 else None
+    first_abbr = first_name[0].upper() if first_name else None
+    last_abbr = last_name[0].upper() if last_name else None
+    public = f"{first_name} {last_abbr}." if last_abbr else full
+    return {
+      "first_name": first_name,
+      "first_abbr": first_abbr,
+      "last_name": last_name,
+      "last_abbr": last_abbr,
+      "public": public,
+    }
+
+
 class WiFiKeySensor(_ReservationSensor):
 class WiFiKeySensor(_ReservationSensor):
   def __init__(self, coordinator, entry, slot, device_info) -> None:
   def __init__(self, coordinator, entry, slot, device_info) -> None:
     super().__init__(coordinator, entry, slot, device_info, "WiFi Key", "wifi_key", "mdi:wifi-lock")
     super().__init__(coordinator, entry, slot, device_info, "WiFi Key", "wifi_key", "mdi:wifi-lock")

+ 43 - 0
tests/test_sensors.py

@@ -13,6 +13,7 @@ from custom_components.room_cal_ha.models import ApiStatusData, ReservationData
 from custom_components.room_cal_ha.sensor import (
 from custom_components.room_cal_ha.sensor import (
   ApiCheckedAtSensor,
   ApiCheckedAtSensor,
   ApiStatusSensor,
   ApiStatusSensor,
+  GuestNameSensor,
   LastRefreshSensor,
   LastRefreshSensor,
   ReservationDateTimeSensor,
   ReservationDateTimeSensor,
   ReservationStrSensor,
   ReservationStrSensor,
@@ -91,6 +92,48 @@ def test_str_sensor_none_when_field_is_none():
   assert s.native_value is None
   assert s.native_value is None
 
 
 
 
+# ---------------------------------------------------------------------------
+# GuestNameSensor
+# ---------------------------------------------------------------------------
+
+def test_guest_name_single_word():
+  coord = _coordinator(current=ReservationData(guest_name="Alice"))
+  s = _sensor(GuestNameSensor, coord, field="guest_name")
+  attrs = s.extra_state_attributes
+  assert attrs["first_name"] == "Alice"
+  assert attrs["first_abbr"] == "A"
+  assert attrs["last_name"] is None
+  assert attrs["last_abbr"] is None
+  assert attrs["public"] == "Alice"
+
+
+def test_guest_name_two_words():
+  coord = _coordinator(current=ReservationData(guest_name="ZiB Guest"))
+  s = _sensor(GuestNameSensor, coord, field="guest_name")
+  attrs = s.extra_state_attributes
+  assert attrs["first_name"] == "ZiB"
+  assert attrs["first_abbr"] == "Z"
+  assert attrs["last_name"] == "Guest"
+  assert attrs["last_abbr"] == "G"
+  assert attrs["public"] == "ZiB G."
+
+
+def test_guest_name_three_words_last_is_final():
+  coord = _coordinator(current=ReservationData(guest_name="ZiB Middle Guest"))
+  s = _sensor(GuestNameSensor, coord, field="guest_name")
+  attrs = s.extra_state_attributes
+  assert attrs["first_name"] == "ZiB Middle"
+  assert attrs["last_name"] == "Guest"
+  assert attrs["last_abbr"] == "G"
+  assert attrs["public"] == "ZiB Middle G."
+
+
+def test_guest_name_none_returns_no_attrs():
+  coord = _coordinator(current=ReservationData(guest_name=None))
+  s = _sensor(GuestNameSensor, coord, field="guest_name")
+  assert s.extra_state_attributes is None
+
+
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
 # ReservationTimeSensor
 # ReservationTimeSensor
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------