mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Add visits today sensor for pets (#147459)
This commit is contained in:
parent
8881919efd
commit
2829cc1248
@ -48,6 +48,9 @@ class LitterRobotDataUpdateCoordinator(DataUpdateCoordinator[None]):
|
||||
"""Update all device states from the Litter-Robot API."""
|
||||
await self.account.refresh_robots()
|
||||
await self.account.load_pets()
|
||||
for pet in self.account.pets:
|
||||
# Need to fetch weight history for `get_visits_since`
|
||||
await pet.fetch_weight_history()
|
||||
|
||||
async def _async_setup(self) -> None:
|
||||
"""Set up the coordinator."""
|
||||
|
@ -49,6 +49,9 @@
|
||||
},
|
||||
"total_cycles": {
|
||||
"default": "mdi:counter"
|
||||
},
|
||||
"visits_today": {
|
||||
"default": "mdi:counter"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
@ -18,6 +18,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfMass
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .coordinator import LitterRobotConfigEntry
|
||||
from .entity import LitterRobotEntity, _WhiskerEntityT
|
||||
@ -39,6 +40,7 @@ class RobotSensorEntityDescription(SensorEntityDescription, Generic[_WhiskerEnti
|
||||
"""A class that describes robot sensor entities."""
|
||||
|
||||
icon_fn: Callable[[Any], str | None] = lambda _: None
|
||||
last_reset_fn: Callable[[], datetime | None] = lambda: None
|
||||
value_fn: Callable[[_WhiskerEntityT], float | datetime | str | None]
|
||||
|
||||
|
||||
@ -179,7 +181,14 @@ PET_SENSORS: list[RobotSensorEntityDescription] = [
|
||||
native_unit_of_measurement=UnitOfMass.POUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda pet: pet.weight,
|
||||
)
|
||||
),
|
||||
RobotSensorEntityDescription[Pet](
|
||||
key="visits_today",
|
||||
translation_key="visits_today",
|
||||
state_class=SensorStateClass.TOTAL,
|
||||
last_reset_fn=dt_util.start_of_local_day,
|
||||
value_fn=lambda pet: pet.get_visits_since(dt_util.start_of_local_day()),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -225,3 +234,8 @@ class LitterRobotSensorEntity(LitterRobotEntity[_WhiskerEntityT], SensorEntity):
|
||||
if (icon := self.entity_description.icon_fn(self.state)) is not None:
|
||||
return icon
|
||||
return super().icon
|
||||
|
||||
@property
|
||||
def last_reset(self) -> datetime | None:
|
||||
"""Return the time when the sensor was last reset, if any."""
|
||||
return self.entity_description.last_reset_fn() or super().last_reset
|
||||
|
@ -122,6 +122,10 @@
|
||||
"name": "Total cycles",
|
||||
"unit_of_measurement": "cycles"
|
||||
},
|
||||
"visits_today": {
|
||||
"name": "Visits today",
|
||||
"unit_of_measurement": "visits"
|
||||
},
|
||||
"waste_drawer": {
|
||||
"name": "Waste drawer"
|
||||
}
|
||||
|
@ -159,6 +159,15 @@ PET_DATA = {
|
||||
"gender": "FEMALE",
|
||||
"lastWeightReading": 9.1,
|
||||
"breeds": ["sphynx"],
|
||||
"weightHistory": [
|
||||
{"weight": 6.48, "timestamp": "2025-06-13T16:12:36"},
|
||||
{"weight": 6.6, "timestamp": "2025-06-14T03:52:00"},
|
||||
{"weight": 6.59, "timestamp": "2025-06-14T17:20:32"},
|
||||
{"weight": 6.5, "timestamp": "2025-06-14T19:22:48"},
|
||||
{"weight": 6.35, "timestamp": "2025-06-15T03:12:15"},
|
||||
{"weight": 6.45, "timestamp": "2025-06-15T15:27:21"},
|
||||
{"weight": 6.25, "timestamp": "2025-06-15T15:29:26"},
|
||||
],
|
||||
}
|
||||
|
||||
VACUUM_ENTITY_ID = "vacuum.test_litter_box"
|
||||
|
@ -52,6 +52,20 @@ def create_mock_robot(
|
||||
return robot
|
||||
|
||||
|
||||
def create_mock_pet(
|
||||
pet_data: dict | None,
|
||||
account: Account,
|
||||
side_effect: Any | None = None,
|
||||
) -> Pet:
|
||||
"""Create a mock Pet."""
|
||||
if not pet_data:
|
||||
pet_data = {}
|
||||
|
||||
pet = Pet(data={**PET_DATA, **pet_data}, session=account.session)
|
||||
pet.fetch_weight_history = AsyncMock(side_effect=side_effect)
|
||||
return pet
|
||||
|
||||
|
||||
def create_mock_account(
|
||||
robot_data: dict | None = None,
|
||||
side_effect: Any | None = None,
|
||||
@ -69,7 +83,7 @@ def create_mock_account(
|
||||
if skip_robots
|
||||
else [create_mock_robot(robot_data, account, v4, feeder, side_effect)]
|
||||
)
|
||||
account.pets = [Pet(PET_DATA, account.session)] if pet else []
|
||||
account.pets = [create_mock_pet(PET_DATA, account, side_effect)] if pet else []
|
||||
return account
|
||||
|
||||
|
||||
|
@ -124,6 +124,16 @@ async def test_pet_weight_sensor(
|
||||
assert sensor.attributes["unit_of_measurement"] == UnitOfMass.POUNDS
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-06-15 12:00:00+00:00")
|
||||
async def test_pet_visits_today_sensor(
|
||||
hass: HomeAssistant, mock_account_with_pet: MagicMock
|
||||
) -> None:
|
||||
"""Tests pet visits today sensors."""
|
||||
await setup_integration(hass, mock_account_with_pet, PLATFORM_DOMAIN)
|
||||
sensor = hass.states.get("sensor.kitty_visits_today")
|
||||
assert sensor.state == "2"
|
||||
|
||||
|
||||
async def test_litterhopper_sensor(
|
||||
hass: HomeAssistant, mock_account_with_litterhopper: MagicMock
|
||||
) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user