33from __future__ import annotations
44
55from enum import IntEnum
6- from typing import TYPE_CHECKING , Any , cast
6+ from typing import TYPE_CHECKING , Any
77
88from chip .clusters import Objects as clusters
9- from chip .clusters .Objects import NullValue
109from matter_server .client .models import device_types
11- import voluptuous as vol
1210
1311from homeassistant .components .vacuum import (
1412 StateVacuumEntity ,
1816)
1917from homeassistant .config_entries import ConfigEntry
2018from homeassistant .const import Platform
21- from homeassistant .core import (
22- HomeAssistant ,
23- ServiceResponse ,
24- SupportsResponse ,
25- callback ,
26- )
19+ from homeassistant .core import HomeAssistant , callback
2720from homeassistant .exceptions import HomeAssistantError
28- from homeassistant .helpers import config_validation as cv , entity_platform
2921from homeassistant .helpers .entity_platform import AddConfigEntryEntitiesCallback
3022
31- from .const import SERVICE_CLEAN_AREAS , SERVICE_GET_AREAS , SERVICE_SELECT_AREAS
3223from .entity import MatterEntity
3324from .helpers import get_matter
3425from .models import MatterDiscoverySchema
3526
36- ATTR_CURRENT_AREA = "current_area"
37- ATTR_CURRENT_AREA_NAME = "current_area_name"
38- ATTR_SELECTED_AREAS = "selected_areas"
39-
4027
4128class OperationalState (IntEnum ):
4229 """Operational State of the vacuum cleaner.
@@ -69,33 +56,6 @@ async def async_setup_entry(
6956 """Set up Matter vacuum platform from Config Entry."""
7057 matter = get_matter (hass )
7158 matter .register_platform_handler (Platform .VACUUM , async_add_entities )
72- platform = entity_platform .async_get_current_platform ()
73-
74- # This will call Entity.async_handle_get_areas
75- platform .async_register_entity_service (
76- SERVICE_GET_AREAS ,
77- schema = None ,
78- func = "async_handle_get_areas" ,
79- supports_response = SupportsResponse .ONLY ,
80- )
81- # This will call Entity.async_handle_clean_areas
82- platform .async_register_entity_service (
83- SERVICE_CLEAN_AREAS ,
84- schema = {
85- vol .Required ("areas" ): vol .All (cv .ensure_list , [cv .positive_int ]),
86- },
87- func = "async_handle_clean_areas" ,
88- supports_response = SupportsResponse .ONLY ,
89- )
90- # This will call Entity.async_handle_select_areas
91- platform .async_register_entity_service (
92- SERVICE_SELECT_AREAS ,
93- schema = {
94- vol .Required ("areas" ): vol .All (cv .ensure_list , [cv .positive_int ]),
95- },
96- func = "async_handle_select_areas" ,
97- supports_response = SupportsResponse .ONLY ,
98- )
9959
10060
10161class MatterVacuum (MatterEntity , StateVacuumEntity ):
@@ -105,23 +65,9 @@ class MatterVacuum(MatterEntity, StateVacuumEntity):
10565 _supported_run_modes : (
10666 dict [int , clusters .RvcRunMode .Structs .ModeOptionStruct ] | None
10767 ) = None
108- _attr_matter_areas : dict [str , Any ] | None = None
109- _attr_current_area : int | None = None
110- _attr_current_area_name : str | None = None
111- _attr_selected_areas : list [int ] | None = None
112- _attr_supported_maps : list [dict [str , Any ]] | None = None
11368 entity_description : StateVacuumEntityDescription
11469 _platform_translation_key = "vacuum"
11570
116- @property
117- def extra_state_attributes (self ) -> dict [str , Any ] | None :
118- """Return the state attributes of the entity."""
119- return {
120- ATTR_CURRENT_AREA : self ._attr_current_area ,
121- ATTR_CURRENT_AREA_NAME : self ._attr_current_area_name ,
122- ATTR_SELECTED_AREAS : self ._attr_selected_areas ,
123- }
124-
12571 def _get_run_mode_by_tag (
12672 self , tag : ModeTag
12773 ) -> clusters .RvcRunMode .Structs .ModeOptionStruct | None :
@@ -190,160 +136,10 @@ async def async_pause(self) -> None:
190136 """Pause the cleaning task."""
191137 await self .send_device_command (clusters .RvcOperationalState .Commands .Pause ())
192138
193- def async_get_areas (self , ** kwargs : Any ) -> dict [str , Any ]:
194- """Get available area and map IDs from vacuum appliance."""
195-
196- supported_areas = self .get_matter_attribute_value (
197- clusters .ServiceArea .Attributes .SupportedAreas
198- )
199- if not supported_areas :
200- raise HomeAssistantError ("Can't get areas from the device." )
201-
202- # Group by area_id: {area_id: {"map_id": ..., "name": ...}}
203- areas = {}
204- for area in supported_areas :
205- area_id = getattr (area , "areaID" , None )
206- map_id = getattr (area , "mapID" , None )
207- location_name = None
208- area_info = getattr (area , "areaInfo" , None )
209- if area_info is not None :
210- location_info = getattr (area_info , "locationInfo" , None )
211- if location_info is not None :
212- location_name = getattr (location_info , "locationName" , None )
213- if area_id is not None :
214- areas [area_id ] = {"map_id" : map_id , "name" : location_name }
215-
216- # Optionally, also extract supported maps if available
217- supported_maps = self .get_matter_attribute_value (
218- clusters .ServiceArea .Attributes .SupportedMaps
219- )
220- maps = []
221- if supported_maps :
222- maps = [
223- {
224- "map_id" : getattr (m , "mapID" , None ),
225- "name" : getattr (m , "name" , None ),
226- }
227- for m in supported_maps
228- ]
229-
230- return {
231- "areas" : areas ,
232- "maps" : maps ,
233- }
234-
235- async def async_handle_get_areas (self , ** kwargs : Any ) -> ServiceResponse :
236- """Get available area and map IDs from vacuum appliance."""
237- # Group by area_id: {area_id: {"map_id": ..., "name": ...}}
238- areas = {}
239- if self ._attr_matter_areas is not None :
240- for area in self ._attr_matter_areas :
241- area_id = getattr (area , "areaID" , None )
242- map_id = getattr (area , "mapID" , None )
243- location_name = None
244- area_info = getattr (area , "areaInfo" , None )
245- if area_info is not None :
246- location_info = getattr (area_info , "locationInfo" , None )
247- if location_info is not None :
248- location_name = getattr (location_info , "locationName" , None )
249- if area_id is not None :
250- if map_id is NullValue :
251- areas [area_id ] = {"name" : location_name }
252- else :
253- areas [area_id ] = {"map_id" : map_id , "name" : location_name }
254-
255- # Optionally, also extract supported maps if available
256- supported_maps = self .get_matter_attribute_value (
257- clusters .ServiceArea .Attributes .SupportedMaps
258- )
259- maps = []
260- if supported_maps != NullValue : # chip.clusters.Types.Nullable
261- maps = [
262- {
263- "map_id" : getattr (m , "mapID" , None )
264- if getattr (m , "mapID" , None ) != NullValue
265- else None ,
266- "name" : getattr (m , "name" , None ),
267- }
268- for m in supported_maps
269- ]
270-
271- return cast (
272- ServiceResponse ,
273- {
274- "areas" : areas ,
275- "maps" : maps ,
276- },
277- )
278- return None
279-
280- async def async_handle_select_areas (
281- self , areas : list [int ], ** kwargs : Any
282- ) -> ServiceResponse :
283- """Select areas to clean."""
284- selected_areas = areas
285- # Matter command to the vacuum cleaner to select the areas.
286- await self .send_device_command (
287- clusters .ServiceArea .Commands .SelectAreas (newAreas = selected_areas )
288- )
289- # Return response indicating selected areas.
290- return cast (
291- ServiceResponse , {"status" : "areas selected" , "areas" : selected_areas }
292- )
293-
294- async def async_handle_clean_areas (
295- self , areas : list [int ], ** kwargs : Any
296- ) -> ServiceResponse :
297- """Start cleaning the specified areas."""
298- # Matter command to the vacuum cleaner to select the areas.
299- await self .send_device_command (
300- clusters .ServiceArea .Commands .SelectAreas (newAreas = areas )
301- )
302- # Start the vacuum cleaner after selecting areas.
303- await self .async_start ()
304- # Return response indicating selected areas.
305- return cast (
306- ServiceResponse , {"status" : "cleaning areas selected" , "areas" : areas }
307- )
308-
309139 @callback
310140 def _update_from_device (self ) -> None :
311141 """Update from device."""
312142 self ._calculate_features ()
313- # ServiceArea: get areas from the device
314- self ._attr_matter_areas = self .get_matter_attribute_value (
315- clusters .ServiceArea .Attributes .SupportedAreas
316- )
317- # optional CurrentArea attribute
318- # pylint: disable=too-many-nested-blocks
319- if self .get_matter_attribute_value (clusters .ServiceArea .Attributes .CurrentArea ):
320- current_area = self .get_matter_attribute_value (
321- clusters .ServiceArea .Attributes .CurrentArea
322- )
323- # get areaInfo.locationInfo.locationName for current_area in SupportedAreas list
324- area_name = None
325- if self ._attr_matter_areas :
326- for area in self ._attr_matter_areas :
327- if getattr (area , "areaID" , None ) == current_area :
328- area_info = getattr (area , "areaInfo" , None )
329- if area_info is not None :
330- location_info = getattr (area_info , "locationInfo" , None )
331- if location_info is not None :
332- area_name = getattr (location_info , "locationName" , None )
333- break
334- self ._attr_current_area = current_area
335- self ._attr_current_area_name = area_name
336- else :
337- self ._attr_current_area = None
338- self ._attr_current_area_name = None
339-
340- # optional SelectedAreas attribute
341- if self .get_matter_attribute_value (
342- clusters .ServiceArea .Attributes .SelectedAreas
343- ):
344- self ._attr_selected_areas = self .get_matter_attribute_value (
345- clusters .ServiceArea .Attributes .SelectedAreas
346- )
347143 # derive state from the run mode + operational state
348144 run_mode_raw : int = self .get_matter_attribute_value (
349145 clusters .RvcRunMode .Attributes .CurrentMode
@@ -424,10 +220,6 @@ def _calculate_features(self) -> None:
424220 clusters .RvcRunMode .Attributes .CurrentMode ,
425221 clusters .RvcOperationalState .Attributes .OperationalState ,
426222 ),
427- optional_attributes = (
428- clusters .ServiceArea .Attributes .SelectedAreas ,
429- clusters .ServiceArea .Attributes .CurrentArea ,
430- ),
431223 device_type = (device_types .RoboticVacuumCleaner ,),
432224 allow_none_value = True ,
433225 ),
0 commit comments