Skip to content

Commit

Permalink
Add time entity for sleep mode start time to Litter-Robot 3 (#94194)
Browse files Browse the repository at this point in the history
  • Loading branch information
natekspencer authored Jun 27, 2023
1 parent 21c619e commit ec8988f
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 1 deletion.
2 changes: 1 addition & 1 deletion homeassistant/components/litterrobot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
Platform.SWITCH,
),
LitterRobot: (Platform.VACUUM,),
LitterRobot3: (Platform.BUTTON,),
LitterRobot3: (Platform.BUTTON, Platform.TIME),
LitterRobot4: (Platform.UPDATE,),
FeederRobot: (Platform.BUTTON,),
}
Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/litterrobot/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@
"name": "Panel lockout"
}
},
"time": {
"sleep_mode_start_time": {
"name": "Sleep mode start time"
}
},
"vacuum": {
"litter_box": {
"name": "Litter box"
Expand Down
82 changes: 82 additions & 0 deletions homeassistant/components/litterrobot/time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Support for Litter-Robot time."""
from __future__ import annotations

from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from datetime import datetime, time
from typing import Any, Generic

from pylitterbot import LitterRobot3

from homeassistant.components.time import TimeEntity, TimeEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util

from .const import DOMAIN
from .entity import LitterRobotEntity, _RobotT
from .hub import LitterRobotHub


@dataclass
class RequiredKeysMixin(Generic[_RobotT]):
"""A class that describes robot time entity required keys."""

value_fn: Callable[[_RobotT], time | None]
set_fn: Callable[[_RobotT, time], Coroutine[Any, Any, bool]]


@dataclass
class RobotTimeEntityDescription(TimeEntityDescription, RequiredKeysMixin[_RobotT]):
"""A class that describes robot time entities."""


def _as_local_time(start: datetime | None) -> time | None:
"""Return a datetime as local time."""
return dt_util.as_local(start).time() if start else None


LITTER_ROBOT_3_SLEEP_START = RobotTimeEntityDescription[LitterRobot3](
key="sleep_mode_start_time",
translation_key="sleep_mode_start_time",
entity_category=EntityCategory.CONFIG,
value_fn=lambda robot: _as_local_time(robot.sleep_mode_start_time),
set_fn=lambda robot, value: robot.set_sleep_mode(
robot.sleep_mode_enabled, value.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE)
),
)


async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Litter-Robot cleaner using config entry."""
hub: LitterRobotHub = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
[
LitterRobotTimeEntity(
robot=robot, hub=hub, description=LITTER_ROBOT_3_SLEEP_START
)
for robot in hub.litter_robots()
if isinstance(robot, LitterRobot3)
]
)


class LitterRobotTimeEntity(LitterRobotEntity[_RobotT], TimeEntity):
"""Litter-Robot time entity."""

entity_description: RobotTimeEntityDescription[_RobotT]

@property
def native_value(self) -> time | None:
"""Return the value reported by the time."""
return self.entity_description.value_fn(self.robot)

async def async_set_value(self, value: time) -> None:
"""Update the current value."""
await self.entity_description.set_fn(self.robot, value)
35 changes: 35 additions & 0 deletions tests/components/litterrobot/test_time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Test the Litter-Robot time entity."""
from __future__ import annotations

from datetime import time
from unittest.mock import MagicMock

from pylitterbot import LitterRobot3

from homeassistant.components.time import DOMAIN as PLATFORM_DOMAIN
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant

from .conftest import setup_integration

SLEEP_START_TIME_ENTITY_ID = "time.test_sleep_mode_start_time"


async def test_sleep_mode_start_time(
hass: HomeAssistant, mock_account: MagicMock
) -> None:
"""Tests the sleep mode start time."""
await setup_integration(hass, mock_account, PLATFORM_DOMAIN)

entity = hass.states.get(SLEEP_START_TIME_ENTITY_ID)
assert entity
assert entity.state == "17:16:00"

robot: LitterRobot3 = mock_account.robots[0]
await hass.services.async_call(
PLATFORM_DOMAIN,
"set_value",
{ATTR_ENTITY_ID: SLEEP_START_TIME_ENTITY_ID, "time": time(23, 0)},
blocking=True,
)
robot.set_sleep_mode.assert_awaited_once_with(True, time(23, 0))

0 comments on commit ec8988f

Please sign in to comment.