221 lines
6.6 KiB
Python
221 lines
6.6 KiB
Python
"""Platform for Miele vacuum integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from enum import IntEnum
|
|
import logging
|
|
from typing import Any, Final
|
|
|
|
from aiohttp import ClientResponseError
|
|
from pymiele import MieleEnum
|
|
|
|
from homeassistant.components.vacuum import (
|
|
StateVacuumEntity,
|
|
StateVacuumEntityDescription,
|
|
VacuumActivity,
|
|
VacuumEntityFeature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
|
|
from .const import DOMAIN, PROCESS_ACTION, PROGRAM_ID, MieleActions, MieleAppliance
|
|
from .coordinator import MieleConfigEntry
|
|
from .entity import MieleEntity
|
|
|
|
PARALLEL_UPDATES = 1
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
# The following const classes define program speeds and programs for the vacuum cleaner.
|
|
# Miele have used the same and overlapping names for fan_speeds and programs even
|
|
# if the contexts are different. This is an attempt to make it clearer in the integration.
|
|
|
|
|
|
class FanSpeed(IntEnum):
|
|
"""Define fan speeds."""
|
|
|
|
normal = 0
|
|
turbo = 1
|
|
silent = 2
|
|
|
|
|
|
class FanProgram(IntEnum):
|
|
"""Define fan programs."""
|
|
|
|
auto = 1
|
|
spot = 2
|
|
turbo = 3
|
|
silent = 4
|
|
|
|
|
|
PROGRAM_MAP = {
|
|
"normal": FanProgram.auto,
|
|
"turbo": FanProgram.turbo,
|
|
"silent": FanProgram.silent,
|
|
}
|
|
|
|
PROGRAM_TO_SPEED: dict[int, str] = {
|
|
FanProgram.auto: "normal",
|
|
FanProgram.turbo: "turbo",
|
|
FanProgram.silent: "silent",
|
|
FanProgram.spot: "normal",
|
|
}
|
|
|
|
|
|
class MieleVacuumStateCode(MieleEnum):
|
|
"""Define vacuum state codes."""
|
|
|
|
idle = 0
|
|
cleaning = 5889
|
|
returning = 5890
|
|
paused = 5891
|
|
going_to_target_area = 5892
|
|
wheel_lifted = 5893
|
|
dirty_sensors = 5894
|
|
dust_box_missing = 5895
|
|
blocked_drive_wheels = 5896
|
|
blocked_brushes = 5897
|
|
check_dust_box_and_filter = 5898
|
|
internal_fault_reboot = 5899
|
|
blocked_front_wheel = 5900
|
|
docked = 5903, 5904
|
|
remote_controlled = 5910
|
|
missing2none = -9999
|
|
|
|
|
|
SUPPORTED_FEATURES = (
|
|
VacuumEntityFeature.STATE
|
|
| VacuumEntityFeature.FAN_SPEED
|
|
| VacuumEntityFeature.START
|
|
| VacuumEntityFeature.STOP
|
|
| VacuumEntityFeature.PAUSE
|
|
| VacuumEntityFeature.CLEAN_SPOT
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True, kw_only=True)
|
|
class MieleVacuumDescription(StateVacuumEntityDescription):
|
|
"""Class describing Miele vacuum entities."""
|
|
|
|
on_value: int
|
|
|
|
|
|
@dataclass
|
|
class MieleVacuumDefinition:
|
|
"""Class for defining vacuum entities."""
|
|
|
|
types: tuple[MieleAppliance, ...]
|
|
description: MieleVacuumDescription
|
|
|
|
|
|
VACUUM_TYPES: Final[tuple[MieleVacuumDefinition, ...]] = (
|
|
MieleVacuumDefinition(
|
|
types=(MieleAppliance.ROBOT_VACUUM_CLEANER,),
|
|
description=MieleVacuumDescription(
|
|
key="vacuum",
|
|
on_value=14,
|
|
name=None,
|
|
translation_key="vacuum",
|
|
),
|
|
),
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: MieleConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up the vacuum platform."""
|
|
coordinator = config_entry.runtime_data
|
|
|
|
async_add_entities(
|
|
MieleVacuum(coordinator, device_id, definition.description)
|
|
for device_id, device in coordinator.data.devices.items()
|
|
for definition in VACUUM_TYPES
|
|
if device.device_type in definition.types
|
|
)
|
|
|
|
|
|
VACUUM_PHASE_TO_ACTIVITY = {
|
|
MieleVacuumStateCode.idle.value: VacuumActivity.IDLE,
|
|
MieleVacuumStateCode.docked.value: VacuumActivity.DOCKED,
|
|
MieleVacuumStateCode.cleaning.value: VacuumActivity.CLEANING,
|
|
MieleVacuumStateCode.going_to_target_area.value: VacuumActivity.CLEANING,
|
|
MieleVacuumStateCode.returning.value: VacuumActivity.RETURNING,
|
|
MieleVacuumStateCode.wheel_lifted.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.dirty_sensors.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.dust_box_missing.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.blocked_drive_wheels.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.blocked_brushes.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.check_dust_box_and_filter.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.internal_fault_reboot.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.blocked_front_wheel.value: VacuumActivity.ERROR,
|
|
MieleVacuumStateCode.paused.value: VacuumActivity.PAUSED,
|
|
MieleVacuumStateCode.remote_controlled.value: VacuumActivity.PAUSED,
|
|
}
|
|
|
|
|
|
class MieleVacuum(MieleEntity, StateVacuumEntity):
|
|
"""Representation of a Vacuum entity."""
|
|
|
|
entity_description: MieleVacuumDescription
|
|
_attr_supported_features = SUPPORTED_FEATURES
|
|
_attr_fan_speed_list = [fan_speed.name for fan_speed in FanSpeed]
|
|
_attr_name = None
|
|
|
|
@property
|
|
def activity(self) -> VacuumActivity | None:
|
|
"""Return activity."""
|
|
return VACUUM_PHASE_TO_ACTIVITY.get(
|
|
MieleVacuumStateCode(self.device.state_program_phase).value
|
|
)
|
|
|
|
@property
|
|
def fan_speed(self) -> str | None:
|
|
"""Return the fan speed."""
|
|
return PROGRAM_TO_SPEED.get(self.device.state_program_id)
|
|
|
|
@property
|
|
def available(self) -> bool:
|
|
"""Return the availability of the entity."""
|
|
|
|
return (
|
|
self.action.power_off_enabled or self.action.power_on_enabled
|
|
) and super().available
|
|
|
|
async def send(self, device_id: str, action: dict[str, Any]) -> None:
|
|
"""Send action to the device."""
|
|
try:
|
|
await self.api.send_action(device_id, action)
|
|
except ClientResponseError as ex:
|
|
raise HomeAssistantError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="set_state_error",
|
|
translation_placeholders={
|
|
"entity": self.entity_id,
|
|
},
|
|
) from ex
|
|
|
|
async def async_clean_spot(self, **kwargs: Any) -> None:
|
|
"""Clean spot."""
|
|
await self.send(self._device_id, {PROGRAM_ID: FanProgram.spot})
|
|
|
|
async def async_start(self, **kwargs: Any) -> None:
|
|
"""Start cleaning."""
|
|
await self.send(self._device_id, {PROCESS_ACTION: MieleActions.START})
|
|
|
|
async def async_stop(self, **kwargs: Any) -> None:
|
|
"""Stop cleaning."""
|
|
await self.send(self._device_id, {PROCESS_ACTION: MieleActions.STOP})
|
|
|
|
async def async_pause(self, **kwargs: Any) -> None:
|
|
"""Pause cleaning."""
|
|
await self.send(self._device_id, {PROCESS_ACTION: MieleActions.PAUSE})
|
|
|
|
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
|
"""Set fan speed."""
|
|
await self.send(self._device_id, {PROGRAM_ID: PROGRAM_MAP[fan_speed]})
|