mirror of https://github.com/home-assistant/core
165 lines
5.5 KiB
Python
165 lines
5.5 KiB
Python
"""Husqvarna Automower lawn mower entity."""
|
|
|
|
from datetime import timedelta
|
|
import logging
|
|
from typing import TYPE_CHECKING
|
|
|
|
from aioautomower.model import MowerActivities, MowerStates, WorkArea
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.components.lawn_mower import (
|
|
LawnMowerActivity,
|
|
LawnMowerEntity,
|
|
LawnMowerEntityFeature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
from homeassistant.helpers import config_validation as cv, entity_platform
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from . import AutomowerConfigEntry
|
|
from .const import DOMAIN
|
|
from .coordinator import AutomowerDataUpdateCoordinator
|
|
from .entity import AutomowerAvailableEntity, handle_sending_exception
|
|
|
|
DOCKED_ACTIVITIES = (MowerActivities.PARKED_IN_CS, MowerActivities.CHARGING)
|
|
MOWING_ACTIVITIES = (
|
|
MowerActivities.MOWING,
|
|
MowerActivities.LEAVING,
|
|
)
|
|
PAUSED_STATES = [
|
|
MowerStates.PAUSED,
|
|
MowerStates.WAIT_UPDATING,
|
|
MowerStates.WAIT_POWER_UP,
|
|
]
|
|
SUPPORT_STATE_SERVICES = (
|
|
LawnMowerEntityFeature.DOCK
|
|
| LawnMowerEntityFeature.PAUSE
|
|
| LawnMowerEntityFeature.START_MOWING
|
|
)
|
|
MOW = "mow"
|
|
PARK = "park"
|
|
OVERRIDE_MODES = [MOW, PARK]
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: AutomowerConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up lawn mower platform."""
|
|
coordinator = entry.runtime_data
|
|
async_add_entities(
|
|
AutomowerLawnMowerEntity(mower_id, coordinator) for mower_id in coordinator.data
|
|
)
|
|
|
|
platform = entity_platform.async_get_current_platform()
|
|
platform.async_register_entity_service(
|
|
"override_schedule",
|
|
{
|
|
vol.Required("override_mode"): vol.In(OVERRIDE_MODES),
|
|
vol.Required("duration"): vol.All(
|
|
cv.time_period,
|
|
cv.positive_timedelta,
|
|
vol.Range(min=timedelta(minutes=1), max=timedelta(days=42)),
|
|
),
|
|
},
|
|
"async_override_schedule",
|
|
)
|
|
platform.async_register_entity_service(
|
|
"override_schedule_work_area",
|
|
{
|
|
vol.Required("work_area_id"): vol.Coerce(int),
|
|
vol.Required("duration"): vol.All(
|
|
cv.time_period,
|
|
cv.positive_timedelta,
|
|
vol.Range(min=timedelta(minutes=1), max=timedelta(days=42)),
|
|
),
|
|
},
|
|
"async_override_schedule_work_area",
|
|
)
|
|
|
|
|
|
class AutomowerLawnMowerEntity(AutomowerAvailableEntity, LawnMowerEntity):
|
|
"""Defining each mower Entity."""
|
|
|
|
_attr_name = None
|
|
_attr_supported_features = SUPPORT_STATE_SERVICES
|
|
|
|
def __init__(
|
|
self,
|
|
mower_id: str,
|
|
coordinator: AutomowerDataUpdateCoordinator,
|
|
) -> None:
|
|
"""Set up HusqvarnaAutomowerEntity."""
|
|
super().__init__(mower_id, coordinator)
|
|
self._attr_unique_id = mower_id
|
|
|
|
@property
|
|
def activity(self) -> LawnMowerActivity:
|
|
"""Return the state of the mower."""
|
|
mower_attributes = self.mower_attributes
|
|
if mower_attributes.mower.state in PAUSED_STATES:
|
|
return LawnMowerActivity.PAUSED
|
|
if mower_attributes.mower.activity in MOWING_ACTIVITIES:
|
|
return LawnMowerActivity.MOWING
|
|
if mower_attributes.mower.activity == MowerActivities.GOING_HOME:
|
|
return LawnMowerActivity.RETURNING
|
|
if (mower_attributes.mower.state == "RESTRICTED") or (
|
|
mower_attributes.mower.activity in DOCKED_ACTIVITIES
|
|
):
|
|
return LawnMowerActivity.DOCKED
|
|
return LawnMowerActivity.ERROR
|
|
|
|
@property
|
|
def work_areas(self) -> dict[int, WorkArea] | None:
|
|
"""Return the work areas of the mower."""
|
|
return self.mower_attributes.work_areas
|
|
|
|
@handle_sending_exception()
|
|
async def async_start_mowing(self) -> None:
|
|
"""Resume schedule."""
|
|
await self.coordinator.api.commands.resume_schedule(self.mower_id)
|
|
|
|
@handle_sending_exception()
|
|
async def async_pause(self) -> None:
|
|
"""Pauses the mower."""
|
|
await self.coordinator.api.commands.pause_mowing(self.mower_id)
|
|
|
|
@handle_sending_exception()
|
|
async def async_dock(self) -> None:
|
|
"""Parks the mower until next schedule."""
|
|
await self.coordinator.api.commands.park_until_next_schedule(self.mower_id)
|
|
|
|
@handle_sending_exception()
|
|
async def async_override_schedule(
|
|
self, override_mode: str, duration: timedelta
|
|
) -> None:
|
|
"""Override the schedule with mowing or parking."""
|
|
if override_mode == MOW:
|
|
await self.coordinator.api.commands.start_for(self.mower_id, duration)
|
|
if override_mode == PARK:
|
|
await self.coordinator.api.commands.park_for(self.mower_id, duration)
|
|
|
|
@handle_sending_exception()
|
|
async def async_override_schedule_work_area(
|
|
self, work_area_id: int, duration: timedelta
|
|
) -> None:
|
|
"""Override the schedule with a certain work area."""
|
|
if not self.mower_attributes.capabilities.work_areas:
|
|
raise ServiceValidationError(
|
|
translation_domain=DOMAIN, translation_key="work_areas_not_supported"
|
|
)
|
|
if TYPE_CHECKING:
|
|
assert self.work_areas is not None
|
|
if work_area_id not in self.work_areas:
|
|
raise ServiceValidationError(
|
|
translation_domain=DOMAIN, translation_key="work_area_not_existing"
|
|
)
|
|
await self.coordinator.api.commands.start_in_workarea(
|
|
self.mower_id, work_area_id, duration
|
|
)
|