From 9fd9d1f106cc7d31f97908f3d069d2bd7934f660 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 20 Sep 2024 17:37:02 +0000 Subject: [PATCH 01/24] Implement new state property for vacuum which is using an enum --- homeassistant/components/vacuum/__init__.py | 112 ++++++++++++++++++-- homeassistant/components/vacuum/const.py | 48 ++++++++- 2 files changed, 146 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index a81dbeacee1..d5442ab8c01 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -2,11 +2,13 @@ from __future__ import annotations +import asyncio from datetime import timedelta from enum import IntFlag from functools import partial +import inspect import logging -from typing import Any +from typing import Any, final from propcache import cached_property import voluptuous as vol @@ -22,8 +24,8 @@ from homeassistant.const import ( # noqa: F401 # STATE_PAUSED/IDLE are API STATE_ON, STATE_PAUSED, ) -from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import config_validation as cv, issue_registry as ir from homeassistant.helpers.deprecation import ( DeprecatedConstantEnum, all_with_deprecated_constants, @@ -32,12 +34,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.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, + STATES, + VacuumEntityState, +) _LOGGER = logging.getLogger(__name__) @@ -64,9 +75,6 @@ SERVICE_START = "start" SERVICE_PAUSE = "pause" SERVICE_STOP = "stop" - -STATES = [STATE_CLEANING, STATE_DOCKED, STATE_RETURNING, STATE_ERROR] - DEFAULT_NAME = "Vacuum cleaner robot" @@ -234,8 +242,82 @@ class StateVacuumEntity( _attr_fan_speed: str | None = None _attr_fan_speed_list: list[str] _attr_state: str | None = None + _attr_vacuum_state: VacuumEntityState | None = None _attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0) + __vacuum_legacy_state: bool = False + __vacuum_legacy_state_reported: 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 'vacuum_state' 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 settings '_attr_state' directly + unless already reported. + """ + if __name == "_attr_state": + if self.__vacuum_legacy_state_reported is not True: + self._report_deprecated_alarm_state_handling() + self.__vacuum_legacy_state_reported = True + 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 and not self.__vacuum_legacy_state_reported: + self._report_deprecated_alarm_state_handling() + + @callback + def _report_deprecated_alarm_state_handling(self) -> None: + """Report on deprecated handling of vacuum state. + + Integrations should implement vacuum_state instead of using state directly. + """ + if self.__vacuum_legacy_state_reported is True: + return + self.__vacuum_legacy_state_reported = True + module = inspect.getmodule(self) + if module and module.__file__ and "custom_components" in module.__file__: + # Do not report on core integrations as they will be fixed. + report_issue = "report it to the custom integration author." + _LOGGER.warning( + "Entity %s (%s) is setting state directly" + " which will stop working in HA Core 2025.10." + " Entities should implement the 'vacuum_state' property and" + " return it's state using the VacuumEntityState enum, please %s", + self.entity_id, + type(self), + report_issue, + ) + ir.async_create_issue( + self.hass, + DOMAIN, + f"deprecated_vacuum_state_{self.platform.platform_name}", + breaks_in_ha_version="2025.10.0", + is_fixable=False, + is_persistent=False, + issue_domain=self.platform.platform_name, + severity=ir.IssueSeverity.WARNING, + translation_key="deprecated_vacuum_state", + translation_placeholders={ + "platform": self.platform.platform_name, + "report_issue": report_issue, + }, + ) + @cached_property def battery_level(self) -> int | None: """Return the battery level of the vacuum cleaner.""" @@ -244,7 +326,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.vacuum_state == VacuumEntityState.DOCKED) return icon_for_battery_level( battery_level=self.battery_level, charging=charging @@ -282,10 +364,22 @@ class StateVacuumEntity( return data + @final @cached_property def state(self) -> str | None: """Return the state of the vacuum cleaner.""" - return self._attr_state + if (vacuum_state := self.vacuum_state) is None: + return None + return str(vacuum_state) + + @cached_property + def vacuum_state(self) -> VacuumEntityState | None: + """Return the current vacuum entity state. + + Integrations should overwrite this or use the 'attr_vacuum_state' + attribute to set the alarm status using the 'VacuumEntityState' enum. + """ + return self._attr_vacuum_state @cached_property def supported_features(self) -> VacuumEntityFeature: diff --git a/homeassistant/components/vacuum/const.py b/homeassistant/components/vacuum/const.py index af1558f8570..205fbeee236 100644 --- a/homeassistant/components/vacuum/const.py +++ b/homeassistant/components/vacuum/const.py @@ -1,10 +1,48 @@ """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 VacuumEntityState(StrEnum): + """Vacuum entity states.""" + + CLEANING = "cleaning" + DOCKED = "docked" + IDLE = "idle" + PAUSED = "paused" + RETURNING = "returning" + ERROR = "error" + + +# These STATE_* constants are deprecated as of Home Assistant 2024.11. +# Please use the VacuumEntityState enum instead. +_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum( + VacuumEntityState.CLEANING, "2025.11" +) +_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumEntityState.DOCKED, "2025.11") +_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum( + VacuumEntityState.RETURNING, "2025.11" +) +_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumEntityState.ERROR, "2025.11") + + +STATES = [cls.value for cls in VacuumEntityState] + +# 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()) From 76574b5a12f3a3d52fe27ce77b603cf0e9e889dc Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 12:29:23 +0000 Subject: [PATCH 02/24] Mod --- homeassistant/components/vacuum/__init__.py | 29 +++++---------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index d5442ab8c01..466d34cf9fc 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -6,7 +6,6 @@ import asyncio from datetime import timedelta from enum import IntFlag from functools import partial -import inspect import logging from typing import Any, final @@ -25,7 +24,7 @@ from homeassistant.const import ( # noqa: F401 # STATE_PAUSED/IDLE are API STATE_PAUSED, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers import config_validation as cv, issue_registry as ir +from homeassistant.helpers import config_validation as cv from homeassistant.helpers.deprecation import ( DeprecatedConstantEnum, all_with_deprecated_constants, @@ -224,7 +223,7 @@ STATE_VACUUM_CACHED_PROPERTIES_WITH_ATTR_ = { "battery_icon", "fan_speed", "fan_speed_list", - "state", + "vacuum_state", } @@ -252,7 +251,7 @@ class StateVacuumEntity( """Post initialisation processing.""" super().__init_subclass__(**kwargs) if any(method in cls.__dict__ for method in ("_attr_state", "state")): - # Integrations should use the 'vacuum_state' property instead of + # Integrations should use the 'alarm_state' property instead of # setting the state directly. cls.__vacuum_legacy_state = True @@ -289,34 +288,18 @@ class StateVacuumEntity( if self.__vacuum_legacy_state_reported is True: return self.__vacuum_legacy_state_reported = True - module = inspect.getmodule(self) - if module and module.__file__ and "custom_components" in module.__file__: - # Do not report on core integrations as they will be fixed. + if "custom_components" in type(self).__module__: + # Do not report on core integrations as they have been fixed. report_issue = "report it to the custom integration author." _LOGGER.warning( "Entity %s (%s) is setting state directly" - " which will stop working in HA Core 2025.10." + " which will stop working in HA Core 2025.11." " Entities should implement the 'vacuum_state' property and" " return it's state using the VacuumEntityState enum, please %s", self.entity_id, type(self), report_issue, ) - ir.async_create_issue( - self.hass, - DOMAIN, - f"deprecated_vacuum_state_{self.platform.platform_name}", - breaks_in_ha_version="2025.10.0", - is_fixable=False, - is_persistent=False, - issue_domain=self.platform.platform_name, - severity=ir.IssueSeverity.WARNING, - translation_key="deprecated_vacuum_state", - translation_placeholders={ - "platform": self.platform.platform_name, - "report_issue": report_issue, - }, - ) @cached_property def battery_level(self) -> int | None: From 2c3c9f057f4736434e25c5c29de1fc17b71a953b Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 12:35:48 +0000 Subject: [PATCH 03/24] Mod init --- homeassistant/components/vacuum/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 466d34cf9fc..ff4443afb06 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -348,7 +348,7 @@ class StateVacuumEntity( return data @final - @cached_property + @property def state(self) -> str | None: """Return the state of the vacuum cleaner.""" if (vacuum_state := self.vacuum_state) is None: From 8ca4097dda9585336e532d624e821a9c455ece6f Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 12:45:54 +0000 Subject: [PATCH 04/24] Mods --- homeassistant/components/vacuum/__init__.py | 7 ++++-- .../components/vacuum/device_condition.py | 6 ++--- .../components/vacuum/device_trigger.py | 6 ++--- .../components/vacuum/reproduce_state.py | 24 ++++++++----------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index ff4443afb06..e8bce62815c 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -19,9 +19,7 @@ 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, callback from homeassistant.helpers import config_validation as cv @@ -76,6 +74,11 @@ SERVICE_STOP = "stop" DEFAULT_NAME = "Vacuum cleaner robot" +# These STATE_* constants are deprecated as of Home Assistant 2024.11. +# Please use the VacuumEntityState enum instead. +_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumEntityState.IDLE, "2025.11") +_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumEntityState.PAUSED, "2025.11") + class VacuumEntityFeature(IntFlag): """Supported features of the vacuum entity.""" diff --git a/homeassistant/components/vacuum/device_condition.py b/homeassistant/components/vacuum/device_condition.py index f528b0918a1..e7955f692ac 100644 --- a/homeassistant/components/vacuum/device_condition.py +++ b/homeassistant/components/vacuum/device_condition.py @@ -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, VacuumEntityState 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 = [VacuumEntityState.DOCKED] else: - test_states = [STATE_CLEANING, STATE_RETURNING] + test_states = [VacuumEntityState.CLEANING, VacuumEntityState.RETURNING] registry = er.async_get(hass) entity_id = er.async_resolve_entity_id(registry, config[CONF_ENTITY_ID]) diff --git a/homeassistant/components/vacuum/device_trigger.py b/homeassistant/components/vacuum/device_trigger.py index 45b0696f871..4d6b7d2c3c0 100644 --- a/homeassistant/components/vacuum/device_trigger.py +++ b/homeassistant/components/vacuum/device_trigger.py @@ -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, VacuumEntityState 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 = VacuumEntityState.CLEANING else: - to_state = STATE_DOCKED + to_state = VacuumEntityState.DOCKED state_config = { CONF_PLATFORM: "state", diff --git a/homeassistant/components/vacuum/reproduce_state.py b/homeassistant/components/vacuum/reproduce_state.py index 762cd6f2e90..62fb9cd9db3 100644 --- a/homeassistant/components/vacuum/reproduce_state.py +++ b/homeassistant/components/vacuum/reproduce_state.py @@ -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, + VacuumEntityState, ) _LOGGER = logging.getLogger(__name__) VALID_STATES_TOGGLE = {STATE_ON, STATE_OFF} VALID_STATES_STATE = { - STATE_CLEANING, - STATE_DOCKED, - STATE_IDLE, - STATE_PAUSED, - STATE_RETURNING, + VacuumEntityState.CLEANING, + VacuumEntityState.DOCKED, + VacuumEntityState.IDLE, + VacuumEntityState.PAUSED, + VacuumEntityState.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 == VacuumEntityState.CLEANING: service = SERVICE_START - elif state.state in [STATE_DOCKED, STATE_RETURNING]: + elif state.state in [VacuumEntityState.DOCKED, VacuumEntityState.RETURNING]: service = SERVICE_RETURN_TO_BASE - elif state.state == STATE_IDLE: + elif state.state == VacuumEntityState.IDLE: service = SERVICE_STOP - elif state.state == STATE_PAUSED: + elif state.state == VacuumEntityState.PAUSED: service = SERVICE_PAUSE await hass.services.async_call( From ea2055c403923bdb5133f0a9efee0c3190c21c0e Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 13:10:44 +0000 Subject: [PATCH 05/24] Fix integrations --- .../components/alexa/capabilities.py | 2 +- homeassistant/components/demo/vacuum.py | 32 +++++----- homeassistant/components/ecovacs/vacuum.py | 33 +++++------ .../components/google_assistant/trait.py | 10 ++-- homeassistant/components/group/registry.py | 8 +-- .../components/homekit/type_switches.py | 4 +- .../components/litterrobot/vacuum.py | 31 +++++----- homeassistant/components/mqtt/vacuum.py | 35 ++++++----- homeassistant/components/neato/vacuum.py | 25 ++++---- homeassistant/components/roborock/vacuum.py | 55 ++++++++--------- homeassistant/components/roomba/entity.py | 48 +++++++-------- homeassistant/components/sharkiq/vacuum.py | 20 +++---- .../components/switchbot_cloud/vacuum.py | 27 ++++----- homeassistant/components/template/vacuum.py | 21 +++---- homeassistant/components/tuya/vacuum.py | 55 ++++++++--------- .../components/xiaomi_miio/vacuum.py | 59 +++++++++---------- 16 files changed, 212 insertions(+), 253 deletions(-) diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index 09b461428ac..290ac6830bc 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -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.VacuumEntityState.CLEANING elif self.entity.domain == timer.DOMAIN: is_on = self.entity.state != STATE_IDLE elif self.entity.domain == water_heater.DOMAIN: diff --git a/homeassistant/components/demo/vacuum.py b/homeassistant/components/demo/vacuum.py index d4c3820d29e..16d6ab4ec33 100644 --- a/homeassistant/components/demo/vacuum.py +++ b/homeassistant/components/demo/vacuum.py @@ -7,13 +7,9 @@ from typing import Any from homeassistant.components.vacuum import ( ATTR_CLEANED_AREA, - STATE_CLEANING, - STATE_DOCKED, - STATE_IDLE, - STATE_PAUSED, - STATE_RETURNING, StateVacuumEntity, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -91,13 +87,13 @@ class StateDemoVacuum(StateVacuumEntity): """Initialize the vacuum.""" self._attr_name = name self._attr_supported_features = supported_features - self._state = STATE_DOCKED + self._state = VacuumEntityState.DOCKED self._fan_speed = FAN_SPEEDS[1] self._cleaned_area: float = 0 self._battery_level = 100 @property - def state(self) -> str: + def vacuum_state(self) -> VacuumEntityState: """Return the current state of the vacuum.""" return self._state @@ -123,33 +119,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._state != VacuumEntityState.CLEANING: + self._state = VacuumEntityState.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._state == VacuumEntityState.CLEANING: + self._state = VacuumEntityState.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._state = VacuumEntityState.IDLE self.schedule_update_ha_state() def return_to_base(self, **kwargs: Any) -> None: """Return dock to charging base.""" - self._state = STATE_RETURNING + self._state = VacuumEntityState.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._state = VacuumEntityState.CLEANING self._cleaned_area += 1.32 self._battery_level -= 1 self.schedule_update_ha_state() @@ -167,12 +163,12 @@ class StateDemoVacuum(StateVacuumEntity): "persistent_notification", service_data={"message": "I'm here!", "title": "Locate request"}, ) - self._state = STATE_IDLE + self._state = VacuumEntityState.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._state = VacuumEntityState.CLEANING self.async_write_ha_state() async def async_send_command( @@ -182,9 +178,9 @@ class StateDemoVacuum(StateVacuumEntity): **kwargs: Any, ) -> None: """Send a command to the vacuum.""" - self._state = STATE_IDLE + self._state = VacuumEntityState.IDLE self.async_write_ha_state() def __set_state_to_dock(self, _: datetime) -> None: - self._state = STATE_DOCKED + self._state = VacuumEntityState.DOCKED self.schedule_update_ha_state() diff --git a/homeassistant/components/ecovacs/vacuum.py b/homeassistant/components/ecovacs/vacuum.py index 0d14267e08d..b7a690bf7d6 100644 --- a/homeassistant/components/ecovacs/vacuum.py +++ b/homeassistant/components/ecovacs/vacuum.py @@ -13,15 +13,10 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.core import HomeAssistant, SupportsResponse from homeassistant.exceptions import ServiceValidationError @@ -123,22 +118,22 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): self.schedule_update_ha_state() @property - def state(self) -> str | None: + def vacuum_state(self) -> VacuumEntityState | None: """Return the state of the vacuum cleaner.""" if self.error is not None: - return STATE_ERROR + return VacuumEntityState.ERROR if self.device.is_cleaning: - return STATE_CLEANING + return VacuumEntityState.CLEANING if self.device.is_charging: - return STATE_DOCKED + return VacuumEntityState.DOCKED if self.device.vacuum_status == sucks.CLEAN_MODE_STOP: - return STATE_IDLE + return VacuumEntityState.IDLE if self.device.vacuum_status == sucks.CHARGE_MODE_RETURNING: - return STATE_RETURNING + return VacuumEntityState.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 == VacuumEntityState.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: VacuumEntityState.IDLE, + State.CLEANING: VacuumEntityState.CLEANING, + State.RETURNING: VacuumEntityState.RETURNING, + State.DOCKED: VacuumEntityState.DOCKED, + State.ERROR: VacuumEntityState.ERROR, + State.PAUSED: VacuumEntityState.PAUSED, } _ATTR_ROOMS = "rooms" diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index f99f1574038..e41725176fa 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -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.VacuumEntityState.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.VacuumEntityState.DOCKED, + "isPluggedIn": self.state.state == vacuum.VacuumEntityState.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.VacuumEntityState.CLEANING, + "isPaused": state == vacuum.VacuumEntityState.PAUSED, } if domain in COVER_VALVE_DOMAINS: diff --git a/homeassistant/components/group/registry.py b/homeassistant/components/group/registry.py index 7ac5770f171..d2f091d95c2 100644 --- a/homeassistant/components/group/registry.py +++ b/homeassistant/components/group/registry.py @@ -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 VacuumEntityState 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, + VacuumEntityState.CLEANING, + VacuumEntityState.RETURNING, + VacuumEntityState.ERROR, }, STATE_ON, STATE_OFF, diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index 68df6c38ad6..d8e3f7bde88 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -21,8 +21,8 @@ from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_RETURN_TO_BASE, SERVICE_START, - STATE_CLEANING, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -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 (VacuumEntityState.CLEANING, STATE_ON) _LOGGER.debug("%s: Set current state to %s", self.entity_id, current_state) self.char_on.set_value(current_state) diff --git a/homeassistant/components/litterrobot/vacuum.py b/homeassistant/components/litterrobot/vacuum.py index f5553bf5d49..baa1215b5da 100644 --- a/homeassistant/components/litterrobot/vacuum.py +++ b/homeassistant/components/litterrobot/vacuum.py @@ -10,13 +10,10 @@ from pylitterbot.enums import LitterBoxStatus import voluptuous as vol from homeassistant.components.vacuum import ( - STATE_CLEANING, - STATE_DOCKED, - STATE_ERROR, - STATE_PAUSED, StateVacuumEntity, StateVacuumEntityDescription, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform @@ -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: VacuumEntityState.CLEANING, + LitterBoxStatus.EMPTY_CYCLE: VacuumEntityState.CLEANING, + LitterBoxStatus.CLEAN_CYCLE_COMPLETE: VacuumEntityState.DOCKED, + LitterBoxStatus.CAT_DETECTED: VacuumEntityState.DOCKED, + LitterBoxStatus.CAT_SENSOR_TIMING: VacuumEntityState.DOCKED, + LitterBoxStatus.DRAWER_FULL_1: VacuumEntityState.DOCKED, + LitterBoxStatus.DRAWER_FULL_2: VacuumEntityState.DOCKED, + LitterBoxStatus.READY: VacuumEntityState.DOCKED, + LitterBoxStatus.CAT_SENSOR_INTERRUPTED: VacuumEntityState.PAUSED, + LitterBoxStatus.OFF: VacuumEntityState.DOCKED, } LITTER_BOX_ENTITY = StateVacuumEntityDescription( @@ -78,9 +75,11 @@ class LitterRobotCleaner(LitterRobotEntity[LitterRobot], StateVacuumEntity): ) @property - def state(self) -> str: + def vacuum_state(self) -> VacuumEntityState: """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, VacuumEntityState.ERROR + ) @property def status(self) -> str: diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index 86b32aa281b..72a3fc57252 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -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, VacuumEntityFeature, + VacuumEntityState, ) 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 @@ -43,13 +35,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, VacuumEntityState] = { + STATE_IDLE: VacuumEntityState.IDLE, + STATE_DOCKED: VacuumEntityState.DOCKED, + STATE_ERROR: VacuumEntityState.ERROR, + STATE_PAUSED: VacuumEntityState.PAUSED, + STATE_RETURNING: VacuumEntityState.RETURNING, + STATE_CLEANING: VacuumEntityState.CLEANING, } CONF_SUPPORTED_FEATURES = ATTR_SUPPORTED_FEATURES @@ -263,7 +262,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_vacuum_state = ( POSSIBLE_STATES[cast(str, state)] if payload[STATE] else None ) del payload[STATE] diff --git a/homeassistant/components/neato/vacuum.py b/homeassistant/components/neato/vacuum.py index 77ca5346b10..1685340c2df 100644 --- a/homeassistant/components/neato/vacuum.py +++ b/homeassistant/components/neato/vacuum.py @@ -12,15 +12,12 @@ import voluptuous as vol from homeassistant.components.vacuum import ( ATTR_STATUS, - STATE_CLEANING, - STATE_DOCKED, - STATE_ERROR, - STATE_RETURNING, StateVacuumEntity, VacuumEntityFeature, + VacuumEntityState, ) 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_state = VacuumEntityState.DOCKED self._status_state = "Charging" elif ( self._state["details"]["isDocked"] and not self._state["details"]["isCharging"] ): - self._attr_state = STATE_DOCKED + self._attr_state = VacuumEntityState.DOCKED self._status_state = "Docked" else: - self._attr_state = STATE_IDLE + self._attr_state = VacuumEntityState.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_state = VacuumEntityState.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_state = VacuumEntityState.PAUSED self._status_state = "Paused" elif self._state["state"] == 4: - self._attr_state = STATE_ERROR + self._attr_state = VacuumEntityState.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_state == VacuumEntityState.CLEANING: self.robot.pause_cleaning() - self._attr_state = STATE_RETURNING + self._attr_state = VacuumEntityState.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_state = VacuumEntityState.CLEANING try: self.robot.start_cleaning(mode, navigation, category, boundary_id) except NeatoRobotException as ex: diff --git a/homeassistant/components/roborock/vacuum.py b/homeassistant/components/roborock/vacuum.py index 3b873f259e4..d2ea3c227d6 100644 --- a/homeassistant/components/roborock/vacuum.py +++ b/homeassistant/components/roborock/vacuum.py @@ -8,14 +8,9 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse from homeassistant.helpers import entity_platform @@ -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: VacuumEntityState.IDLE, # "Starting" + RoborockStateCode.charger_disconnected: VacuumEntityState.IDLE, # "Charger disconnected" + RoborockStateCode.idle: VacuumEntityState.IDLE, # "Idle" + RoborockStateCode.remote_control_active: VacuumEntityState.CLEANING, # "Remote control active" + RoborockStateCode.cleaning: VacuumEntityState.CLEANING, # "Cleaning" + RoborockStateCode.returning_home: VacuumEntityState.RETURNING, # "Returning home" + RoborockStateCode.manual_mode: VacuumEntityState.CLEANING, # "Manual mode" + RoborockStateCode.charging: VacuumEntityState.DOCKED, # "Charging" + RoborockStateCode.charging_problem: VacuumEntityState.ERROR, # "Charging problem" + RoborockStateCode.paused: VacuumEntityState.PAUSED, # "Paused" + RoborockStateCode.spot_cleaning: VacuumEntityState.CLEANING, # "Spot cleaning" + RoborockStateCode.error: VacuumEntityState.ERROR, # "Error" + RoborockStateCode.shutting_down: VacuumEntityState.IDLE, # "Shutting down" + RoborockStateCode.updating: VacuumEntityState.DOCKED, # "Updating" + RoborockStateCode.docking: VacuumEntityState.RETURNING, # "Docking" + RoborockStateCode.going_to_target: VacuumEntityState.CLEANING, # "Going to target" + RoborockStateCode.zoned_cleaning: VacuumEntityState.CLEANING, # "Zoned cleaning" + RoborockStateCode.segment_cleaning: VacuumEntityState.CLEANING, # "Segment cleaning" + RoborockStateCode.emptying_the_bin: VacuumEntityState.DOCKED, # "Emptying the bin" on s7+ + RoborockStateCode.washing_the_mop: VacuumEntityState.DOCKED, # "Washing the mop" on s7maxV + RoborockStateCode.going_to_wash_the_mop: VacuumEntityState.RETURNING, # "Going to wash the mop" on s7maxV + RoborockStateCode.charging_complete: VacuumEntityState.DOCKED, # "Charging complete" + RoborockStateCode.device_offline: VacuumEntityState.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 vacuum_state(self) -> VacuumEntityState | 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) diff --git a/homeassistant/components/roomba/entity.py b/homeassistant/components/roomba/entity.py index 10c3d36de12..e4b9e7377ca 100644 --- a/homeassistant/components/roomba/entity.py +++ b/homeassistant/components/roomba/entity.py @@ -7,14 +7,11 @@ import logging from homeassistant.components.vacuum import ( ATTR_STATUS, - STATE_CLEANING, - STATE_DOCKED, - STATE_ERROR, - STATE_RETURNING, StateVacuumEntity, VacuumEntityFeature, + VacuumEntityState, ) -from homeassistant.const import ATTR_CONNECTIONS, STATE_IDLE, STATE_PAUSED +from homeassistant.const import ATTR_CONNECTIONS import homeassistant.helpers.device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import Entity @@ -46,16 +43,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, + "": VacuumEntityState.IDLE, + "charge": VacuumEntityState.DOCKED, + "evac": VacuumEntityState.RETURNING, # Emptying at cleanbase + "hmMidMsn": VacuumEntityState.CLEANING, # Recharging at the middle of a cycle + "hmPostMsn": VacuumEntityState.RETURNING, # Cycle finished + "hmUsrDock": VacuumEntityState.RETURNING, + "pause": VacuumEntityState.PAUSED, + "run": VacuumEntityState.CLEANING, + "stop": VacuumEntityState.IDLE, + "stuck": VacuumEntityState.ERROR, } @@ -128,7 +125,7 @@ class IRobotEntity(Entity): return dt_util.utc_from_timestamp(ts) @property - def _robot_state(self): + def _robot_state(self) -> VacuumEntityState: """Return the state of the vacuum cleaner.""" clean_mission_status = self.vacuum_state.get("cleanMissionStatus", {}) cycle = clean_mission_status.get("cycle") @@ -136,9 +133,12 @@ class IRobotEntity(Entity): try: state = STATE_MAP[phase] except KeyError: - return STATE_ERROR - if cycle != "none" and state in (STATE_IDLE, STATE_DOCKED): - state = STATE_PAUSED + return VacuumEntityState.ERROR + if cycle != "none" and state in ( + VacuumEntityState.IDLE, + VacuumEntityState.DOCKED, + ): + state = VacuumEntityState.PAUSED return state async def async_added_to_hass(self): @@ -169,7 +169,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf self._cap_position = self.vacuum_state.get("cap", {}).get("pose") == 1 @property - def state(self): + def vacuum_state(self) -> VacuumEntityState: """Return the state of the vacuum cleaner.""" return self._robot_state @@ -189,7 +189,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf # Only add cleaning time and cleaned area attrs when the vacuum is # currently on - if self.state == STATE_CLEANING: + if self.state == VacuumEntityState.CLEANING: # Get clean mission status ( state_attrs[ATTR_CLEANING_TIME], @@ -243,7 +243,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_start(self): """Start or resume the cleaning task.""" - if self.state == STATE_PAUSED: + if self.vacuum_state == VacuumEntityState.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") @@ -258,10 +258,10 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" - if self.state == STATE_CLEANING: + if self.vacuum_state == VacuumEntityState.CLEANING: await self.async_pause() for _ in range(10): - if self.state == STATE_PAUSED: + if self.state == VacuumEntityState.PAUSED: break await asyncio.sleep(1) await self.hass.async_add_executor_job(self.vacuum.send_command, "dock") diff --git a/homeassistant/components/sharkiq/vacuum.py b/homeassistant/components/sharkiq/vacuum.py index 8f0547980c3..bcf706ef575 100644 --- a/homeassistant/components/sharkiq/vacuum.py +++ b/homeassistant/components/sharkiq/vacuum.py @@ -9,13 +9,9 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -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: VacuumEntityState.PAUSED, + OperatingModes.START: VacuumEntityState.CLEANING, + OperatingModes.STOP: VacuumEntityState.IDLE, + OperatingModes.RETURN: VacuumEntityState.RETURNING, } FAN_SPEEDS_MAP = { @@ -151,7 +147,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.error_text @property - def operating_mode(self) -> str | None: + def operating_mode(self) -> VacuumEntityState | None: """Operating mode.""" op_mode = self.sharkiq.get_property_value(Properties.OPERATING_MODE) return OPERATING_STATE_MAP.get(op_mode) @@ -162,7 +158,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.get_property_value(Properties.RECHARGING_TO_RESUME) @property - def state(self) -> str | None: + def vacuum_state(self) -> VacuumEntityState | None: """Get the current vacuum state. NB: Currently, we do not return an error state because they can be very, very stale. @@ -170,7 +166,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum user a notification. """ if self.sharkiq.get_property_value(Properties.CHARGING_STATUS): - return STATE_DOCKED + return VacuumEntityState.DOCKED return self.operating_mode @property diff --git a/homeassistant/components/switchbot_cloud/vacuum.py b/homeassistant/components/switchbot_cloud/vacuum.py index f9236507037..6a115fbb9cd 100644 --- a/homeassistant/components/switchbot_cloud/vacuum.py +++ b/homeassistant/components/switchbot_cloud/vacuum.py @@ -5,14 +5,9 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -44,16 +39,16 @@ 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, + "StandBy": VacuumEntityState.IDLE, + "Clearing": VacuumEntityState.CLEANING, + "Paused": VacuumEntityState.PAUSED, + "GotoChargeBase": VacuumEntityState.RETURNING, + "Charging": VacuumEntityState.DOCKED, + "ChargeDone": VacuumEntityState.DOCKED, + "Dormant": VacuumEntityState.IDLE, + "InTrouble": VacuumEntityState.ERROR, + "InRemoteControl": VacuumEntityState.CLEANING, + "InDustCollecting": VacuumEntityState.DOCKED, } VACUUM_FAN_SPEED_TO_SWITCHBOT_FAN_SPEED: dict[str, str] = { diff --git a/homeassistant/components/template/vacuum.py b/homeassistant/components/template/vacuum.py index 1d021bcb571..9db93cfcd6a 100644 --- a/homeassistant/components/template/vacuum.py +++ b/homeassistant/components/template/vacuum.py @@ -17,14 +17,9 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.const import ( CONF_ENTITY_ID, @@ -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, + VacuumEntityState.CLEANING, + VacuumEntityState.DOCKED, + VacuumEntityState.PAUSED, + VacuumEntityState.IDLE, + VacuumEntityState.RETURNING, + VacuumEntityState.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 vacuum_state(self) -> VacuumEntityState | None: """Return the status of the vacuum cleaner.""" return self._state diff --git a/homeassistant/components/tuya/vacuum.py b/homeassistant/components/tuya/vacuum.py index 2e0a154e670..02c5e0bdc71 100644 --- a/homeassistant/components/tuya/vacuum.py +++ b/homeassistant/components/tuya/vacuum.py @@ -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, VacuumEntityFeature, + VacuumEntityState, ) -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": VacuumEntityState.DOCKED, + "chargecompleted": VacuumEntityState.DOCKED, + "chargego": VacuumEntityState.DOCKED, + "charging": VacuumEntityState.DOCKED, + "cleaning": VacuumEntityState.CLEANING, + "docking": VacuumEntityState.RETURNING, + "goto_charge": VacuumEntityState.RETURNING, + "goto_pos": VacuumEntityState.CLEANING, + "mop_clean": VacuumEntityState.CLEANING, + "part_clean": VacuumEntityState.CLEANING, + "paused": VacuumEntityState.PAUSED, + "pick_zone_clean": VacuumEntityState.CLEANING, + "pos_arrived": VacuumEntityState.CLEANING, + "pos_unarrive": VacuumEntityState.CLEANING, + "random": VacuumEntityState.CLEANING, + "sleep": VacuumEntityState.IDLE, + "smart_clean": VacuumEntityState.CLEANING, + "smart": VacuumEntityState.CLEANING, + "spot_clean": VacuumEntityState.CLEANING, + "standby": VacuumEntityState.IDLE, + "wall_clean": VacuumEntityState.CLEANING, + "wall_follow": VacuumEntityState.CLEANING, + "zone_clean": VacuumEntityState.CLEANING, } @@ -137,12 +134,12 @@ class TuyaVacuumEntity(TuyaEntity, StateVacuumEntity): return self.device.status.get(DPCode.SUCTION) @property - def state(self) -> str | None: + def vacuum_state(self) -> VacuumEntityState | 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 VacuumEntityState.PAUSED if not (status := self.device.status.get(DPCode.STATUS)): return None return TUYA_STATUS_TO_HA.get(status) diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index b720cc90d2c..5e45a74ff40 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -10,14 +10,9 @@ 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, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_DEVICE @@ -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: VacuumEntityState.IDLE, # "Starting" + 2: VacuumEntityState.IDLE, # "Charger disconnected" + 3: VacuumEntityState.IDLE, # "Idle" + 4: VacuumEntityState.CLEANING, # "Remote control active" + 5: VacuumEntityState.CLEANING, # "Cleaning" + 6: VacuumEntityState.RETURNING, # "Returning home" + 7: VacuumEntityState.CLEANING, # "Manual mode" + 8: VacuumEntityState.DOCKED, # "Charging" + 9: VacuumEntityState.ERROR, # "Charging problem" + 10: VacuumEntityState.PAUSED, # "Paused" + 11: VacuumEntityState.CLEANING, # "Spot cleaning" + 12: VacuumEntityState.ERROR, # "Error" + 13: VacuumEntityState.IDLE, # "Shutting down" + 14: VacuumEntityState.DOCKED, # "Updating" + 15: VacuumEntityState.RETURNING, # "Docking" + 16: VacuumEntityState.CLEANING, # "Going to target" + 17: VacuumEntityState.CLEANING, # "Zoned cleaning" + 18: VacuumEntityState.CLEANING, # "Segment cleaning" + 22: VacuumEntityState.DOCKED, # "Emptying the bin" on s7+ + 23: VacuumEntityState.DOCKED, # "Washing the mop" on s7maxV + 26: VacuumEntityState.RETURNING, # "Going to wash the mop" on s7maxV + 100: VacuumEntityState.DOCKED, # "Charging complete" + 101: VacuumEntityState.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: VacuumEntityState | 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 vacuum_state(self) -> VacuumEntityState | 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 VacuumEntityState.ERROR return self._state From d638a3b6e31e68ad58daa7ff5410470412fea0d0 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 13:25:36 +0000 Subject: [PATCH 06/24] Tests --- tests/components/demo/test_vacuum.py | 36 +++++------ .../components/google_assistant/test_trait.py | 12 ++-- .../components/homekit/test_type_switches.py | 7 +-- tests/components/mqtt/test_vacuum.py | 13 ++-- tests/components/sharkiq/test_vacuum.py | 15 ++--- tests/components/template/test_vacuum.py | 63 ++++++++++--------- tests/components/vacuum/__init__.py | 18 +++--- .../vacuum/test_device_condition.py | 15 ++--- .../components/vacuum/test_device_trigger.py | 16 ++--- tests/components/vacuum/test_init.py | 15 ++--- .../components/vacuum/test_reproduce_state.py | 43 +++++-------- tests/components/xiaomi_miio/test_vacuum.py | 7 +-- 12 files changed, 117 insertions(+), 143 deletions(-) diff --git a/tests/components/demo/test_vacuum.py b/tests/components/demo/test_vacuum.py index a4e4d6f0e1f..64c6cac5f5c 100644 --- a/tests/components/demo/test_vacuum.py +++ b/tests/components/demo/test_vacuum.py @@ -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, + VacuumEntityState, ) 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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.IDLE diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 1e42edf8e7b..8052ec20c01 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -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.VacuumEntityState.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.VacuumEntityState.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.VacuumEntityState.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.VacuumEntityState.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.VacuumEntityState.PAUSED, {ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.PAUSE}, ), BASIC_CONFIG, diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 9b708f18b8a..64358058234 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -26,9 +26,8 @@ from homeassistant.components.vacuum import ( SERVICE_START, SERVICE_TURN_OFF, SERVICE_TURN_ON, - STATE_CLEANING, - STATE_DOCKED, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -295,7 +294,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support( hass.states.async_set( entity_id, - STATE_CLEANING, + VacuumEntityState.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, + VacuumEntityState.DOCKED, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME | VacuumEntityFeature.START diff --git a/tests/components/mqtt/test_vacuum.py b/tests/components/mqtt/test_vacuum.py index fef62c33a93..907ef8b5c84 100644 --- a/tests/components/mqtt/test_vacuum.py +++ b/tests/components/mqtt/test_vacuum.py @@ -27,8 +27,7 @@ from homeassistant.components.vacuum import ( SERVICE_RETURN_TO_BASE, SERVICE_START, SERVICE_STOP, - STATE_CLEANING, - STATE_DOCKED, + VacuumEntityState, ) 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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.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 == VacuumEntityState.DOCKED assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-charging-60" assert state.attributes.get(ATTR_BATTERY_LEVEL) == 61 diff --git a/tests/components/sharkiq/test_vacuum.py b/tests/components/sharkiq/test_vacuum.py index 3748cfd6dc4..ed3d9715521 100644 --- a/tests/components/sharkiq/test_vacuum.py +++ b/tests/components/sharkiq/test_vacuum.py @@ -35,11 +35,8 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - STATE_CLEANING, - STATE_IDLE, - STATE_PAUSED, - STATE_RETURNING, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -160,7 +157,7 @@ async def test_simple_properties( assert entity assert state - assert state.state == STATE_CLEANING + assert state.state == VacuumEntityState.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, VacuumEntityState.IDLE), + (SERVICE_PAUSE, VacuumEntityState.PAUSED), + (SERVICE_RETURN_TO_BASE, VacuumEntityState.RETURNING), + (SERVICE_START, VacuumEntityState.CLEANING), ], ) async def test_cleaning_states( diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index ff428c5d4b4..ab7991fa948 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -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, VacuumEntityState 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, + VacuumEntityState.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, VacuumEntityState.CLEANING) hass.states.async_set(_BATTERY_LEVEL_INPUT_NUMBER, 100) await hass.async_block_till_done() - _verify(hass, STATE_CLEANING, 100) + _verify(hass, VacuumEntityState.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 == VacuumEntityState.CLEANING + _verify(hass, VacuumEntityState.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 == VacuumEntityState.PAUSED + _verify(hass, VacuumEntityState.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 == VacuumEntityState.IDLE + _verify(hass, VacuumEntityState.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 == VacuumEntityState.RETURNING + _verify(hass, VacuumEntityState.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": [VacuumEntityState.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": VacuumEntityState.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, + VacuumEntityState.CLEANING, + VacuumEntityState.DOCKED, + VacuumEntityState.IDLE, + VacuumEntityState.PAUSED, + VacuumEntityState.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": VacuumEntityState.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": VacuumEntityState.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": VacuumEntityState.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": VacuumEntityState.RETURNING, }, }, { diff --git a/tests/components/vacuum/__init__.py b/tests/components/vacuum/__init__.py index 0a681730cb2..6b8aba9cc02 100644 --- a/tests/components/vacuum/__init__.py +++ b/tests/components/vacuum/__init__.py @@ -4,13 +4,9 @@ from typing import Any from homeassistant.components.vacuum import ( DOMAIN, - STATE_CLEANING, - STATE_DOCKED, - STATE_IDLE, - STATE_PAUSED, - STATE_RETURNING, StateVacuumEntity, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform @@ -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_state = VacuumEntityState.DOCKED self._attr_fan_speed = "slow" def stop(self, **kwargs: Any) -> None: """Stop cleaning.""" - self._attr_state = STATE_IDLE + self._attr_state = VacuumEntityState.IDLE def return_to_base(self, **kwargs: Any) -> None: """Return to base.""" - self._attr_state = STATE_RETURNING + self._attr_state = VacuumEntityState.RETURNING def clean_spot(self, **kwargs: Any) -> None: """Clean a spot.""" - self._attr_state = STATE_CLEANING + self._attr_state = VacuumEntityState.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_state = VacuumEntityState.CLEANING def pause(self) -> None: """Pause cleaning.""" - self._attr_state = STATE_PAUSED + self._attr_state = VacuumEntityState.PAUSED async def help_async_setup_entry_init( diff --git a/tests/components/vacuum/test_device_condition.py b/tests/components/vacuum/test_device_condition.py index 9a2a67f7141..6d083bb47ba 100644 --- a/tests/components/vacuum/test_device_condition.py +++ b/tests/components/vacuum/test_device_condition.py @@ -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, VacuumEntityState 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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.CLEANING) assert await async_setup_component( hass, diff --git a/tests/components/vacuum/test_device_trigger.py b/tests/components/vacuum/test_device_trigger.py index c186bd4d9eb..31152e749e3 100644 --- a/tests/components/vacuum/test_device_trigger.py +++ b/tests/components/vacuum/test_device_trigger.py @@ -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, VacuumEntityState 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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.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, VacuumEntityState.CLEANING) await hass.async_block_till_done() assert len(service_calls) == 0 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index d03f1d28b58..cd082f5004e 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -19,12 +19,9 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - STATE_CLEANING, - STATE_IDLE, - STATE_PAUSED, - STATE_RETURNING, StateVacuumEntity, VacuumEntityFeature, + VacuumEntityState, ) from homeassistant.core import HomeAssistant @@ -75,11 +72,11 @@ def test_deprecated_constants( @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, VacuumEntityState.CLEANING), + (SERVICE_PAUSE, VacuumEntityState.PAUSED), + (SERVICE_RETURN_TO_BASE, VacuumEntityState.RETURNING), + (SERVICE_START, VacuumEntityState.CLEANING), + (SERVICE_STOP, VacuumEntityState.IDLE), ], ) async def test_state_services( diff --git a/tests/components/vacuum/test_reproduce_state.py b/tests/components/vacuum/test_reproduce_state.py index ff8da28e98c..c83e86336f1 100644 --- a/tests/components/vacuum/test_reproduce_state.py +++ b/tests/components/vacuum/test_reproduce_state.py @@ -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, + VacuumEntityState, ) +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", VacuumEntityState.CLEANING, {}) + hass.states.async_set("vacuum.entity_docked", VacuumEntityState.DOCKED, {}) + hass.states.async_set("vacuum.entity_idle", VacuumEntityState.IDLE, {}) + hass.states.async_set("vacuum.entity_returning", VacuumEntityState.RETURNING, {}) + hass.states.async_set("vacuum.entity_paused", VacuumEntityState.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", VacuumEntityState.CLEANING), + State("vacuum.entity_docked", VacuumEntityState.DOCKED), + State("vacuum.entity_idle", VacuumEntityState.IDLE), + State("vacuum.entity_returning", VacuumEntityState.RETURNING), + State("vacuum.entity_paused", VacuumEntityState.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", VacuumEntityState.PAUSED), + State("vacuum.entity_docked", VacuumEntityState.CLEANING), + State("vacuum.entity_idle", VacuumEntityState.DOCKED), + State("vacuum.entity_returning", VacuumEntityState.CLEANING), + State("vacuum.entity_paused", VacuumEntityState.IDLE), # Should not raise State("vacuum.non_existing", STATE_ON), ], diff --git a/tests/components/xiaomi_miio/test_vacuum.py b/tests/components/xiaomi_miio/test_vacuum.py index 76321a1a0a8..e2e485e785c 100644 --- a/tests/components/xiaomi_miio/test_vacuum.py +++ b/tests/components/xiaomi_miio/test_vacuum.py @@ -21,8 +21,7 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - STATE_CLEANING, - STATE_ERROR, + VacuumEntityState, ) 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 == VacuumEntityState.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 == VacuumEntityState.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" From 1026758abdc031732d718298af35155cc366a308 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 13:39:42 +0000 Subject: [PATCH 07/24] Fix state --- homeassistant/components/ecovacs/vacuum.py | 2 +- homeassistant/components/mqtt/vacuum.py | 2 +- homeassistant/components/neato/vacuum.py | 18 +++++++++--------- homeassistant/components/romy/vacuum.py | 12 ++++++++++-- .../components/switchbot_cloud/vacuum.py | 6 ++++-- homeassistant/components/vacuum/__init__.py | 1 - tests/components/vacuum/__init__.py | 12 ++++++------ 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/ecovacs/vacuum.py b/homeassistant/components/ecovacs/vacuum.py index b7a690bf7d6..cd1bd3f7f2b 100644 --- a/homeassistant/components/ecovacs/vacuum.py +++ b/homeassistant/components/ecovacs/vacuum.py @@ -279,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_vacuum_state = _STATE_TO_VACUUM_STATE[event.state] self.async_write_ha_state() self._subscribe(self._capability.battery.event, on_battery) diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index 72a3fc57252..998583d28c4 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -274,7 +274,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_vacuum_state"}, ) async def _subscribe_topics(self) -> None: diff --git a/homeassistant/components/neato/vacuum.py b/homeassistant/components/neato/vacuum.py index 1685340c2df..47ba61c7783 100644 --- a/homeassistant/components/neato/vacuum.py +++ b/homeassistant/components/neato/vacuum.py @@ -166,23 +166,23 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): robot_alert = None if self._state["state"] == 1: if self._state["details"]["isCharging"]: - self._attr_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumEntityState.DOCKED self._status_state = "Charging" elif ( self._state["details"]["isDocked"] and not self._state["details"]["isCharging"] ): - self._attr_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumEntityState.DOCKED self._status_state = "Docked" else: - self._attr_state = VacuumEntityState.IDLE + self._attr_vacuum_state = VacuumEntityState.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 = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumEntityState.CLEANING self._status_state = ( f"{MODE.get(self._state['cleaning']['mode'])} " f"{ACTION.get(self._state['action'])}" @@ -197,10 +197,10 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): else: self._status_state = robot_alert elif self._state["state"] == 3: - self._attr_state = VacuumEntityState.PAUSED + self._attr_vacuum_state = VacuumEntityState.PAUSED self._status_state = "Paused" elif self._state["state"] == 4: - self._attr_state = VacuumEntityState.ERROR + self._attr_vacuum_state = VacuumEntityState.ERROR self._status_state = ERRORS.get(self._state["error"]) self._attr_battery_level = self._state["details"]["charge"] @@ -323,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 == VacuumEntityState.CLEANING: + if self._attr_vacuum_state == VacuumEntityState.CLEANING: self.robot.pause_cleaning() - self._attr_state = VacuumEntityState.RETURNING + self._attr_vacuum_state = VacuumEntityState.RETURNING self.robot.send_to_base() except NeatoRobotException as ex: _LOGGER.error( @@ -377,7 +377,7 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): "Start cleaning zone '%s' with robot %s", zone, self.entity_id ) - self._attr_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumEntityState.CLEANING try: self.robot.start_cleaning(mode, navigation, category, boundary_id) except NeatoRobotException as ex: diff --git a/homeassistant/components/romy/vacuum.py b/homeassistant/components/romy/vacuum.py index de74d371f0e..ecf2c758ae4 100644 --- a/homeassistant/components/romy/vacuum.py +++ b/homeassistant/components/romy/vacuum.py @@ -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, + VacuumEntityFeature, + VacuumEntityState, +) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -75,7 +79,11 @@ 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 + try: + assert self.romy.status is not None + self._attr_vacuum_state = VacuumEntityState(self.romy.status) + except (AssertionError, ValueError): + self._attr_vacuum_state = None self.async_write_ha_state() diff --git a/homeassistant/components/switchbot_cloud/vacuum.py b/homeassistant/components/switchbot_cloud/vacuum.py index 6a115fbb9cd..88f80df907f 100644 --- a/homeassistant/components/switchbot_cloud/vacuum.py +++ b/homeassistant/components/switchbot_cloud/vacuum.py @@ -38,7 +38,7 @@ async def async_setup_entry( ) -VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, str] = { +VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, VacuumEntityState] = { "StandBy": VacuumEntityState.IDLE, "Clearing": VacuumEntityState.CLEANING, "Paused": VacuumEntityState.PAUSED, @@ -109,7 +109,9 @@ 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_vacuum_state = VACUUM_SWITCHBOT_STATE_TO_HA_STATE.get( + switchbot_state + ) self.async_write_ha_state() diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index e8bce62815c..7aac5c36709 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -243,7 +243,6 @@ 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_vacuum_state: VacuumEntityState | None = None _attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0) diff --git a/tests/components/vacuum/__init__.py b/tests/components/vacuum/__init__.py index 6b8aba9cc02..daab7b81420 100644 --- a/tests/components/vacuum/__init__.py +++ b/tests/components/vacuum/__init__.py @@ -35,20 +35,20 @@ class MockVacuum(MockEntity, StateVacuumEntity): def __init__(self, **values: Any) -> None: """Initialize a mock vacuum entity.""" super().__init__(**values) - self._attr_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumEntityState.DOCKED self._attr_fan_speed = "slow" def stop(self, **kwargs: Any) -> None: """Stop cleaning.""" - self._attr_state = VacuumEntityState.IDLE + self._attr_vacuum_state = VacuumEntityState.IDLE def return_to_base(self, **kwargs: Any) -> None: """Return to base.""" - self._attr_state = VacuumEntityState.RETURNING + self._attr_vacuum_state = VacuumEntityState.RETURNING def clean_spot(self, **kwargs: Any) -> None: """Clean a spot.""" - self._attr_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumEntityState.CLEANING def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: """Set the fan speed.""" @@ -56,11 +56,11 @@ class MockVacuum(MockEntity, StateVacuumEntity): def start(self) -> None: """Start cleaning.""" - self._attr_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumEntityState.CLEANING def pause(self) -> None: """Pause cleaning.""" - self._attr_state = VacuumEntityState.PAUSED + self._attr_vacuum_state = VacuumEntityState.PAUSED async def help_async_setup_entry_init( From 82aa7797661b36d02cfa24822729d7e65977f3b2 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 14:19:56 +0000 Subject: [PATCH 08/24] Add vacuum tests --- tests/components/vacuum/conftest.py | 95 +++++++++++- tests/components/vacuum/test_init.py | 214 +++++++++++++++++++++++++-- 2 files changed, 296 insertions(+), 13 deletions(-) diff --git a/tests/components/vacuum/conftest.py b/tests/components/vacuum/conftest.py index d298260c575..d6c197cc56a 100644 --- a/tests/components/vacuum/conftest.py +++ b/tests/components/vacuum/conftest.py @@ -1,13 +1,28 @@ """Fixtures for Vacuum platform tests.""" from collections.abc import Generator +from unittest.mock import MagicMock 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 +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,79 @@ 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 alarm_control_panel_supported_features() -> VacuumEntityFeature: + """Return the supported features for the test alarm control panel 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 alarm control panel 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, + ), + ) + + # Unnamed sensor without device class -> no name + 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 diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index cd082f5004e..7c5c45022e2 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -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, @@ -23,16 +24,22 @@ from homeassistant.components.vacuum import ( VacuumEntityFeature, VacuumEntityState, ) +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import MockVacuum, help_async_setup_entry_init, help_async_unload_entry +from .common import async_start +from .conftest import TEST_DOMAIN from tests.common import ( MockConfigEntry, MockModule, + MockPlatform, help_test_all, import_and_test_deprecated_constant_enum, mock_integration, + mock_platform, setup_test_component_platform, ) @@ -69,6 +76,25 @@ def test_deprecated_constants( ) +@pytest.mark.parametrize( + ("enum", "constant_prefix"), _create_tuples(vacuum.VacuumEntityState, "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, "2025.11" + ) + + @pytest.mark.parametrize( ("service", "expected_state"), [ @@ -98,11 +124,13 @@ 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, @@ -129,14 +157,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, @@ -175,11 +205,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, @@ -224,11 +256,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, @@ -275,3 +309,165 @@ 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 vacuum_state doesn't log issue or raise repair.""" + state = hass.states.get(mock_vacuum_entity.entity_id) + assert state is not None + assert ( + "Entities should implement the 'vacuum_state' property and" not in caplog.text + ) + + +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.""" + + 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, + ), + ) + + class MockLegacyVacuum(MockVacuum): + """Mocked vacuum entity.""" + + @property + def state(self) -> str: + """Return the state of the entity.""" + return "disarmed" + + entity = MockLegacyVacuum() + + 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), + ) + + with patch.object( + MockLegacyVacuum, + "__module__", + "tests.custom_components.test.vacuum", + ): + 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 + + assert "Entities should implement the 'vacuum_state' property and" in caplog.text + + +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.""" + + 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, + ), + ) + + class MockLegacyVacuum(MockVacuum): + """Mocked vacuum entity.""" + + def start(self) -> None: + """Start cleaning.""" + self._attr_state = VacuumEntityState.CLEANING + + entity = MockLegacyVacuum() + + 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), + ) + + with patch.object( + MockLegacyVacuum, + "__module__", + "tests.custom_components.test.vacuum", + ): + 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 + + assert ( + "Entities should implement the 'vacuum_state' property and" not in caplog.text + ) + + with patch.object( + MockLegacyVacuum, + "__module__", + "tests.custom_components.test.vacuum", + ): + await async_start(hass, entity.entity_id) + + assert "Entities should implement the 'vacuum_state' property and" in caplog.text + caplog.clear() + with patch.object( + MockLegacyVacuum, + "__module__", + "tests.custom_components.test.vacuum", + ): + await async_start(hass, entity.entity_id) + # Test we only log once + assert ( + "Entities should implement the 'vacuum_state' property and" not in caplog.text + ) From ae64169b723726dcdc3da65c984292ae676dd4ee Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 14:30:12 +0000 Subject: [PATCH 09/24] Fix last test --- tests/components/litterrobot/test_vacuum.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/components/litterrobot/test_vacuum.py b/tests/components/litterrobot/test_vacuum.py index 735ee6653aa..bf0d1569d0d 100644 --- a/tests/components/litterrobot/test_vacuum.py +++ b/tests/components/litterrobot/test_vacuum.py @@ -15,9 +15,7 @@ from homeassistant.components.vacuum import ( DOMAIN as PLATFORM_DOMAIN, SERVICE_START, SERVICE_STOP, - STATE_DOCKED, - STATE_ERROR, - STATE_PAUSED, + VacuumEntityState, ) 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 == VacuumEntityState.DOCKED assert vacuum.attributes["is_sleeping"] is False ent_reg_entry = entity_registry.async_get(VACUUM_ENTITY_ID) @@ -95,15 +93,18 @@ async def test_vacuum_with_error( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == STATE_ERROR + assert vacuum.state == VacuumEntityState.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"}, VacuumEntityState.DOCKED), + ({"isDFIFull": True}, VacuumEntityState.ERROR), + ( + {"robotCycleState": "CYCLE_VacuumEntityState.CAT_DETECT"}, + VacuumEntityState.PAUSED, + ), ], ) async def test_vacuum_states( @@ -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 == VacuumEntityState.DOCKED extra = extra or {} data = {ATTR_ENTITY_ID: VACUUM_ENTITY_ID, **extra.get("data", {})} From 2bc1b6bddd1469fa6730e175279a0a269281ee47 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Sun, 13 Oct 2024 15:45:07 +0000 Subject: [PATCH 10/24] Litterrobot tests --- tests/components/litterrobot/test_init.py | 4 ++-- tests/components/litterrobot/test_vacuum.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/litterrobot/test_init.py b/tests/components/litterrobot/test_init.py index 21b16097603..6430f94b9d9 100644 --- a/tests/components/litterrobot/test_init.py +++ b/tests/components/litterrobot/test_init.py @@ -9,7 +9,7 @@ from homeassistant.components import litterrobot from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_START, - STATE_DOCKED, + VacuumEntityState, ) 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 == VacuumEntityState.DOCKED await hass.services.async_call( VACUUM_DOMAIN, diff --git a/tests/components/litterrobot/test_vacuum.py b/tests/components/litterrobot/test_vacuum.py index bf0d1569d0d..89366261a38 100644 --- a/tests/components/litterrobot/test_vacuum.py +++ b/tests/components/litterrobot/test_vacuum.py @@ -102,7 +102,7 @@ async def test_vacuum_with_error( ({"displayCode": "DC_CAT_DETECT"}, VacuumEntityState.DOCKED), ({"isDFIFull": True}, VacuumEntityState.ERROR), ( - {"robotCycleState": "CYCLE_VacuumEntityState.CAT_DETECT"}, + {"robotCycleState": "CYCLE_STATE_CAT_DETECT"}, VacuumEntityState.PAUSED, ), ], From aef136449fc41360aa36a5444b824c311e8dacee Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 21 Oct 2024 16:06:48 +0000 Subject: [PATCH 11/24] Fixes --- .../components/alexa/capabilities.py | 2 +- homeassistant/components/demo/vacuum.py | 28 +++++----- homeassistant/components/ecovacs/vacuum.py | 28 +++++----- .../components/google_assistant/trait.py | 10 ++-- homeassistant/components/group/registry.py | 8 +-- .../components/homekit/type_switches.py | 4 +- .../components/litterrobot/vacuum.py | 28 +++++----- homeassistant/components/mqtt/vacuum.py | 16 +++--- homeassistant/components/neato/vacuum.py | 20 +++---- homeassistant/components/roborock/vacuum.py | 50 ++++++++--------- homeassistant/components/romy/vacuum.py | 4 +- homeassistant/components/roomba/entity.py | 42 +++++++-------- homeassistant/components/sharkiq/vacuum.py | 16 +++--- .../components/switchbot_cloud/vacuum.py | 24 ++++----- homeassistant/components/template/vacuum.py | 16 +++--- homeassistant/components/tuya/vacuum.py | 52 +++++++++--------- homeassistant/components/vacuum/__init__.py | 42 ++++++--------- homeassistant/components/vacuum/const.py | 18 +++---- .../components/vacuum/device_condition.py | 6 +-- .../components/vacuum/device_trigger.py | 6 +-- .../components/vacuum/reproduce_state.py | 20 +++---- .../components/xiaomi_miio/vacuum.py | 54 +++++++++---------- 22 files changed, 239 insertions(+), 255 deletions(-) diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index 290ac6830bc..027d52be28c 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -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.VacuumEntityState.CLEANING + is_on = self.entity.state == vacuum.VacuumState.CLEANING elif self.entity.domain == timer.DOMAIN: is_on = self.entity.state != STATE_IDLE elif self.entity.domain == water_heater.DOMAIN: diff --git a/homeassistant/components/demo/vacuum.py b/homeassistant/components/demo/vacuum.py index 16d6ab4ec33..d5552f79f33 100644 --- a/homeassistant/components/demo/vacuum.py +++ b/homeassistant/components/demo/vacuum.py @@ -9,7 +9,7 @@ from homeassistant.components.vacuum import ( ATTR_CLEANED_AREA, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -87,13 +87,13 @@ class StateDemoVacuum(StateVacuumEntity): """Initialize the vacuum.""" self._attr_name = name self._attr_supported_features = supported_features - self._state = VacuumEntityState.DOCKED + self._state = VacuumState.DOCKED self._fan_speed = FAN_SPEEDS[1] self._cleaned_area: float = 0 self._battery_level = 100 @property - def vacuum_state(self) -> VacuumEntityState: + def vacuum_state(self) -> VacuumState: """Return the current state of the vacuum.""" return self._state @@ -119,33 +119,33 @@ class StateDemoVacuum(StateVacuumEntity): def start(self) -> None: """Start or resume the cleaning task.""" - if self._state != VacuumEntityState.CLEANING: - self._state = VacuumEntityState.CLEANING + if self._state != VacuumState.CLEANING: + self._state = VacuumState.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 == VacuumEntityState.CLEANING: - self._state = VacuumEntityState.PAUSED + if self._state == VacuumState.CLEANING: + self._state = VacuumState.PAUSED self.schedule_update_ha_state() def stop(self, **kwargs: Any) -> None: """Stop the cleaning task, do not return to dock.""" - self._state = VacuumEntityState.IDLE + self._state = VacuumState.IDLE self.schedule_update_ha_state() def return_to_base(self, **kwargs: Any) -> None: """Return dock to charging base.""" - self._state = VacuumEntityState.RETURNING + self._state = VacuumState.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 = VacuumEntityState.CLEANING + self._state = VacuumState.CLEANING self._cleaned_area += 1.32 self._battery_level -= 1 self.schedule_update_ha_state() @@ -163,12 +163,12 @@ class StateDemoVacuum(StateVacuumEntity): "persistent_notification", service_data={"message": "I'm here!", "title": "Locate request"}, ) - self._state = VacuumEntityState.IDLE + self._state = VacuumState.IDLE self.async_write_ha_state() async def async_clean_spot(self, **kwargs: Any) -> None: """Locate the vacuum's position.""" - self._state = VacuumEntityState.CLEANING + self._state = VacuumState.CLEANING self.async_write_ha_state() async def async_send_command( @@ -178,9 +178,9 @@ class StateDemoVacuum(StateVacuumEntity): **kwargs: Any, ) -> None: """Send a command to the vacuum.""" - self._state = VacuumEntityState.IDLE + self._state = VacuumState.IDLE self.async_write_ha_state() def __set_state_to_dock(self, _: datetime) -> None: - self._state = VacuumEntityState.DOCKED + self._state = VacuumState.DOCKED self.schedule_update_ha_state() diff --git a/homeassistant/components/ecovacs/vacuum.py b/homeassistant/components/ecovacs/vacuum.py index cd1bd3f7f2b..73efd7e4e3e 100644 --- a/homeassistant/components/ecovacs/vacuum.py +++ b/homeassistant/components/ecovacs/vacuum.py @@ -16,7 +16,7 @@ from homeassistant.components.vacuum import ( StateVacuumEntity, StateVacuumEntityDescription, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.core import HomeAssistant, SupportsResponse from homeassistant.exceptions import ServiceValidationError @@ -118,22 +118,22 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): self.schedule_update_ha_state() @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | None: """Return the state of the vacuum cleaner.""" if self.error is not None: - return VacuumEntityState.ERROR + return VacuumState.ERROR if self.device.is_cleaning: - return VacuumEntityState.CLEANING + return VacuumState.CLEANING if self.device.is_charging: - return VacuumEntityState.DOCKED + return VacuumState.DOCKED if self.device.vacuum_status == sucks.CLEAN_MODE_STOP: - return VacuumEntityState.IDLE + return VacuumState.IDLE if self.device.vacuum_status == sucks.CHARGE_MODE_RETURNING: - return VacuumEntityState.RETURNING + return VacuumState.RETURNING return None @@ -197,7 +197,7 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: """Set fan speed.""" - if self.state == VacuumEntityState.CLEANING: + if self.state == VacuumState.CLEANING: self.device.run(sucks.Clean(mode=self.device.clean_status, speed=fan_speed)) def send_command( @@ -220,12 +220,12 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): _STATE_TO_VACUUM_STATE = { - State.IDLE: VacuumEntityState.IDLE, - State.CLEANING: VacuumEntityState.CLEANING, - State.RETURNING: VacuumEntityState.RETURNING, - State.DOCKED: VacuumEntityState.DOCKED, - State.ERROR: VacuumEntityState.ERROR, - State.PAUSED: VacuumEntityState.PAUSED, + State.IDLE: VacuumState.IDLE, + State.CLEANING: VacuumState.CLEANING, + State.RETURNING: VacuumState.RETURNING, + State.DOCKED: VacuumState.DOCKED, + State.ERROR: VacuumState.ERROR, + State.PAUSED: VacuumState.PAUSED, } _ATTR_ROOMS = "rooms" diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index e41725176fa..899f0e3d8c7 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -729,7 +729,7 @@ class DockTrait(_Trait): def query_attributes(self) -> dict[str, Any]: """Return dock query attributes.""" - return {"isDocked": self.state.state == vacuum.VacuumEntityState.DOCKED} + return {"isDocked": self.state.state == vacuum.VacuumState.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.VacuumEntityState.DOCKED, - "isPluggedIn": self.state.state == vacuum.VacuumEntityState.DOCKED, + "isCharging": self.state.state == vacuum.VacuumState.DOCKED, + "isPluggedIn": self.state.state == vacuum.VacuumState.DOCKED, } async def execute(self, command, data, params, challenge): @@ -882,8 +882,8 @@ class StartStopTrait(_Trait): if domain == vacuum.DOMAIN: return { - "isRunning": state == vacuum.VacuumEntityState.CLEANING, - "isPaused": state == vacuum.VacuumEntityState.PAUSED, + "isRunning": state == vacuum.VacuumState.CLEANING, + "isPaused": state == vacuum.VacuumState.PAUSED, } if domain in COVER_VALVE_DOMAINS: diff --git a/homeassistant/components/group/registry.py b/homeassistant/components/group/registry.py index d2f091d95c2..38fe29fd253 100644 --- a/homeassistant/components/group/registry.py +++ b/homeassistant/components/group/registry.py @@ -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 VacuumEntityState +from homeassistant.components.vacuum import VacuumState 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, - VacuumEntityState.CLEANING, - VacuumEntityState.RETURNING, - VacuumEntityState.ERROR, + VacuumState.CLEANING, + VacuumState.RETURNING, + VacuumState.ERROR, }, STATE_ON, STATE_OFF, diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index d8e3f7bde88..fa2ac2cc404 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -22,7 +22,7 @@ from homeassistant.components.vacuum import ( SERVICE_RETURN_TO_BASE, SERVICE_START, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -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 (VacuumEntityState.CLEANING, STATE_ON) + current_state = new_state.state in (VacuumState.CLEANING, STATE_ON) _LOGGER.debug("%s: Set current state to %s", self.entity_id, current_state) self.char_on.set_value(current_state) diff --git a/homeassistant/components/litterrobot/vacuum.py b/homeassistant/components/litterrobot/vacuum.py index baa1215b5da..0d1f32f4ac5 100644 --- a/homeassistant/components/litterrobot/vacuum.py +++ b/homeassistant/components/litterrobot/vacuum.py @@ -13,7 +13,7 @@ from homeassistant.components.vacuum import ( StateVacuumEntity, StateVacuumEntityDescription, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform @@ -26,16 +26,16 @@ from .entity import LitterRobotEntity SERVICE_SET_SLEEP_MODE = "set_sleep_mode" LITTER_BOX_STATUS_STATE_MAP = { - LitterBoxStatus.CLEAN_CYCLE: VacuumEntityState.CLEANING, - LitterBoxStatus.EMPTY_CYCLE: VacuumEntityState.CLEANING, - LitterBoxStatus.CLEAN_CYCLE_COMPLETE: VacuumEntityState.DOCKED, - LitterBoxStatus.CAT_DETECTED: VacuumEntityState.DOCKED, - LitterBoxStatus.CAT_SENSOR_TIMING: VacuumEntityState.DOCKED, - LitterBoxStatus.DRAWER_FULL_1: VacuumEntityState.DOCKED, - LitterBoxStatus.DRAWER_FULL_2: VacuumEntityState.DOCKED, - LitterBoxStatus.READY: VacuumEntityState.DOCKED, - LitterBoxStatus.CAT_SENSOR_INTERRUPTED: VacuumEntityState.PAUSED, - LitterBoxStatus.OFF: VacuumEntityState.DOCKED, + LitterBoxStatus.CLEAN_CYCLE: VacuumState.CLEANING, + LitterBoxStatus.EMPTY_CYCLE: VacuumState.CLEANING, + LitterBoxStatus.CLEAN_CYCLE_COMPLETE: VacuumState.DOCKED, + LitterBoxStatus.CAT_DETECTED: VacuumState.DOCKED, + LitterBoxStatus.CAT_SENSOR_TIMING: VacuumState.DOCKED, + LitterBoxStatus.DRAWER_FULL_1: VacuumState.DOCKED, + LitterBoxStatus.DRAWER_FULL_2: VacuumState.DOCKED, + LitterBoxStatus.READY: VacuumState.DOCKED, + LitterBoxStatus.CAT_SENSOR_INTERRUPTED: VacuumState.PAUSED, + LitterBoxStatus.OFF: VacuumState.DOCKED, } LITTER_BOX_ENTITY = StateVacuumEntityDescription( @@ -75,11 +75,9 @@ class LitterRobotCleaner(LitterRobotEntity[LitterRobot], StateVacuumEntity): ) @property - def vacuum_state(self) -> VacuumEntityState: + def vacuum_state(self) -> VacuumState: """Return the state of the cleaner.""" - return LITTER_BOX_STATUS_STATE_MAP.get( - self.robot.status, VacuumEntityState.ERROR - ) + return LITTER_BOX_STATUS_STATE_MAP.get(self.robot.status, VacuumState.ERROR) @property def status(self) -> str: diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index 998583d28c4..9891e844f74 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -12,7 +12,7 @@ from homeassistant.components.vacuum import ( ENTITY_ID_FORMAT, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_SUPPORTED_FEATURES, CONF_NAME @@ -42,13 +42,13 @@ STATE_PAUSED = "paused" STATE_RETURNING = "returning" STATE_CLEANING = "cleaning" -POSSIBLE_STATES: dict[str, VacuumEntityState] = { - STATE_IDLE: VacuumEntityState.IDLE, - STATE_DOCKED: VacuumEntityState.DOCKED, - STATE_ERROR: VacuumEntityState.ERROR, - STATE_PAUSED: VacuumEntityState.PAUSED, - STATE_RETURNING: VacuumEntityState.RETURNING, - STATE_CLEANING: VacuumEntityState.CLEANING, +POSSIBLE_STATES: dict[str, VacuumState] = { + STATE_IDLE: VacuumState.IDLE, + STATE_DOCKED: VacuumState.DOCKED, + STATE_ERROR: VacuumState.ERROR, + STATE_PAUSED: VacuumState.PAUSED, + STATE_RETURNING: VacuumState.RETURNING, + STATE_CLEANING: VacuumState.CLEANING, } CONF_SUPPORTED_FEATURES = ATTR_SUPPORTED_FEATURES diff --git a/homeassistant/components/neato/vacuum.py b/homeassistant/components/neato/vacuum.py index 47ba61c7783..ae1b93346b9 100644 --- a/homeassistant/components/neato/vacuum.py +++ b/homeassistant/components/neato/vacuum.py @@ -14,7 +14,7 @@ from homeassistant.components.vacuum import ( ATTR_STATUS, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_MODE @@ -166,23 +166,23 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): robot_alert = None if self._state["state"] == 1: if self._state["details"]["isCharging"]: - self._attr_vacuum_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumState.DOCKED self._status_state = "Charging" elif ( self._state["details"]["isDocked"] and not self._state["details"]["isCharging"] ): - self._attr_vacuum_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumState.DOCKED self._status_state = "Docked" else: - self._attr_vacuum_state = VacuumEntityState.IDLE + self._attr_vacuum_state = VacuumState.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_vacuum_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumState.CLEANING self._status_state = ( f"{MODE.get(self._state['cleaning']['mode'])} " f"{ACTION.get(self._state['action'])}" @@ -197,10 +197,10 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): else: self._status_state = robot_alert elif self._state["state"] == 3: - self._attr_vacuum_state = VacuumEntityState.PAUSED + self._attr_vacuum_state = VacuumState.PAUSED self._status_state = "Paused" elif self._state["state"] == 4: - self._attr_vacuum_state = VacuumEntityState.ERROR + self._attr_vacuum_state = VacuumState.ERROR self._status_state = ERRORS.get(self._state["error"]) self._attr_battery_level = self._state["details"]["charge"] @@ -323,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_vacuum_state == VacuumEntityState.CLEANING: + if self._attr_vacuum_state == VacuumState.CLEANING: self.robot.pause_cleaning() - self._attr_vacuum_state = VacuumEntityState.RETURNING + self._attr_vacuum_state = VacuumState.RETURNING self.robot.send_to_base() except NeatoRobotException as ex: _LOGGER.error( @@ -377,7 +377,7 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): "Start cleaning zone '%s' with robot %s", zone, self.entity_id ) - self._attr_vacuum_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumState.CLEANING try: self.robot.start_cleaning(mode, navigation, category, boundary_id) except NeatoRobotException as ex: diff --git a/homeassistant/components/roborock/vacuum.py b/homeassistant/components/roborock/vacuum.py index d2ea3c227d6..457152ad01c 100644 --- a/homeassistant/components/roborock/vacuum.py +++ b/homeassistant/components/roborock/vacuum.py @@ -10,7 +10,7 @@ from roborock.roborock_typing import RoborockCommand from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse from homeassistant.helpers import entity_platform @@ -22,29 +22,29 @@ from .coordinator import RoborockDataUpdateCoordinator from .entity import RoborockCoordinatedEntityV1 STATE_CODE_TO_STATE = { - RoborockStateCode.starting: VacuumEntityState.IDLE, # "Starting" - RoborockStateCode.charger_disconnected: VacuumEntityState.IDLE, # "Charger disconnected" - RoborockStateCode.idle: VacuumEntityState.IDLE, # "Idle" - RoborockStateCode.remote_control_active: VacuumEntityState.CLEANING, # "Remote control active" - RoborockStateCode.cleaning: VacuumEntityState.CLEANING, # "Cleaning" - RoborockStateCode.returning_home: VacuumEntityState.RETURNING, # "Returning home" - RoborockStateCode.manual_mode: VacuumEntityState.CLEANING, # "Manual mode" - RoborockStateCode.charging: VacuumEntityState.DOCKED, # "Charging" - RoborockStateCode.charging_problem: VacuumEntityState.ERROR, # "Charging problem" - RoborockStateCode.paused: VacuumEntityState.PAUSED, # "Paused" - RoborockStateCode.spot_cleaning: VacuumEntityState.CLEANING, # "Spot cleaning" - RoborockStateCode.error: VacuumEntityState.ERROR, # "Error" - RoborockStateCode.shutting_down: VacuumEntityState.IDLE, # "Shutting down" - RoborockStateCode.updating: VacuumEntityState.DOCKED, # "Updating" - RoborockStateCode.docking: VacuumEntityState.RETURNING, # "Docking" - RoborockStateCode.going_to_target: VacuumEntityState.CLEANING, # "Going to target" - RoborockStateCode.zoned_cleaning: VacuumEntityState.CLEANING, # "Zoned cleaning" - RoborockStateCode.segment_cleaning: VacuumEntityState.CLEANING, # "Segment cleaning" - RoborockStateCode.emptying_the_bin: VacuumEntityState.DOCKED, # "Emptying the bin" on s7+ - RoborockStateCode.washing_the_mop: VacuumEntityState.DOCKED, # "Washing the mop" on s7maxV - RoborockStateCode.going_to_wash_the_mop: VacuumEntityState.RETURNING, # "Going to wash the mop" on s7maxV - RoborockStateCode.charging_complete: VacuumEntityState.DOCKED, # "Charging complete" - RoborockStateCode.device_offline: VacuumEntityState.ERROR, # "Device offline" + RoborockStateCode.starting: VacuumState.IDLE, # "Starting" + RoborockStateCode.charger_disconnected: VacuumState.IDLE, # "Charger disconnected" + RoborockStateCode.idle: VacuumState.IDLE, # "Idle" + RoborockStateCode.remote_control_active: VacuumState.CLEANING, # "Remote control active" + RoborockStateCode.cleaning: VacuumState.CLEANING, # "Cleaning" + RoborockStateCode.returning_home: VacuumState.RETURNING, # "Returning home" + RoborockStateCode.manual_mode: VacuumState.CLEANING, # "Manual mode" + RoborockStateCode.charging: VacuumState.DOCKED, # "Charging" + RoborockStateCode.charging_problem: VacuumState.ERROR, # "Charging problem" + RoborockStateCode.paused: VacuumState.PAUSED, # "Paused" + RoborockStateCode.spot_cleaning: VacuumState.CLEANING, # "Spot cleaning" + RoborockStateCode.error: VacuumState.ERROR, # "Error" + RoborockStateCode.shutting_down: VacuumState.IDLE, # "Shutting down" + RoborockStateCode.updating: VacuumState.DOCKED, # "Updating" + RoborockStateCode.docking: VacuumState.RETURNING, # "Docking" + RoborockStateCode.going_to_target: VacuumState.CLEANING, # "Going to target" + RoborockStateCode.zoned_cleaning: VacuumState.CLEANING, # "Zoned cleaning" + RoborockStateCode.segment_cleaning: VacuumState.CLEANING, # "Segment cleaning" + RoborockStateCode.emptying_the_bin: VacuumState.DOCKED, # "Emptying the bin" on s7+ + RoborockStateCode.washing_the_mop: VacuumState.DOCKED, # "Washing the mop" on s7maxV + RoborockStateCode.going_to_wash_the_mop: VacuumState.RETURNING, # "Going to wash the mop" on s7maxV + RoborockStateCode.charging_complete: VacuumState.DOCKED, # "Charging complete" + RoborockStateCode.device_offline: VacuumState.ERROR, # "Device offline" } @@ -107,7 +107,7 @@ class RoborockVacuum(RoborockCoordinatedEntityV1, StateVacuumEntity): self._attr_fan_speed_list = self._device_status.fan_power_options @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | 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) diff --git a/homeassistant/components/romy/vacuum.py b/homeassistant/components/romy/vacuum.py index ecf2c758ae4..eff335cbd81 100644 --- a/homeassistant/components/romy/vacuum.py +++ b/homeassistant/components/romy/vacuum.py @@ -9,7 +9,7 @@ from typing import Any from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -81,7 +81,7 @@ class RomyVacuumEntity(RomyEntity, StateVacuumEntity): self._attr_battery_level = self.romy.battery_level try: assert self.romy.status is not None - self._attr_vacuum_state = VacuumEntityState(self.romy.status) + self._attr_vacuum_state = VacuumState(self.romy.status) except (AssertionError, ValueError): self._attr_vacuum_state = None diff --git a/homeassistant/components/roomba/entity.py b/homeassistant/components/roomba/entity.py index e4b9e7377ca..47d1072c534 100644 --- a/homeassistant/components/roomba/entity.py +++ b/homeassistant/components/roomba/entity.py @@ -9,7 +9,7 @@ from homeassistant.components.vacuum import ( ATTR_STATUS, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ATTR_CONNECTIONS import homeassistant.helpers.device_registry as dr @@ -43,16 +43,16 @@ SUPPORT_IROBOT = ( ) STATE_MAP = { - "": VacuumEntityState.IDLE, - "charge": VacuumEntityState.DOCKED, - "evac": VacuumEntityState.RETURNING, # Emptying at cleanbase - "hmMidMsn": VacuumEntityState.CLEANING, # Recharging at the middle of a cycle - "hmPostMsn": VacuumEntityState.RETURNING, # Cycle finished - "hmUsrDock": VacuumEntityState.RETURNING, - "pause": VacuumEntityState.PAUSED, - "run": VacuumEntityState.CLEANING, - "stop": VacuumEntityState.IDLE, - "stuck": VacuumEntityState.ERROR, + "": VacuumState.IDLE, + "charge": VacuumState.DOCKED, + "evac": VacuumState.RETURNING, # Emptying at cleanbase + "hmMidMsn": VacuumState.CLEANING, # Recharging at the middle of a cycle + "hmPostMsn": VacuumState.RETURNING, # Cycle finished + "hmUsrDock": VacuumState.RETURNING, + "pause": VacuumState.PAUSED, + "run": VacuumState.CLEANING, + "stop": VacuumState.IDLE, + "stuck": VacuumState.ERROR, } @@ -125,7 +125,7 @@ class IRobotEntity(Entity): return dt_util.utc_from_timestamp(ts) @property - def _robot_state(self) -> VacuumEntityState: + def _robot_state(self) -> VacuumState: """Return the state of the vacuum cleaner.""" clean_mission_status = self.vacuum_state.get("cleanMissionStatus", {}) cycle = clean_mission_status.get("cycle") @@ -133,12 +133,12 @@ class IRobotEntity(Entity): try: state = STATE_MAP[phase] except KeyError: - return VacuumEntityState.ERROR + return VacuumState.ERROR if cycle != "none" and state in ( - VacuumEntityState.IDLE, - VacuumEntityState.DOCKED, + VacuumState.IDLE, + VacuumState.DOCKED, ): - state = VacuumEntityState.PAUSED + state = VacuumState.PAUSED return state async def async_added_to_hass(self): @@ -169,7 +169,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf self._cap_position = self.vacuum_state.get("cap", {}).get("pose") == 1 @property - def vacuum_state(self) -> VacuumEntityState: + def vacuum_state(self) -> VacuumState: """Return the state of the vacuum cleaner.""" return self._robot_state @@ -189,7 +189,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf # Only add cleaning time and cleaned area attrs when the vacuum is # currently on - if self.state == VacuumEntityState.CLEANING: + if self.state == VacuumState.CLEANING: # Get clean mission status ( state_attrs[ATTR_CLEANING_TIME], @@ -243,7 +243,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_start(self): """Start or resume the cleaning task.""" - if self.vacuum_state == VacuumEntityState.PAUSED: + if self.vacuum_state == VacuumState.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") @@ -258,10 +258,10 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" - if self.vacuum_state == VacuumEntityState.CLEANING: + if self.vacuum_state == VacuumState.CLEANING: await self.async_pause() for _ in range(10): - if self.state == VacuumEntityState.PAUSED: + if self.state == VacuumState.PAUSED: break await asyncio.sleep(1) await self.hass.async_add_executor_job(self.vacuum.send_command, "dock") diff --git a/homeassistant/components/sharkiq/vacuum.py b/homeassistant/components/sharkiq/vacuum.py index bcf706ef575..db0f5bba9d6 100644 --- a/homeassistant/components/sharkiq/vacuum.py +++ b/homeassistant/components/sharkiq/vacuum.py @@ -11,7 +11,7 @@ import voluptuous as vol from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -26,10 +26,10 @@ from .const import DOMAIN, LOGGER, SERVICE_CLEAN_ROOM, SHARK from .coordinator import SharkIqUpdateCoordinator OPERATING_STATE_MAP = { - OperatingModes.PAUSE: VacuumEntityState.PAUSED, - OperatingModes.START: VacuumEntityState.CLEANING, - OperatingModes.STOP: VacuumEntityState.IDLE, - OperatingModes.RETURN: VacuumEntityState.RETURNING, + OperatingModes.PAUSE: VacuumState.PAUSED, + OperatingModes.START: VacuumState.CLEANING, + OperatingModes.STOP: VacuumState.IDLE, + OperatingModes.RETURN: VacuumState.RETURNING, } FAN_SPEEDS_MAP = { @@ -147,7 +147,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.error_text @property - def operating_mode(self) -> VacuumEntityState | None: + def operating_mode(self) -> VacuumState | None: """Operating mode.""" op_mode = self.sharkiq.get_property_value(Properties.OPERATING_MODE) return OPERATING_STATE_MAP.get(op_mode) @@ -158,7 +158,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.get_property_value(Properties.RECHARGING_TO_RESUME) @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | None: """Get the current vacuum state. NB: Currently, we do not return an error state because they can be very, very stale. @@ -166,7 +166,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum user a notification. """ if self.sharkiq.get_property_value(Properties.CHARGING_STATUS): - return VacuumEntityState.DOCKED + return VacuumState.DOCKED return self.operating_mode @property diff --git a/homeassistant/components/switchbot_cloud/vacuum.py b/homeassistant/components/switchbot_cloud/vacuum.py index 88f80df907f..94231a83fb5 100644 --- a/homeassistant/components/switchbot_cloud/vacuum.py +++ b/homeassistant/components/switchbot_cloud/vacuum.py @@ -7,7 +7,7 @@ from switchbot_api import Device, Remote, SwitchBotAPI, VacuumCommands from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -38,17 +38,17 @@ async def async_setup_entry( ) -VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, VacuumEntityState] = { - "StandBy": VacuumEntityState.IDLE, - "Clearing": VacuumEntityState.CLEANING, - "Paused": VacuumEntityState.PAUSED, - "GotoChargeBase": VacuumEntityState.RETURNING, - "Charging": VacuumEntityState.DOCKED, - "ChargeDone": VacuumEntityState.DOCKED, - "Dormant": VacuumEntityState.IDLE, - "InTrouble": VacuumEntityState.ERROR, - "InRemoteControl": VacuumEntityState.CLEANING, - "InDustCollecting": VacuumEntityState.DOCKED, +VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, VacuumState] = { + "StandBy": VacuumState.IDLE, + "Clearing": VacuumState.CLEANING, + "Paused": VacuumState.PAUSED, + "GotoChargeBase": VacuumState.RETURNING, + "Charging": VacuumState.DOCKED, + "ChargeDone": VacuumState.DOCKED, + "Dormant": VacuumState.IDLE, + "InTrouble": VacuumState.ERROR, + "InRemoteControl": VacuumState.CLEANING, + "InDustCollecting": VacuumState.DOCKED, } VACUUM_FAN_SPEED_TO_SWITCHBOT_FAN_SPEED: dict[str, str] = { diff --git a/homeassistant/components/template/vacuum.py b/homeassistant/components/template/vacuum.py index 9db93cfcd6a..62d55c2375e 100644 --- a/homeassistant/components/template/vacuum.py +++ b/homeassistant/components/template/vacuum.py @@ -19,7 +19,7 @@ from homeassistant.components.vacuum import ( SERVICE_STOP, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ( CONF_ENTITY_ID, @@ -53,12 +53,12 @@ CONF_FAN_SPEED_TEMPLATE = "fan_speed_template" ENTITY_ID_FORMAT = VACUUM_DOMAIN + ".{}" _VALID_STATES = [ - VacuumEntityState.CLEANING, - VacuumEntityState.DOCKED, - VacuumEntityState.PAUSED, - VacuumEntityState.IDLE, - VacuumEntityState.RETURNING, - VacuumEntityState.ERROR, + VacuumState.CLEANING, + VacuumState.DOCKED, + VacuumState.PAUSED, + VacuumState.IDLE, + VacuumState.RETURNING, + VacuumState.ERROR, ] VACUUM_SCHEMA = vol.All( @@ -197,7 +197,7 @@ class TemplateVacuum(TemplateEntity, StateVacuumEntity): self._attr_fan_speed_list = config[CONF_FAN_SPEED_LIST] @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | None: """Return the status of the vacuum cleaner.""" return self._state diff --git a/homeassistant/components/tuya/vacuum.py b/homeassistant/components/tuya/vacuum.py index 02c5e0bdc71..0a9429f98ae 100644 --- a/homeassistant/components/tuya/vacuum.py +++ b/homeassistant/components/tuya/vacuum.py @@ -9,7 +9,7 @@ from tuya_sharing import CustomerDevice, Manager from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -21,29 +21,29 @@ from .entity import EnumTypeData, IntegerTypeData, TuyaEntity TUYA_MODE_RETURN_HOME = "chargego" TUYA_STATUS_TO_HA = { - "charge_done": VacuumEntityState.DOCKED, - "chargecompleted": VacuumEntityState.DOCKED, - "chargego": VacuumEntityState.DOCKED, - "charging": VacuumEntityState.DOCKED, - "cleaning": VacuumEntityState.CLEANING, - "docking": VacuumEntityState.RETURNING, - "goto_charge": VacuumEntityState.RETURNING, - "goto_pos": VacuumEntityState.CLEANING, - "mop_clean": VacuumEntityState.CLEANING, - "part_clean": VacuumEntityState.CLEANING, - "paused": VacuumEntityState.PAUSED, - "pick_zone_clean": VacuumEntityState.CLEANING, - "pos_arrived": VacuumEntityState.CLEANING, - "pos_unarrive": VacuumEntityState.CLEANING, - "random": VacuumEntityState.CLEANING, - "sleep": VacuumEntityState.IDLE, - "smart_clean": VacuumEntityState.CLEANING, - "smart": VacuumEntityState.CLEANING, - "spot_clean": VacuumEntityState.CLEANING, - "standby": VacuumEntityState.IDLE, - "wall_clean": VacuumEntityState.CLEANING, - "wall_follow": VacuumEntityState.CLEANING, - "zone_clean": VacuumEntityState.CLEANING, + "charge_done": VacuumState.DOCKED, + "chargecompleted": VacuumState.DOCKED, + "chargego": VacuumState.DOCKED, + "charging": VacuumState.DOCKED, + "cleaning": VacuumState.CLEANING, + "docking": VacuumState.RETURNING, + "goto_charge": VacuumState.RETURNING, + "goto_pos": VacuumState.CLEANING, + "mop_clean": VacuumState.CLEANING, + "part_clean": VacuumState.CLEANING, + "paused": VacuumState.PAUSED, + "pick_zone_clean": VacuumState.CLEANING, + "pos_arrived": VacuumState.CLEANING, + "pos_unarrive": VacuumState.CLEANING, + "random": VacuumState.CLEANING, + "sleep": VacuumState.IDLE, + "smart_clean": VacuumState.CLEANING, + "smart": VacuumState.CLEANING, + "spot_clean": VacuumState.CLEANING, + "standby": VacuumState.IDLE, + "wall_clean": VacuumState.CLEANING, + "wall_follow": VacuumState.CLEANING, + "zone_clean": VacuumState.CLEANING, } @@ -134,12 +134,12 @@ class TuyaVacuumEntity(TuyaEntity, StateVacuumEntity): return self.device.status.get(DPCode.SUCTION) @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | None: """Return Tuya vacuum device state.""" if self.device.status.get(DPCode.PAUSE) and not ( self.device.status.get(DPCode.STATUS) ): - return VacuumEntityState.PAUSED + return VacuumState.PAUSED if not (status := self.device.status.get(DPCode.STATUS)): return None return TUYA_STATUS_TO_HA.get(status) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 7aac5c36709..0d2af17f425 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -44,7 +44,7 @@ from .const import ( # noqa: F401 _DEPRECATED_STATE_RETURNING, DOMAIN, STATES, - VacuumEntityState, + VacuumState, ) _LOGGER = logging.getLogger(__name__) @@ -75,9 +75,9 @@ SERVICE_STOP = "stop" DEFAULT_NAME = "Vacuum cleaner robot" # These STATE_* constants are deprecated as of Home Assistant 2024.11. -# Please use the VacuumEntityState enum instead. -_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumEntityState.IDLE, "2025.11") -_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumEntityState.PAUSED, "2025.11") +# Please use the VacuumState enum instead. +_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumState.IDLE, "2025.11") +_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumState.PAUSED, "2025.11") class VacuumEntityFeature(IntFlag): @@ -243,29 +243,21 @@ class StateVacuumEntity( _attr_battery_level: int | None = None _attr_fan_speed: str | None = None _attr_fan_speed_list: list[str] - _attr_vacuum_state: VacuumEntityState | None = None + _attr_vacuum_state: VacuumState | None = None _attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0) __vacuum_legacy_state: bool = False __vacuum_legacy_state_reported: 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 'alarm_state' 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 settings '_attr_state' directly + Deprecation warning if setting '_attr_state' directly unless already reported. """ if __name == "_attr_state": if self.__vacuum_legacy_state_reported is not True: - self._report_deprecated_alarm_state_handling() + self._report_deprecated_vacuum_state_handling() self.__vacuum_legacy_state_reported = True return super().__setattr__(__name, __value) @@ -279,16 +271,14 @@ class StateVacuumEntity( """Start adding an entity to a platform.""" super().add_to_platform_start(hass, platform, parallel_updates) if self.__vacuum_legacy_state and not self.__vacuum_legacy_state_reported: - self._report_deprecated_alarm_state_handling() + self._report_deprecated_vacuum_state_handling() @callback - def _report_deprecated_alarm_state_handling(self) -> None: + def _report_deprecated_vacuum_state_handling(self) -> None: """Report on deprecated handling of vacuum state. Integrations should implement vacuum_state instead of using state directly. """ - if self.__vacuum_legacy_state_reported is True: - return self.__vacuum_legacy_state_reported = True if "custom_components" in type(self).__module__: # Do not report on core integrations as they have been fixed. @@ -297,7 +287,7 @@ class StateVacuumEntity( "Entity %s (%s) is setting state directly" " which will stop working in HA Core 2025.11." " Entities should implement the 'vacuum_state' property and" - " return it's state using the VacuumEntityState enum, please %s", + " return its state using the VacuumState enum, please %s", self.entity_id, type(self), report_issue, @@ -311,7 +301,7 @@ class StateVacuumEntity( @property def battery_icon(self) -> str: """Return the battery icon for the vacuum cleaner.""" - charging = bool(self.vacuum_state == VacuumEntityState.DOCKED) + charging = bool(self.vacuum_state == VacuumState.DOCKED) return icon_for_battery_level( battery_level=self.battery_level, charging=charging @@ -355,14 +345,14 @@ class StateVacuumEntity( """Return the state of the vacuum cleaner.""" if (vacuum_state := self.vacuum_state) is None: return None - return str(vacuum_state) + return vacuum_state @cached_property - def vacuum_state(self) -> VacuumEntityState | None: - """Return the current vacuum entity state. + def vacuum_state(self) -> VacuumState | None: + """Return the current vacuum state. - Integrations should overwrite this or use the 'attr_vacuum_state' - attribute to set the alarm status using the 'VacuumEntityState' enum. + Integrations should overwrite this or use the '_attr_vacuum_state' + attribute to set the vacuum status using the 'VacuumState' enum. """ return self._attr_vacuum_state diff --git a/homeassistant/components/vacuum/const.py b/homeassistant/components/vacuum/const.py index 205fbeee236..05b631b5afe 100644 --- a/homeassistant/components/vacuum/const.py +++ b/homeassistant/components/vacuum/const.py @@ -15,7 +15,7 @@ from homeassistant.helpers.deprecation import ( DOMAIN = "vacuum" -class VacuumEntityState(StrEnum): +class VacuumState(StrEnum): """Vacuum entity states.""" CLEANING = "cleaning" @@ -27,18 +27,14 @@ class VacuumEntityState(StrEnum): # These STATE_* constants are deprecated as of Home Assistant 2024.11. -# Please use the VacuumEntityState enum instead. -_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum( - VacuumEntityState.CLEANING, "2025.11" -) -_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumEntityState.DOCKED, "2025.11") -_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum( - VacuumEntityState.RETURNING, "2025.11" -) -_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumEntityState.ERROR, "2025.11") +# Please use the VacuumState enum instead. +_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumState.CLEANING, "2025.11") +_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumState.DOCKED, "2025.11") +_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum(VacuumState.RETURNING, "2025.11") +_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumState.ERROR, "2025.11") -STATES = [cls.value for cls in VacuumEntityState] +STATES = [cls.value for cls in VacuumState] # These can be removed if no deprecated constant are in this module anymore __getattr__ = partial(check_if_deprecated_constant, module_globals=globals()) diff --git a/homeassistant/components/vacuum/device_condition.py b/homeassistant/components/vacuum/device_condition.py index e7955f692ac..072136b5a4a 100644 --- a/homeassistant/components/vacuum/device_condition.py +++ b/homeassistant/components/vacuum/device_condition.py @@ -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, VacuumEntityState +from . import DOMAIN, VacuumState 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 = [VacuumEntityState.DOCKED] + test_states = [VacuumState.DOCKED] else: - test_states = [VacuumEntityState.CLEANING, VacuumEntityState.RETURNING] + test_states = [VacuumState.CLEANING, VacuumState.RETURNING] registry = er.async_get(hass) entity_id = er.async_resolve_entity_id(registry, config[CONF_ENTITY_ID]) diff --git a/homeassistant/components/vacuum/device_trigger.py b/homeassistant/components/vacuum/device_trigger.py index 4d6b7d2c3c0..ec4238674af 100644 --- a/homeassistant/components/vacuum/device_trigger.py +++ b/homeassistant/components/vacuum/device_trigger.py @@ -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, VacuumEntityState +from . import DOMAIN, VacuumState 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 = VacuumEntityState.CLEANING + to_state = VacuumState.CLEANING else: - to_state = VacuumEntityState.DOCKED + to_state = VacuumState.DOCKED state_config = { CONF_PLATFORM: "state", diff --git a/homeassistant/components/vacuum/reproduce_state.py b/homeassistant/components/vacuum/reproduce_state.py index 62fb9cd9db3..dde9d6ca980 100644 --- a/homeassistant/components/vacuum/reproduce_state.py +++ b/homeassistant/components/vacuum/reproduce_state.py @@ -24,18 +24,18 @@ from . import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumEntityState, + VacuumState, ) _LOGGER = logging.getLogger(__name__) VALID_STATES_TOGGLE = {STATE_ON, STATE_OFF} VALID_STATES_STATE = { - VacuumEntityState.CLEANING, - VacuumEntityState.DOCKED, - VacuumEntityState.IDLE, - VacuumEntityState.PAUSED, - VacuumEntityState.RETURNING, + VacuumState.CLEANING, + VacuumState.DOCKED, + VacuumState.IDLE, + VacuumState.PAUSED, + VacuumState.RETURNING, } @@ -71,13 +71,13 @@ async def _async_reproduce_state( service = SERVICE_TURN_ON elif state.state == STATE_OFF: service = SERVICE_TURN_OFF - elif state.state == VacuumEntityState.CLEANING: + elif state.state == VacuumState.CLEANING: service = SERVICE_START - elif state.state in [VacuumEntityState.DOCKED, VacuumEntityState.RETURNING]: + elif state.state in [VacuumState.DOCKED, VacuumState.RETURNING]: service = SERVICE_RETURN_TO_BASE - elif state.state == VacuumEntityState.IDLE: + elif state.state == VacuumState.IDLE: service = SERVICE_STOP - elif state.state == VacuumEntityState.PAUSED: + elif state.state == VacuumState.PAUSED: service = SERVICE_PAUSE await hass.services.async_call( diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index 5e45a74ff40..1b5fed2b7d3 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -12,7 +12,7 @@ import voluptuous as vol from homeassistant.components.vacuum import ( StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_DEVICE @@ -50,29 +50,29 @@ ATTR_ZONE_REPEATER = "repeats" ATTR_TIMERS = "timers" STATE_CODE_TO_STATE = { - 1: VacuumEntityState.IDLE, # "Starting" - 2: VacuumEntityState.IDLE, # "Charger disconnected" - 3: VacuumEntityState.IDLE, # "Idle" - 4: VacuumEntityState.CLEANING, # "Remote control active" - 5: VacuumEntityState.CLEANING, # "Cleaning" - 6: VacuumEntityState.RETURNING, # "Returning home" - 7: VacuumEntityState.CLEANING, # "Manual mode" - 8: VacuumEntityState.DOCKED, # "Charging" - 9: VacuumEntityState.ERROR, # "Charging problem" - 10: VacuumEntityState.PAUSED, # "Paused" - 11: VacuumEntityState.CLEANING, # "Spot cleaning" - 12: VacuumEntityState.ERROR, # "Error" - 13: VacuumEntityState.IDLE, # "Shutting down" - 14: VacuumEntityState.DOCKED, # "Updating" - 15: VacuumEntityState.RETURNING, # "Docking" - 16: VacuumEntityState.CLEANING, # "Going to target" - 17: VacuumEntityState.CLEANING, # "Zoned cleaning" - 18: VacuumEntityState.CLEANING, # "Segment cleaning" - 22: VacuumEntityState.DOCKED, # "Emptying the bin" on s7+ - 23: VacuumEntityState.DOCKED, # "Washing the mop" on s7maxV - 26: VacuumEntityState.RETURNING, # "Going to wash the mop" on s7maxV - 100: VacuumEntityState.DOCKED, # "Charging complete" - 101: VacuumEntityState.ERROR, # "Device offline" + 1: VacuumState.IDLE, # "Starting" + 2: VacuumState.IDLE, # "Charger disconnected" + 3: VacuumState.IDLE, # "Idle" + 4: VacuumState.CLEANING, # "Remote control active" + 5: VacuumState.CLEANING, # "Cleaning" + 6: VacuumState.RETURNING, # "Returning home" + 7: VacuumState.CLEANING, # "Manual mode" + 8: VacuumState.DOCKED, # "Charging" + 9: VacuumState.ERROR, # "Charging problem" + 10: VacuumState.PAUSED, # "Paused" + 11: VacuumState.CLEANING, # "Spot cleaning" + 12: VacuumState.ERROR, # "Error" + 13: VacuumState.IDLE, # "Shutting down" + 14: VacuumState.DOCKED, # "Updating" + 15: VacuumState.RETURNING, # "Docking" + 16: VacuumState.CLEANING, # "Going to target" + 17: VacuumState.CLEANING, # "Zoned cleaning" + 18: VacuumState.CLEANING, # "Segment cleaning" + 22: VacuumState.DOCKED, # "Emptying the bin" on s7+ + 23: VacuumState.DOCKED, # "Washing the mop" on s7maxV + 26: VacuumState.RETURNING, # "Going to wash the mop" on s7maxV + 100: VacuumState.DOCKED, # "Charging complete" + 101: VacuumState.ERROR, # "Device offline" } @@ -206,7 +206,7 @@ class MiroboVacuum( ) -> None: """Initialize the Xiaomi vacuum cleaner robot handler.""" super().__init__(device, entry, unique_id, coordinator) - self._state: VacuumEntityState | None = None + self._state: VacuumState | None = None async def async_added_to_hass(self) -> None: """Run when entity is about to be added to hass.""" @@ -214,12 +214,12 @@ class MiroboVacuum( self._handle_coordinator_update() @property - def vacuum_state(self) -> VacuumEntityState | None: + def vacuum_state(self) -> VacuumState | 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 VacuumEntityState.ERROR + return VacuumState.ERROR return self._state From 3cfef0cc86b0d7834cf81f923d672ce4e3f8b2a7 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 21 Oct 2024 16:07:47 +0000 Subject: [PATCH 12/24] Tests --- tests/components/demo/test_vacuum.py | 32 ++++++------- .../components/google_assistant/test_trait.py | 10 ++-- .../components/homekit/test_type_switches.py | 6 +-- tests/components/litterrobot/test_init.py | 4 +- tests/components/litterrobot/test_vacuum.py | 14 +++--- tests/components/mqtt/test_vacuum.py | 12 ++--- tests/components/sharkiq/test_vacuum.py | 12 ++--- tests/components/template/test_vacuum.py | 46 +++++++++---------- tests/components/vacuum/__init__.py | 14 +++--- .../vacuum/test_device_condition.py | 10 ++-- .../components/vacuum/test_device_trigger.py | 16 +++---- tests/components/vacuum/test_init.py | 16 +++---- .../components/vacuum/test_reproduce_state.py | 32 ++++++------- tests/components/xiaomi_miio/test_vacuum.py | 6 +-- 14 files changed, 115 insertions(+), 115 deletions(-) diff --git a/tests/components/demo/test_vacuum.py b/tests/components/demo/test_vacuum.py index 64c6cac5f5c..8e2bf5acf6a 100644 --- a/tests/components/demo/test_vacuum.py +++ b/tests/components/demo/test_vacuum.py @@ -22,7 +22,7 @@ from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_SEND_COMMAND, SERVICE_SET_FAN_SPEED, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -71,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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.DOCKED async def test_methods(hass: HomeAssistant) -> None: @@ -107,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 == VacuumEntityState.CLEANING + assert state.state == VacuumState.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 == VacuumEntityState.IDLE + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.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 == VacuumEntityState.IDLE + assert state.state == VacuumState.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 == VacuumEntityState.RETURNING + assert state.state == VacuumState.RETURNING await common.async_set_fan_speed( hass, FAN_SPEEDS[-1], entity_id=ENTITY_VACUUM_COMPLETE @@ -141,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 == VacuumEntityState.CLEANING + assert state.state == VacuumState.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 == VacuumEntityState.PAUSED + assert state.state == VacuumState.PAUSED await common.async_return_to_base(hass, ENTITY_VACUUM_COMPLETE) state = hass.states.get(ENTITY_VACUUM_COMPLETE) - assert state.state == VacuumEntityState.RETURNING + assert state.state == VacuumState.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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.DOCKED async def test_unsupported_methods(hass: HomeAssistant) -> None: @@ -247,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 == VacuumEntityState.IDLE + assert new_state_complete.state == VacuumState.IDLE diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 8052ec20c01..14108e6d16d 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -432,7 +432,7 @@ async def test_dock_vacuum(hass: HomeAssistant) -> None: assert trait.DockTrait.supported(vacuum.DOMAIN, 0, None, None) trt = trait.DockTrait( - hass, State("vacuum.bla", vacuum.VacuumEntityState.IDLE), BASIC_CONFIG + hass, State("vacuum.bla", vacuum.VacuumState.IDLE), BASIC_CONFIG ) assert trt.sync_attributes() == {} @@ -456,7 +456,7 @@ async def test_locate_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumEntityState.IDLE, + vacuum.VacuumState.IDLE, {ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.LOCATE}, ), BASIC_CONFIG, @@ -487,7 +487,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumEntityState.DOCKED, + vacuum.VacuumState.DOCKED, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY, ATTR_BATTERY_LEVEL: 100, @@ -513,7 +513,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumEntityState.CLEANING, + vacuum.VacuumState.CLEANING, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY, ATTR_BATTERY_LEVEL: 20, @@ -553,7 +553,7 @@ async def test_startstop_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumEntityState.PAUSED, + vacuum.VacuumState.PAUSED, {ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.PAUSE}, ), BASIC_CONFIG, diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 64358058234..1b1699f5282 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -27,7 +27,7 @@ from homeassistant.components.vacuum import ( SERVICE_TURN_OFF, SERVICE_TURN_ON, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -294,7 +294,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support( hass.states.async_set( entity_id, - VacuumEntityState.CLEANING, + VacuumState.CLEANING, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME | VacuumEntityFeature.START @@ -305,7 +305,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support( hass.states.async_set( entity_id, - VacuumEntityState.DOCKED, + VacuumState.DOCKED, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME | VacuumEntityFeature.START diff --git a/tests/components/litterrobot/test_init.py b/tests/components/litterrobot/test_init.py index 6430f94b9d9..b23b5373579 100644 --- a/tests/components/litterrobot/test_init.py +++ b/tests/components/litterrobot/test_init.py @@ -9,7 +9,7 @@ from homeassistant.components import litterrobot from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_START, - VacuumEntityState, + VacuumState, ) 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 == VacuumEntityState.DOCKED + assert vacuum.state == VacuumState.DOCKED await hass.services.async_call( VACUUM_DOMAIN, diff --git a/tests/components/litterrobot/test_vacuum.py b/tests/components/litterrobot/test_vacuum.py index 89366261a38..4bfe50a3839 100644 --- a/tests/components/litterrobot/test_vacuum.py +++ b/tests/components/litterrobot/test_vacuum.py @@ -15,7 +15,7 @@ from homeassistant.components.vacuum import ( DOMAIN as PLATFORM_DOMAIN, SERVICE_START, SERVICE_STOP, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant @@ -51,7 +51,7 @@ async def test_vacuum( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumEntityState.DOCKED + assert vacuum.state == VacuumState.DOCKED assert vacuum.attributes["is_sleeping"] is False ent_reg_entry = entity_registry.async_get(VACUUM_ENTITY_ID) @@ -93,17 +93,17 @@ async def test_vacuum_with_error( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumEntityState.ERROR + assert vacuum.state == VacuumState.ERROR @pytest.mark.parametrize( ("robot_data", "expected_state"), [ - ({"displayCode": "DC_CAT_DETECT"}, VacuumEntityState.DOCKED), - ({"isDFIFull": True}, VacuumEntityState.ERROR), + ({"displayCode": "DC_CAT_DETECT"}, VacuumState.DOCKED), + ({"isDFIFull": True}, VacuumState.ERROR), ( {"robotCycleState": "CYCLE_STATE_CAT_DETECT"}, - VacuumEntityState.PAUSED, + VacuumState.PAUSED, ), ], ) @@ -151,7 +151,7 @@ async def test_commands( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumEntityState.DOCKED + assert vacuum.state == VacuumState.DOCKED extra = extra or {} data = {ATTR_ENTITY_ID: VACUUM_ENTITY_ID, **extra.get("data", {})} diff --git a/tests/components/mqtt/test_vacuum.py b/tests/components/mqtt/test_vacuum.py index 907ef8b5c84..f90f323d199 100644 --- a/tests/components/mqtt/test_vacuum.py +++ b/tests/components/mqtt/test_vacuum.py @@ -27,7 +27,7 @@ from homeassistant.components.vacuum import ( SERVICE_RETURN_TO_BASE, SERVICE_START, SERVICE_STOP, - VacuumEntityState, + VacuumState, ) from homeassistant.const import CONF_NAME, ENTITY_MATCH_ALL, STATE_UNKNOWN from homeassistant.core import HomeAssistant @@ -312,7 +312,7 @@ async def test_status( }""" async_fire_mqtt_message(hass, "vacuum/state", message) state = hass.states.get("vacuum.mqtttest") - assert state.state == VacuumEntityState.CLEANING + assert state.state == VacuumState.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" @@ -325,7 +325,7 @@ async def test_status( async_fire_mqtt_message(hass, "vacuum/state", message) state = hass.states.get("vacuum.mqtttest") - assert state.state == VacuumEntityState.DOCKED + assert state.state == VacuumState.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" @@ -365,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 == VacuumEntityState.CLEANING + assert state.state == VacuumState.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 @@ -379,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 == VacuumEntityState.CLEANING + assert state.state == VacuumState.CLEANING assert state.attributes.get(ATTR_FAN_SPEED) is None assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None @@ -393,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 == VacuumEntityState.DOCKED + assert state.state == VacuumState.DOCKED assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-charging-60" assert state.attributes.get(ATTR_BATTERY_LEVEL) == 61 diff --git a/tests/components/sharkiq/test_vacuum.py b/tests/components/sharkiq/test_vacuum.py index ed3d9715521..2437f8372b7 100644 --- a/tests/components/sharkiq/test_vacuum.py +++ b/tests/components/sharkiq/test_vacuum.py @@ -36,7 +36,7 @@ from homeassistant.components.vacuum import ( SERVICE_START, SERVICE_STOP, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -157,7 +157,7 @@ async def test_simple_properties( assert entity assert state - assert state.state == VacuumEntityState.CLEANING + assert state.state == VacuumState.CLEANING assert entity.unique_id == "AC000Wxxxxxxxxx" @@ -186,10 +186,10 @@ async def test_initial_attributes( @pytest.mark.parametrize( ("service", "target_state"), [ - (SERVICE_STOP, VacuumEntityState.IDLE), - (SERVICE_PAUSE, VacuumEntityState.PAUSED), - (SERVICE_RETURN_TO_BASE, VacuumEntityState.RETURNING), - (SERVICE_START, VacuumEntityState.CLEANING), + (SERVICE_STOP, VacuumState.IDLE), + (SERVICE_PAUSE, VacuumState.PAUSED), + (SERVICE_RETURN_TO_BASE, VacuumState.RETURNING), + (SERVICE_START, VacuumState.CLEANING), ], ) async def test_cleaning_states( diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index ab7991fa948..da44c1c8e2d 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -3,7 +3,7 @@ import pytest from homeassistant import setup -from homeassistant.components.vacuum import ATTR_BATTERY_LEVEL, VacuumEntityState +from homeassistant.components.vacuum import ATTR_BATTERY_LEVEL, VacuumState from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import HomeAssistantError @@ -37,7 +37,7 @@ _BATTERY_LEVEL_INPUT_NUMBER = "input_number.battery_level" }, ), ( - VacuumEntityState.CLEANING, + VacuumState.CLEANING, 100, { "vacuum": { @@ -142,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, VacuumEntityState.CLEANING) + hass.states.async_set(_STATE_INPUT_SELECT, VacuumState.CLEANING) hass.states.async_set(_BATTERY_LEVEL_INPUT_NUMBER, 100) await hass.async_block_till_done() - _verify(hass, VacuumEntityState.CLEANING, 100) + _verify(hass, VacuumState.CLEANING, 100) @pytest.mark.parametrize( @@ -363,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 == VacuumEntityState.CLEANING - _verify(hass, VacuumEntityState.CLEANING, None) + assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumState.CLEANING + _verify(hass, VacuumState.CLEANING, None) assert len(calls) == 1 assert calls[-1].data["action"] == "start" assert calls[-1].data["caller"] == _TEST_VACUUM @@ -374,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 == VacuumEntityState.PAUSED - _verify(hass, VacuumEntityState.PAUSED, None) + assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumState.PAUSED + _verify(hass, VacuumState.PAUSED, None) assert len(calls) == 2 assert calls[-1].data["action"] == "pause" assert calls[-1].data["caller"] == _TEST_VACUUM @@ -385,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 == VacuumEntityState.IDLE - _verify(hass, VacuumEntityState.IDLE, None) + assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumState.IDLE + _verify(hass, VacuumState.IDLE, None) assert len(calls) == 3 assert calls[-1].data["action"] == "stop" assert calls[-1].data["caller"] == _TEST_VACUUM @@ -396,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 == VacuumEntityState.RETURNING - _verify(hass, VacuumEntityState.RETURNING, None) + assert hass.states.get(_STATE_INPUT_SELECT).state == VacuumState.RETURNING + _verify(hass, VacuumState.RETURNING, None) assert len(calls) == 4 assert calls[-1].data["action"] == "return_to_base" assert calls[-1].data["caller"] == _TEST_VACUUM @@ -501,7 +501,7 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None: "input_select", { "input_select": { - "state": {"name": "State", "options": [VacuumEntityState.CLEANING]} + "state": {"name": "State", "options": [VacuumState.CLEANING]} } }, ) @@ -519,7 +519,7 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumEntityState.CLEANING, + "option": VacuumState.CLEANING, }, } } @@ -551,11 +551,11 @@ async def _register_components(hass: HomeAssistant) -> None: "state": { "name": "State", "options": [ - VacuumEntityState.CLEANING, - VacuumEntityState.DOCKED, - VacuumEntityState.IDLE, - VacuumEntityState.PAUSED, - VacuumEntityState.RETURNING, + VacuumState.CLEANING, + VacuumState.DOCKED, + VacuumState.IDLE, + VacuumState.PAUSED, + VacuumState.RETURNING, ], }, "fan_speed": { @@ -575,7 +575,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumEntityState.CLEANING, + "option": VacuumState.CLEANING, }, }, { @@ -591,7 +591,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumEntityState.PAUSED, + "option": VacuumState.PAUSED, }, }, { @@ -607,7 +607,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumEntityState.IDLE, + "option": VacuumState.IDLE, }, }, { @@ -623,7 +623,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumEntityState.RETURNING, + "option": VacuumState.RETURNING, }, }, { diff --git a/tests/components/vacuum/__init__.py b/tests/components/vacuum/__init__.py index daab7b81420..ab41e8bed7f 100644 --- a/tests/components/vacuum/__init__.py +++ b/tests/components/vacuum/__init__.py @@ -6,7 +6,7 @@ from homeassistant.components.vacuum import ( DOMAIN, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform @@ -35,20 +35,20 @@ class MockVacuum(MockEntity, StateVacuumEntity): def __init__(self, **values: Any) -> None: """Initialize a mock vacuum entity.""" super().__init__(**values) - self._attr_vacuum_state = VacuumEntityState.DOCKED + self._attr_vacuum_state = VacuumState.DOCKED self._attr_fan_speed = "slow" def stop(self, **kwargs: Any) -> None: """Stop cleaning.""" - self._attr_vacuum_state = VacuumEntityState.IDLE + self._attr_vacuum_state = VacuumState.IDLE def return_to_base(self, **kwargs: Any) -> None: """Return to base.""" - self._attr_vacuum_state = VacuumEntityState.RETURNING + self._attr_vacuum_state = VacuumState.RETURNING def clean_spot(self, **kwargs: Any) -> None: """Clean a spot.""" - self._attr_vacuum_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumState.CLEANING def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: """Set the fan speed.""" @@ -56,11 +56,11 @@ class MockVacuum(MockEntity, StateVacuumEntity): def start(self) -> None: """Start cleaning.""" - self._attr_vacuum_state = VacuumEntityState.CLEANING + self._attr_vacuum_state = VacuumState.CLEANING def pause(self) -> None: """Pause cleaning.""" - self._attr_vacuum_state = VacuumEntityState.PAUSED + self._attr_vacuum_state = VacuumState.PAUSED async def help_async_setup_entry_init( diff --git a/tests/components/vacuum/test_device_condition.py b/tests/components/vacuum/test_device_condition.py index 6d083bb47ba..d0573c27ffc 100644 --- a/tests/components/vacuum/test_device_condition.py +++ b/tests/components/vacuum/test_device_condition.py @@ -5,7 +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, VacuumEntityState +from homeassistant.components.vacuum import DOMAIN, VacuumState from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -117,7 +117,7 @@ async def test_if_state( DOMAIN, "test", "5678", device_id=device_entry.id ) - hass.states.async_set(entry.entity_id, VacuumEntityState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumState.DOCKED) assert await async_setup_component( hass, @@ -169,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, VacuumEntityState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumState.CLEANING) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() @@ -177,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, VacuumEntityState.RETURNING) + hass.states.async_set(entry.entity_id, VacuumState.RETURNING) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() @@ -202,7 +202,7 @@ async def test_if_state_legacy( DOMAIN, "test", "5678", device_id=device_entry.id ) - hass.states.async_set(entry.entity_id, VacuumEntityState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumState.CLEANING) assert await async_setup_component( hass, diff --git a/tests/components/vacuum/test_device_trigger.py b/tests/components/vacuum/test_device_trigger.py index 31152e749e3..4fb5e281ccf 100644 --- a/tests/components/vacuum/test_device_trigger.py +++ b/tests/components/vacuum/test_device_trigger.py @@ -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, VacuumEntityState +from homeassistant.components.vacuum import DOMAIN, VacuumState 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, VacuumEntityState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumState.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, VacuumEntityState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumState.CLEANING) await hass.async_block_till_done() assert len(service_calls) == 0 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index 7c5c45022e2..286ca729ab2 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -22,7 +22,7 @@ from homeassistant.components.vacuum import ( SERVICE_STOP, StateVacuumEntity, VacuumEntityFeature, - VacuumEntityState, + VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -77,7 +77,7 @@ def test_deprecated_constants( @pytest.mark.parametrize( - ("enum", "constant_prefix"), _create_tuples(vacuum.VacuumEntityState, "STATE_") + ("enum", "constant_prefix"), _create_tuples(vacuum.VacuumState, "STATE_") ) @pytest.mark.parametrize( "module", @@ -98,11 +98,11 @@ def test_deprecated_constants_for_state( @pytest.mark.parametrize( ("service", "expected_state"), [ - (SERVICE_CLEAN_SPOT, VacuumEntityState.CLEANING), - (SERVICE_PAUSE, VacuumEntityState.PAUSED), - (SERVICE_RETURN_TO_BASE, VacuumEntityState.RETURNING), - (SERVICE_START, VacuumEntityState.CLEANING), - (SERVICE_STOP, VacuumEntityState.IDLE), + (SERVICE_CLEAN_SPOT, VacuumState.CLEANING), + (SERVICE_PAUSE, VacuumState.PAUSED), + (SERVICE_RETURN_TO_BASE, VacuumState.RETURNING), + (SERVICE_START, VacuumState.CLEANING), + (SERVICE_STOP, VacuumState.IDLE), ], ) async def test_state_services( @@ -417,7 +417,7 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( def start(self) -> None: """Start cleaning.""" - self._attr_state = VacuumEntityState.CLEANING + self._attr_state = VacuumState.CLEANING entity = MockLegacyVacuum() diff --git a/tests/components/vacuum/test_reproduce_state.py b/tests/components/vacuum/test_reproduce_state.py index c83e86336f1..98d6afd3ea8 100644 --- a/tests/components/vacuum/test_reproduce_state.py +++ b/tests/components/vacuum/test_reproduce_state.py @@ -9,7 +9,7 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumEntityState, + VacuumState, ) from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant, State @@ -30,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", VacuumEntityState.CLEANING, {}) - hass.states.async_set("vacuum.entity_docked", VacuumEntityState.DOCKED, {}) - hass.states.async_set("vacuum.entity_idle", VacuumEntityState.IDLE, {}) - hass.states.async_set("vacuum.entity_returning", VacuumEntityState.RETURNING, {}) - hass.states.async_set("vacuum.entity_paused", VacuumEntityState.PAUSED, {}) + hass.states.async_set("vacuum.entity_cleaning", VacuumState.CLEANING, {}) + hass.states.async_set("vacuum.entity_docked", VacuumState.DOCKED, {}) + hass.states.async_set("vacuum.entity_idle", VacuumState.IDLE, {}) + hass.states.async_set("vacuum.entity_returning", VacuumState.RETURNING, {}) + hass.states.async_set("vacuum.entity_paused", VacuumState.PAUSED, {}) turn_on_calls = async_mock_service(hass, "vacuum", SERVICE_TURN_ON) turn_off_calls = async_mock_service(hass, "vacuum", SERVICE_TURN_OFF) @@ -51,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", VacuumEntityState.CLEANING), - State("vacuum.entity_docked", VacuumEntityState.DOCKED), - State("vacuum.entity_idle", VacuumEntityState.IDLE), - State("vacuum.entity_returning", VacuumEntityState.RETURNING), - State("vacuum.entity_paused", VacuumEntityState.PAUSED), + State("vacuum.entity_cleaning", VacuumState.CLEANING), + State("vacuum.entity_docked", VacuumState.DOCKED), + State("vacuum.entity_idle", VacuumState.IDLE), + State("vacuum.entity_returning", VacuumState.RETURNING), + State("vacuum.entity_paused", VacuumState.PAUSED), ], ) @@ -86,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", VacuumEntityState.PAUSED), - State("vacuum.entity_docked", VacuumEntityState.CLEANING), - State("vacuum.entity_idle", VacuumEntityState.DOCKED), - State("vacuum.entity_returning", VacuumEntityState.CLEANING), - State("vacuum.entity_paused", VacuumEntityState.IDLE), + State("vacuum.entity_cleaning", VacuumState.PAUSED), + State("vacuum.entity_docked", VacuumState.CLEANING), + State("vacuum.entity_idle", VacuumState.DOCKED), + State("vacuum.entity_returning", VacuumState.CLEANING), + State("vacuum.entity_paused", VacuumState.IDLE), # Should not raise State("vacuum.non_existing", STATE_ON), ], diff --git a/tests/components/xiaomi_miio/test_vacuum.py b/tests/components/xiaomi_miio/test_vacuum.py index e2e485e785c..8e9ef3976eb 100644 --- a/tests/components/xiaomi_miio/test_vacuum.py +++ b/tests/components/xiaomi_miio/test_vacuum.py @@ -21,7 +21,7 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumEntityState, + VacuumState, ) from homeassistant.components.xiaomi_miio.const import ( CONF_FLOW_TYPE, @@ -263,7 +263,7 @@ async def test_xiaomi_vacuum_services( # Check state attributes state = hass.states.get(entity_id) - assert state.state == VacuumEntityState.ERROR + assert state.state == VacuumState.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" @@ -449,7 +449,7 @@ async def test_xiaomi_specific_services( # Check state attributes state = hass.states.get(entity_id) - assert state.state == VacuumEntityState.CLEANING + assert state.state == VacuumState.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" From 4caaaf86bcb3ae1138a8ce33298d9f0f59192e6c Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 21 Oct 2024 16:17:27 +0000 Subject: [PATCH 13/24] Fixes --- homeassistant/components/vacuum/__init__.py | 8 ++++++++ tests/components/vacuum/conftest.py | 7 +++---- tests/components/vacuum/test_init.py | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 0d2af17f425..1b4ff98bf80 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -249,6 +249,14 @@ class StateVacuumEntity( __vacuum_legacy_state: bool = False __vacuum_legacy_state_reported: 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 'vacuum_state' property instead of + # setting the state directly. + cls.__vacuum_legacy_state = True + def __setattr__(self, __name: str, __value: Any) -> None: """Set attribute. diff --git a/tests/components/vacuum/conftest.py b/tests/components/vacuum/conftest.py index d6c197cc56a..7420614b5a3 100644 --- a/tests/components/vacuum/conftest.py +++ b/tests/components/vacuum/conftest.py @@ -39,8 +39,8 @@ def config_flow_fixture(hass: HomeAssistant) -> Generator[None]: @pytest.fixture(name="supported_features") -async def alarm_control_panel_supported_features() -> VacuumEntityFeature: - """Return the supported features for the test alarm control panel entity.""" +async def vacuum_supported_features() -> VacuumEntityFeature: + """Return the supported features for the test vacuum entity.""" return ( VacuumEntityFeature.PAUSE | VacuumEntityFeature.STOP @@ -61,7 +61,7 @@ async def setup_vacuum_platform_test_entity( entity_registry: er.EntityRegistry, supported_features: VacuumEntityFeature, ) -> MagicMock: - """Set up alarm control panel entity using an entity platform.""" + """Set up vacuum entity using an entity platform.""" async def async_setup_entry_init( hass: HomeAssistant, config_entry: ConfigEntry @@ -80,7 +80,6 @@ async def setup_vacuum_platform_test_entity( ), ) - # Unnamed sensor without device class -> no name entity = MockVacuum( supported_features=supported_features, ) diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index 286ca729ab2..e52832f58dd 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -354,7 +354,7 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( @property def state(self) -> str: """Return the state of the entity.""" - return "disarmed" + return VacuumState.CLEANING entity = MockLegacyVacuum() From 9a9673aaa47b86a36495f52843281d508472540f Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:26:39 +0000 Subject: [PATCH 14/24] Fix VacuumEntity --- homeassistant/components/vacuum/__init__.py | 56 ++++++++----------- homeassistant/components/vacuum/const.py | 16 +++--- .../components/vacuum/device_condition.py | 6 +- .../components/vacuum/device_trigger.py | 6 +- .../components/vacuum/reproduce_state.py | 20 +++---- 5 files changed, 49 insertions(+), 55 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 1b4ff98bf80..10ee0c4bf48 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -32,6 +32,7 @@ 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 report from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.typing import ConfigType from homeassistant.loader import bind_hass @@ -44,7 +45,7 @@ from .const import ( # noqa: F401 _DEPRECATED_STATE_RETURNING, DOMAIN, STATES, - VacuumState, + VacuumActivity, ) _LOGGER = logging.getLogger(__name__) @@ -76,8 +77,8 @@ DEFAULT_NAME = "Vacuum cleaner robot" # These STATE_* constants are deprecated as of Home Assistant 2024.11. # Please use the VacuumState enum instead. -_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumState.IDLE, "2025.11") -_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumState.PAUSED, "2025.11") +_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumActivity.IDLE, "2025.11") +_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumActivity.PAUSED, "2025.11") class VacuumEntityFeature(IntFlag): @@ -243,17 +244,16 @@ class StateVacuumEntity( _attr_battery_level: int | None = None _attr_fan_speed: str | None = None _attr_fan_speed_list: list[str] - _attr_vacuum_state: VacuumState | None = None + _attr_activity: VacuumActivity | None = None _attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0) __vacuum_legacy_state: bool = False - __vacuum_legacy_state_reported: 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 'vacuum_state' property instead of + # Integrations should use the 'activity' property instead of # setting the state directly. cls.__vacuum_legacy_state = True @@ -264,9 +264,7 @@ class StateVacuumEntity( unless already reported. """ if __name == "_attr_state": - if self.__vacuum_legacy_state_reported is not True: - self._report_deprecated_vacuum_state_handling() - self.__vacuum_legacy_state_reported = True + self._report_deprecated_vacuum_state_handling() return super().__setattr__(__name, __value) @callback @@ -278,28 +276,22 @@ class StateVacuumEntity( ) -> None: """Start adding an entity to a platform.""" super().add_to_platform_start(hass, platform, parallel_updates) - if self.__vacuum_legacy_state and not self.__vacuum_legacy_state_reported: + if self.__vacuum_legacy_state: self._report_deprecated_vacuum_state_handling() @callback def _report_deprecated_vacuum_state_handling(self) -> None: """Report on deprecated handling of vacuum state. - Integrations should implement vacuum_state instead of using state directly. + Integrations should implement activity instead of using state directly. """ - self.__vacuum_legacy_state_reported = True - if "custom_components" in type(self).__module__: - # Do not report on core integrations as they have been fixed. - report_issue = "report it to the custom integration author." - _LOGGER.warning( - "Entity %s (%s) is setting state directly" - " which will stop working in HA Core 2025.11." - " Entities should implement the 'vacuum_state' property and" - " return its state using the VacuumState enum, please %s", - self.entity_id, - type(self), - report_issue, - ) + report( + "is setting state directly which will stop working in HA Core 2025.11." + f" Entity {self.entity_id} ({type(self)}) should implement the 'activity' property and" + " return its state using the VacuumActivity enum, please ", + error_if_core=True, + error_if_integration=False, + ) @cached_property def battery_level(self) -> int | None: @@ -309,7 +301,7 @@ class StateVacuumEntity( @property def battery_icon(self) -> str: """Return the battery icon for the vacuum cleaner.""" - charging = bool(self.vacuum_state == VacuumState.DOCKED) + charging = bool(self.activity == VacuumActivity.DOCKED) return icon_for_battery_level( battery_level=self.battery_level, charging=charging @@ -351,18 +343,18 @@ class StateVacuumEntity( @property def state(self) -> str | None: """Return the state of the vacuum cleaner.""" - if (vacuum_state := self.vacuum_state) is None: + if (activity := self.activity) is None: return None - return vacuum_state + return activity @cached_property - def vacuum_state(self) -> VacuumState | None: - """Return the current vacuum state. + def activity(self) -> VacuumActivity | None: + """Return the current vacuum activity. - Integrations should overwrite this or use the '_attr_vacuum_state' - attribute to set the vacuum status using the 'VacuumState' enum. + Integrations should overwrite this or use the '_attr_activity' + attribute to set the vacuum activity using the 'VacuumActivity' enum. """ - return self._attr_vacuum_state + return self._attr_activity @cached_property def supported_features(self) -> VacuumEntityFeature: diff --git a/homeassistant/components/vacuum/const.py b/homeassistant/components/vacuum/const.py index 05b631b5afe..1eb14144140 100644 --- a/homeassistant/components/vacuum/const.py +++ b/homeassistant/components/vacuum/const.py @@ -15,8 +15,8 @@ from homeassistant.helpers.deprecation import ( DOMAIN = "vacuum" -class VacuumState(StrEnum): - """Vacuum entity states.""" +class VacuumActivity(StrEnum): + """Vacuum activity states.""" CLEANING = "cleaning" DOCKED = "docked" @@ -28,13 +28,15 @@ class VacuumState(StrEnum): # These STATE_* constants are deprecated as of Home Assistant 2024.11. # Please use the VacuumState enum instead. -_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumState.CLEANING, "2025.11") -_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumState.DOCKED, "2025.11") -_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum(VacuumState.RETURNING, "2025.11") -_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumState.ERROR, "2025.11") +_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumActivity.CLEANING, "2025.11") +_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumActivity.DOCKED, "2025.11") +_DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum( + VacuumActivity.RETURNING, "2025.11" +) +_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumActivity.ERROR, "2025.11") -STATES = [cls.value for cls in VacuumState] +STATES = [cls.value for cls in VacuumActivity] # These can be removed if no deprecated constant are in this module anymore __getattr__ = partial(check_if_deprecated_constant, module_globals=globals()) diff --git a/homeassistant/components/vacuum/device_condition.py b/homeassistant/components/vacuum/device_condition.py index 072136b5a4a..4da64484bf7 100644 --- a/homeassistant/components/vacuum/device_condition.py +++ b/homeassistant/components/vacuum/device_condition.py @@ -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, VacuumState +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 = [VacuumState.DOCKED] + test_states = [VacuumActivity.DOCKED] else: - test_states = [VacuumState.CLEANING, VacuumState.RETURNING] + test_states = [VacuumActivity.CLEANING, VacuumActivity.RETURNING] registry = er.async_get(hass) entity_id = er.async_resolve_entity_id(registry, config[CONF_ENTITY_ID]) diff --git a/homeassistant/components/vacuum/device_trigger.py b/homeassistant/components/vacuum/device_trigger.py index ec4238674af..fe682ef21d3 100644 --- a/homeassistant/components/vacuum/device_trigger.py +++ b/homeassistant/components/vacuum/device_trigger.py @@ -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, VacuumState +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 = VacuumState.CLEANING + to_state = VacuumActivity.CLEANING else: - to_state = VacuumState.DOCKED + to_state = VacuumActivity.DOCKED state_config = { CONF_PLATFORM: "state", diff --git a/homeassistant/components/vacuum/reproduce_state.py b/homeassistant/components/vacuum/reproduce_state.py index dde9d6ca980..ef3fb329686 100644 --- a/homeassistant/components/vacuum/reproduce_state.py +++ b/homeassistant/components/vacuum/reproduce_state.py @@ -24,18 +24,18 @@ from . import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumState, + VacuumActivity, ) _LOGGER = logging.getLogger(__name__) VALID_STATES_TOGGLE = {STATE_ON, STATE_OFF} VALID_STATES_STATE = { - VacuumState.CLEANING, - VacuumState.DOCKED, - VacuumState.IDLE, - VacuumState.PAUSED, - VacuumState.RETURNING, + VacuumActivity.CLEANING, + VacuumActivity.DOCKED, + VacuumActivity.IDLE, + VacuumActivity.PAUSED, + VacuumActivity.RETURNING, } @@ -71,13 +71,13 @@ async def _async_reproduce_state( service = SERVICE_TURN_ON elif state.state == STATE_OFF: service = SERVICE_TURN_OFF - elif state.state == VacuumState.CLEANING: + elif state.state == VacuumActivity.CLEANING: service = SERVICE_START - elif state.state in [VacuumState.DOCKED, VacuumState.RETURNING]: + elif state.state in [VacuumActivity.DOCKED, VacuumActivity.RETURNING]: service = SERVICE_RETURN_TO_BASE - elif state.state == VacuumState.IDLE: + elif state.state == VacuumActivity.IDLE: service = SERVICE_STOP - elif state.state == VacuumState.PAUSED: + elif state.state == VacuumActivity.PAUSED: service = SERVICE_PAUSE await hass.services.async_call( From e4835a31c72c17181814c6eb9d38f400805c8c25 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:38:57 +0000 Subject: [PATCH 15/24] Mods --- tests/components/vacuum/__init__.py | 14 +++---- .../vacuum/test_device_condition.py | 10 ++--- .../components/vacuum/test_device_trigger.py | 16 ++++---- tests/components/vacuum/test_init.py | 40 ++++++++----------- .../components/vacuum/test_reproduce_state.py | 32 +++++++-------- 5 files changed, 53 insertions(+), 59 deletions(-) diff --git a/tests/components/vacuum/__init__.py b/tests/components/vacuum/__init__.py index ab41e8bed7f..26e31a87eee 100644 --- a/tests/components/vacuum/__init__.py +++ b/tests/components/vacuum/__init__.py @@ -5,8 +5,8 @@ from typing import Any from homeassistant.components.vacuum import ( DOMAIN, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform @@ -35,20 +35,20 @@ class MockVacuum(MockEntity, StateVacuumEntity): def __init__(self, **values: Any) -> None: """Initialize a mock vacuum entity.""" super().__init__(**values) - self._attr_vacuum_state = VacuumState.DOCKED + self._attr_activity = VacuumActivity.DOCKED self._attr_fan_speed = "slow" def stop(self, **kwargs: Any) -> None: """Stop cleaning.""" - self._attr_vacuum_state = VacuumState.IDLE + self._attr_activity = VacuumActivity.IDLE def return_to_base(self, **kwargs: Any) -> None: """Return to base.""" - self._attr_vacuum_state = VacuumState.RETURNING + self._attr_activity = VacuumActivity.RETURNING def clean_spot(self, **kwargs: Any) -> None: """Clean a spot.""" - self._attr_vacuum_state = VacuumState.CLEANING + self._attr_activity = VacuumActivity.CLEANING def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: """Set the fan speed.""" @@ -56,11 +56,11 @@ class MockVacuum(MockEntity, StateVacuumEntity): def start(self) -> None: """Start cleaning.""" - self._attr_vacuum_state = VacuumState.CLEANING + self._attr_activity = VacuumActivity.CLEANING def pause(self) -> None: """Pause cleaning.""" - self._attr_vacuum_state = VacuumState.PAUSED + self._attr_activity = VacuumActivity.PAUSED async def help_async_setup_entry_init( diff --git a/tests/components/vacuum/test_device_condition.py b/tests/components/vacuum/test_device_condition.py index d0573c27ffc..5a1b1fea7de 100644 --- a/tests/components/vacuum/test_device_condition.py +++ b/tests/components/vacuum/test_device_condition.py @@ -5,7 +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, VacuumState +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 @@ -117,7 +117,7 @@ async def test_if_state( DOMAIN, "test", "5678", device_id=device_entry.id ) - hass.states.async_set(entry.entity_id, VacuumState.DOCKED) + hass.states.async_set(entry.entity_id, VacuumActivity.DOCKED) assert await async_setup_component( hass, @@ -169,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, VacuumState.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() @@ -177,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, VacuumState.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() @@ -202,7 +202,7 @@ async def test_if_state_legacy( DOMAIN, "test", "5678", device_id=device_entry.id ) - hass.states.async_set(entry.entity_id, VacuumState.CLEANING) + hass.states.async_set(entry.entity_id, VacuumActivity.CLEANING) assert await async_setup_component( hass, diff --git a/tests/components/vacuum/test_device_trigger.py b/tests/components/vacuum/test_device_trigger.py index 4fb5e281ccf..3a0cbafb4a1 100644 --- a/tests/components/vacuum/test_device_trigger.py +++ b/tests/components/vacuum/test_device_trigger.py @@ -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, VacuumState +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, VacuumState.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, VacuumState.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, VacuumState.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, VacuumState.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, VacuumState.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, VacuumState.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, VacuumState.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)) diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index e52832f58dd..e1f240b37cb 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -21,8 +21,8 @@ from homeassistant.components.vacuum import ( SERVICE_START, SERVICE_STOP, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -77,7 +77,7 @@ def test_deprecated_constants( @pytest.mark.parametrize( - ("enum", "constant_prefix"), _create_tuples(vacuum.VacuumState, "STATE_") + ("enum", "constant_prefix"), _create_tuples(vacuum.VacuumActivity, "STATE_") ) @pytest.mark.parametrize( "module", @@ -98,11 +98,11 @@ def test_deprecated_constants_for_state( @pytest.mark.parametrize( ("service", "expected_state"), [ - (SERVICE_CLEAN_SPOT, VacuumState.CLEANING), - (SERVICE_PAUSE, VacuumState.PAUSED), - (SERVICE_RETURN_TO_BASE, VacuumState.RETURNING), - (SERVICE_START, VacuumState.CLEANING), - (SERVICE_STOP, VacuumState.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( @@ -135,9 +135,9 @@ async def test_state_services( {"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: @@ -316,12 +316,10 @@ async def test_vacuum_not_log_deprecated_state_warning( mock_vacuum_entity: MockVacuum, caplog: pytest.LogCaptureFixture, ) -> None: - """Test correctly using vacuum_state doesn't log issue or raise repair.""" + """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 ( - "Entities should implement the 'vacuum_state' property and" not in caplog.text - ) + assert "Entities should implement the 'activity' property and" not in caplog.text async def test_vacuum_log_deprecated_state_warning_using_state_prop( @@ -354,7 +352,7 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( @property def state(self) -> str: """Return the state of the entity.""" - return VacuumState.CLEANING + return VacuumActivity.CLEANING entity = MockLegacyVacuum() @@ -385,7 +383,7 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( state = hass.states.get(entity.entity_id) assert state is not None - assert "Entities should implement the 'vacuum_state' property and" in caplog.text + assert "Entities should implement the 'activity' property and" in caplog.text async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( @@ -417,7 +415,7 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( def start(self) -> None: """Start cleaning.""" - self._attr_state = VacuumState.CLEANING + self._attr_state = VacuumActivity.CLEANING entity = MockLegacyVacuum() @@ -448,9 +446,7 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( state = hass.states.get(entity.entity_id) assert state is not None - assert ( - "Entities should implement the 'vacuum_state' property and" not in caplog.text - ) + assert "Entities should implement the 'activity' property and" not in caplog.text with patch.object( MockLegacyVacuum, @@ -459,7 +455,7 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( ): await async_start(hass, entity.entity_id) - assert "Entities should implement the 'vacuum_state' property and" in caplog.text + assert "Entities should implement the 'activity' property and" in caplog.text caplog.clear() with patch.object( MockLegacyVacuum, @@ -468,6 +464,4 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( ): await async_start(hass, entity.entity_id) # Test we only log once - assert ( - "Entities should implement the 'vacuum_state' property and" not in caplog.text - ) + assert "Entities should implement the 'activity' property and" not in caplog.text diff --git a/tests/components/vacuum/test_reproduce_state.py b/tests/components/vacuum/test_reproduce_state.py index 98d6afd3ea8..dc5d81e8f08 100644 --- a/tests/components/vacuum/test_reproduce_state.py +++ b/tests/components/vacuum/test_reproduce_state.py @@ -9,7 +9,7 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumState, + VacuumActivity, ) from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant, State @@ -30,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", VacuumState.CLEANING, {}) - hass.states.async_set("vacuum.entity_docked", VacuumState.DOCKED, {}) - hass.states.async_set("vacuum.entity_idle", VacuumState.IDLE, {}) - hass.states.async_set("vacuum.entity_returning", VacuumState.RETURNING, {}) - hass.states.async_set("vacuum.entity_paused", VacuumState.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) @@ -51,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", VacuumState.CLEANING), - State("vacuum.entity_docked", VacuumState.DOCKED), - State("vacuum.entity_idle", VacuumState.IDLE), - State("vacuum.entity_returning", VacuumState.RETURNING), - State("vacuum.entity_paused", VacuumState.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), ], ) @@ -86,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", VacuumState.PAUSED), - State("vacuum.entity_docked", VacuumState.CLEANING), - State("vacuum.entity_idle", VacuumState.DOCKED), - State("vacuum.entity_returning", VacuumState.CLEANING), - State("vacuum.entity_paused", VacuumState.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), ], From 02f496f465b95c26a3434ea09c8b06719b8dd981 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:39:15 +0000 Subject: [PATCH 16/24] Mods --- .../components/alexa/capabilities.py | 2 +- homeassistant/components/demo/vacuum.py | 28 +++++------ homeassistant/components/ecovacs/vacuum.py | 30 +++++------ .../components/google_assistant/trait.py | 10 ++-- homeassistant/components/group/registry.py | 8 +-- .../components/homekit/type_switches.py | 4 +- .../components/litterrobot/vacuum.py | 26 +++++----- homeassistant/components/mqtt/vacuum.py | 20 ++++---- homeassistant/components/neato/vacuum.py | 20 ++++---- homeassistant/components/roborock/vacuum.py | 50 +++++++++---------- homeassistant/components/romy/vacuum.py | 6 +-- 11 files changed, 102 insertions(+), 102 deletions(-) diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index 027d52be28c..9f15c9adc54 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -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.VacuumState.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: diff --git a/homeassistant/components/demo/vacuum.py b/homeassistant/components/demo/vacuum.py index d5552f79f33..0059f7c6a54 100644 --- a/homeassistant/components/demo/vacuum.py +++ b/homeassistant/components/demo/vacuum.py @@ -8,8 +8,8 @@ from typing import Any from homeassistant.components.vacuum import ( ATTR_CLEANED_AREA, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -87,13 +87,13 @@ class StateDemoVacuum(StateVacuumEntity): """Initialize the vacuum.""" self._attr_name = name self._attr_supported_features = supported_features - self._state = VacuumState.DOCKED + self._state = VacuumActivity.DOCKED self._fan_speed = FAN_SPEEDS[1] self._cleaned_area: float = 0 self._battery_level = 100 @property - def vacuum_state(self) -> VacuumState: + def activity(self) -> VacuumActivity: """Return the current state of the vacuum.""" return self._state @@ -119,33 +119,33 @@ class StateDemoVacuum(StateVacuumEntity): def start(self) -> None: """Start or resume the cleaning task.""" - if self._state != VacuumState.CLEANING: - self._state = VacuumState.CLEANING + if self._state != VacuumActivity.CLEANING: + self._state = 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 == VacuumState.CLEANING: - self._state = VacuumState.PAUSED + if self._state == VacuumActivity.CLEANING: + self._state = VacuumActivity.PAUSED self.schedule_update_ha_state() def stop(self, **kwargs: Any) -> None: """Stop the cleaning task, do not return to dock.""" - self._state = VacuumState.IDLE + self._state = VacuumActivity.IDLE self.schedule_update_ha_state() def return_to_base(self, **kwargs: Any) -> None: """Return dock to charging base.""" - self._state = VacuumState.RETURNING + self._state = 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 = VacuumState.CLEANING + self._state = VacuumActivity.CLEANING self._cleaned_area += 1.32 self._battery_level -= 1 self.schedule_update_ha_state() @@ -163,12 +163,12 @@ class StateDemoVacuum(StateVacuumEntity): "persistent_notification", service_data={"message": "I'm here!", "title": "Locate request"}, ) - self._state = VacuumState.IDLE + self._state = VacuumActivity.IDLE self.async_write_ha_state() async def async_clean_spot(self, **kwargs: Any) -> None: """Locate the vacuum's position.""" - self._state = VacuumState.CLEANING + self._state = VacuumActivity.CLEANING self.async_write_ha_state() async def async_send_command( @@ -178,9 +178,9 @@ class StateDemoVacuum(StateVacuumEntity): **kwargs: Any, ) -> None: """Send a command to the vacuum.""" - self._state = VacuumState.IDLE + self._state = VacuumActivity.IDLE self.async_write_ha_state() def __set_state_to_dock(self, _: datetime) -> None: - self._state = VacuumState.DOCKED + self._state = VacuumActivity.DOCKED self.schedule_update_ha_state() diff --git a/homeassistant/components/ecovacs/vacuum.py b/homeassistant/components/ecovacs/vacuum.py index 73efd7e4e3e..dde4fd64b56 100644 --- a/homeassistant/components/ecovacs/vacuum.py +++ b/homeassistant/components/ecovacs/vacuum.py @@ -15,8 +15,8 @@ import sucks from homeassistant.components.vacuum import ( StateVacuumEntity, StateVacuumEntityDescription, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.core import HomeAssistant, SupportsResponse from homeassistant.exceptions import ServiceValidationError @@ -118,22 +118,22 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): self.schedule_update_ha_state() @property - def vacuum_state(self) -> VacuumState | None: + def activity(self) -> VacuumActivity | None: """Return the state of the vacuum cleaner.""" if self.error is not None: - return VacuumState.ERROR + return VacuumActivity.ERROR if self.device.is_cleaning: - return VacuumState.CLEANING + return VacuumActivity.CLEANING if self.device.is_charging: - return VacuumState.DOCKED + return VacuumActivity.DOCKED if self.device.vacuum_status == sucks.CLEAN_MODE_STOP: - return VacuumState.IDLE + return VacuumActivity.IDLE if self.device.vacuum_status == sucks.CHARGE_MODE_RETURNING: - return VacuumState.RETURNING + return VacuumActivity.RETURNING return None @@ -197,7 +197,7 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: """Set fan speed.""" - if self.state == VacuumState.CLEANING: + if self.state == VacuumActivity.CLEANING: self.device.run(sucks.Clean(mode=self.device.clean_status, speed=fan_speed)) def send_command( @@ -220,12 +220,12 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity): _STATE_TO_VACUUM_STATE = { - State.IDLE: VacuumState.IDLE, - State.CLEANING: VacuumState.CLEANING, - State.RETURNING: VacuumState.RETURNING, - State.DOCKED: VacuumState.DOCKED, - State.ERROR: VacuumState.ERROR, - State.PAUSED: VacuumState.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" @@ -279,7 +279,7 @@ class EcovacsVacuum( self.async_write_ha_state() async def on_status(event: StateEvent) -> None: - self._attr_vacuum_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) diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 899f0e3d8c7..8025a291031 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -729,7 +729,7 @@ class DockTrait(_Trait): def query_attributes(self) -> dict[str, Any]: """Return dock query attributes.""" - return {"isDocked": self.state.state == vacuum.VacuumState.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.VacuumState.DOCKED, - "isPluggedIn": self.state.state == vacuum.VacuumState.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.VacuumState.CLEANING, - "isPaused": state == vacuum.VacuumState.PAUSED, + "isRunning": state == vacuum.VacuumActivity.CLEANING, + "isPaused": state == vacuum.VacuumActivity.PAUSED, } if domain in COVER_VALVE_DOMAINS: diff --git a/homeassistant/components/group/registry.py b/homeassistant/components/group/registry.py index 38fe29fd253..2f3c4aa5221 100644 --- a/homeassistant/components/group/registry.py +++ b/homeassistant/components/group/registry.py @@ -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 VacuumState +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, - VacuumState.CLEANING, - VacuumState.RETURNING, - VacuumState.ERROR, + VacuumActivity.CLEANING, + VacuumActivity.RETURNING, + VacuumActivity.ERROR, }, STATE_ON, STATE_OFF, diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index fa2ac2cc404..0482a5956ac 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -21,8 +21,8 @@ from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_RETURN_TO_BASE, SERVICE_START, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -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 (VacuumState.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) diff --git a/homeassistant/components/litterrobot/vacuum.py b/homeassistant/components/litterrobot/vacuum.py index 0d1f32f4ac5..bd00c328233 100644 --- a/homeassistant/components/litterrobot/vacuum.py +++ b/homeassistant/components/litterrobot/vacuum.py @@ -12,8 +12,8 @@ import voluptuous as vol from homeassistant.components.vacuum import ( StateVacuumEntity, StateVacuumEntityDescription, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform @@ -26,16 +26,16 @@ from .entity import LitterRobotEntity SERVICE_SET_SLEEP_MODE = "set_sleep_mode" LITTER_BOX_STATUS_STATE_MAP = { - LitterBoxStatus.CLEAN_CYCLE: VacuumState.CLEANING, - LitterBoxStatus.EMPTY_CYCLE: VacuumState.CLEANING, - LitterBoxStatus.CLEAN_CYCLE_COMPLETE: VacuumState.DOCKED, - LitterBoxStatus.CAT_DETECTED: VacuumState.DOCKED, - LitterBoxStatus.CAT_SENSOR_TIMING: VacuumState.DOCKED, - LitterBoxStatus.DRAWER_FULL_1: VacuumState.DOCKED, - LitterBoxStatus.DRAWER_FULL_2: VacuumState.DOCKED, - LitterBoxStatus.READY: VacuumState.DOCKED, - LitterBoxStatus.CAT_SENSOR_INTERRUPTED: VacuumState.PAUSED, - LitterBoxStatus.OFF: VacuumState.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( @@ -75,9 +75,9 @@ class LitterRobotCleaner(LitterRobotEntity[LitterRobot], StateVacuumEntity): ) @property - def vacuum_state(self) -> VacuumState: + def activity(self) -> VacuumActivity: """Return the state of the cleaner.""" - return LITTER_BOX_STATUS_STATE_MAP.get(self.robot.status, VacuumState.ERROR) + return LITTER_BOX_STATUS_STATE_MAP.get(self.robot.status, VacuumActivity.ERROR) @property def status(self) -> str: diff --git a/homeassistant/components/mqtt/vacuum.py b/homeassistant/components/mqtt/vacuum.py index 9891e844f74..e1dbc061ebc 100644 --- a/homeassistant/components/mqtt/vacuum.py +++ b/homeassistant/components/mqtt/vacuum.py @@ -11,8 +11,8 @@ from homeassistant.components import vacuum from homeassistant.components.vacuum import ( ENTITY_ID_FORMAT, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_SUPPORTED_FEATURES, CONF_NAME @@ -42,13 +42,13 @@ STATE_PAUSED = "paused" STATE_RETURNING = "returning" STATE_CLEANING = "cleaning" -POSSIBLE_STATES: dict[str, VacuumState] = { - STATE_IDLE: VacuumState.IDLE, - STATE_DOCKED: VacuumState.DOCKED, - STATE_ERROR: VacuumState.ERROR, - STATE_PAUSED: VacuumState.PAUSED, - STATE_RETURNING: VacuumState.RETURNING, - STATE_CLEANING: VacuumState.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 @@ -262,7 +262,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity): if STATE in payload and ( (state := payload[STATE]) in POSSIBLE_STATES or state is None ): - self._attr_vacuum_state = ( + self._attr_activity = ( POSSIBLE_STATES[cast(str, state)] if payload[STATE] else None ) del payload[STATE] @@ -274,7 +274,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity): self.add_subscription( CONF_STATE_TOPIC, self._state_message_received, - {"_attr_battery_level", "_attr_fan_speed", "_attr_vacuum_state"}, + {"_attr_battery_level", "_attr_fan_speed", "_attr_activity"}, ) async def _subscribe_topics(self) -> None: diff --git a/homeassistant/components/neato/vacuum.py b/homeassistant/components/neato/vacuum.py index ae1b93346b9..1a9285964a2 100644 --- a/homeassistant/components/neato/vacuum.py +++ b/homeassistant/components/neato/vacuum.py @@ -13,8 +13,8 @@ import voluptuous as vol from homeassistant.components.vacuum import ( ATTR_STATUS, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_MODE @@ -166,23 +166,23 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): robot_alert = None if self._state["state"] == 1: if self._state["details"]["isCharging"]: - self._attr_vacuum_state = VacuumState.DOCKED + self._attr_activity = VacuumActivity.DOCKED self._status_state = "Charging" elif ( self._state["details"]["isDocked"] and not self._state["details"]["isCharging"] ): - self._attr_vacuum_state = VacuumState.DOCKED + self._attr_activity = VacuumActivity.DOCKED self._status_state = "Docked" else: - self._attr_vacuum_state = VacuumState.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_vacuum_state = VacuumState.CLEANING + self._attr_activity = VacuumActivity.CLEANING self._status_state = ( f"{MODE.get(self._state['cleaning']['mode'])} " f"{ACTION.get(self._state['action'])}" @@ -197,10 +197,10 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): else: self._status_state = robot_alert elif self._state["state"] == 3: - self._attr_vacuum_state = VacuumState.PAUSED + self._attr_activity = VacuumActivity.PAUSED self._status_state = "Paused" elif self._state["state"] == 4: - self._attr_vacuum_state = VacuumState.ERROR + self._attr_activity = VacuumActivity.ERROR self._status_state = ERRORS.get(self._state["error"]) self._attr_battery_level = self._state["details"]["charge"] @@ -323,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_vacuum_state == VacuumState.CLEANING: + if self._attr_activity == VacuumActivity.CLEANING: self.robot.pause_cleaning() - self._attr_vacuum_state = VacuumState.RETURNING + self._attr_activity = VacuumActivity.RETURNING self.robot.send_to_base() except NeatoRobotException as ex: _LOGGER.error( @@ -377,7 +377,7 @@ class NeatoConnectedVacuum(NeatoEntity, StateVacuumEntity): "Start cleaning zone '%s' with robot %s", zone, self.entity_id ) - self._attr_vacuum_state = VacuumState.CLEANING + self._attr_activity = VacuumActivity.CLEANING try: self.robot.start_cleaning(mode, navigation, category, boundary_id) except NeatoRobotException as ex: diff --git a/homeassistant/components/roborock/vacuum.py b/homeassistant/components/roborock/vacuum.py index 457152ad01c..d3413bd7cbd 100644 --- a/homeassistant/components/roborock/vacuum.py +++ b/homeassistant/components/roborock/vacuum.py @@ -9,8 +9,8 @@ from roborock.roborock_typing import RoborockCommand from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse from homeassistant.helpers import entity_platform @@ -22,29 +22,29 @@ from .coordinator import RoborockDataUpdateCoordinator from .entity import RoborockCoordinatedEntityV1 STATE_CODE_TO_STATE = { - RoborockStateCode.starting: VacuumState.IDLE, # "Starting" - RoborockStateCode.charger_disconnected: VacuumState.IDLE, # "Charger disconnected" - RoborockStateCode.idle: VacuumState.IDLE, # "Idle" - RoborockStateCode.remote_control_active: VacuumState.CLEANING, # "Remote control active" - RoborockStateCode.cleaning: VacuumState.CLEANING, # "Cleaning" - RoborockStateCode.returning_home: VacuumState.RETURNING, # "Returning home" - RoborockStateCode.manual_mode: VacuumState.CLEANING, # "Manual mode" - RoborockStateCode.charging: VacuumState.DOCKED, # "Charging" - RoborockStateCode.charging_problem: VacuumState.ERROR, # "Charging problem" - RoborockStateCode.paused: VacuumState.PAUSED, # "Paused" - RoborockStateCode.spot_cleaning: VacuumState.CLEANING, # "Spot cleaning" - RoborockStateCode.error: VacuumState.ERROR, # "Error" - RoborockStateCode.shutting_down: VacuumState.IDLE, # "Shutting down" - RoborockStateCode.updating: VacuumState.DOCKED, # "Updating" - RoborockStateCode.docking: VacuumState.RETURNING, # "Docking" - RoborockStateCode.going_to_target: VacuumState.CLEANING, # "Going to target" - RoborockStateCode.zoned_cleaning: VacuumState.CLEANING, # "Zoned cleaning" - RoborockStateCode.segment_cleaning: VacuumState.CLEANING, # "Segment cleaning" - RoborockStateCode.emptying_the_bin: VacuumState.DOCKED, # "Emptying the bin" on s7+ - RoborockStateCode.washing_the_mop: VacuumState.DOCKED, # "Washing the mop" on s7maxV - RoborockStateCode.going_to_wash_the_mop: VacuumState.RETURNING, # "Going to wash the mop" on s7maxV - RoborockStateCode.charging_complete: VacuumState.DOCKED, # "Charging complete" - RoborockStateCode.device_offline: VacuumState.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" } @@ -107,7 +107,7 @@ class RoborockVacuum(RoborockCoordinatedEntityV1, StateVacuumEntity): self._attr_fan_speed_list = self._device_status.fan_power_options @property - def vacuum_state(self) -> VacuumState | 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) diff --git a/homeassistant/components/romy/vacuum.py b/homeassistant/components/romy/vacuum.py index eff335cbd81..b6974d7edae 100644 --- a/homeassistant/components/romy/vacuum.py +++ b/homeassistant/components/romy/vacuum.py @@ -8,8 +8,8 @@ from typing import Any from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -81,9 +81,9 @@ class RomyVacuumEntity(RomyEntity, StateVacuumEntity): self._attr_battery_level = self.romy.battery_level try: assert self.romy.status is not None - self._attr_vacuum_state = VacuumState(self.romy.status) + self._attr_activity = VacuumActivity(self.romy.status) except (AssertionError, ValueError): - self._attr_vacuum_state = None + self._attr_activity = None self.async_write_ha_state() From 6b50da1db2724a055193e09412ee22cae7fc0a40 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:40:02 +0000 Subject: [PATCH 17/24] Mods --- homeassistant/components/roomba/entity.py | 42 +++++++-------- homeassistant/components/sharkiq/vacuum.py | 16 +++--- .../components/switchbot_cloud/vacuum.py | 28 +++++----- homeassistant/components/template/vacuum.py | 16 +++--- homeassistant/components/tuya/vacuum.py | 52 +++++++++--------- homeassistant/components/vacuum/__init__.py | 10 ++-- homeassistant/components/vacuum/const.py | 2 +- .../components/xiaomi_miio/vacuum.py | 54 +++++++++---------- tests/components/demo/test_vacuum.py | 32 +++++------ .../components/google_assistant/test_trait.py | 10 ++-- .../components/homekit/test_type_switches.py | 6 +-- tests/components/litterrobot/test_init.py | 4 +- tests/components/litterrobot/test_vacuum.py | 16 +++--- tests/components/mqtt/test_vacuum.py | 12 ++--- tests/components/sharkiq/test_vacuum.py | 12 ++--- tests/components/template/test_vacuum.py | 46 ++++++++-------- tests/components/xiaomi_miio/test_vacuum.py | 6 +-- 17 files changed, 181 insertions(+), 183 deletions(-) diff --git a/homeassistant/components/roomba/entity.py b/homeassistant/components/roomba/entity.py index 47d1072c534..ae9486f2254 100644 --- a/homeassistant/components/roomba/entity.py +++ b/homeassistant/components/roomba/entity.py @@ -8,8 +8,8 @@ import logging from homeassistant.components.vacuum import ( ATTR_STATUS, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.const import ATTR_CONNECTIONS import homeassistant.helpers.device_registry as dr @@ -43,16 +43,16 @@ SUPPORT_IROBOT = ( ) STATE_MAP = { - "": VacuumState.IDLE, - "charge": VacuumState.DOCKED, - "evac": VacuumState.RETURNING, # Emptying at cleanbase - "hmMidMsn": VacuumState.CLEANING, # Recharging at the middle of a cycle - "hmPostMsn": VacuumState.RETURNING, # Cycle finished - "hmUsrDock": VacuumState.RETURNING, - "pause": VacuumState.PAUSED, - "run": VacuumState.CLEANING, - "stop": VacuumState.IDLE, - "stuck": VacuumState.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, } @@ -125,7 +125,7 @@ class IRobotEntity(Entity): return dt_util.utc_from_timestamp(ts) @property - def _robot_state(self) -> VacuumState: + def _robot_state(self) -> VacuumActivity: """Return the state of the vacuum cleaner.""" clean_mission_status = self.vacuum_state.get("cleanMissionStatus", {}) cycle = clean_mission_status.get("cycle") @@ -133,12 +133,12 @@ class IRobotEntity(Entity): try: state = STATE_MAP[phase] except KeyError: - return VacuumState.ERROR + return VacuumActivity.ERROR if cycle != "none" and state in ( - VacuumState.IDLE, - VacuumState.DOCKED, + VacuumActivity.IDLE, + VacuumActivity.DOCKED, ): - state = VacuumState.PAUSED + state = VacuumActivity.PAUSED return state async def async_added_to_hass(self): @@ -169,7 +169,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf self._cap_position = self.vacuum_state.get("cap", {}).get("pose") == 1 @property - def vacuum_state(self) -> VacuumState: + def vacuum_state(self) -> VacuumActivity: """Return the state of the vacuum cleaner.""" return self._robot_state @@ -189,7 +189,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf # Only add cleaning time and cleaned area attrs when the vacuum is # currently on - if self.state == VacuumState.CLEANING: + if self.state == VacuumActivity.CLEANING: # Get clean mission status ( state_attrs[ATTR_CLEANING_TIME], @@ -243,7 +243,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_start(self): """Start or resume the cleaning task.""" - if self.vacuum_state == VacuumState.PAUSED: + if self.vacuum_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") @@ -258,10 +258,10 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf async def async_return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" - if self.vacuum_state == VacuumState.CLEANING: + if self.vacuum_state == VacuumActivity.CLEANING: await self.async_pause() for _ in range(10): - if self.state == VacuumState.PAUSED: + if self.state == VacuumActivity.PAUSED: break await asyncio.sleep(1) await self.hass.async_add_executor_job(self.vacuum.send_command, "dock") diff --git a/homeassistant/components/sharkiq/vacuum.py b/homeassistant/components/sharkiq/vacuum.py index db0f5bba9d6..9fa0a463465 100644 --- a/homeassistant/components/sharkiq/vacuum.py +++ b/homeassistant/components/sharkiq/vacuum.py @@ -10,8 +10,8 @@ import voluptuous as vol from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -26,10 +26,10 @@ from .const import DOMAIN, LOGGER, SERVICE_CLEAN_ROOM, SHARK from .coordinator import SharkIqUpdateCoordinator OPERATING_STATE_MAP = { - OperatingModes.PAUSE: VacuumState.PAUSED, - OperatingModes.START: VacuumState.CLEANING, - OperatingModes.STOP: VacuumState.IDLE, - OperatingModes.RETURN: VacuumState.RETURNING, + OperatingModes.PAUSE: VacuumActivity.PAUSED, + OperatingModes.START: VacuumActivity.CLEANING, + OperatingModes.STOP: VacuumActivity.IDLE, + OperatingModes.RETURN: VacuumActivity.RETURNING, } FAN_SPEEDS_MAP = { @@ -147,7 +147,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.error_text @property - def operating_mode(self) -> VacuumState | None: + def operating_mode(self) -> VacuumActivity | None: """Operating mode.""" op_mode = self.sharkiq.get_property_value(Properties.OPERATING_MODE) return OPERATING_STATE_MAP.get(op_mode) @@ -158,7 +158,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum return self.sharkiq.get_property_value(Properties.RECHARGING_TO_RESUME) @property - def vacuum_state(self) -> VacuumState | 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. @@ -166,7 +166,7 @@ class SharkVacuumEntity(CoordinatorEntity[SharkIqUpdateCoordinator], StateVacuum user a notification. """ if self.sharkiq.get_property_value(Properties.CHARGING_STATUS): - return VacuumState.DOCKED + return VacuumActivity.DOCKED return self.operating_mode @property diff --git a/homeassistant/components/switchbot_cloud/vacuum.py b/homeassistant/components/switchbot_cloud/vacuum.py index 94231a83fb5..2d2a1783d73 100644 --- a/homeassistant/components/switchbot_cloud/vacuum.py +++ b/homeassistant/components/switchbot_cloud/vacuum.py @@ -6,8 +6,8 @@ from switchbot_api import Device, Remote, SwitchBotAPI, VacuumCommands from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback @@ -38,17 +38,17 @@ async def async_setup_entry( ) -VACUUM_SWITCHBOT_STATE_TO_HA_STATE: dict[str, VacuumState] = { - "StandBy": VacuumState.IDLE, - "Clearing": VacuumState.CLEANING, - "Paused": VacuumState.PAUSED, - "GotoChargeBase": VacuumState.RETURNING, - "Charging": VacuumState.DOCKED, - "ChargeDone": VacuumState.DOCKED, - "Dormant": VacuumState.IDLE, - "InTrouble": VacuumState.ERROR, - "InRemoteControl": VacuumState.CLEANING, - "InDustCollecting": VacuumState.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] = { @@ -109,9 +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_vacuum_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() diff --git a/homeassistant/components/template/vacuum.py b/homeassistant/components/template/vacuum.py index 62d55c2375e..19029cc708b 100644 --- a/homeassistant/components/template/vacuum.py +++ b/homeassistant/components/template/vacuum.py @@ -18,8 +18,8 @@ from homeassistant.components.vacuum import ( SERVICE_START, SERVICE_STOP, StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.const import ( CONF_ENTITY_ID, @@ -53,12 +53,12 @@ CONF_FAN_SPEED_TEMPLATE = "fan_speed_template" ENTITY_ID_FORMAT = VACUUM_DOMAIN + ".{}" _VALID_STATES = [ - VacuumState.CLEANING, - VacuumState.DOCKED, - VacuumState.PAUSED, - VacuumState.IDLE, - VacuumState.RETURNING, - VacuumState.ERROR, + VacuumActivity.CLEANING, + VacuumActivity.DOCKED, + VacuumActivity.PAUSED, + VacuumActivity.IDLE, + VacuumActivity.RETURNING, + VacuumActivity.ERROR, ] VACUUM_SCHEMA = vol.All( @@ -197,7 +197,7 @@ class TemplateVacuum(TemplateEntity, StateVacuumEntity): self._attr_fan_speed_list = config[CONF_FAN_SPEED_LIST] @property - def vacuum_state(self) -> VacuumState | None: + def activity(self) -> VacuumActivity | None: """Return the status of the vacuum cleaner.""" return self._state diff --git a/homeassistant/components/tuya/vacuum.py b/homeassistant/components/tuya/vacuum.py index 0a9429f98ae..738492102a1 100644 --- a/homeassistant/components/tuya/vacuum.py +++ b/homeassistant/components/tuya/vacuum.py @@ -8,8 +8,8 @@ from tuya_sharing import CustomerDevice, Manager from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -21,29 +21,29 @@ from .entity import EnumTypeData, IntegerTypeData, TuyaEntity TUYA_MODE_RETURN_HOME = "chargego" TUYA_STATUS_TO_HA = { - "charge_done": VacuumState.DOCKED, - "chargecompleted": VacuumState.DOCKED, - "chargego": VacuumState.DOCKED, - "charging": VacuumState.DOCKED, - "cleaning": VacuumState.CLEANING, - "docking": VacuumState.RETURNING, - "goto_charge": VacuumState.RETURNING, - "goto_pos": VacuumState.CLEANING, - "mop_clean": VacuumState.CLEANING, - "part_clean": VacuumState.CLEANING, - "paused": VacuumState.PAUSED, - "pick_zone_clean": VacuumState.CLEANING, - "pos_arrived": VacuumState.CLEANING, - "pos_unarrive": VacuumState.CLEANING, - "random": VacuumState.CLEANING, - "sleep": VacuumState.IDLE, - "smart_clean": VacuumState.CLEANING, - "smart": VacuumState.CLEANING, - "spot_clean": VacuumState.CLEANING, - "standby": VacuumState.IDLE, - "wall_clean": VacuumState.CLEANING, - "wall_follow": VacuumState.CLEANING, - "zone_clean": VacuumState.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, } @@ -134,12 +134,12 @@ class TuyaVacuumEntity(TuyaEntity, StateVacuumEntity): return self.device.status.get(DPCode.SUCTION) @property - def vacuum_state(self) -> VacuumState | 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 VacuumState.PAUSED + return VacuumActivity.PAUSED if not (status := self.device.status.get(DPCode.STATUS)): return None return TUYA_STATUS_TO_HA.get(status) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 10ee0c4bf48..f03ff4833fa 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -76,7 +76,7 @@ SERVICE_STOP = "stop" DEFAULT_NAME = "Vacuum cleaner robot" # These STATE_* constants are deprecated as of Home Assistant 2024.11. -# Please use the VacuumState enum instead. +# Please use the VacuumActivity enum instead. _DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumActivity.IDLE, "2025.11") _DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumActivity.PAUSED, "2025.11") @@ -227,7 +227,7 @@ STATE_VACUUM_CACHED_PROPERTIES_WITH_ATTR_ = { "battery_icon", "fan_speed", "fan_speed_list", - "vacuum_state", + "activity", } @@ -264,7 +264,7 @@ class StateVacuumEntity( unless already reported. """ if __name == "_attr_state": - self._report_deprecated_vacuum_state_handling() + self._report_deprecated_activity_handling() return super().__setattr__(__name, __value) @callback @@ -277,10 +277,10 @@ class StateVacuumEntity( """Start adding an entity to a platform.""" super().add_to_platform_start(hass, platform, parallel_updates) if self.__vacuum_legacy_state: - self._report_deprecated_vacuum_state_handling() + self._report_deprecated_activity_handling() @callback - def _report_deprecated_vacuum_state_handling(self) -> None: + def _report_deprecated_activity_handling(self) -> None: """Report on deprecated handling of vacuum state. Integrations should implement activity instead of using state directly. diff --git a/homeassistant/components/vacuum/const.py b/homeassistant/components/vacuum/const.py index 1eb14144140..117f9fdde78 100644 --- a/homeassistant/components/vacuum/const.py +++ b/homeassistant/components/vacuum/const.py @@ -27,7 +27,7 @@ class VacuumActivity(StrEnum): # These STATE_* constants are deprecated as of Home Assistant 2024.11. -# Please use the VacuumState enum instead. +# Please use the VacuumActivity enum instead. _DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumActivity.CLEANING, "2025.11") _DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumActivity.DOCKED, "2025.11") _DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum( diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index 1b5fed2b7d3..532eb9581cd 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -11,8 +11,8 @@ import voluptuous as vol from homeassistant.components.vacuum import ( StateVacuumEntity, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_DEVICE @@ -50,29 +50,29 @@ ATTR_ZONE_REPEATER = "repeats" ATTR_TIMERS = "timers" STATE_CODE_TO_STATE = { - 1: VacuumState.IDLE, # "Starting" - 2: VacuumState.IDLE, # "Charger disconnected" - 3: VacuumState.IDLE, # "Idle" - 4: VacuumState.CLEANING, # "Remote control active" - 5: VacuumState.CLEANING, # "Cleaning" - 6: VacuumState.RETURNING, # "Returning home" - 7: VacuumState.CLEANING, # "Manual mode" - 8: VacuumState.DOCKED, # "Charging" - 9: VacuumState.ERROR, # "Charging problem" - 10: VacuumState.PAUSED, # "Paused" - 11: VacuumState.CLEANING, # "Spot cleaning" - 12: VacuumState.ERROR, # "Error" - 13: VacuumState.IDLE, # "Shutting down" - 14: VacuumState.DOCKED, # "Updating" - 15: VacuumState.RETURNING, # "Docking" - 16: VacuumState.CLEANING, # "Going to target" - 17: VacuumState.CLEANING, # "Zoned cleaning" - 18: VacuumState.CLEANING, # "Segment cleaning" - 22: VacuumState.DOCKED, # "Emptying the bin" on s7+ - 23: VacuumState.DOCKED, # "Washing the mop" on s7maxV - 26: VacuumState.RETURNING, # "Going to wash the mop" on s7maxV - 100: VacuumState.DOCKED, # "Charging complete" - 101: VacuumState.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" } @@ -206,7 +206,7 @@ class MiroboVacuum( ) -> None: """Initialize the Xiaomi vacuum cleaner robot handler.""" super().__init__(device, entry, unique_id, coordinator) - self._state: VacuumState | 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.""" @@ -214,12 +214,12 @@ class MiroboVacuum( self._handle_coordinator_update() @property - def vacuum_state(self) -> VacuumState | 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 VacuumState.ERROR + return VacuumActivity.ERROR return self._state diff --git a/tests/components/demo/test_vacuum.py b/tests/components/demo/test_vacuum.py index 8e2bf5acf6a..f910e6e53ac 100644 --- a/tests/components/demo/test_vacuum.py +++ b/tests/components/demo/test_vacuum.py @@ -22,7 +22,7 @@ from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_SEND_COMMAND, SERVICE_SET_FAN_SPEED, - VacuumState, + VacuumActivity, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -71,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 == VacuumState.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 == VacuumState.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 == VacuumState.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 == VacuumState.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 == VacuumState.DOCKED + assert state.state == VacuumActivity.DOCKED async def test_methods(hass: HomeAssistant) -> None: @@ -107,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 == VacuumState.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 == VacuumState.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 == VacuumState.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 == VacuumState.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 == VacuumState.RETURNING + assert state.state == VacuumActivity.RETURNING await common.async_set_fan_speed( hass, FAN_SPEEDS[-1], entity_id=ENTITY_VACUUM_COMPLETE @@ -141,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 == VacuumState.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 == VacuumState.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 == VacuumState.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 == VacuumState.DOCKED + assert state.state == VacuumActivity.DOCKED async def test_unsupported_methods(hass: HomeAssistant) -> None: @@ -247,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 == VacuumState.IDLE + assert new_state_complete.state == VacuumActivity.IDLE diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 14108e6d16d..9e9c7015674 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -432,7 +432,7 @@ async def test_dock_vacuum(hass: HomeAssistant) -> None: assert trait.DockTrait.supported(vacuum.DOMAIN, 0, None, None) trt = trait.DockTrait( - hass, State("vacuum.bla", vacuum.VacuumState.IDLE), BASIC_CONFIG + hass, State("vacuum.bla", vacuum.VacuumActivity.IDLE), BASIC_CONFIG ) assert trt.sync_attributes() == {} @@ -456,7 +456,7 @@ async def test_locate_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumState.IDLE, + vacuum.VacuumActivity.IDLE, {ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.LOCATE}, ), BASIC_CONFIG, @@ -487,7 +487,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumState.DOCKED, + vacuum.VacuumActivity.DOCKED, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY, ATTR_BATTERY_LEVEL: 100, @@ -513,7 +513,7 @@ async def test_energystorage_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumState.CLEANING, + vacuum.VacuumActivity.CLEANING, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.BATTERY, ATTR_BATTERY_LEVEL: 20, @@ -553,7 +553,7 @@ async def test_startstop_vacuum(hass: HomeAssistant) -> None: hass, State( "vacuum.bla", - vacuum.VacuumState.PAUSED, + vacuum.VacuumActivity.PAUSED, {ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.PAUSE}, ), BASIC_CONFIG, diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 1b1699f5282..0d19763e4c7 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -26,8 +26,8 @@ from homeassistant.components.vacuum import ( SERVICE_START, SERVICE_TURN_OFF, SERVICE_TURN_ON, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -294,7 +294,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support( hass.states.async_set( entity_id, - VacuumState.CLEANING, + VacuumActivity.CLEANING, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME | VacuumEntityFeature.START @@ -305,7 +305,7 @@ async def test_vacuum_set_state_with_returnhome_and_start_support( hass.states.async_set( entity_id, - VacuumState.DOCKED, + VacuumActivity.DOCKED, { ATTR_SUPPORTED_FEATURES: VacuumEntityFeature.RETURN_HOME | VacuumEntityFeature.START diff --git a/tests/components/litterrobot/test_init.py b/tests/components/litterrobot/test_init.py index b23b5373579..1c8e0742b26 100644 --- a/tests/components/litterrobot/test_init.py +++ b/tests/components/litterrobot/test_init.py @@ -9,7 +9,7 @@ from homeassistant.components import litterrobot from homeassistant.components.vacuum import ( DOMAIN as VACUUM_DOMAIN, SERVICE_START, - VacuumState, + 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 == VacuumState.DOCKED + assert vacuum.state == VacuumActivity.DOCKED await hass.services.async_call( VACUUM_DOMAIN, diff --git a/tests/components/litterrobot/test_vacuum.py b/tests/components/litterrobot/test_vacuum.py index 4bfe50a3839..69fb99d7d13 100644 --- a/tests/components/litterrobot/test_vacuum.py +++ b/tests/components/litterrobot/test_vacuum.py @@ -15,7 +15,7 @@ from homeassistant.components.vacuum import ( DOMAIN as PLATFORM_DOMAIN, SERVICE_START, SERVICE_STOP, - VacuumState, + VacuumActivity, ) from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant @@ -51,7 +51,7 @@ async def test_vacuum( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumState.DOCKED + assert vacuum.state == VacuumActivity.DOCKED assert vacuum.attributes["is_sleeping"] is False ent_reg_entry = entity_registry.async_get(VACUUM_ENTITY_ID) @@ -93,21 +93,21 @@ async def test_vacuum_with_error( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumState.ERROR + assert vacuum.state == VacuumActivity.ERROR @pytest.mark.parametrize( ("robot_data", "expected_state"), [ - ({"displayCode": "DC_CAT_DETECT"}, VacuumState.DOCKED), - ({"isDFIFull": True}, VacuumState.ERROR), + ({"displayCode": "DC_CAT_DETECT"}, VacuumActivity.DOCKED), + ({"isDFIFull": True}, VacuumActivity.ERROR), ( {"robotCycleState": "CYCLE_STATE_CAT_DETECT"}, - VacuumState.PAUSED, + VacuumActivity.PAUSED, ), ], ) -async def test_vacuum_states( +async def test_activitys( hass: HomeAssistant, mock_account_with_litterrobot_4: MagicMock, robot_data: dict[str, str | bool], @@ -151,7 +151,7 @@ async def test_commands( vacuum = hass.states.get(VACUUM_ENTITY_ID) assert vacuum - assert vacuum.state == VacuumState.DOCKED + assert vacuum.state == VacuumActivity.DOCKED extra = extra or {} data = {ATTR_ENTITY_ID: VACUUM_ENTITY_ID, **extra.get("data", {})} diff --git a/tests/components/mqtt/test_vacuum.py b/tests/components/mqtt/test_vacuum.py index f90f323d199..c1c662048d7 100644 --- a/tests/components/mqtt/test_vacuum.py +++ b/tests/components/mqtt/test_vacuum.py @@ -27,7 +27,7 @@ from homeassistant.components.vacuum import ( SERVICE_RETURN_TO_BASE, SERVICE_START, SERVICE_STOP, - VacuumState, + VacuumActivity, ) from homeassistant.const import CONF_NAME, ENTITY_MATCH_ALL, STATE_UNKNOWN from homeassistant.core import HomeAssistant @@ -312,7 +312,7 @@ async def test_status( }""" async_fire_mqtt_message(hass, "vacuum/state", message) state = hass.states.get("vacuum.mqtttest") - assert state.state == VacuumState.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" @@ -325,7 +325,7 @@ async def test_status( async_fire_mqtt_message(hass, "vacuum/state", message) state = hass.states.get("vacuum.mqtttest") - assert state.state == VacuumState.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" @@ -365,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 == VacuumState.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 @@ -379,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 == VacuumState.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 @@ -393,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 == VacuumState.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 diff --git a/tests/components/sharkiq/test_vacuum.py b/tests/components/sharkiq/test_vacuum.py index 2437f8372b7..bfb2176026b 100644 --- a/tests/components/sharkiq/test_vacuum.py +++ b/tests/components/sharkiq/test_vacuum.py @@ -35,8 +35,8 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, + VacuumActivity, VacuumEntityFeature, - VacuumState, ) from homeassistant.const import ( ATTR_ENTITY_ID, @@ -157,7 +157,7 @@ async def test_simple_properties( assert entity assert state - assert state.state == VacuumState.CLEANING + assert state.state == VacuumActivity.CLEANING assert entity.unique_id == "AC000Wxxxxxxxxx" @@ -186,10 +186,10 @@ async def test_initial_attributes( @pytest.mark.parametrize( ("service", "target_state"), [ - (SERVICE_STOP, VacuumState.IDLE), - (SERVICE_PAUSE, VacuumState.PAUSED), - (SERVICE_RETURN_TO_BASE, VacuumState.RETURNING), - (SERVICE_START, VacuumState.CLEANING), + (SERVICE_STOP, VacuumActivity.IDLE), + (SERVICE_PAUSE, VacuumActivity.PAUSED), + (SERVICE_RETURN_TO_BASE, VacuumActivity.RETURNING), + (SERVICE_START, VacuumActivity.CLEANING), ], ) async def test_cleaning_states( diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index da44c1c8e2d..6053a2bd9ec 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -3,7 +3,7 @@ import pytest from homeassistant import setup -from homeassistant.components.vacuum import ATTR_BATTERY_LEVEL, VacuumState +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 @@ -37,7 +37,7 @@ _BATTERY_LEVEL_INPUT_NUMBER = "input_number.battery_level" }, ), ( - VacuumState.CLEANING, + VacuumActivity.CLEANING, 100, { "vacuum": { @@ -142,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, VacuumState.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, VacuumState.CLEANING, 100) + _verify(hass, VacuumActivity.CLEANING, 100) @pytest.mark.parametrize( @@ -363,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 == VacuumState.CLEANING - _verify(hass, VacuumState.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 @@ -374,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 == VacuumState.PAUSED - _verify(hass, VacuumState.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 @@ -385,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 == VacuumState.IDLE - _verify(hass, VacuumState.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 @@ -396,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 == VacuumState.RETURNING - _verify(hass, VacuumState.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 @@ -501,7 +501,7 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None: "input_select", { "input_select": { - "state": {"name": "State", "options": [VacuumState.CLEANING]} + "state": {"name": "State", "options": [VacuumActivity.CLEANING]} } }, ) @@ -519,7 +519,7 @@ async def _register_basic_vacuum(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumState.CLEANING, + "option": VacuumActivity.CLEANING, }, } } @@ -551,11 +551,11 @@ async def _register_components(hass: HomeAssistant) -> None: "state": { "name": "State", "options": [ - VacuumState.CLEANING, - VacuumState.DOCKED, - VacuumState.IDLE, - VacuumState.PAUSED, - VacuumState.RETURNING, + VacuumActivity.CLEANING, + VacuumActivity.DOCKED, + VacuumActivity.IDLE, + VacuumActivity.PAUSED, + VacuumActivity.RETURNING, ], }, "fan_speed": { @@ -575,7 +575,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumState.CLEANING, + "option": VacuumActivity.CLEANING, }, }, { @@ -591,7 +591,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumState.PAUSED, + "option": VacuumActivity.PAUSED, }, }, { @@ -607,7 +607,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumState.IDLE, + "option": VacuumActivity.IDLE, }, }, { @@ -623,7 +623,7 @@ async def _register_components(hass: HomeAssistant) -> None: "service": "input_select.select_option", "data": { "entity_id": _STATE_INPUT_SELECT, - "option": VacuumState.RETURNING, + "option": VacuumActivity.RETURNING, }, }, { diff --git a/tests/components/xiaomi_miio/test_vacuum.py b/tests/components/xiaomi_miio/test_vacuum.py index 8e9ef3976eb..e58f21e387b 100644 --- a/tests/components/xiaomi_miio/test_vacuum.py +++ b/tests/components/xiaomi_miio/test_vacuum.py @@ -21,7 +21,7 @@ from homeassistant.components.vacuum import ( SERVICE_SET_FAN_SPEED, SERVICE_START, SERVICE_STOP, - VacuumState, + VacuumActivity, ) from homeassistant.components.xiaomi_miio.const import ( CONF_FLOW_TYPE, @@ -263,7 +263,7 @@ async def test_xiaomi_vacuum_services( # Check state attributes state = hass.states.get(entity_id) - assert state.state == VacuumState.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" @@ -449,7 +449,7 @@ async def test_xiaomi_specific_services( # Check state attributes state = hass.states.get(entity_id) - assert state.state == VacuumState.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" From f832cacb9a0a9e030d12f7b5de19f156f74ee803 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:43:15 +0000 Subject: [PATCH 18/24] Update demo --- homeassistant/components/demo/vacuum.py | 29 ++++++++++--------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/demo/vacuum.py b/homeassistant/components/demo/vacuum.py index 0059f7c6a54..3dd945ab82e 100644 --- a/homeassistant/components/demo/vacuum.py +++ b/homeassistant/components/demo/vacuum.py @@ -87,16 +87,11 @@ class StateDemoVacuum(StateVacuumEntity): """Initialize the vacuum.""" self._attr_name = name self._attr_supported_features = supported_features - self._state = VacuumActivity.DOCKED + self._attr_activity = VacuumActivity.DOCKED self._fan_speed = FAN_SPEEDS[1] self._cleaned_area: float = 0 self._battery_level = 100 - @property - def activity(self) -> VacuumActivity: - """Return the current state of the vacuum.""" - return self._state - @property def battery_level(self) -> int: """Return the current battery level of the vacuum.""" @@ -119,33 +114,33 @@ class StateDemoVacuum(StateVacuumEntity): def start(self) -> None: """Start or resume the cleaning task.""" - if self._state != VacuumActivity.CLEANING: - self._state = VacuumActivity.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 == VacuumActivity.CLEANING: - self._state = VacuumActivity.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 = VacuumActivity.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 = VacuumActivity.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 = VacuumActivity.CLEANING + self._attr_activity = VacuumActivity.CLEANING self._cleaned_area += 1.32 self._battery_level -= 1 self.schedule_update_ha_state() @@ -163,12 +158,12 @@ class StateDemoVacuum(StateVacuumEntity): "persistent_notification", service_data={"message": "I'm here!", "title": "Locate request"}, ) - self._state = VacuumActivity.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 = VacuumActivity.CLEANING + self._attr_activity = VacuumActivity.CLEANING self.async_write_ha_state() async def async_send_command( @@ -178,9 +173,9 @@ class StateDemoVacuum(StateVacuumEntity): **kwargs: Any, ) -> None: """Send a command to the vacuum.""" - self._state = VacuumActivity.IDLE + self._attr_activity = VacuumActivity.IDLE self.async_write_ha_state() def __set_state_to_dock(self, _: datetime) -> None: - self._state = VacuumActivity.DOCKED + self._attr_activity = VacuumActivity.DOCKED self.schedule_update_ha_state() From e53d165db5f269670622bb219a992d2302750e7c Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 20:46:31 +0000 Subject: [PATCH 19/24] Mod roomba --- homeassistant/components/roomba/entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/roomba/entity.py b/homeassistant/components/roomba/entity.py index ae9486f2254..57d84908550 100644 --- a/homeassistant/components/roomba/entity.py +++ b/homeassistant/components/roomba/entity.py @@ -169,7 +169,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumEntity): # pylint: disable=hass-enf self._cap_position = self.vacuum_state.get("cap", {}).get("pose") == 1 @property - def vacuum_state(self) -> VacuumActivity: + def activity(self) -> VacuumActivity: """Return the state of the vacuum cleaner.""" return self._robot_state From 3ec070440555b5ca52703158404dcc237c13633b Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 21:11:56 +0000 Subject: [PATCH 20/24] LG --- homeassistant/components/lg_thinq/vacuum.py | 40 ++++++++++----------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/lg_thinq/vacuum.py b/homeassistant/components/lg_thinq/vacuum.py index 138b9ba55bf..6cbb731869c 100644 --- a/homeassistant/components/lg_thinq/vacuum.py +++ b/homeassistant/components/lg_thinq/vacuum.py @@ -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 From bb4f13fdb5d126c2a6049258afade4813e799fbe Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 21:19:41 +0000 Subject: [PATCH 21/24] Fix vacuum --- homeassistant/components/vacuum/__init__.py | 10 ++++---- homeassistant/components/vacuum/const.py | 8 +++--- tests/components/vacuum/test_init.py | 28 +++++++++++++++++---- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index f03ff4833fa..f4548b96c6b 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -77,8 +77,8 @@ DEFAULT_NAME = "Vacuum cleaner robot" # These STATE_* constants are deprecated as of Home Assistant 2024.11. # Please use the VacuumActivity enum instead. -_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumActivity.IDLE, "2025.11") -_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumActivity.PAUSED, "2025.11") +_DEPRECATED_STATE_IDLE = DeprecatedConstantEnum(VacuumActivity.IDLE, "2025.12") +_DEPRECATED_STATE_PAUSED = DeprecatedConstantEnum(VacuumActivity.PAUSED, "2025.12") class VacuumEntityFeature(IntFlag): @@ -286,9 +286,9 @@ class StateVacuumEntity( Integrations should implement activity instead of using state directly. """ report( - "is setting state directly which will stop working in HA Core 2025.11." - f" Entity {self.entity_id} ({type(self)}) should implement the 'activity' property and" - " return its state using the VacuumActivity enum, please ", + "is setting state directly which will stop working in HA Core 2025.12." + f" Entity {self.entity_id} ({type(self)}) should implement the 'activity'" + " property and return its state using the VacuumActivity enum.", error_if_core=True, error_if_integration=False, ) diff --git a/homeassistant/components/vacuum/const.py b/homeassistant/components/vacuum/const.py index 117f9fdde78..8f80b35bbd9 100644 --- a/homeassistant/components/vacuum/const.py +++ b/homeassistant/components/vacuum/const.py @@ -28,12 +28,12 @@ class VacuumActivity(StrEnum): # These STATE_* constants are deprecated as of Home Assistant 2024.11. # Please use the VacuumActivity enum instead. -_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumActivity.CLEANING, "2025.11") -_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumActivity.DOCKED, "2025.11") +_DEPRECATED_STATE_CLEANING = DeprecatedConstantEnum(VacuumActivity.CLEANING, "2025.12") +_DEPRECATED_STATE_DOCKED = DeprecatedConstantEnum(VacuumActivity.DOCKED, "2025.12") _DEPRECATED_STATE_RETURNING = DeprecatedConstantEnum( - VacuumActivity.RETURNING, "2025.11" + VacuumActivity.RETURNING, "2025.12" ) -_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumActivity.ERROR, "2025.11") +_DEPRECATED_STATE_ERROR = DeprecatedConstantEnum(VacuumActivity.ERROR, "2025.12") STATES = [cls.value for cls in VacuumActivity] diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index e1f240b37cb..5b8e2c57a46 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -26,6 +26,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.helpers import frame from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import MockVacuum, help_async_setup_entry_init, help_async_unload_entry @@ -319,9 +320,13 @@ async def test_vacuum_not_log_deprecated_state_warning( """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 "Entities should implement the 'activity' property and" not in caplog.text + assert ( + "should implement the 'activity' property and return its state using the VacuumActivity enum" + not in caplog.text + ) +@patch.object(frame, "_REPORTED_INTEGRATIONS", set()) async def test_vacuum_log_deprecated_state_warning_using_state_prop( hass: HomeAssistant, config_flow_fixture: None, @@ -383,9 +388,13 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( state = hass.states.get(entity.entity_id) assert state is not None - assert "Entities should implement the 'activity' property and" in caplog.text + assert ( + "should implement the 'activity' property and return its state using the VacuumActivity enum" + in caplog.text + ) +@patch.object(frame, "_REPORTED_INTEGRATIONS", set()) async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( hass: HomeAssistant, config_flow_fixture: None, @@ -446,7 +455,10 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( state = hass.states.get(entity.entity_id) assert state is not None - assert "Entities should implement the 'activity' property and" not in caplog.text + assert ( + "should implement the 'activity' property and return its state using the VacuumActivity enum" + not in caplog.text + ) with patch.object( MockLegacyVacuum, @@ -455,7 +467,10 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( ): await async_start(hass, entity.entity_id) - assert "Entities should implement the 'activity' property and" in caplog.text + assert ( + "should implement the 'activity' property and return its state using the VacuumActivity enum" + in caplog.text + ) caplog.clear() with patch.object( MockLegacyVacuum, @@ -464,4 +479,7 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( ): await async_start(hass, entity.entity_id) # Test we only log once - assert "Entities should implement the 'activity' property and" not in caplog.text + assert ( + "should implement the 'activity' property and return its state using the VacuumActivity enum" + not in caplog.text + ) From c1581bc18b67b5bd2786107aa9537fc2722e3575 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 11 Nov 2024 21:25:06 +0000 Subject: [PATCH 22/24] Fix Matter --- homeassistant/components/matter/vacuum.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/matter/vacuum.py b/homeassistant/components/matter/vacuum.py index 2ecd7128df6..e98e1ad0bbd 100644 --- a/homeassistant/components/matter/vacuum.py +++ b/homeassistant/components/matter/vacuum.py @@ -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: From 10a6f22addad3254abcd0804f8fa408a95a12ebb Mon Sep 17 00:00:00 2001 From: G Johansson Date: Tue, 12 Nov 2024 16:20:18 +0000 Subject: [PATCH 23/24] Fix deprecation version --- tests/components/vacuum/test_init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index 5b8e2c57a46..c7295f73170 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -92,7 +92,7 @@ def test_deprecated_constants_for_state( ) -> None: """Test deprecated constants.""" import_and_test_deprecated_constant_enum( - caplog, module, enum, constant_prefix, "2025.11" + caplog, module, enum, constant_prefix, "2025.12" ) From 7e487f95631798895230173b9ba88e8cf36c25e6 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Wed, 13 Nov 2024 17:20:15 +0000 Subject: [PATCH 24/24] Mods --- homeassistant/components/vacuum/__init__.py | 14 +- tests/components/vacuum/test_init.py | 179 ++++++++++---------- 2 files changed, 104 insertions(+), 89 deletions(-) diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index f4548b96c6b..189b621d95e 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -7,7 +7,7 @@ from datetime import timedelta from enum import IntFlag from functools import partial import logging -from typing import Any, final +from typing import TYPE_CHECKING, Any, final from propcache import cached_property import voluptuous as vol @@ -343,9 +343,15 @@ class StateVacuumEntity( @property def state(self) -> str | None: """Return the state of the vacuum cleaner.""" - if (activity := self.activity) is None: - return None - return activity + 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 2025.12 + if TYPE_CHECKING: + assert isinstance(self._attr_state, str) + return self._attr_state + return None @cached_property def activity(self) -> VacuumActivity | None: diff --git a/tests/components/vacuum/test_init.py b/tests/components/vacuum/test_init.py index c7295f73170..5ff7720c1d5 100644 --- a/tests/components/vacuum/test_init.py +++ b/tests/components/vacuum/test_init.py @@ -24,23 +24,19 @@ from homeassistant.components.vacuum import ( VacuumActivity, VacuumEntityFeature, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers import frame -from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import MockVacuum, help_async_setup_entry_init, help_async_unload_entry from .common import async_start -from .conftest import TEST_DOMAIN from tests.common import ( MockConfigEntry, + MockEntity, MockModule, - MockPlatform, help_test_all, import_and_test_deprecated_constant_enum, mock_integration, - mock_platform, setup_test_component_platform, ) @@ -334,23 +330,6 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( ) -> None: """Test incorrectly using state property does log issue and raise repair.""" - 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, - ), - ) - class MockLegacyVacuum(MockVacuum): """Mocked vacuum entity.""" @@ -359,31 +338,23 @@ async def test_vacuum_log_deprecated_state_warning_using_state_prop( """Return the state of the entity.""" return VacuumActivity.CLEANING - entity = MockLegacyVacuum() - - 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), + entity = MockLegacyVacuum( + name="Testing", + entity_id="vacuum.test", ) + config_entry = MockConfigEntry(domain="test") + config_entry.add_to_hass(hass) - with patch.object( - MockLegacyVacuum, - "__module__", - "tests.custom_components.test.vacuum", - ): - 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() + 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 @@ -402,23 +373,6 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( ) -> None: """Test incorrectly using _attr_state attribute does log issue and raise repair.""" - 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, - ), - ) - class MockLegacyVacuum(MockVacuum): """Mocked vacuum entity.""" @@ -426,31 +380,23 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( """Start cleaning.""" self._attr_state = VacuumActivity.CLEANING - entity = MockLegacyVacuum() - - 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), + entity = MockLegacyVacuum( + name="Testing", + entity_id="vacuum.test", ) + config_entry = MockConfigEntry(domain="test") + config_entry.add_to_hass(hass) - with patch.object( - MockLegacyVacuum, - "__module__", - "tests.custom_components.test.vacuum", - ): - 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() + 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 @@ -483,3 +429,66 @@ async def test_vacuum_log_deprecated_state_warning_using_attr_state_attr( "should implement the 'activity' property and return its state using the VacuumActivity enum" not in caplog.text ) + + +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" + + with patch.object( + MockLegacyVacuum, + "__module__", + "tests.custom_components.test.alarm_control_panel", + ): + 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"