Skip to content
11 changes: 7 additions & 4 deletions custom_components/petlibro/devices/feeders/air_smart_feeder.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,13 @@ def screen_display_switch(self) -> bool:
return bool(self._data.get("realInfo", {}).get("screenDisplaySwitch", False))

@property
def remaining_desiccant(self) -> str:
def remaining_desiccant(self) -> float | None:
"""Get the remaining desiccant days."""
return cast(str, self._data.get("remainingDesiccantDays", "unknown"))
value = self._data.get("remainingDesiccantDays")
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def last_feed_time(self) -> str | None:
Expand All @@ -185,7 +189,7 @@ def last_feed_time(self) -> str | None:

if not raw or not isinstance(raw, list):
return None

for day_entry in raw:
work_records = day_entry.get("workRecords", [])
for record in work_records:
Expand All @@ -196,7 +200,6 @@ def last_feed_time(self) -> str | None:
dt = datetime.fromtimestamp(timestamp_ms / 1000)
_LOGGER.debug("Returning formatted time: %s", dt.strftime("%Y-%m-%d %H:%M:%S"))
return dt.strftime("%Y-%m-%d %H:%M:%S")

return None

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,14 @@ def video_record_mode(self) -> str:
return self._data.get("realInfo", {}).get("videoRecordMode", "unknown")

@property
def remaining_desiccant(self) -> str:
def remaining_desiccant(self) -> float | None:
"""Get the remaining desiccant days."""
return cast(str, self._data.get("remainingDesiccantDays", "unknown"))

value = self._data.get("remainingDesiccantDays")
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def last_feed_time(self) -> str | None:
"""Return the recordTime of the last successful grain output as a formatted string."""
Expand All @@ -207,7 +211,7 @@ def last_feed_time(self) -> str | None:

if not raw or not isinstance(raw, list):
return None

for day_entry in raw:
work_records = day_entry.get("workRecords", [])
for record in work_records:
Expand All @@ -218,7 +222,6 @@ def last_feed_time(self) -> str | None:
dt = datetime.fromtimestamp(timestamp_ms / 1000)
_LOGGER.debug("Returning formatted time: %s", dt.strftime("%Y-%m-%d %H:%M:%S"))
return dt.strftime("%Y-%m-%d %H:%M:%S")

return None

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,13 @@ def screen_display_switch(self) -> bool:
return bool(self._data.get("realInfo", {}).get("screenDisplaySwitch", False))

@property
def remaining_desiccant(self) -> str:
"""Get the remaining desiccant days."""
return cast(str, self._data.get("remainingDesiccantDays", "unknown"))

def remaining_desiccant(self) -> float | None:
value = self._data.get("remainingDesiccantDays")
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def last_feed_time(self) -> str | None:
"""Return the recordTime of the last successful grain output as a formatted string."""
Expand All @@ -186,7 +189,7 @@ def last_feed_time(self) -> str | None:

if not raw or not isinstance(raw, list):
return None

for day_entry in raw:
work_records = day_entry.get("workRecords", [])
for record in work_records:
Expand All @@ -197,7 +200,6 @@ def last_feed_time(self) -> str | None:
dt = datetime.fromtimestamp(timestamp_ms / 1000)
_LOGGER.debug("Returning formatted time: %s", dt.strftime("%Y-%m-%d %H:%M:%S"))
return dt.strftime("%Y-%m-%d %H:%M:%S")

return None

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,13 @@ def child_lock_switch(self) -> bool:
return not self._data.get("realInfo", {}).get("childLockSwitch", False)

@property
def remaining_desiccant(self) -> str:
def remaining_desiccant(self) -> float | None:
"""Get the remaining desiccant days."""
return cast(str, self._data.get("remainingDesiccantDays", "unknown"))
value = self._data.get("remainingDesiccantDays")
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def desiccant_cycle(self) -> float:
Expand All @@ -214,7 +218,7 @@ def last_feed_time(self) -> str | None:

if not raw or not isinstance(raw, list):
return None

for day_entry in raw:
work_records = day_entry.get("workRecords", [])
for record in work_records:
Expand All @@ -225,7 +229,6 @@ def last_feed_time(self) -> str | None:
dt = datetime.fromtimestamp(timestamp_ms / 1000)
_LOGGER.debug("Returning formatted time: %s", dt.strftime("%Y-%m-%d %H:%M:%S"))
return dt.strftime("%Y-%m-%d %H:%M:%S")

return None

@property
Expand Down
11 changes: 7 additions & 4 deletions custom_components/petlibro/devices/feeders/space_smart_feeder.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,13 @@ def screen_display_switch(self) -> bool:
return bool(self._data.get("realInfo", {}).get("screenDisplaySwitch", False))

@property
def remaining_desiccant(self) -> str:
def remaining_desiccant(self) -> float | None:
"""Get the remaining desiccant days."""
return cast(str, self._data.get("remainingDesiccantDays", "unknown"))
value = self._data.get("remainingDesiccantDays")
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def last_feed_time(self) -> str | None:
Expand All @@ -182,7 +186,7 @@ def last_feed_time(self) -> str | None:

if not raw or not isinstance(raw, list):
return None

