mirror of
				https://github.com/XiaoMi/ha_xiaomi_home.git
				synced 2025-10-31 01:12:05 +08:00 
			
		
		
		
	fix: Fix the HA warning in the logs related to vacuum state setting (#694)
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	
This commit is contained in:
		| @@ -47,29 +47,26 @@ Vacuum entities for Xiaomi Home. | ||||
| """ | ||||
| from __future__ import annotations | ||||
| from typing import Any, Optional | ||||
| import re | ||||
| import logging | ||||
|  | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.core import HomeAssistant | ||||
| from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||||
| from homeassistant.components.vacuum import ( | ||||
|     StateVacuumEntity, | ||||
|     VacuumEntityFeature | ||||
| ) | ||||
| from homeassistant.components.vacuum import (StateVacuumEntity, | ||||
|                                              VacuumEntityFeature) | ||||
|  | ||||
| from .miot.const import DOMAIN | ||||
| from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData | ||||
| from .miot.miot_spec import ( | ||||
|     MIoTSpecAction, | ||||
|     MIoTSpecProperty) | ||||
| from .miot.miot_spec import (MIoTSpecAction, MIoTSpecProperty) | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| async def async_setup_entry( | ||||
|         hass: HomeAssistant, | ||||
|         config_entry: ConfigEntry, | ||||
|         async_add_entities: AddEntitiesCallback, | ||||
|     hass: HomeAssistant, | ||||
|     config_entry: ConfigEntry, | ||||
|     async_add_entities: AddEntitiesCallback, | ||||
| ) -> None: | ||||
|     device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][ | ||||
|         config_entry.entry_id] | ||||
| @@ -99,10 +96,12 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity): | ||||
|     _status_map: Optional[dict[int, str]] | ||||
|     _fan_level_map: Optional[dict[int, str]] | ||||
|  | ||||
|     def __init__( | ||||
|         self, miot_device: MIoTDevice, entity_data: MIoTEntityData | ||||
|     ) -> None: | ||||
|     _device_name: str | ||||
|  | ||||
|     def __init__(self, miot_device: MIoTDevice, | ||||
|                  entity_data: MIoTEntityData) -> None: | ||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||
|         self._device_name = miot_device.name | ||||
|         self._attr_supported_features = VacuumEntityFeature(0) | ||||
|  | ||||
|         self._prop_status = None | ||||
| @@ -121,21 +120,21 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity): | ||||
|         for prop in entity_data.props: | ||||
|             if prop.name == 'status': | ||||
|                 if not prop.value_list: | ||||
|                     _LOGGER.error( | ||||
|                         'invalid status value_list, %s', self.entity_id) | ||||
|                     _LOGGER.error('invalid status value_list, %s', | ||||
|                                   self.entity_id) | ||||
|                     continue | ||||
|                 self._status_map = prop.value_list.to_map() | ||||
|                 self._attr_supported_features |= VacuumEntityFeature.STATE | ||||
|                 self._prop_status = prop | ||||
|             elif prop.name == 'fan-level': | ||||
|                 if not prop.value_list: | ||||
|                     _LOGGER.error( | ||||
|                         'invalid fan-level value_list, %s', self.entity_id) | ||||
|                     _LOGGER.error('invalid fan-level value_list, %s', | ||||
|                                   self.entity_id) | ||||
|                     continue | ||||
|                 self._fan_level_map = prop.value_list.to_map() | ||||
|                 self._attr_fan_speed_list = list(self._fan_level_map.values()) | ||||
|                 self._attr_supported_features |= VacuumEntityFeature.FAN_SPEED | ||||
|                 self._prop_fan_level = prop | ||||
|  | ||||
|             elif prop.name == 'battery-level': | ||||
|                 self._attr_supported_features |= VacuumEntityFeature.BATTERY | ||||
|                 self._prop_battery_level = prop | ||||
| @@ -155,16 +154,24 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity): | ||||
|             elif action.name == 'stop-and-gocharge': | ||||
|                 self._attr_supported_features |= VacuumEntityFeature.RETURN_HOME | ||||
|                 self._action_stop_and_gocharge = action | ||||
|  | ||||
|             elif action.name == 'identify': | ||||
|                 self._attr_supported_features |= VacuumEntityFeature.LOCATE | ||||
|                 self._action_identify = action | ||||
|  | ||||
|     async def async_start(self) -> None: | ||||
|         """Start or resume the cleaning task.""" | ||||
|         if self.state.lower() in ['paused', '暂停中']: | ||||
|             await self.action_async(action=self._action_continue_sweep) | ||||
|             return | ||||
|         try:  # VacuumActivity is introduced in HA core 2025.1.0 | ||||
|             # pylint: disable=import-outside-toplevel | ||||
|             from homeassistant.components.vacuum import VacuumActivity | ||||
|             if (self.activity | ||||
|                     == VacuumActivity.PAUSED) and self._action_continue_sweep: | ||||
|                 await self.action_async(action=self._action_continue_sweep) | ||||
|                 return | ||||
|         except ImportError: | ||||
|             if self.state and (self.state in {'paused', 'pause' | ||||
|                                              }) and self._action_continue_sweep: | ||||
|                 await self.action_async(action=self._action_continue_sweep) | ||||
|                 return | ||||
|         await self.action_async(action=self._action_start_sweep) | ||||
|  | ||||
|     async def async_stop(self, **kwargs: Any) -> None: | ||||
| @@ -179,31 +186,92 @@ class Vacuum(MIoTServiceEntity, StateVacuumEntity): | ||||
|         """Set the vacuum cleaner to return to the dock.""" | ||||
|         await self.action_async(action=self._action_stop_and_gocharge) | ||||
|  | ||||
|     async def async_clean_spot(self, **kwargs: Any) -> None: | ||||
|         """Perform a spot clean-up.""" | ||||
|  | ||||
|     async def async_locate(self, **kwargs: Any) -> None: | ||||
|         """Locate the vacuum cleaner.""" | ||||
|         await self.action_async(action=self._action_identify) | ||||
|  | ||||
|     async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: | ||||
|         """Set fan speed.""" | ||||
|         fan_level_value = self.get_map_key(map_=self._fan_level_map, | ||||
|                                            value=fan_speed) | ||||
|         await self.set_property_async(prop=self._prop_fan_level, | ||||
|                                       value=fan_level_value) | ||||
|  | ||||
|     @property | ||||
|     def name(self) -> Optional[str]: | ||||
|         """Name of the vacuum entity.""" | ||||
|         return self._device_name | ||||
|  | ||||
|     @property | ||||
|     def state(self) -> Optional[str]: | ||||
|         """Return the current state of the vacuum cleaner.""" | ||||
|         return self.get_map_value( | ||||
|             map_=self._status_map, | ||||
|             key=self.get_prop_value(prop=self._prop_status)) | ||||
|         """Return the current state of the vacuum cleaner. | ||||
|  | ||||
|         To fix the HA warning below: | ||||
|             Detected that custom integration 'xiaomi_home' is setting state | ||||
|             directly.Entity XXX(<class 'custom_components.xiaomi_home.vacuum | ||||
|             .Vacuum'>)should implement the 'activity' property and return | ||||
|             its state using the VacuumActivity enum.This will stop working in | ||||
|             Home Assistant 2026.1. | ||||
|  | ||||
|         Refer to | ||||
|         https://developers.home-assistant.io/blog/2024/12/08/new-vacuum-state-property | ||||
|  | ||||
|         There are only 6 states in VacuumActivity enum. To be compatible with | ||||
|         more constants, try get matching VacuumActivity enum first, return state | ||||
|         string as before if there is no match. In Home Assistant 2026.1, every | ||||
|         state should map to a VacuumActivity enum. | ||||
|         """ | ||||
|         return self.activity | ||||
|  | ||||
|     @property | ||||
|     def activity(self) -> Optional[str]: | ||||
|         """The current vacuum activity.""" | ||||
|         status = self.get_prop_value(prop=self._prop_status) | ||||
|         if status is None: | ||||
|             return None | ||||
|         status_value = self.get_map_value(map_=self._status_map, key=status) | ||||
|         if status_value is None: | ||||
|             return None | ||||
|         try: | ||||
|             # pylint: disable=import-outside-toplevel | ||||
|             from homeassistant.components.vacuum import VacuumActivity | ||||
|             status_value = status_value.lower() | ||||
|             status_str = re.sub(r'[^a-z]', '', status_value) | ||||
|             if status_str in { | ||||
|                     'charging', 'charged', 'chargingcompleted', 'fullcharge', | ||||
|                     'fullpower', 'findchargerpause', 'drying', 'washing', | ||||
|                     'wash', 'inthewash', 'inthedry', 'stationworking', | ||||
|                     'dustcollecting', 'upgrade', 'upgrading', 'updating' | ||||
|             }: | ||||
|                 return VacuumActivity.DOCKED | ||||
|             if status_str in {'paused', 'pause'}: | ||||
|                 return VacuumActivity.PAUSED | ||||
|             if status_str in { | ||||
|                     'gocharging', 'cleancompletegocharging', 'findchargewash', | ||||
|                     'backtowashmop', 'gowash', 'gowashing', 'summon' | ||||
|             }: | ||||
|                 return VacuumActivity.RETURNING | ||||
|             if (status_str.find('sweeping') | ||||
|                     != -1) or (status_str.find('mopping') | ||||
|                                != -1) or (status_str in { | ||||
|                                    'cleaning', 'remoteclean', 'continuesweep', | ||||
|                                    'busy', 'building', 'buildingmap', 'mapping' | ||||
|                                }): | ||||
|                 return VacuumActivity.CLEANING | ||||
|             if status_str in {'error', 'breakcharging', 'gochargebreak'}: | ||||
|                 return VacuumActivity.ERROR | ||||
|             return VacuumActivity.IDLE | ||||
|         except ImportError: | ||||
|             return status_value | ||||
|  | ||||
|     @property | ||||
|     def battery_level(self) -> Optional[int]: | ||||
|         """Return the current battery level of the vacuum cleaner.""" | ||||
|         """The current battery level of the vacuum cleaner.""" | ||||
|         return self.get_prop_value(prop=self._prop_battery_level) | ||||
|  | ||||
|     @property | ||||
|     def fan_speed(self) -> Optional[str]: | ||||
|         """Return the current fan speed of the vacuum cleaner.""" | ||||
|         """The current fan speed of the vacuum cleaner.""" | ||||
|         return self.get_map_value( | ||||
|             map_=self._fan_level_map, | ||||
|             key=self.get_prop_value(prop=self._prop_fan_level)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user