Implement new state property for vacuum which is using an enum (#126353)
* Implement new state property for vacuum which is using an enum * Mod * Mod init * Mods * Fix integrations * Tests * Fix state * Add vacuum tests * Fix last test * Litterrobot tests * Fixes * Tests * Fixes * Fix VacuumEntity * Mods * Mods * Mods * Update demo * LG * Fix vacuum * Fix Matter * Fix deprecation version * Mods * Fixes * Fix ruff * Fix tests * Fix roomba * Fix breaking datespull/132475/head
parent
bd9aefda62
commit
2eaf206562
|
@ -436,7 +436,7 @@ class AlexaPowerController(AlexaCapability):
|
|||
elif self.entity.domain == remote.DOMAIN:
|
||||
is_on = self.entity.state not in (STATE_OFF, STATE_UNKNOWN)
|
||||
elif self.entity.domain == vacuum.DOMAIN:
|
||||
is_on = self.entity.state == vacuum.STATE_CLEANING
|
||||
is_on = self.entity.state == vacuum.VacuumActivity.CLEANING
|
||||
elif self.entity.domain == timer.DOMAIN:
|
||||
is_on = self.entity.state != STATE_IDLE
|
||||
elif self.entity.domain == water_heater.DOMAIN:
|
||||
|
|
|
@ -7,12 +7,8 @@ from typing import Any
|
|||
|
||||
from homeassistant.components.vacuum import (
|
||||
ATTR_CLEANED_AREA,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -91,16 +87,11 @@ class StateDemoVacuum(StateVacuumEntity):
|
|||
"""Initialize the vacuum."""
|
||||
self._attr_name = name
|
||||
self._attr_supported_features = supported_features
|
||||
self._state = STATE_DOCKED
|
||||
self._attr_activity = VacuumActivity.DOCKED
|
||||
self._fan_speed = FAN_SPEEDS[1]
|
||||
self._cleaned_area: float = 0
|
||||
self._battery_level = 100
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Return the current state of the vacuum."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def battery_level(self) -> int:
|
||||
"""Return the current battery level of the vacuum."""
|
||||
|
@ -123,33 +114,33 @@ class StateDemoVacuum(StateVacuumEntity):
|
|||
|
||||
def start(self) -> None:
|
||||
"""Start or resume the cleaning task."""
|
||||
if self._state != STATE_CLEANING:
|
||||
self._state = STATE_CLEANING
|
||||
if self._attr_activity != VacuumActivity.CLEANING:
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
self._cleaned_area += 1.32
|
||||
self._battery_level -= 1
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def pause(self) -> None:
|
||||
"""Pause the cleaning task."""
|
||||
if self._state == STATE_CLEANING:
|
||||
self._state = STATE_PAUSED
|
||||
if self._attr_activity == VacuumActivity.CLEANING:
|
||||
self._attr_activity = VacuumActivity.PAUSED
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def stop(self, **kwargs: Any) -> None:
|
||||
"""Stop the cleaning task, do not return to dock."""
|
||||
self._state = STATE_IDLE
|
||||
self._attr_activity = VacuumActivity.IDLE
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
def return_to_base(self, **kwargs: Any) -> None:
|
||||
"""Return dock to charging base."""
|
||||
self._state = STATE_RETURNING
|
||||
self._attr_activity = VacuumActivity.RETURNING
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
event.call_later(self.hass, 30, self.__set_state_to_dock)
|
||||
|
||||
def clean_spot(self, **kwargs: Any) -> None:
|
||||
"""Perform a spot clean-up."""
|
||||
self._state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
self._cleaned_area += 1.32
|
||||
self._battery_level -= 1
|
||||
self.schedule_update_ha_state()
|
||||
|
@ -167,12 +158,12 @@ class StateDemoVacuum(StateVacuumEntity):
|
|||
"persistent_notification",
|
||||
service_data={"message": "I'm here!", "title": "Locate request"},
|
||||
)
|
||||
self._state = STATE_IDLE
|
||||
self._attr_activity = VacuumActivity.IDLE
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_clean_spot(self, **kwargs: Any) -> None:
|
||||
"""Locate the vacuum's position."""
|
||||
self._state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_send_command(
|
||||
|
@ -182,9 +173,9 @@ class StateDemoVacuum(StateVacuumEntity):
|
|||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Send a command to the vacuum."""
|
||||
self._state = STATE_IDLE
|
||||
self._attr_activity = VacuumActivity.IDLE
|
||||
self.async_write_ha_state()
|
||||
|
||||
def __set_state_to_dock(self, _: datetime) -> None:
|
||||
self._state = STATE_DOCKED
|
||||
self._attr_activity = VacuumActivity.DOCKED
|
||||
self.schedule_update_ha_state()
|
||||
|
|
|
@ -13,14 +13,9 @@ from deebot_client.models import CleanAction, CleanMode, Room, State
|
|||
import sucks
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
StateVacuumEntityDescription,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, SupportsResponse
|
||||
|
@ -123,22 +118,22 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
if self.error is not None:
|
||||
return STATE_ERROR
|
||||
return VacuumActivity.ERROR
|
||||
|
||||
if self.device.is_cleaning:
|
||||
return STATE_CLEANING
|
||||
return VacuumActivity.CLEANING
|
||||
|
||||
if self.device.is_charging:
|
||||
return STATE_DOCKED
|
||||
return VacuumActivity.DOCKED
|
||||
|
||||
if self.device.vacuum_status == sucks.CLEAN_MODE_STOP:
|
||||
return STATE_IDLE
|
||||
return VacuumActivity.IDLE
|
||||
|
||||
if self.device.vacuum_status == sucks.CHARGE_MODE_RETURNING:
|
||||
return STATE_RETURNING
|
||||
return VacuumActivity.RETURNING
|
||||
|
||||
return None
|
||||
|
||||
|
@ -202,7 +197,7 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||
|
||||
def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
||||
"""Set fan speed."""
|
||||
if self.state == STATE_CLEANING:
|
||||
if self.state == VacuumActivity.CLEANING:
|
||||
self.device.run(sucks.Clean(mode=self.device.clean_status, speed=fan_speed))
|
||||
|
||||
def send_command(
|
||||
|
@ -225,12 +220,12 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||
|
||||
|
||||
_STATE_TO_VACUUM_STATE = {
|
||||
State.IDLE: STATE_IDLE,
|
||||
State.CLEANING: STATE_CLEANING,
|
||||
State.RETURNING: STATE_RETURNING,
|
||||
State.DOCKED: STATE_DOCKED,
|
||||
State.ERROR: STATE_ERROR,
|
||||
State.PAUSED: STATE_PAUSED,
|
||||
State.IDLE: VacuumActivity.IDLE,
|
||||
State.CLEANING: VacuumActivity.CLEANING,
|
||||
State.RETURNING: VacuumActivity.RETURNING,
|
||||
State.DOCKED: VacuumActivity.DOCKED,
|
||||
State.ERROR: VacuumActivity.ERROR,
|
||||
State.PAUSED: VacuumActivity.PAUSED,
|
||||
}
|
||||
|
||||
_ATTR_ROOMS = "rooms"
|
||||
|
@ -284,7 +279,7 @@ class EcovacsVacuum(
|
|||
self.async_write_ha_state()
|
||||
|
||||
async def on_status(event: StateEvent) -> None:
|
||||
self._attr_state = _STATE_TO_VACUUM_STATE[event.state]
|
||||
self._attr_activity = _STATE_TO_VACUUM_STATE[event.state]
|
||||
self.async_write_ha_state()
|
||||
|
||||
self._subscribe(self._capability.battery.event, on_battery)
|
||||
|
|
|
@ -729,7 +729,7 @@ class DockTrait(_Trait):
|
|||
|
||||
def query_attributes(self) -> dict[str, Any]:
|
||||
"""Return dock query attributes."""
|
||||
return {"isDocked": self.state.state == vacuum.STATE_DOCKED}
|
||||
return {"isDocked": self.state.state == vacuum.VacuumActivity.DOCKED}
|
||||
|
||||
async def execute(self, command, data, params, challenge):
|
||||
"""Execute a dock command."""
|
||||
|
@ -825,8 +825,8 @@ class EnergyStorageTrait(_Trait):
|
|||
"capacityUntilFull": [
|
||||
{"rawValue": 100 - battery_level, "unit": "PERCENTAGE"}
|
||||
],
|
||||
"isCharging": self.state.state == vacuum.STATE_DOCKED,
|
||||
"isPluggedIn": self.state.state == vacuum.STATE_DOCKED,
|
||||
"isCharging": self.state.state == vacuum.VacuumActivity.DOCKED,
|
||||
"isPluggedIn": self.state.state == vacuum.VacuumActivity.DOCKED,
|
||||
}
|
||||
|
||||
async def execute(self, command, data, params, challenge):
|
||||
|
@ -882,8 +882,8 @@ class StartStopTrait(_Trait):
|
|||
|
||||
if domain == vacuum.DOMAIN:
|
||||
return {
|
||||
"isRunning": state == vacuum.STATE_CLEANING,
|
||||
"isPaused": state == vacuum.STATE_PAUSED,
|
||||
"isRunning": state == vacuum.VacuumActivity.CLEANING,
|
||||
"isPaused": state == vacuum.VacuumActivity.PAUSED,
|
||||
}
|
||||
|
||||
if domain in COVER_VALVE_DOMAINS:
|
||||
|
|
|
@ -11,7 +11,7 @@ from typing import Protocol
|
|||
from homeassistant.components.alarm_control_panel import AlarmControlPanelState
|
||||
from homeassistant.components.climate import HVACMode
|
||||
from homeassistant.components.lock import LockState
|
||||
from homeassistant.components.vacuum import STATE_CLEANING, STATE_ERROR, STATE_RETURNING
|
||||
from homeassistant.components.vacuum import VacuumActivity
|
||||
from homeassistant.components.water_heater import (
|
||||
STATE_ECO,
|
||||
STATE_ELECTRIC,
|
||||
|
@ -105,9 +105,9 @@ ON_OFF_STATES: dict[Platform | str, tuple[set[str], str, str]] = {
|
|||
Platform.VACUUM: (
|
||||
{
|
||||
STATE_ON,
|
||||
STATE_CLEANING,
|
||||
STATE_RETURNING,
|
||||
STATE_ERROR,
|
||||
VacuumActivity.CLEANING,
|
||||
VacuumActivity.RETURNING,
|
||||
VacuumActivity.ERROR,
|
||||
},
|
||||
STATE_ON,
|
||||
STATE_OFF,
|
||||
|
|
|
@ -21,7 +21,7 @@ from homeassistant.components.vacuum import (
|
|||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_RETURN_TO_BASE,
|
||||
SERVICE_START,
|
||||
STATE_CLEANING,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
|
@ -213,7 +213,7 @@ class Vacuum(Switch):
|
|||
@callback
|
||||
def async_update_state(self, new_state: State) -> None:
|
||||
"""Update switch state after state changed."""
|
||||
current_state = new_state.state in (STATE_CLEANING, STATE_ON)
|
||||
current_state = new_state.state in (VacuumActivity.CLEANING, STATE_ON)
|
||||
_LOGGER.debug("%s: Set current state to %s", self.entity_id, current_state)
|
||||
self.char_on.set_value(current_state)
|
||||
|
||||
|
|
|
@ -9,15 +9,11 @@ from thinqconnect import DeviceType
|
|||
from thinqconnect.integration import ExtendedProperty
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
StateVacuumEntityDescription,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import STATE_IDLE, STATE_PAUSED
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
|
@ -46,21 +42,21 @@ class State(StrEnum):
|
|||
|
||||
|
||||
ROBOT_STATUS_TO_HA = {
|
||||
"charging": STATE_DOCKED,
|
||||
"diagnosis": STATE_IDLE,
|
||||
"homing": STATE_RETURNING,
|
||||
"initializing": STATE_IDLE,
|
||||
"macrosector": STATE_IDLE,
|
||||
"monitoring_detecting": STATE_IDLE,
|
||||
"monitoring_moving": STATE_IDLE,
|
||||
"monitoring_positioning": STATE_IDLE,
|
||||
"pause": STATE_PAUSED,
|
||||
"reservation": STATE_IDLE,
|
||||
"setdate": STATE_IDLE,
|
||||
"sleep": STATE_IDLE,
|
||||
"standby": STATE_IDLE,
|
||||
"working": STATE_CLEANING,
|
||||
"error": STATE_ERROR,
|
||||
"charging": VacuumActivity.DOCKED,
|
||||
"diagnosis": VacuumActivity.IDLE,
|
||||
"homing": VacuumActivity.RETURNING,
|
||||
"initializing": VacuumActivity.IDLE,
|
||||
"macrosector": VacuumActivity.IDLE,
|
||||
"monitoring_detecting": VacuumActivity.IDLE,
|
||||
"monitoring_moving": VacuumActivity.IDLE,
|
||||
"monitoring_positioning": VacuumActivity.IDLE,
|
||||
"pause": VacuumActivity.PAUSED,
|
||||
"reservation": VacuumActivity.IDLE,
|
||||
"setdate": VacuumActivity.IDLE,
|
||||
"sleep": VacuumActivity.IDLE,
|
||||
"standby": VacuumActivity.IDLE,
|
||||
"working": VacuumActivity.CLEANING,
|
||||
"error": VacuumActivity.ERROR,
|
||||
}
|
||||
ROBOT_BATT_TO_HA = {
|
||||
"moveless": 5,
|
||||
|
@ -114,7 +110,7 @@ class ThinQStateVacuumEntity(ThinQEntity, StateVacuumEntity):
|
|||
super()._update_status()
|
||||
|
||||
# Update state.
|
||||
self._attr_state = ROBOT_STATUS_TO_HA[self.data.current_state]
|
||||
self._attr_activity = ROBOT_STATUS_TO_HA[self.data.current_state]
|
||||
|
||||
# Update battery.
|
||||
if (level := self.data.battery) is not None:
|
||||
|
@ -135,7 +131,7 @@ class ThinQStateVacuumEntity(ThinQEntity, StateVacuumEntity):
|
|||
"""Start the device."""
|
||||
if self.data.current_state == State.SLEEP:
|
||||
value = State.WAKE_UP
|
||||
elif self._attr_state == STATE_PAUSED:
|
||||
elif self._attr_activity == VacuumActivity.PAUSED:
|
||||
value = State.RESUME
|
||||
else:
|
||||
value = State.START
|
||||
|
|
|
@ -10,12 +10,9 @@ from pylitterbot.enums import LitterBoxStatus
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_PAUSED,
|
||||
StateVacuumEntity,
|
||||
StateVacuumEntityDescription,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -29,16 +26,16 @@ from .entity import LitterRobotEntity
|
|||
SERVICE_SET_SLEEP_MODE = "set_sleep_mode"
|
||||
|
||||
LITTER_BOX_STATUS_STATE_MAP = {
|
||||
LitterBoxStatus.CLEAN_CYCLE: STATE_CLEANING,
|
||||
LitterBoxStatus.EMPTY_CYCLE: STATE_CLEANING,
|
||||
LitterBoxStatus.CLEAN_CYCLE_COMPLETE: STATE_DOCKED,
|
||||
LitterBoxStatus.CAT_DETECTED: STATE_DOCKED,
|
||||
LitterBoxStatus.CAT_SENSOR_TIMING: STATE_DOCKED,
|
||||
LitterBoxStatus.DRAWER_FULL_1: STATE_DOCKED,
|
||||
LitterBoxStatus.DRAWER_FULL_2: STATE_DOCKED,
|
||||
LitterBoxStatus.READY: STATE_DOCKED,
|
||||
LitterBoxStatus.CAT_SENSOR_INTERRUPTED: STATE_PAUSED,
|
||||
LitterBoxStatus.OFF: STATE_DOCKED,
|
||||
LitterBoxStatus.CLEAN_CYCLE: VacuumActivity.CLEANING,
|
||||
LitterBoxStatus.EMPTY_CYCLE: VacuumActivity.CLEANING,
|
||||
LitterBoxStatus.CLEAN_CYCLE_COMPLETE: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.CAT_DETECTED: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.CAT_SENSOR_TIMING: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.DRAWER_FULL_1: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.DRAWER_FULL_2: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.READY: VacuumActivity.DOCKED,
|
||||
LitterBoxStatus.CAT_SENSOR_INTERRUPTED: VacuumActivity.PAUSED,
|
||||
LitterBoxStatus.OFF: VacuumActivity.DOCKED,
|
||||
}
|
||||
|
||||
LITTER_BOX_ENTITY = StateVacuumEntityDescription(
|
||||
|
@ -78,9 +75,9 @@ class LitterRobotCleaner(LitterRobotEntity[LitterRobot], StateVacuumEntity):
|
|||
)
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
def activity(self) -> VacuumActivity:
|
||||
"""Return the state of the cleaner."""
|
||||
return LITTER_BOX_STATUS_STATE_MAP.get(self.robot.status, STATE_ERROR)
|
||||
return LITTER_BOX_STATUS_STATE_MAP.get(self.robot.status, VacuumActivity.ERROR)
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
|
|
|
@ -9,16 +9,13 @@ from chip.clusters import Objects as clusters
|
|||
from matter_server.client.models import device_types
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
StateVacuumEntityDescription,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_IDLE, Platform
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
|
@ -127,25 +124,25 @@ class MatterVacuum(MatterEntity, StateVacuumEntity):
|
|||
operational_state: int = self.get_matter_attribute_value(
|
||||
clusters.RvcOperationalState.Attributes.OperationalState
|
||||
)
|
||||
state: str | None = None
|
||||
state: VacuumActivity | None = None
|
||||
if TYPE_CHECKING:
|
||||
assert self._supported_run_modes is not None
|
||||
if operational_state in (OperationalState.CHARGING, OperationalState.DOCKED):
|
||||
state = STATE_DOCKED
|
||||
state = VacuumActivity.DOCKED
|
||||
elif operational_state == OperationalState.SEEKING_CHARGER:
|
||||
state = STATE_RETURNING
|
||||
state = VacuumActivity.RETURNING
|
||||
elif operational_state in (
|
||||
OperationalState.UNABLE_TO_COMPLETE_OPERATION,
|
||||
OperationalState.UNABLE_TO_START_OR_RESUME,
|
||||
):
|
||||
state = STATE_ERROR
|
||||
state = VacuumActivity.ERROR
|
||||
elif (run_mode := self._supported_run_modes.get(run_mode_raw)) is not None:
|
||||
tags = {x.value for x in run_mode.modeTags}
|
||||
if ModeTag.CLEANING in tags:
|
||||
state = STATE_CLEANING
|
||||
state = VacuumActivity.CLEANING
|
||||
elif ModeTag.IDLE in tags:
|
||||
state = STATE_IDLE
|
||||
self._attr_state = state
|
||||
state = VacuumActivity.IDLE
|
||||
self._attr_activity = state
|
||||
|
||||
@callback
|
||||
def _calculate_features(self) -> None:
|
||||
|
|
|
@ -10,20 +10,12 @@ import voluptuous as vol
|
|||
from homeassistant.components import vacuum
|
||||
from homeassistant.components.vacuum import (
|
||||
ENTITY_ID_FORMAT,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_SUPPORTED_FEATURES,
|
||||
CONF_NAME,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
)
|
||||
from homeassistant.const import ATTR_SUPPORTED_FEATURES, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
@ -45,13 +37,20 @@ BATTERY = "battery_level"
|
|||
FAN_SPEED = "fan_speed"
|
||||
STATE = "state"
|
||||
|
||||
POSSIBLE_STATES: dict[str, str] = {
|
||||
STATE_IDLE: STATE_IDLE,
|
||||
STATE_DOCKED: STATE_DOCKED,
|
||||
STATE_ERROR: STATE_ERROR,
|
||||
STATE_PAUSED: STATE_PAUSED,
|
||||
STATE_RETURNING: STATE_RETURNING,
|
||||
STATE_CLEANING: STATE_CLEANING,
|
||||
STATE_IDLE = "idle"
|
||||
STATE_DOCKED = "docked"
|
||||
STATE_ERROR = "error"
|
||||
STATE_PAUSED = "paused"
|
||||
STATE_RETURNING = "returning"
|
||||
STATE_CLEANING = "cleaning"
|
||||
|
||||
POSSIBLE_STATES: dict[str, VacuumActivity] = {
|
||||
STATE_IDLE: VacuumActivity.IDLE,
|
||||
STATE_DOCKED: VacuumActivity.DOCKED,
|
||||
STATE_ERROR: VacuumActivity.ERROR,
|
||||
STATE_PAUSED: VacuumActivity.PAUSED,
|
||||
STATE_RETURNING: VacuumActivity.RETURNING,
|
||||
STATE_CLEANING: VacuumActivity.CLEANING,
|
||||
}
|
||||
|
||||
CONF_SUPPORTED_FEATURES = ATTR_SUPPORTED_FEATURES
|
||||
|
@ -265,7 +264,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity):
|
|||
if STATE in payload and (
|
||||
(state := payload[STATE]) in POSSIBLE_STATES or state is None
|
||||
):
|
||||
self._attr_state = (
|
||||
self._attr_activity = (
|
||||
POSSIBLE_STATES[cast(str, state)] if payload[STATE] else None
|
||||
)
|
||||
del payload[STATE]
|
||||
|
@ -277,7 +276,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity):
|
|||
self.add_subscription(
|
||||
CONF_STATE_TOPIC,
|
||||
self._state_message_received,
|
||||
{"_attr_battery_level", "_attr_fan_speed", "_attr_state"},
|
||||
{"_attr_battery_level", "_attr_fan_speed", "_attr_activity"},
|
||||
)
|
||||
|
||||
async def _subscribe_topics(self) -> None:
|
||||
|
|
|
@ -12,15 +12,12 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.components.vacuum import (
|
||||
ATTR_STATUS,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_MODE, STATE_IDLE, STATE_PAUSED
|
||||
from homeassistant.const import ATTR_MODE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
|
@ -169,23 +166,23 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity):
|
|||
robot_alert = None
|
||||
if self._state["state"] == 1:
|
||||
if self._state["details"]["isCharging"]:
|
||||
self._attr_state = STATE_DOCKED
|
||||
self._attr_activity = VacuumActivity.DOCKED
|
||||
self._status_state = "Charging"
|
||||
elif (
|
||||
self._state["details"]["isDocked"]
|
||||
and not self._state["details"]["isCharging"]
|
||||
):
|
||||
self._attr_state = STATE_DOCKED
|
||||
self._attr_activity = VacuumActivity.DOCKED
|
||||
self._status_state = "Docked"
|
||||
else:
|
||||
self._attr_state = STATE_IDLE
|
||||
self._attr_activity = VacuumActivity.IDLE
|
||||
self._status_state = "Stopped"
|
||||
|
||||
if robot_alert is not None:
|
||||
self._status_state = robot_alert
|
||||
elif self._state["state"] == 2:
|
||||
if robot_alert is None:
|
||||
self._attr_state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
self._status_state = (
|
||||
f"{MODE.get(self._state['cleaning']['mode'])} "
|
||||
f"{ACTION.get(self._state['action'])}"
|
||||
|
@ -200,10 +197,10 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity):
|
|||
else:
|
||||
self._status_state = robot_alert
|
||||
elif self._state["state"] == 3:
|
||||
self._attr_state = STATE_PAUSED
|
||||
self._attr_activity = VacuumActivity.PAUSED
|
||||
self._status_state = "Paused"
|
||||
elif self._state["state"] == 4:
|
||||
self._attr_state = STATE_ERROR
|
||||
self._attr_activity = VacuumActivity.ERROR
|
||||
self._status_state = ERRORS.get(self._state["error"])
|
||||
|
||||
self._attr_battery_level = self._state["details"]["charge"]
|
||||
|
@ -326,9 +323,9 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity):
|
|||
def return_to_base(self, **kwargs: Any) -> None:
|
||||
"""Set the vacuum cleaner to return to the dock."""
|
||||
try:
|
||||
if self._attr_state == STATE_CLEANING:
|
||||
if self._attr_activity == VacuumActivity.CLEANING:
|
||||
self.robot.pause_cleaning()
|
||||
self._attr_state = STATE_RETURNING
|
||||
self._attr_activity = VacuumActivity.RETURNING
|
||||
self.robot.send_to_base()
|
||||
except NeatoRobotException as ex:
|
||||
_LOGGER.error(
|
||||
|
@ -380,7 +377,7 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity):
|
|||
"Start cleaning zone '%s' with robot %s", zone, self.entity_id
|
||||
)
|
||||
|
||||
self._attr_state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
try:
|
||||
self.robot.start_cleaning(mode, navigation, category, boundary_id)
|
||||
except NeatoRobotException as ex:
|
||||
|
|
|
@ -8,13 +8,8 @@ from roborock.roborock_message import RoborockDataProtocol
|
|||
from roborock.roborock_typing import RoborockCommand
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse
|
||||
|
@ -27,29 +22,29 @@ from .coordinator import RoborockDataUpdateCoordinator
|
|||
from .entity import RoborockCoordinatedEntityV1
|
||||
|
||||
STATE_CODE_TO_STATE = {
|
||||
RoborockStateCode.starting: STATE_IDLE, # "Starting"
|
||||
RoborockStateCode.charger_disconnected: STATE_IDLE, # "Charger disconnected"
|
||||
RoborockStateCode.idle: STATE_IDLE, # "Idle"
|
||||
RoborockStateCode.remote_control_active: STATE_CLEANING, # "Remote control active"
|
||||
RoborockStateCode.cleaning: STATE_CLEANING, # "Cleaning"
|
||||
RoborockStateCode.returning_home: STATE_RETURNING, # "Returning home"
|
||||
RoborockStateCode.manual_mode: STATE_CLEANING, # "Manual mode"
|
||||
RoborockStateCode.charging: STATE_DOCKED, # "Charging"
|
||||
RoborockStateCode.charging_problem: STATE_ERROR, # "Charging problem"
|
||||
RoborockStateCode.paused: STATE_PAUSED, # "Paused"
|
||||
RoborockStateCode.spot_cleaning: STATE_CLEANING, # "Spot cleaning"
|
||||
RoborockStateCode.error: STATE_ERROR, # "Error"
|
||||
RoborockStateCode.shutting_down: STATE_IDLE, # "Shutting down"
|
||||
RoborockStateCode.updating: STATE_DOCKED, # "Updating"
|
||||
RoborockStateCode.docking: STATE_RETURNING, # "Docking"
|
||||
RoborockStateCode.going_to_target: STATE_CLEANING, # "Going to target"
|
||||
RoborockStateCode.zoned_cleaning: STATE_CLEANING, # "Zoned cleaning"
|
||||
RoborockStateCode.segment_cleaning: STATE_CLEANING, # "Segment cleaning"
|
||||
RoborockStateCode.emptying_the_bin: STATE_DOCKED, # "Emptying the bin" on s7+
|
||||
RoborockStateCode.washing_the_mop: STATE_DOCKED, # "Washing the mop" on s7maxV
|
||||
RoborockStateCode.going_to_wash_the_mop: STATE_RETURNING, # "Going to wash the mop" on s7maxV
|
||||
RoborockStateCode.charging_complete: STATE_DOCKED, # "Charging complete"
|
||||
RoborockStateCode.device_offline: STATE_ERROR, # "Device offline"
|
||||
RoborockStateCode.starting: VacuumActivity.IDLE, # "Starting"
|
||||
RoborockStateCode.charger_disconnected: VacuumActivity.IDLE, # "Charger disconnected"
|
||||
RoborockStateCode.idle: VacuumActivity.IDLE, # "Idle"
|
||||
RoborockStateCode.remote_control_active: VacuumActivity.CLEANING, # "Remote control active"
|
||||
RoborockStateCode.cleaning: VacuumActivity.CLEANING, # "Cleaning"
|
||||
RoborockStateCode.returning_home: VacuumActivity.RETURNING, # "Returning home"
|
||||
RoborockStateCode.manual_mode: VacuumActivity.CLEANING, # "Manual mode"
|
||||
RoborockStateCode.charging: VacuumActivity.DOCKED, # "Charging"
|
||||
RoborockStateCode.charging_problem: VacuumActivity.ERROR, # "Charging problem"
|
||||
RoborockStateCode.paused: VacuumActivity.PAUSED, # "Paused"
|
||||
RoborockStateCode.spot_cleaning: VacuumActivity.CLEANING, # "Spot cleaning"
|
||||
RoborockStateCode.error: VacuumActivity.ERROR, # "Error"
|
||||
RoborockStateCode.shutting_down: VacuumActivity.IDLE, # "Shutting down"
|
||||
RoborockStateCode.updating: VacuumActivity.DOCKED, # "Updating"
|
||||
RoborockStateCode.docking: VacuumActivity.RETURNING, # "Docking"
|
||||
RoborockStateCode.going_to_target: VacuumActivity.CLEANING, # "Going to target"
|
||||
RoborockStateCode.zoned_cleaning: VacuumActivity.CLEANING, # "Zoned cleaning"
|
||||
RoborockStateCode.segment_cleaning: VacuumActivity.CLEANING, # "Segment cleaning"
|
||||
RoborockStateCode.emptying_the_bin: VacuumActivity.DOCKED, # "Emptying the bin" on s7+
|
||||
RoborockStateCode.washing_the_mop: VacuumActivity.DOCKED, # "Washing the mop" on s7maxV
|
||||
RoborockStateCode.going_to_wash_the_mop: VacuumActivity.RETURNING, # "Going to wash the mop" on s7maxV
|
||||
RoborockStateCode.charging_complete: VacuumActivity.DOCKED, # "Charging complete"
|
||||
RoborockStateCode.device_offline: VacuumActivity.ERROR, # "Device offline"
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,7 +107,7 @@ class RoborockVacuum(RoborockCoordinatedEntityV1, StateVacuumEntity):
|
|||
self._attr_fan_speed_list = self._device_status.fan_power_options
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the status of the vacuum cleaner."""
|
||||
assert self._device_status.state is not None
|
||||
return STATE_CODE_TO_STATE.get(self._device_status.state)
|
||||
|
|
|
@ -6,7 +6,11 @@ https://home-assistant.io/components/vacuum.romy/.
|
|||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.vacuum import StateVacuumEntity, VacuumEntityFeature
|
||||
from homeassistant.components.vacuum import (
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
@ -75,7 +79,14 @@ class RomyVacuumEntity(RomyEntity, StateVacuumEntity):
|
|||
"""Handle updated data from the coordinator."""
|
||||
self._attr_fan_speed = FAN_SPEEDS[self.romy.fan_speed]
|
||||
self._attr_battery_level = self.romy.battery_level
|
||||
self._attr_state = self.romy.status
|
||||
if (status := self.romy.status) is None:
|
||||
self._attr_activity = None
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
try:
|
||||
self._attr_activity = VacuumActivity(status)
|
||||
except ValueError:
|
||||
self._attr_activity = None
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
|
|
@ -8,15 +8,11 @@ from typing import Any
|
|||
|
||||
from homeassistant.components.vacuum import (
|
||||
ATTR_STATUS,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_IDLE, STATE_PAUSED
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
@ -39,16 +35,16 @@ SUPPORT_IROBOT = (
|
|||
)
|
||||
|
||||
STATE_MAP = {
|
||||
"": STATE_IDLE,
|
||||
"charge": STATE_DOCKED,
|
||||
"evac": STATE_RETURNING, # Emptying at cleanbase
|
||||
"hmMidMsn": STATE_CLEANING, # Recharging at the middle of a cycle
|
||||
"hmPostMsn": STATE_RETURNING, # Cycle finished
|
||||
"hmUsrDock": STATE_RETURNING,
|
||||
"pause": STATE_PAUSED,
|
||||
"run": STATE_CLEANING,
|
||||
"stop": STATE_IDLE,
|
||||
"stuck": STATE_ERROR,
|
||||
"": VacuumActivity.IDLE,
|
||||
"charge": VacuumActivity.DOCKED,
|
||||
"evac": VacuumActivity.RETURNING, # Emptying at cleanbase
|
||||
"hmMidMsn": VacuumActivity.CLEANING, # Recharging at the middle of a cycle
|
||||
"hmPostMsn": VacuumActivity.RETURNING, # Cycle finished
|
||||
"hmUsrDock": VacuumActivity.RETURNING,
|
||||
"pause": VacuumActivity.PAUSED,
|
||||
"run": VacuumActivity.CLEANING,
|
||||
"stop": VacuumActivity.IDLE,
|
||||
"stuck": VacuumActivity.ERROR,
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -130,7 +126,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity):
|
|||
self._cap_position = self.vacuum_state.get("cap", {}).get("pose") == 1
|
||||
|
||||
@property
|
||||
def _robot_state(self):
|
||||
def activity(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
clean_mission_status = self.vacuum_state.get("cleanMissionStatus", {})
|
||||
cycle = clean_mission_status.get("cycle")
|
||||
|
@ -138,16 +134,11 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity):
|
|||
try:
|
||||
state = STATE_MAP[phase]
|
||||
except KeyError:
|
||||
return STATE_ERROR
|
||||
if cycle != "none" and state in (STATE_IDLE, STATE_DOCKED):
|
||||
state = STATE_PAUSED
|
||||
return VacuumActivity.ERROR
|
||||
if cycle != "none" and state in (VacuumActivity.IDLE, VacuumActivity.DOCKED):
|
||||
state = VacuumActivity.PAUSED
|
||||
return state
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
return self._robot_state
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes of the device."""
|
||||
|
@ -164,7 +155,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity):
|
|||
|
||||
# Only add cleaning time and cleaned area attrs when the vacuum is
|
||||
# currently on
|
||||
if self.state == STATE_CLEANING:
|
||||
if self.state == VacuumActivity.CLEANING:
|
||||
# Get clean mission status
|
||||
(
|
||||
state_attrs[ATTR_CLEANING_TIME],
|
||||
|
@ -218,7 +209,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity):
|
|||
|
||||
async def async_start(self) -> None:
|
||||
"""Start or resume the cleaning task."""
|
||||
if self.state == STATE_PAUSED:
|
||||
if self.state == VacuumActivity.PAUSED:
|
||||
await self.hass.async_add_executor_job(self.vacuum.send_command, "resume")
|
||||
else:
|
||||
await self.hass.async_add_executor_job(self.vacuum.send_command, "start")
|
||||
|
@ -233,10 +224,10 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity):
|
|||
|
||||
async def async_return_to_base(self, **kwargs):
|
||||
"""Set the vacuum cleaner to return to the dock."""
|
||||
if self.state == STATE_CLEANING:
|
||||
if self.state == VacuumActivity.CLEANING:
|
||||
await self.async_pause()
|
||||
for _ in range(10):
|
||||
if self.state == STATE_PAUSED:
|
||||
if self.state == VacuumActivity.PAUSED:
|
||||
break
|
||||
await asyncio.sleep(1)
|
||||
await self.hass.async_add_executor_job(self.vacuum.send_command, "dock")
|
||||
|
|
|
@ -9,12 +9,8 @@ from sharkiq import OperatingModes, PowerModes, Properties, SharkIqVacuum
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -30,10 +26,10 @@ from .const import DOMAIN, LOGGER, SERVICE_CLEAN_ROOM, SHARK
|
|||
from .coordinator import SharkIqUpdateCoordinator
|
||||
|
||||
OPERATING_STATE_MAP = {
|
||||
OperatingModes.PAUSE: STATE_PAUSED,
|
||||
OperatingModes.START: STATE_CLEANING,
|
||||
OperatingModes.STOP: STATE_IDLE,
|
||||
OperatingModes.RETURN: STATE_RETURNING,
|
||||
OperatingModes.PAUSE: VacuumActivity.PAUSED,
|
||||
OperatingModes.START: VacuumActivity.CLEANING,
|
||||
OperatingModes.STOP: VacuumActivity.IDLE,
|
||||
OperatingModes.RETURN: VacuumActivity.RETURNING,
|
||||
}
|
||||
|
||||
FAN_SPEEDS_MAP = {
|
||||
|
@ -156,7 +152,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum
|
|||
return self.sharkiq.get_property_value(Properties.RECHARGING_TO_RESUME)
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Get the current vacuum state.
|
||||
|
||||
NB: Currently, we do not return an error state because they can be very, very stale.
|
||||
|
@ -164,7 +160,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum
|
|||
user a notification.
|
||||
"""
|
||||
if self.sharkiq.get_property_value(Properties.CHARGING_STATUS):
|
||||
return STATE_DOCKED
|
||||
return VacuumActivity.DOCKED
|
||||
op_mode = self.sharkiq.get_property_value(Properties.OPERATING_MODE)
|
||||
return OPERATING_STATE_MAP.get(op_mode)
|
||||
|
||||
|
|
|
@ -5,13 +5,8 @@ from typing import Any
|
|||
from switchbot_api import Device, Remote, SwitchBotAPI, VacuumCommands
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -43,17 +38,17 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
|
||||
VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, str] = {
|
||||
"StandBy": STATE_IDLE,
|
||||
"Clearing": STATE_CLEANING,
|
||||
"Paused": STATE_PAUSED,
|
||||
"GotoChargeBase": STATE_RETURNING,
|
||||
"Charging": STATE_DOCKED,
|
||||
"ChargeDone": STATE_DOCKED,
|
||||
"Dormant": STATE_IDLE,
|
||||
"InTrouble": STATE_ERROR,
|
||||
"InRemoteControl": STATE_CLEANING,
|
||||
"InDustCollecting": STATE_DOCKED,
|
||||
VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, VacuumActivity] = {
|
||||
"StandBy": VacuumActivity.IDLE,
|
||||
"Clearing": VacuumActivity.CLEANING,
|
||||
"Paused": VacuumActivity.PAUSED,
|
||||
"GotoChargeBase": VacuumActivity.RETURNING,
|
||||
"Charging": VacuumActivity.DOCKED,
|
||||
"ChargeDone": VacuumActivity.DOCKED,
|
||||
"Dormant": VacuumActivity.IDLE,
|
||||
"InTrouble": VacuumActivity.ERROR,
|
||||
"InRemoteControl": VacuumActivity.CLEANING,
|
||||
"InDustCollecting": VacuumActivity.DOCKED,
|
||||
}
|
||||
|
||||
VACUUM_FAN_SPEED_TO_SWITCHBOT_FAN_SPEED: dict[str, str] = {
|
||||
|
@ -114,7 +109,7 @@ class SwitchBotCloudVacuum(SwitchBotCloudEntity, StateVacuumEntity):
|
|||
self._attr_available = self.coordinator.data.get("onlineStatus") == "online"
|
||||
|
||||
switchbot_state = str(self.coordinator.data.get("workingStatus"))
|
||||
self._attr_state = VACUUM_SWITCHBOT_STATE_TO_HA_STATE.get(switchbot_state)
|
||||
self._attr_activity = VACUUM_SWITCHBOT_STATE_TO_HA_STATE.get(switchbot_state)
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
|
|
@ -17,13 +17,8 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
|
@ -58,12 +53,12 @@ CONF_FAN_SPEED_TEMPLATE = "fan_speed_template"
|
|||
|
||||
ENTITY_ID_FORMAT = VACUUM_DOMAIN + ".{}"
|
||||
_VALID_STATES = [
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_PAUSED,
|
||||
STATE_IDLE,
|
||||
STATE_RETURNING,
|
||||
STATE_ERROR,
|
||||
VacuumActivity.CLEANING,
|
||||
VacuumActivity.DOCKED,
|
||||
VacuumActivity.PAUSED,
|
||||
VacuumActivity.IDLE,
|
||||
VacuumActivity.RETURNING,
|
||||
VacuumActivity.ERROR,
|
||||
]
|
||||
|
||||
VACUUM_SCHEMA = vol.All(
|
||||
|
@ -202,7 +197,7 @@ class TemplateVacuum(TemplateEntity, StateVacuumEntity):
|
|||
self._attr_fan_speed_list = config[CONF_FAN_SPEED_LIST]
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the status of the vacuum cleaner."""
|
||||
return self._state
|
||||
|
||||
|
|
|
@ -7,13 +7,10 @@ from typing import Any
|
|||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import STATE_IDLE, STATE_PAUSED
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
@ -24,29 +21,29 @@ from .entity import EnumTypeData, IntegerTypeData, TuyaEntity
|
|||
|
||||
TUYA_MODE_RETURN_HOME = "chargego"
|
||||
TUYA_STATUS_TO_HA = {
|
||||
"charge_done": STATE_DOCKED,
|
||||
"chargecompleted": STATE_DOCKED,
|
||||
"chargego": STATE_DOCKED,
|
||||
"charging": STATE_DOCKED,
|
||||
"cleaning": STATE_CLEANING,
|
||||
"docking": STATE_RETURNING,
|
||||
"goto_charge": STATE_RETURNING,
|
||||
"goto_pos": STATE_CLEANING,
|
||||
"mop_clean": STATE_CLEANING,
|
||||
"part_clean": STATE_CLEANING,
|
||||
"paused": STATE_PAUSED,
|
||||
"pick_zone_clean": STATE_CLEANING,
|
||||
"pos_arrived": STATE_CLEANING,
|
||||
"pos_unarrive": STATE_CLEANING,
|
||||
"random": STATE_CLEANING,
|
||||
"sleep": STATE_IDLE,
|
||||
"smart_clean": STATE_CLEANING,
|
||||
"smart": STATE_CLEANING,
|
||||
"spot_clean": STATE_CLEANING,
|
||||
"standby": STATE_IDLE,
|
||||
"wall_clean": STATE_CLEANING,
|
||||
"wall_follow": STATE_CLEANING,
|
||||
"zone_clean": STATE_CLEANING,
|
||||
"charge_done": VacuumActivity.DOCKED,
|
||||
"chargecompleted": VacuumActivity.DOCKED,
|
||||
"chargego": VacuumActivity.DOCKED,
|
||||
"charging": VacuumActivity.DOCKED,
|
||||
"cleaning": VacuumActivity.CLEANING,
|
||||
"docking": VacuumActivity.RETURNING,
|
||||
"goto_charge": VacuumActivity.RETURNING,
|
||||
"goto_pos": VacuumActivity.CLEANING,
|
||||
"mop_clean": VacuumActivity.CLEANING,
|
||||
"part_clean": VacuumActivity.CLEANING,
|
||||
"paused": VacuumActivity.PAUSED,
|
||||
"pick_zone_clean": VacuumActivity.CLEANING,
|
||||
"pos_arrived": VacuumActivity.CLEANING,
|
||||
"pos_unarrive": VacuumActivity.CLEANING,
|
||||
"random": VacuumActivity.CLEANING,
|
||||
"sleep": VacuumActivity.IDLE,
|
||||
"smart_clean": VacuumActivity.CLEANING,
|
||||
"smart": VacuumActivity.CLEANING,
|
||||
"spot_clean": VacuumActivity.CLEANING,
|
||||
"standby": VacuumActivity.IDLE,
|
||||
"wall_clean": VacuumActivity.CLEANING,
|
||||
"wall_follow": VacuumActivity.CLEANING,
|
||||
"zone_clean": VacuumActivity.CLEANING,
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,12 +134,12 @@ class TuyaVacuumEntity(TuyaEntity, StateVacuumEntity):
|
|||
return self.device.status.get(DPCode.SUCTION)
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return Tuya vacuum device state."""
|
||||
if self.device.status.get(DPCode.PAUSE) and not (
|
||||
self.device.status.get(DPCode.STATUS)
|
||||
):
|
||||
return STATE_PAUSED
|
||||
return VacuumActivity.PAUSED
|
||||
if not (status := self.device.status.get(DPCode.STATUS)):
|
||||
return None
|
||||
return TUYA_STATUS_TO_HA.get(status)
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
from enum import IntFlag
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any, final
|
||||
|
||||
from propcache import cached_property
|
||||
import voluptuous as vol
|
||||
|
@ -18,11 +19,9 @@ from homeassistant.const import ( # noqa: F401 # STATE_PAUSED/IDLE are API
|
|||
SERVICE_TOGGLE,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_IDLE,
|
||||
STATE_ON,
|
||||
STATE_PAUSED,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.deprecation import (
|
||||
DeprecatedConstantEnum,
|
||||
|
@ -32,12 +31,21 @@ from homeassistant.helpers.deprecation import (
|
|||
)
|
||||
from homeassistant.helpers.entity import Entity, EntityDescription
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
from homeassistant.helpers.frame import ReportBehavior, report_usage
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
from .const import DOMAIN, STATE_CLEANING, STATE_DOCKED, STATE_ERROR, STATE_RETURNING
|
||||
from .const import ( # noqa: F401
|
||||
_DEPRECATED_STATE_CLEANING,
|
||||
_DEPRECATED_STATE_DOCKED,
|
||||
_DEPRECATED_STATE_ERROR,
|
||||
_DEPRECATED_STATE_RETURNING,
|
||||
DOMAIN,
|
||||
VacuumActivity,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -64,11 +72,13 @@ SERVICE_START = "start"
|
|||
SERVICE_PAUSE = "pause"
|
||||
SERVICE_STOP = "stop"
|
||||
|
||||
|
||||
STATES = [STATE_CLEANING, STATE_DOCKED, STATE_RETURNING, STATE_ERROR]
|
||||
|
||||
DEFAULT_NAME = "Vacuum cleaner robot"
|
||||
|
||||
# These STATE_* constants are deprecated as of Home Assistant 2025.1.
|
||||
# Please use the VacuumActivity enum instead.
|
||||
_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumActivity.IDLE, "2026.1")
|
||||
_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumActivity.PAUSED, "2026.1")
|
||||
|
||||
|
||||
class VacuumEntityFeature(IntFlag):
|
||||
"""Supported features of the vacuum entity."""
|
||||
|
@ -216,7 +226,7 @@ STATE_VACUUM_CACHED_PROPERTIES_WITH_ATTR_ = {
|
|||
"battery_icon",
|
||||
"fan_speed",
|
||||
"fan_speed_list",
|
||||
"state",
|
||||
"activity",
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,9 +243,58 @@ class StateVacuumEntity(
|
|||
_attr_battery_level: int | None = None
|
||||
_attr_fan_speed: str | None = None
|
||||
_attr_fan_speed_list: list[str]
|
||||
_attr_state: str | None = None
|
||||
_attr_activity: VacuumActivity | None = None
|
||||
_attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0)
|
||||
|
||||
__vacuum_legacy_state: bool = False
|
||||
|
||||
def __init_subclass__(cls, **kwargs: Any) -> None:
|
||||
"""Post initialisation processing."""
|
||||
super().__init_subclass__(**kwargs)
|
||||
if any(method in cls.__dict__ for method in ("_attr_state", "state")):
|
||||
# Integrations should use the 'activity' property instead of
|
||||
# setting the state directly.
|
||||
cls.__vacuum_legacy_state = True
|
||||
|
||||
def __setattr__(self, name: str, value: Any) -> None:
|
||||
"""Set attribute.
|
||||
|
||||
Deprecation warning if setting '_attr_state' directly
|
||||
unless already reported.
|
||||
"""
|
||||
if name == "_attr_state":
|
||||
self._report_deprecated_activity_handling()
|
||||
return super().__setattr__(name, value)
|
||||
|
||||
@callback
|
||||
def add_to_platform_start(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
platform: EntityPlatform,
|
||||
parallel_updates: asyncio.Semaphore | None,
|
||||
) -> None:
|
||||
"""Start adding an entity to a platform."""
|
||||
super().add_to_platform_start(hass, platform, parallel_updates)
|
||||
if self.__vacuum_legacy_state:
|
||||
self._report_deprecated_activity_handling()
|
||||
|
||||
@callback
|
||||
def _report_deprecated_activity_handling(self) -> None:
|
||||
"""Report on deprecated handling of vacuum state.
|
||||
|
||||
Integrations should implement activity instead of using state directly.
|
||||
"""
|
||||
report_usage(
|
||||
"is setting state directly."
|
||||
f" Entity {self.entity_id} ({type(self)}) should implement the 'activity'"
|
||||
" property and return its state using the VacuumActivity enum",
|
||||
core_integration_behavior=ReportBehavior.ERROR,
|
||||
custom_integration_behavior=ReportBehavior.LOG,
|
||||
breaks_in_ha_version="2026.1",
|
||||
integration_domain=self.platform.platform_name if self.platform else None,
|
||||
exclude_integrations={DOMAIN},
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def battery_level(self) -> int | None:
|
||||
"""Return the battery level of the vacuum cleaner."""
|
||||
|
@ -244,7 +303,7 @@ class StateVacuumEntity(
|
|||
@property
|
||||
def battery_icon(self) -> str:
|
||||
"""Return the battery icon for the vacuum cleaner."""
|
||||
charging = bool(self.state == STATE_DOCKED)
|
||||
charging = bool(self.activity == VacuumActivity.DOCKED)
|
||||
|
||||
return icon_for_battery_level(
|
||||
battery_level=self.battery_level, charging=charging
|
||||
|
@ -282,10 +341,28 @@ class StateVacuumEntity(
|
|||
|
||||
return data
|
||||
|
||||
@cached_property
|
||||
@final
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
if (activity := self.activity) is not None:
|
||||
return activity
|
||||
if self._attr_state is not None:
|
||||
# Backwards compatibility for integrations that set state directly
|
||||
# Should be removed in 2026.1
|
||||
if TYPE_CHECKING:
|
||||
assert isinstance(self._attr_state, str)
|
||||
return self._attr_state
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the current vacuum activity.
|
||||
|
||||
Integrations should overwrite this or use the '_attr_activity'
|
||||
attribute to set the vacuum activity using the 'VacuumActivity' enum.
|
||||
"""
|
||||
return self._attr_activity
|
||||
|
||||
@cached_property
|
||||
def supported_features(self) -> VacuumEntityFeature:
|
||||
|
|
|
@ -1,10 +1,42 @@
|
|||
"""Support for vacuum cleaner robots (botvacs)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
from functools import partial
|
||||
|
||||
from homeassistant.helpers.deprecation import (
|
||||
DeprecatedConstantEnum,
|
||||
all_with_deprecated_constants,
|
||||
check_if_deprecated_constant,
|
||||
dir_with_deprecated_constants,
|
||||
)
|
||||
|
||||
DOMAIN = "vacuum"
|
||||
|
||||
STATE_CLEANING = "cleaning"
|
||||
STATE_DOCKED = "docked"
|
||||
STATE_RETURNING = "returning"
|
||||
STATE_ERROR = "error"
|
||||
|
||||
STATES = [STATE_CLEANING, STATE_DOCKED, STATE_RETURNING, STATE_ERROR]
|
||||
class VacuumActivity(StrEnum):
|
||||
"""Vacuum activity states."""
|
||||
|
||||
CLEANING = "cleaning"
|
||||
DOCKED = "docked"
|
||||
IDLE = "idle"
|
||||
PAUSED = "paused"
|
||||
RETURNING = "returning"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
# These STATE_* constants are deprecated as of Home Assistant 2025.1.
|
||||
# Please use the VacuumActivity enum instead.
|
||||
_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumActivity.CLEANING, "2026.1")
|
||||
_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumActivity.DOCKED, "2026.1")
|
||||
_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum(VacuumActivity.RETURNING, "2026.1")
|
||||
_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumActivity.ERROR, "2026.1")
|
||||
|
||||
|
||||
# These can be removed if no deprecated constant are in this module anymore
|
||||
__getattr__ = partial(check_if_deprecated_constant, module_globals=globals())
|
||||
__dir__ = partial(
|
||||
dir_with_deprecated_constants, module_globals_keys=[*globals().keys()]
|
||||
)
|
||||
__all__ = all_with_deprecated_constants(globals())
|
||||
|
|
|
@ -20,7 +20,7 @@ from homeassistant.helpers import (
|
|||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
from . import DOMAIN, STATE_CLEANING, STATE_DOCKED, STATE_RETURNING
|
||||
from . import DOMAIN, VacuumActivity
|
||||
|
||||
CONDITION_TYPES = {"is_cleaning", "is_docked"}
|
||||
|
||||
|
@ -62,9 +62,9 @@ def async_condition_from_config(
|
|||
) -> condition.ConditionCheckerType:
|
||||
"""Create a function to test a device condition."""
|
||||
if config[CONF_TYPE] == "is_docked":
|
||||
test_states = [STATE_DOCKED]
|
||||
test_states = [VacuumActivity.DOCKED]
|
||||
else:
|
||||
test_states = [STATE_CLEANING, STATE_RETURNING]
|
||||
test_states = [VacuumActivity.CLEANING, VacuumActivity.RETURNING]
|
||||
|
||||
registry = er.async_get(hass)
|
||||
entity_id = er.async_resolve_entity_id(registry, config[CONF_ENTITY_ID])
|
||||
|
|
|
@ -19,7 +19,7 @@ from homeassistant.helpers import config_validation as cv, entity_registry as er
|
|||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import DOMAIN, STATE_CLEANING, STATE_DOCKED
|
||||
from . import DOMAIN, VacuumActivity
|
||||
|
||||
TRIGGER_TYPES = {"cleaning", "docked"}
|
||||
|
||||
|
@ -77,9 +77,9 @@ async def async_attach_trigger(
|
|||
) -> CALLBACK_TYPE:
|
||||
"""Attach a trigger."""
|
||||
if config[CONF_TYPE] == "cleaning":
|
||||
to_state = STATE_CLEANING
|
||||
to_state = VacuumActivity.CLEANING
|
||||
else:
|
||||
to_state = STATE_DOCKED
|
||||
to_state = VacuumActivity.DOCKED
|
||||
|
||||
state_config = {
|
||||
CONF_PLATFORM: "state",
|
||||
|
|
|
@ -11,10 +11,8 @@ from homeassistant.const import (
|
|||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_IDLE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_PAUSED,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant, State
|
||||
|
||||
|
@ -26,20 +24,18 @@ from . import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_RETURNING,
|
||||
VacuumActivity,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
VALID_STATES_TOGGLE = {STATE_ON, STATE_OFF}
|
||||
VALID_STATES_STATE = {
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
VacuumActivity.CLEANING,
|
||||
VacuumActivity.DOCKED,
|
||||
VacuumActivity.IDLE,
|
||||
VacuumActivity.PAUSED,
|
||||
VacuumActivity.RETURNING,
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,13 +71,13 @@ async def _async_reproduce_state(
|
|||
service = SERVICE_TURN_ON
|
||||
elif state.state == STATE_OFF:
|
||||
service = SERVICE_TURN_OFF
|
||||
elif state.state == STATE_CLEANING:
|
||||
elif state.state == VacuumActivity.CLEANING:
|
||||
service = SERVICE_START
|
||||
elif state.state in [STATE_DOCKED, STATE_RETURNING]:
|
||||
elif state.state in [VacuumActivity.DOCKED, VacuumActivity.RETURNING]:
|
||||
service = SERVICE_RETURN_TO_BASE
|
||||
elif state.state == STATE_IDLE:
|
||||
elif state.state == VacuumActivity.IDLE:
|
||||
service = SERVICE_STOP
|
||||
elif state.state == STATE_PAUSED:
|
||||
elif state.state == VacuumActivity.PAUSED:
|
||||
service = SERVICE_PAUSE
|
||||
|
||||
await hass.services.async_call(
|
||||
|
|
|
@ -10,13 +10,8 @@ from miio import DeviceException
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -55,29 +50,29 @@ ATTR_ZONE_REPEATER = "repeats"
|
|||
ATTR_TIMERS = "timers"
|
||||
|
||||
STATE_CODE_TO_STATE = {
|
||||
1: STATE_IDLE, # "Starting"
|
||||
2: STATE_IDLE, # "Charger disconnected"
|
||||
3: STATE_IDLE, # "Idle"
|
||||
4: STATE_CLEANING, # "Remote control active"
|
||||
5: STATE_CLEANING, # "Cleaning"
|
||||
6: STATE_RETURNING, # "Returning home"
|
||||
7: STATE_CLEANING, # "Manual mode"
|
||||
8: STATE_DOCKED, # "Charging"
|
||||
9: STATE_ERROR, # "Charging problem"
|
||||
10: STATE_PAUSED, # "Paused"
|
||||
11: STATE_CLEANING, # "Spot cleaning"
|
||||
12: STATE_ERROR, # "Error"
|
||||
13: STATE_IDLE, # "Shutting down"
|
||||
14: STATE_DOCKED, # "Updating"
|
||||
15: STATE_RETURNING, # "Docking"
|
||||
16: STATE_CLEANING, # "Going to target"
|
||||
17: STATE_CLEANING, # "Zoned cleaning"
|
||||
18: STATE_CLEANING, # "Segment cleaning"
|
||||
22: STATE_DOCKED, # "Emptying the bin" on s7+
|
||||
23: STATE_DOCKED, # "Washing the mop" on s7maxV
|
||||
26: STATE_RETURNING, # "Going to wash the mop" on s7maxV
|
||||
100: STATE_DOCKED, # "Charging complete"
|
||||
101: STATE_ERROR, # "Device offline"
|
||||
1: VacuumActivity.IDLE, # "Starting"
|
||||
2: VacuumActivity.IDLE, # "Charger disconnected"
|
||||
3: VacuumActivity.IDLE, # "Idle"
|
||||
4: VacuumActivity.CLEANING, # "Remote control active"
|
||||
5: VacuumActivity.CLEANING, # "Cleaning"
|
||||
6: VacuumActivity.RETURNING, # "Returning home"
|
||||
7: VacuumActivity.CLEANING, # "Manual mode"
|
||||
8: VacuumActivity.DOCKED, # "Charging"
|
||||
9: VacuumActivity.ERROR, # "Charging problem"
|
||||
10: VacuumActivity.PAUSED, # "Paused"
|
||||
11: VacuumActivity.CLEANING, # "Spot cleaning"
|
||||
12: VacuumActivity.ERROR, # "Error"
|
||||
13: VacuumActivity.IDLE, # "Shutting down"
|
||||
14: VacuumActivity.DOCKED, # "Updating"
|
||||
15: VacuumActivity.RETURNING, # "Docking"
|
||||
16: VacuumActivity.CLEANING, # "Going to target"
|
||||
17: VacuumActivity.CLEANING, # "Zoned cleaning"
|
||||
18: VacuumActivity.CLEANING, # "Segment cleaning"
|
||||
22: VacuumActivity.DOCKED, # "Emptying the bin" on s7+
|
||||
23: VacuumActivity.DOCKED, # "Washing the mop" on s7maxV
|
||||
26: VacuumActivity.RETURNING, # "Going to wash the mop" on s7maxV
|
||||
100: VacuumActivity.DOCKED, # "Charging complete"
|
||||
101: VacuumActivity.ERROR, # "Device offline"
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,7 +206,7 @@ class MiroboVacuum(
|
|||
) -> None:
|
||||
"""Initialize the Xiaomi vacuum cleaner robot handler."""
|
||||
super().__init__(device, entry, unique_id, coordinator)
|
||||
self._state: str | None = None
|
||||
self._state: VacuumActivity | None = None
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Run when entity is about to be added to hass."""
|
||||
|
@ -219,12 +214,12 @@ class MiroboVacuum(
|
|||
self._handle_coordinator_update()
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
def activity(self) -> VacuumActivity | None:
|
||||
"""Return the status of the vacuum cleaner."""
|
||||
# The vacuum reverts back to an idle state after erroring out.
|
||||
# We want to keep returning an error until it has been cleared.
|
||||
if self.coordinator.data.status.got_error:
|
||||
return STATE_ERROR
|
||||
return VacuumActivity.ERROR
|
||||
|
||||
return self._state
|
||||
|
||||
|
|
|
@ -22,11 +22,7 @@ from homeassistant.components.vacuum import (
|
|||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
SERVICE_SET_FAN_SPEED,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
|
@ -75,35 +71,35 @@ async def test_supported_features(hass: HomeAssistant) -> None:
|
|||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 100
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) == "medium"
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) == FAN_SPEEDS
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
state = hass.states.get(ENTITY_VACUUM_MOST)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 12412
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 100
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) == "medium"
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) == FAN_SPEEDS
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
state = hass.states.get(ENTITY_VACUUM_BASIC)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 12360
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 100
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
state = hass.states.get(ENTITY_VACUUM_MINIMAL)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 3
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
state = hass.states.get(ENTITY_VACUUM_NONE)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
|
||||
async def test_methods(hass: HomeAssistant) -> None:
|
||||
|
@ -111,29 +107,29 @@ async def test_methods(hass: HomeAssistant) -> None:
|
|||
await common.async_start(hass, ENTITY_VACUUM_BASIC)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_BASIC)
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
|
||||
await common.async_stop(hass, ENTITY_VACUUM_BASIC)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_BASIC)
|
||||
assert state.state == STATE_IDLE
|
||||
assert state.state == VacuumActivity.IDLE
|
||||
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
await hass.async_block_till_done()
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 100
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
await async_setup_component(hass, "notify", {})
|
||||
await hass.async_block_till_done()
|
||||
await common.async_locate(hass, ENTITY_VACUUM_COMPLETE)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_IDLE
|
||||
assert state.state == VacuumActivity.IDLE
|
||||
|
||||
await common.async_return_to_base(hass, ENTITY_VACUUM_COMPLETE)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_RETURNING
|
||||
assert state.state == VacuumActivity.RETURNING
|
||||
|
||||
await common.async_set_fan_speed(
|
||||
hass, FAN_SPEEDS[-1], entity_id=ENTITY_VACUUM_COMPLETE
|
||||
|
@ -145,21 +141,21 @@ async def test_methods(hass: HomeAssistant) -> None:
|
|||
await common.async_clean_spot(hass, ENTITY_VACUUM_COMPLETE)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
|
||||
await common.async_pause(hass, ENTITY_VACUUM_COMPLETE)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_PAUSED
|
||||
assert state.state == VacuumActivity.PAUSED
|
||||
|
||||
await common.async_return_to_base(hass, ENTITY_VACUUM_COMPLETE)
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_RETURNING
|
||||
assert state.state == VacuumActivity.RETURNING
|
||||
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=31))
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
|
||||
|
||||
async def test_unsupported_methods(hass: HomeAssistant) -> None:
|
||||
|
@ -251,4 +247,4 @@ async def test_send_command(hass: HomeAssistant) -> None:
|
|||
new_state_complete = hass.states.get(ENTITY_VACUUM_COMPLETE)
|
||||
|
||||
assert old_state_complete != new_state_complete
|
||||
assert new_state_complete.state == STATE_IDLE
|
||||
assert new_state_complete.state == VacuumActivity.IDLE
|
||||
|
|
|
@ -431,7 +431,9 @@ async def test_dock_vacuum(hass: HomeAssistant) -> None:
|
|||
assert helpers.get_google_type(vacuum.DOMAIN, None) is not None
|
||||
assert trait.DockTrait.supported(vacuum.DOMAIN, 0, None, None)
|
||||
|
||||
trt = trait.DockTrait(hass, State("vacuum.bla", vacuum.STATE_IDLE), BASIC_CONFIG)
|
||||
trt = trait.DockTrait(
|
||||
hass, State("vacuum.bla", vacuum.VacuumActivity.IDLE), BASIC_CONFIG
|
||||
)
|
||||
|
||||
assert trt.sync_attributes() == {}
|
||||
|
||||
|
@ -454,7 +456,7 @@ async def test_locate_vacuum(hass: HomeAssistant) -> None:
|
|||
hass,
|
||||
State(
|
||||
"vacuum.bla",
|
||||
vacuum.STATE_IDLE,
|
||||
vacuum.VacuumActivity.IDLE,
|
||||
{ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.LOCATE},
|
||||
),
|
||||
BASIC_CONFIG,
|
||||
|
@ -485,7 +487,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None:
|
|||
hass,
|
||||
State(
|
||||
"vacuum.bla",
|
||||
vacuum.STATE_DOCKED,
|
||||
vacuum.VacuumActivity.DOCKED,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY,
|
||||
ATTR_BATTERY_LEVEL: 100,
|
||||
|
@ -511,7 +513,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None:
|
|||
hass,
|
||||
State(
|
||||
"vacuum.bla",
|
||||
vacuum.STATE_CLEANING,
|
||||
vacuum.VacuumActivity.CLEANING,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY,
|
||||
ATTR_BATTERY_LEVEL: 20,
|
||||
|
@ -551,7 +553,7 @@ async def test_startstop_vacuum(hass: HomeAssistant) -> None:
|
|||
hass,
|
||||
State(
|
||||
"vacuum.bla",
|
||||
vacuum.STATE_PAUSED,
|
||||
vacuum.VacuumActivity.PAUSED,
|
||||
{ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.PAUSE},
|
||||
),
|
||||
BASIC_CONFIG,
|
||||
|
|
|
@ -26,8 +26,7 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_START,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
|
@ -295,7 +294,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support(
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
STATE_CLEANING,
|
||||
VacuumActivity.CLEANING,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME
|
||||
| VacuumEntityFeature.START
|
||||
|
@ -306,7 +305,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support(
|
|||
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
STATE_DOCKED,
|
||||
VacuumActivity.DOCKED,
|
||||
{
|
||||
ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME
|
||||
| VacuumEntityFeature.START
|
||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.components import litterrobot
|
|||
from homeassistant.components.vacuum import (
|
||||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_START,
|
||||
STATE_DOCKED,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
|
@ -30,7 +30,7 @@ async def test_unload_entry(hass: HomeAssistant, mock_account: MagicMock) -> Non
|
|||
|
||||
vacuum = hass.states.get(VACUUM_ENTITY_ID)
|
||||
assert vacuum
|
||||
assert vacuum.state == STATE_DOCKED
|
||||
assert vacuum.state == VacuumActivity.DOCKED
|
||||
|
||||
await hass.services.async_call(
|
||||
VACUUM_DOMAIN,
|
||||
|
|
|
@ -15,9 +15,7 @@ from homeassistant.components.vacuum import (
|
|||
DOMAIN as PLATFORM_DOMAIN,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_PAUSED,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -53,7 +51,7 @@ async def test_vacuum(
|
|||
|
||||
vacuum = hass.states.get(VACUUM_ENTITY_ID)
|
||||
assert vacuum
|
||||
assert vacuum.state == STATE_DOCKED
|
||||
assert vacuum.state == VacuumActivity.DOCKED
|
||||
assert vacuum.attributes["is_sleeping"] is False
|
||||
|
||||
ent_reg_entry = entity_registry.async_get(VACUUM_ENTITY_ID)
|
||||
|
@ -95,18 +93,21 @@ async def test_vacuum_with_error(
|
|||
|
||||
vacuum = hass.states.get(VACUUM_ENTITY_ID)
|
||||
assert vacuum
|
||||
assert vacuum.state == STATE_ERROR
|
||||
assert vacuum.state == VacuumActivity.ERROR
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("robot_data", "expected_state"),
|
||||
[
|
||||
({"displayCode": "DC_CAT_DETECT"}, STATE_DOCKED),
|
||||
({"isDFIFull": True}, STATE_ERROR),
|
||||
({"robotCycleState": "CYCLE_STATE_CAT_DETECT"}, STATE_PAUSED),
|
||||
({"displayCode": "DC_CAT_DETECT"}, VacuumActivity.DOCKED),
|
||||
({"isDFIFull": True}, VacuumActivity.ERROR),
|
||||
(
|
||||
{"robotCycleState": "CYCLE_STATE_CAT_DETECT"},
|
||||
VacuumActivity.PAUSED,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_vacuum_states(
|
||||
async def test_activities(
|
||||
hass: HomeAssistant,
|
||||
mock_account_with_litterrobot_4: MagicMock,
|
||||
robot_data: dict[str, str | bool],
|
||||
|
@ -150,7 +151,7 @@ async def test_commands(
|
|||
|
||||
vacuum = hass.states.get(VACUUM_ENTITY_ID)
|
||||
assert vacuum
|
||||
assert vacuum.state == STATE_DOCKED
|
||||
assert vacuum.state == VacuumActivity.DOCKED
|
||||
|
||||
extra = extra or {}
|
||||
data = {ATTR_ENTITY_ID: VACUUM_ENTITY_ID, **extra.get("data", {})}
|
||||
|
|
|
@ -27,8 +27,7 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_RETURN_TO_BASE,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.const import CONF_NAME, ENTITY_MATCH_ALL, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -313,7 +312,7 @@ async def test_status(
|
|||
}"""
|
||||
async_fire_mqtt_message(hass, "vacuum/state", message)
|
||||
state = hass.states.get("vacuum.mqtttest")
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 54
|
||||
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-50"
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) == "max"
|
||||
|
@ -326,7 +325,7 @@ async def test_status(
|
|||
|
||||
async_fire_mqtt_message(hass, "vacuum/state", message)
|
||||
state = hass.states.get("vacuum.mqtttest")
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-charging-60"
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 61
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) == "min"
|
||||
|
@ -366,7 +365,7 @@ async def test_no_fan_vacuum(
|
|||
}"""
|
||||
async_fire_mqtt_message(hass, "vacuum/state", message)
|
||||
state = hass.states.get("vacuum.mqtttest")
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 54
|
||||
|
@ -380,7 +379,7 @@ async def test_no_fan_vacuum(
|
|||
async_fire_mqtt_message(hass, "vacuum/state", message)
|
||||
state = hass.states.get("vacuum.mqtttest")
|
||||
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
assert state.attributes.get(ATTR_FAN_SPEED) is None
|
||||
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
|
||||
|
||||
|
@ -394,7 +393,7 @@ async def test_no_fan_vacuum(
|
|||
|
||||
async_fire_mqtt_message(hass, "vacuum/state", message)
|
||||
state = hass.states.get("vacuum.mqtttest")
|
||||
assert state.state == STATE_DOCKED
|
||||
assert state.state == VacuumActivity.DOCKED
|
||||
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-charging-60"
|
||||
assert state.attributes.get(ATTR_BATTERY_LEVEL) == 61
|
||||
|
||||
|
|
|
@ -35,10 +35,7 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
|
@ -160,7 +157,7 @@ async def test_simple_properties(
|
|||
|
||||
assert entity
|
||||
assert state
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
assert entity.unique_id == "AC000Wxxxxxxxxx"
|
||||
|
||||
|
||||
|
@ -189,10 +186,10 @@ async def test_initial_attributes(
|
|||
@pytest.mark.parametrize(
|
||||
("service", "target_state"),
|
||||
[
|
||||
(SERVICE_STOP, STATE_IDLE),
|
||||
(SERVICE_PAUSE, STATE_PAUSED),
|
||||
(SERVICE_RETURN_TO_BASE, STATE_RETURNING),
|
||||
(SERVICE_START, STATE_CLEANING),
|
||||
(SERVICE_STOP, VacuumActivity.IDLE),
|
||||
(SERVICE_PAUSE, VacuumActivity.PAUSED),
|
||||
(SERVICE_RETURN_TO_BASE, VacuumActivity.RETURNING),
|
||||
(SERVICE_START, VacuumActivity.CLEANING),
|
||||
],
|
||||
)
|
||||
async def test_cleaning_states(
|
||||
|
|
|
@ -3,14 +3,7 @@
|
|||
import pytest
|
||||
|
||||
from homeassistant import setup
|
||||
from homeassistant.components.vacuum import (
|
||||
ATTR_BATTERY_LEVEL,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
)
|
||||
from homeassistant.components.vacuum import ATTR_BATTERY_LEVEL, VacuumActivity
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -44,7 +37,7 @@ _BATTERY_LEVEL_INPUT_NUMBER = "input_number.battery_level"
|
|||
},
|
||||
),
|
||||
(
|
||||
STATE_CLEANING,
|
||||
VacuumActivity.CLEANING,
|
||||
100,
|
||||
{
|
||||
"vacuum": {
|
||||
|
@ -149,10 +142,10 @@ async def test_templates_with_entities(hass: HomeAssistant) -> None:
|
|||
"""Test templates with values from other entities."""
|
||||
_verify(hass, STATE_UNKNOWN, None)
|
||||
|
||||
hass.states.async_set(_STATE_INPUT_SELECT, STATE_CLEANING)
|
||||
hass.states.async_set(_STATE_INPUT_SELECT, VacuumActivity.CLEANING)
|
||||
hass.states.async_set(_BATTERY_LEVEL_INPUT_NUMBER, 100)
|
||||
await hass.async_block_till_done()
|
||||
_verify(hass, STATE_CLEANING, 100)
|
||||
_verify(hass, VacuumActivity.CLEANING, 100)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -370,8 +363,8 @@ async def test_state_services(hass: HomeAssistant, calls: list[ServiceCall]) ->
|
|||
await hass.async_block_till_done()
|
||||
|
||||
# verify
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_CLEANING
|
||||
_verify(hass, STATE_CLEANING, None)
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumActivity.CLEANING
|
||||
_verify(hass, VacuumActivity.CLEANING, None)
|
||||
assert len(calls) == 1
|
||||
assert calls[-1].data["action"] == "start"
|
||||
assert calls[-1].data["caller"] == _TEST_VACUUM
|
||||
|
@ -381,8 +374,8 @@ async def test_state_services(hass: HomeAssistant, calls: list[ServiceCall]) ->
|
|||
await hass.async_block_till_done()
|
||||
|
||||
# verify
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_PAUSED
|
||||
_verify(hass, STATE_PAUSED, None)
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumActivity.PAUSED
|
||||
_verify(hass, VacuumActivity.PAUSED, None)
|
||||
assert len(calls) == 2
|
||||
assert calls[-1].data["action"] == "pause"
|
||||
assert calls[-1].data["caller"] == _TEST_VACUUM
|
||||
|
@ -392,8 +385,8 @@ async def test_state_services(hass: HomeAssistant, calls: list[ServiceCall]) ->
|
|||
await hass.async_block_till_done()
|
||||
|
||||
# verify
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_IDLE
|
||||
_verify(hass, STATE_IDLE, None)
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumActivity.IDLE
|
||||
_verify(hass, VacuumActivity.IDLE, None)
|
||||
assert len(calls) == 3
|
||||
assert calls[-1].data["action"] == "stop"
|
||||
assert calls[-1].data["caller"] == _TEST_VACUUM
|
||||
|
@ -403,8 +396,8 @@ async def test_state_services(hass: HomeAssistant, calls: list[ServiceCall]) ->
|
|||
await hass.async_block_till_done()
|
||||
|
||||
# verify
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_RETURNING
|
||||
_verify(hass, STATE_RETURNING, None)
|
||||
assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumActivity.RETURNING
|
||||
_verify(hass, VacuumActivity.RETURNING, None)
|
||||
assert len(calls) == 4
|
||||
assert calls[-1].data["action"] == "return_to_base"
|
||||
assert calls[-1].data["caller"] == _TEST_VACUUM
|
||||
|
@ -506,7 +499,11 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None:
|
|||
assert await setup.async_setup_component(
|
||||
hass,
|
||||
"input_select",
|
||||
{"input_select": {"state": {"name": "State", "options": [STATE_CLEANING]}}},
|
||||
{
|
||||
"input_select": {
|
||||
"state": {"name": "State", "options": [VacuumActivity.CLEANING]}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
with assert_setup_component(1, "vacuum"):
|
||||
|
@ -522,7 +519,7 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None:
|
|||
"service": "input_select.select_option",
|
||||
"data": {
|
||||
"entity_id": _STATE_INPUT_SELECT,
|
||||
"option": STATE_CLEANING,
|
||||
"option": VacuumActivity.CLEANING,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -554,11 +551,11 @@ async def _register_components(hass: HomeAssistant) -> None:
|
|||
"state": {
|
||||
"name": "State",
|
||||
"options": [
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
VacuumActivity.CLEANING,
|
||||
VacuumActivity.DOCKED,
|
||||
VacuumActivity.IDLE,
|
||||
VacuumActivity.PAUSED,
|
||||
VacuumActivity.RETURNING,
|
||||
],
|
||||
},
|
||||
"fan_speed": {
|
||||
|
@ -578,7 +575,7 @@ async def _register_components(hass: HomeAssistant) -> None:
|
|||
"service": "input_select.select_option",
|
||||
"data": {
|
||||
"entity_id": _STATE_INPUT_SELECT,
|
||||
"option": STATE_CLEANING,
|
||||
"option": VacuumActivity.CLEANING,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -592,7 +589,10 @@ async def _register_components(hass: HomeAssistant) -> None:
|
|||
"pause": [
|
||||
{
|
||||
"service": "input_select.select_option",
|
||||
"data": {"entity_id": _STATE_INPUT_SELECT, "option": STATE_PAUSED},
|
||||
"data": {
|
||||
"entity_id": _STATE_INPUT_SELECT,
|
||||
"option": VacuumActivity.PAUSED,
|
||||
},
|
||||
},
|
||||
{
|
||||
"service": "test.automation",
|
||||
|
@ -605,7 +605,10 @@ async def _register_components(hass: HomeAssistant) -> None:
|
|||
"stop": [
|
||||
{
|
||||
"service": "input_select.select_option",
|
||||
"data": {"entity_id": _STATE_INPUT_SELECT, "option": STATE_IDLE},
|
||||
"data": {
|
||||
"entity_id": _STATE_INPUT_SELECT,
|
||||
"option": VacuumActivity.IDLE,
|
||||
},
|
||||
},
|
||||
{
|
||||
"service": "test.automation",
|
||||
|
@ -620,7 +623,7 @@ async def _register_components(hass: HomeAssistant) -> None:
|
|||
"service": "input_select.select_option",
|
||||
"data": {
|
||||
"entity_id": _STATE_INPUT_SELECT,
|
||||
"option": STATE_RETURNING,
|
||||
"option": VacuumActivity.RETURNING,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -4,12 +4,8 @@ from typing import Any
|
|||
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -39,20 +35,20 @@ class MockVacuum(MockEntity, StateVacuumEntity):
|
|||
def __init__(self, **values: Any) -> None:
|
||||
"""Initialize a mock vacuum entity."""
|
||||
super().__init__(**values)
|
||||
self._attr_state = STATE_DOCKED
|
||||
self._attr_activity = VacuumActivity.DOCKED
|
||||
self._attr_fan_speed = "slow"
|
||||
|
||||
def stop(self, **kwargs: Any) -> None:
|
||||
"""Stop cleaning."""
|
||||
self._attr_state = STATE_IDLE
|
||||
self._attr_activity = VacuumActivity.IDLE
|
||||
|
||||
def return_to_base(self, **kwargs: Any) -> None:
|
||||
"""Return to base."""
|
||||
self._attr_state = STATE_RETURNING
|
||||
self._attr_activity = VacuumActivity.RETURNING
|
||||
|
||||
def clean_spot(self, **kwargs: Any) -> None:
|
||||
"""Clean a spot."""
|
||||
self._attr_state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
|
||||
def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
|
||||
"""Set the fan speed."""
|
||||
|
@ -60,11 +56,11 @@ class MockVacuum(MockEntity, StateVacuumEntity):
|
|||
|
||||
def start(self) -> None:
|
||||
"""Start cleaning."""
|
||||
self._attr_state = STATE_CLEANING
|
||||
self._attr_activity = VacuumActivity.CLEANING
|
||||
|
||||
def pause(self) -> None:
|
||||
"""Pause cleaning."""
|
||||
self._attr_state = STATE_PAUSED
|
||||
self._attr_activity = VacuumActivity.PAUSED
|
||||
|
||||
|
||||
async def help_async_setup_entry_init(
|
||||
|
|
|
@ -1,13 +1,28 @@
|
|||
"""Fixtures for Vacuum platform tests."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from collections.abc import AsyncGenerator, Generator
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.components.vacuum import DOMAIN as VACUUM_DOMAIN, VacuumEntityFeature
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er, frame
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from tests.common import mock_config_flow, mock_platform
|
||||
from . import MockVacuum
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
MockModule,
|
||||
MockPlatform,
|
||||
mock_config_flow,
|
||||
mock_integration,
|
||||
mock_platform,
|
||||
)
|
||||
|
||||
TEST_DOMAIN = "test"
|
||||
|
||||
|
||||
class MockFlow(ConfigFlow):
|
||||
|
@ -17,7 +32,94 @@ class MockFlow(ConfigFlow):
|
|||
@pytest.fixture
|
||||
def config_flow_fixture(hass: HomeAssistant) -> Generator[None]:
|
||||
"""Mock config flow."""
|
||||
mock_platform(hass, "test.config_flow")
|
||||
mock_platform(hass, f"{TEST_DOMAIN}.config_flow")
|
||||
|
||||
with mock_config_flow("test", MockFlow):
|
||||
with mock_config_flow(TEST_DOMAIN, MockFlow):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="supported_features")
|
||||
async def vacuum_supported_features() -> VacuumEntityFeature:
|
||||
"""Return the supported features for the test vacuum entity."""
|
||||
return (
|
||||
VacuumEntityFeature.PAUSE
|
||||
| VacuumEntityFeature.STOP
|
||||
| VacuumEntityFeature.RETURN_HOME
|
||||
| VacuumEntityFeature.FAN_SPEED
|
||||
| VacuumEntityFeature.BATTERY
|
||||
| VacuumEntityFeature.CLEAN_SPOT
|
||||
| VacuumEntityFeature.MAP
|
||||
| VacuumEntityFeature.STATE
|
||||
| VacuumEntityFeature.START
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_vacuum_entity")
|
||||
async def setup_vacuum_platform_test_entity(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
entity_registry: er.EntityRegistry,
|
||||
supported_features: VacuumEntityFeature,
|
||||
) -> MagicMock:
|
||||
"""Set up vacuum entity using an entity platform."""
|
||||
|
||||
async def async_setup_entry_init(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up test config entry."""
|
||||
await hass.config_entries.async_forward_entry_setups(
|
||||
config_entry, [VACUUM_DOMAIN]
|
||||
)
|
||||
return True
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
TEST_DOMAIN,
|
||||
async_setup_entry=async_setup_entry_init,
|
||||
),
|
||||
)
|
||||
|
||||
entity = MockVacuum(
|
||||
supported_features=supported_features,
|
||||
)
|
||||
|
||||
async def async_setup_entry_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up test vacuum platform via config entry."""
|
||||
async_add_entities([entity])
|
||||
|
||||
mock_platform(
|
||||
hass,
|
||||
f"{TEST_DOMAIN}.{VACUUM_DOMAIN}",
|
||||
MockPlatform(async_setup_entry=async_setup_entry_platform),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(domain=TEST_DOMAIN)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
|
||||
return entity
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_as_custom_component")
|
||||
async def mock_frame(hass: HomeAssistant) -> AsyncGenerator[None]:
|
||||
"""Mock frame."""
|
||||
with patch(
|
||||
"homeassistant.helpers.frame.get_integration_frame",
|
||||
return_value=frame.IntegrationFrame(
|
||||
custom_integration=True,
|
||||
integration="alarm_control_panel",
|
||||
module="test_init.py",
|
||||
relative_filename="test_init.py",
|
||||
frame=frame.get_current_frame(),
|
||||
),
|
||||
):
|
||||
yield
|
||||
|
|
|
@ -5,12 +5,7 @@ from pytest_unordered import unordered
|
|||
|
||||
from homeassistant.components import automation
|
||||
from homeassistant.components.device_automation import DeviceAutomationType
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_RETURNING,
|
||||
)
|
||||
from homeassistant.components.vacuum import DOMAIN, VacuumActivity
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
@ -122,7 +117,7 @@ async def test_if_state(
|
|||
DOMAIN, "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_DOCKED)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
@ -174,7 +169,7 @@ async def test_if_state(
|
|||
assert len(service_calls) == 1
|
||||
assert service_calls[0].data["some"] == "is_docked - event - test_event2"
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_CLEANING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING)
|
||||
hass.bus.async_fire("test_event1")
|
||||
hass.bus.async_fire("test_event2")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -182,7 +177,7 @@ async def test_if_state(
|
|||
assert service_calls[1].data["some"] == "is_cleaning - event - test_event1"
|
||||
|
||||
# Returning means it's still cleaning
|
||||
hass.states.async_set(entry.entity_id, STATE_RETURNING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.RETURNING)
|
||||
hass.bus.async_fire("test_event1")
|
||||
hass.bus.async_fire("test_event2")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -207,7 +202,7 @@ async def test_if_state_legacy(
|
|||
DOMAIN, "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_CLEANING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
|
|
@ -7,7 +7,7 @@ from pytest_unordered import unordered
|
|||
|
||||
from homeassistant.components import automation
|
||||
from homeassistant.components.device_automation import DeviceAutomationType
|
||||
from homeassistant.components.vacuum import DOMAIN, STATE_CLEANING, STATE_DOCKED
|
||||
from homeassistant.components.vacuum import DOMAIN, VacuumActivity
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
@ -188,7 +188,7 @@ async def test_if_fires_on_state_change(
|
|||
DOMAIN, "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_DOCKED)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
@ -238,7 +238,7 @@ async def test_if_fires_on_state_change(
|
|||
)
|
||||
|
||||
# Fake that the entity is cleaning
|
||||
hass.states.async_set(entry.entity_id, STATE_CLEANING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 1
|
||||
assert (
|
||||
|
@ -247,7 +247,7 @@ async def test_if_fires_on_state_change(
|
|||
)
|
||||
|
||||
# Fake that the entity is docked
|
||||
hass.states.async_set(entry.entity_id, STATE_DOCKED)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 2
|
||||
assert (
|
||||
|
@ -273,7 +273,7 @@ async def test_if_fires_on_state_change_legacy(
|
|||
DOMAIN, "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_DOCKED)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
@ -304,7 +304,7 @@ async def test_if_fires_on_state_change_legacy(
|
|||
)
|
||||
|
||||
# Fake that the entity is cleaning
|
||||
hass.states.async_set(entry.entity_id, STATE_CLEANING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 1
|
||||
assert (
|
||||
|
@ -330,7 +330,7 @@ async def test_if_fires_on_state_change_with_for(
|
|||
DOMAIN, "test", "5678", device_id=device_entry.id
|
||||
)
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_DOCKED)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
@ -365,7 +365,7 @@ async def test_if_fires_on_state_change_with_for(
|
|||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 0
|
||||
|
||||
hass.states.async_set(entry.entity_id, STATE_CLEANING)
|
||||
hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 0
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
|
||||
|
|
|
@ -5,12 +5,13 @@ from __future__ import annotations
|
|||
from enum import Enum
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import vacuum
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN,
|
||||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_CLEAN_SPOT,
|
||||
SERVICE_LOCATE,
|
||||
SERVICE_PAUSE,
|
||||
|
@ -19,19 +20,19 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
StateVacuumEntity,
|
||||
VacuumActivity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import frame
|
||||
|
||||
from . import MockVacuum, help_async_setup_entry_init, help_async_unload_entry
|
||||
from .common import async_start
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
MockEntity,
|
||||
MockModule,
|
||||
help_test_all,
|
||||
import_and_test_deprecated_constant_enum,
|
||||
|
@ -72,14 +73,33 @@ def test_deprecated_constants(
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("enum", "constant_prefix"), _create_tuples(vacuum.VacuumActivity, "STATE_")
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"module",
|
||||
[vacuum],
|
||||
)
|
||||
def test_deprecated_constants_for_state(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
enum: Enum,
|
||||
constant_prefix: str,
|
||||
module: ModuleType,
|
||||
) -> None:
|
||||
"""Test deprecated constants."""
|
||||
import_and_test_deprecated_constant_enum(
|
||||
caplog, module, enum, constant_prefix, "2026.1"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("service", "expected_state"),
|
||||
[
|
||||
(SERVICE_CLEAN_SPOT, STATE_CLEANING),
|
||||
(SERVICE_PAUSE, STATE_PAUSED),
|
||||
(SERVICE_RETURN_TO_BASE, STATE_RETURNING),
|
||||
(SERVICE_START, STATE_CLEANING),
|
||||
(SERVICE_STOP, STATE_IDLE),
|
||||
(SERVICE_CLEAN_SPOT, VacuumActivity.CLEANING),
|
||||
(SERVICE_PAUSE, VacuumActivity.PAUSED),
|
||||
(SERVICE_RETURN_TO_BASE, VacuumActivity.RETURNING),
|
||||
(SERVICE_START, VacuumActivity.CLEANING),
|
||||
(SERVICE_STOP, VacuumActivity.IDLE),
|
||||
],
|
||||
)
|
||||
async def test_state_services(
|
||||
|
@ -101,18 +121,20 @@ async def test_state_services(
|
|||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
|
||||
setup_test_component_platform(
|
||||
hass, VACUUM_DOMAIN, [mock_vacuum], from_config_entry=True
|
||||
)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
VACUUM_DOMAIN,
|
||||
service,
|
||||
{"entity_id": mock_vacuum.entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
vacuum_state = hass.states.get(mock_vacuum.entity_id)
|
||||
activity = hass.states.get(mock_vacuum.entity_id)
|
||||
|
||||
assert vacuum_state.state == expected_state
|
||||
assert activity.state == expected_state
|
||||
|
||||
|
||||
async def test_fan_speed(hass: HomeAssistant, config_flow_fixture: None) -> None:
|
||||
|
@ -132,14 +154,16 @@ async def test_fan_speed(hass: HomeAssistant, config_flow_fixture: None) -> None
|
|||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
|
||||
setup_test_component_platform(
|
||||
hass, VACUUM_DOMAIN, [mock_vacuum], from_config_entry=True
|
||||
)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
VACUUM_DOMAIN,
|
||||
SERVICE_SET_FAN_SPEED,
|
||||
{"entity_id": mock_vacuum.entity_id, "fan_speed": "high"},
|
||||
blocking=True,
|
||||
|
@ -178,11 +202,13 @@ async def test_locate(hass: HomeAssistant, config_flow_fixture: None) -> None:
|
|||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
|
||||
setup_test_component_platform(
|
||||
hass, VACUUM_DOMAIN, [mock_vacuum], from_config_entry=True
|
||||
)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
VACUUM_DOMAIN,
|
||||
SERVICE_LOCATE,
|
||||
{"entity_id": mock_vacuum.entity_id},
|
||||
blocking=True,
|
||||
|
@ -227,11 +253,13 @@ async def test_send_command(hass: HomeAssistant, config_flow_fixture: None) -> N
|
|||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
|
||||
setup_test_component_platform(
|
||||
hass, VACUUM_DOMAIN, [mock_vacuum], from_config_entry=True
|
||||
)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
VACUUM_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
{
|
||||
"entity_id": mock_vacuum.entity_id,
|
||||
|
@ -278,3 +306,178 @@ async def test_supported_features_compat(hass: HomeAssistant) -> None:
|
|||
"fan_speed_list": ["silent", "normal", "pet hair"]
|
||||
}
|
||||
assert entity._deprecated_supported_features_reported
|
||||
|
||||
|
||||
async def test_vacuum_not_log_deprecated_state_warning(
|
||||
hass: HomeAssistant,
|
||||
mock_vacuum_entity: MockVacuum,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test correctly using activity doesn't log issue or raise repair."""
|
||||
state = hass.states.get(mock_vacuum_entity.entity_id)
|
||||
assert state is not None
|
||||
assert (
|
||||
"should implement the 'activity' property and return its state using the VacuumActivity enum"
|
||||
not in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
@patch.object(frame, "_REPORTED_INTEGRATIONS", set())
|
||||
async def test_vacuum_log_deprecated_state_warning_using_state_prop(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test incorrectly using state property does log issue and raise repair."""
|
||||
|
||||
class MockLegacyVacuum(MockVacuum):
|
||||
"""Mocked vacuum entity."""
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Return the state of the entity."""
|
||||
return VacuumActivity.CLEANING
|
||||
|
||||
entity = MockLegacyVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, VACUUM_DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"should implement the 'activity' property and return its state using the VacuumActivity enum"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
@patch.object(frame, "_REPORTED_INTEGRATIONS", set())
|
||||
async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test incorrectly using _attr_state attribute does log issue and raise repair."""
|
||||
|
||||
class MockLegacyVacuum(MockVacuum):
|
||||
"""Mocked vacuum entity."""
|
||||
|
||||
def start(self) -> None:
|
||||
"""Start cleaning."""
|
||||
self._attr_state = VacuumActivity.CLEANING
|
||||
|
||||
entity = MockLegacyVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, VACUUM_DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"should implement the 'activity' property and return its state using the VacuumActivity enum"
|
||||
not in caplog.text
|
||||
)
|
||||
|
||||
await async_start(hass, entity.entity_id)
|
||||
|
||||
assert (
|
||||
"should implement the 'activity' property and return its state using the VacuumActivity enum"
|
||||
in caplog.text
|
||||
)
|
||||
caplog.clear()
|
||||
await async_start(hass, entity.entity_id)
|
||||
# Test we only log once
|
||||
assert (
|
||||
"should implement the 'activity' property and return its state using the VacuumActivity enum"
|
||||
not in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
@patch.object(frame, "_REPORTED_INTEGRATIONS", set())
|
||||
async def test_alarm_control_panel_deprecated_state_does_not_break_state(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test using _attr_state attribute does not break state."""
|
||||
|
||||
class MockLegacyVacuum(MockEntity, StateVacuumEntity):
|
||||
"""Mocked vacuum entity."""
|
||||
|
||||
_attr_supported_features = VacuumEntityFeature.STATE | VacuumEntityFeature.START
|
||||
|
||||
def __init__(self, **values: Any) -> None:
|
||||
"""Initialize a mock vacuum entity."""
|
||||
super().__init__(**values)
|
||||
self._attr_state = VacuumActivity.DOCKED
|
||||
|
||||
def start(self) -> None:
|
||||
"""Start cleaning."""
|
||||
self._attr_state = VacuumActivity.CLEANING
|
||||
|
||||
entity = MockLegacyVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
)
|
||||
setup_test_component_platform(hass, VACUUM_DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "docked"
|
||||
|
||||
await hass.services.async_call(
|
||||
VACUUM_DOMAIN,
|
||||
SERVICE_START,
|
||||
{
|
||||
"entity_id": entity.entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "cleaning"
|
||||
|
|
|
@ -9,18 +9,9 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_RETURNING,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_IDLE,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_PAUSED,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.helpers.state import async_reproduce_state
|
||||
|
||||
|
@ -39,11 +30,11 @@ async def test_reproducing_states(
|
|||
hass.states.async_set(
|
||||
"vacuum.entity_on_fan", STATE_ON, {ATTR_FAN_SPEED: FAN_SPEED_LOW}
|
||||
)
|
||||
hass.states.async_set("vacuum.entity_cleaning", STATE_CLEANING, {})
|
||||
hass.states.async_set("vacuum.entity_docked", STATE_DOCKED, {})
|
||||
hass.states.async_set("vacuum.entity_idle", STATE_IDLE, {})
|
||||
hass.states.async_set("vacuum.entity_returning", STATE_RETURNING, {})
|
||||
hass.states.async_set("vacuum.entity_paused", STATE_PAUSED, {})
|
||||
hass.states.async_set("vacuum.entity_cleaning", VacuumActivity.CLEANING, {})
|
||||
hass.states.async_set("vacuum.entity_docked", VacuumActivity.DOCKED, {})
|
||||
hass.states.async_set("vacuum.entity_idle", VacuumActivity.IDLE, {})
|
||||
hass.states.async_set("vacuum.entity_returning", VacuumActivity.RETURNING, {})
|
||||
hass.states.async_set("vacuum.entity_paused", VacuumActivity.PAUSED, {})
|
||||
|
||||
turn_on_calls = async_mock_service(hass, "vacuum", SERVICE_TURN_ON)
|
||||
turn_off_calls = async_mock_service(hass, "vacuum", SERVICE_TURN_OFF)
|
||||
|
@ -60,11 +51,11 @@ async def test_reproducing_states(
|
|||
State("vacuum.entity_off", STATE_OFF),
|
||||
State("vacuum.entity_on", STATE_ON),
|
||||
State("vacuum.entity_on_fan", STATE_ON, {ATTR_FAN_SPEED: FAN_SPEED_LOW}),
|
||||
State("vacuum.entity_cleaning", STATE_CLEANING),
|
||||
State("vacuum.entity_docked", STATE_DOCKED),
|
||||
State("vacuum.entity_idle", STATE_IDLE),
|
||||
State("vacuum.entity_returning", STATE_RETURNING),
|
||||
State("vacuum.entity_paused", STATE_PAUSED),
|
||||
State("vacuum.entity_cleaning", VacuumActivity.CLEANING),
|
||||
State("vacuum.entity_docked", VacuumActivity.DOCKED),
|
||||
State("vacuum.entity_idle", VacuumActivity.IDLE),
|
||||
State("vacuum.entity_returning", VacuumActivity.RETURNING),
|
||||
State("vacuum.entity_paused", VacuumActivity.PAUSED),
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -95,11 +86,11 @@ async def test_reproducing_states(
|
|||
State("vacuum.entity_off", STATE_ON),
|
||||
State("vacuum.entity_on", STATE_OFF),
|
||||
State("vacuum.entity_on_fan", STATE_ON, {ATTR_FAN_SPEED: FAN_SPEED_HIGH}),
|
||||
State("vacuum.entity_cleaning", STATE_PAUSED),
|
||||
State("vacuum.entity_docked", STATE_CLEANING),
|
||||
State("vacuum.entity_idle", STATE_DOCKED),
|
||||
State("vacuum.entity_returning", STATE_CLEANING),
|
||||
State("vacuum.entity_paused", STATE_IDLE),
|
||||
State("vacuum.entity_cleaning", VacuumActivity.PAUSED),
|
||||
State("vacuum.entity_docked", VacuumActivity.CLEANING),
|
||||
State("vacuum.entity_idle", VacuumActivity.DOCKED),
|
||||
State("vacuum.entity_returning", VacuumActivity.CLEANING),
|
||||
State("vacuum.entity_paused", VacuumActivity.IDLE),
|
||||
# Should not raise
|
||||
State("vacuum.non_existing", STATE_ON),
|
||||
],
|
||||
|
|
|
@ -21,8 +21,7 @@ from homeassistant.components.vacuum import (
|
|||
SERVICE_SET_FAN_SPEED,
|
||||
SERVICE_START,
|
||||
SERVICE_STOP,
|
||||
STATE_CLEANING,
|
||||
STATE_ERROR,
|
||||
VacuumActivity,
|
||||
)
|
||||
from homeassistant.components.xiaomi_miio.const import (
|
||||
CONF_FLOW_TYPE,
|
||||
|
@ -264,7 +263,7 @@ async def test_xiaomi_vacuum_services(
|
|||
# Check state attributes
|
||||
state = hass.states.get(entity_id)
|
||||
|
||||
assert state.state == STATE_ERROR
|
||||
assert state.state == VacuumActivity.ERROR
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 14204
|
||||
assert state.attributes.get(ATTR_ERROR) == "Error message"
|
||||
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-80"
|
||||
|
@ -450,7 +449,7 @@ async def test_xiaomi_specific_services(
|
|||
|
||||
# Check state attributes
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_CLEANING
|
||||
assert state.state == VacuumActivity.CLEANING
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 14204
|
||||
assert state.attributes.get(ATTR_ERROR) is None
|
||||
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-30"
|
||||
|
|
Loading…
Reference in New Issue