for day_entry in raw:
work_records = day_entry.get("workRecords", [])
for record in work_records:
Expand All @@ -193,7 +197,6 @@ def last_feed_time(self) -> str | None:
dt = datetime.fromtimestamp(timestamp_ms / 1000)
_LOGGER.debug("Returning formatted time: %s", dt.strftime("%Y-%m-%d %H:%M:%S"))
return dt.strftime("%Y-%m-%d %H:%M:%S")

return None

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,22 @@ def weight_percent(self) -> int:
return self._data.get("realInfo", {}).get("weightPercent", 0)

@property
def remaining_filter_days(self) -> int:
"""Get the number of days remaining for the filter replacement."""
return self._data.get("realInfo", {}).get("remainingReplacementDays", 0)
def remaining_filter_days(self) -> float | None:
"""Get the remaining desiccant days."""
value = self._data.get("realInfo", {}).get("remainingReplacementDays", 0)
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def remaining_cleaning_days(self) -> int:
"""Get the number of days remaining for machine cleaning."""
return self._data.get("realInfo", {}).get("remainingCleaningDays", 0)
def remaining_cleaning_days(self) -> float | None:
"""Get the remaining desiccant days."""
value = self._data.get("realInfo", {}).get("remainingCleaningDays", 0)
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def vacuum_state(self) -> bool:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,22 @@ def weight_percent(self) -> int:
return self._data.get("realInfo", {}).get("weightPercent", 0)

@property
def remaining_filter_days(self) -> int:
"""Get the number of days remaining for the filter replacement."""
return self._data.get("realInfo", {}).get("remainingReplacementDays", 0)
def remaining_filter_days(self) -> float | None:
"""Get the remaining desiccant days."""
value = self._data.get("realInfo", {}).get("remainingReplacementDays", 0)
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def remaining_cleaning_days(self) -> int:
"""Get the number of days remaining for machine cleaning."""
return self._data.get("realInfo", {}).get("remainingCleaningDays", 0)
def remaining_cleaning_days(self) -> float | None:
"""Get the remaining desiccant days."""
value = self._data.get("realInfo", {}).get("remainingCleaningDays", 0)
try:
return float(value) if value is not None else None
except (TypeError, ValueError):
return None

@property
def vacuum_state(self) -> bool:
Expand Down
31 changes: 27 additions & 4 deletions custom_components/petlibro/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ def _format_state(self, state):
key="remaining_desiccant",
translation_key="remaining_desiccant",
icon="mdi:package",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Desiccant Days"
),
PetLibroSensorEntityDescription[GranarySmartFeeder](
Expand Down Expand Up @@ -425,7 +428,9 @@ def _format_state(self, state):
key="remaining_desiccant",
translation_key="remaining_desiccant",
icon="mdi:package",
native_unit_of_measurement="days",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Desiccant Days"
),
PetLibroSensorEntityDescription[GranarySmartCameraFeeder](
Expand Down Expand Up @@ -544,6 +549,9 @@ def _format_state(self, state):
key="remaining_desiccant",
translation_key="remaining_desiccant",
icon="mdi:package",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Desiccant Days"
),
PetLibroSensorEntityDescription[OneRFIDSmartFeeder](
Expand Down Expand Up @@ -595,7 +603,8 @@ def _format_state(self, state):
key="today_eating_time",
translation_key="today_eating_time",
icon="mdi:history",
name="Last Feed Time"
state_class=SensorStateClass.TOTAL_INCREASING,
name="Today's Total Eating Time"
),
PetLibroSensorEntityDescription[OneRFIDSmartFeeder](
key="last_feed_time",
Expand Down Expand Up @@ -800,6 +809,9 @@ def _format_state(self, state):
key="remaining_cleaning_days",
translation_key="remaining_cleaning_days",
icon="mdi:package",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Cleaning Days"
),
PetLibroSensorEntityDescription[DockstreamSmartFountain](
Expand Down Expand Up @@ -836,7 +848,9 @@ def _format_state(self, state):
key="remaining_filter_days",
translation_key="remaining_filter_days",
icon="mdi:package",
native_unit_of_measurement="days",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Filter Days"
),
],
Expand Down Expand Up @@ -870,6 +884,9 @@ def _format_state(self, state):
key="remaining_cleaning_days",
translation_key="remaining_cleaning_days",
icon="mdi:package",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Cleaning Days"
),
PetLibroSensorEntityDescription[DockstreamSmartRFIDFountain](
Expand All @@ -893,13 +910,17 @@ def _format_state(self, state):
translation_key="use_water_interval",
icon="mdi:water",
native_unit_of_measurement="min",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Water Interval"
),
PetLibroSensorEntityDescription[DockstreamSmartRFIDFountain](
key="use_water_duration",
translation_key="use_water_duration",
icon="mdi:water",
native_unit_of_measurement="min",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Water Time Duration"
),
# Does not work with multi pet tracking, but may use this code later once I have the API info for the RFID tags.
Expand All @@ -915,7 +936,9 @@ def _format_state(self, state):
key="remaining_filter_days",
translation_key="remaining_filter_days",
icon="mdi:package",
native_unit_of_measurement="days",
native_unit_of_measurement="d",
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
name="Remaining Filter Days"
),
]
Expand Down