python-roborock 4.19.0__tar.gz → 4.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. {python_roborock-4.19.0 → python_roborock-4.20.0}/PKG-INFO +1 -1
  2. {python_roborock-4.19.0 → python_roborock-4.20.0}/pyproject.toml +1 -1
  3. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/containers.py +27 -2
  4. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/v1/v1_containers.py +22 -1
  5. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/home.py +20 -24
  6. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/rooms.py +22 -30
  7. {python_roborock-4.19.0 → python_roborock-4.20.0}/.gitignore +0 -0
  8. {python_roborock-4.19.0 → python_roborock-4.20.0}/LICENSE +0 -0
  9. {python_roborock-4.19.0 → python_roborock-4.20.0}/README.md +0 -0
  10. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/__init__.py +0 -0
  11. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/broadcast_protocol.py +0 -0
  12. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/callbacks.py +0 -0
  13. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/cli.py +0 -0
  14. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/const.py +0 -0
  15. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/__init__.py +0 -0
  16. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q10/__init__.py +0 -0
  17. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  18. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  19. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q7/__init__.py +0 -0
  20. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  21. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  22. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/code_mappings.py +0 -0
  23. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/dyad/__init__.py +0 -0
  24. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  25. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/dyad/dyad_containers.py +0 -0
  26. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/v1/__init__.py +0 -0
  27. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/v1/v1_clean_modes.py +0 -0
  28. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/v1/v1_code_mappings.py +0 -0
  29. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/zeo/__init__.py +0 -0
  30. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  31. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/data/zeo/zeo_containers.py +0 -0
  32. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/device_features.py +0 -0
  33. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/README.md +0 -0
  34. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/__init__.py +0 -0
  35. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/cache.py +0 -0
  36. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/device.py +0 -0
  37. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/device_manager.py +0 -0
  38. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/file_cache.py +0 -0
  39. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/rpc/__init__.py +0 -0
  40. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/rpc/a01_channel.py +0 -0
  41. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  42. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  43. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/rpc/v1_channel.py +0 -0
  44. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/__init__.py +0 -0
  45. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/a01/__init__.py +0 -0
  46. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/__init__.py +0 -0
  47. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  48. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q10/command.py +0 -0
  49. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q10/common.py +0 -0
  50. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q10/status.py +0 -0
  51. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
  52. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  53. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
  54. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/traits_mixin.py +0 -0
  55. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/__init__.py +0 -0
  56. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/child_lock.py +0 -0
  57. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
  58. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/command.py +0 -0
  59. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/common.py +0 -0
  60. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/consumeable.py +0 -0
  61. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/device_features.py +0 -0
  62. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  63. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  64. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  65. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/led_status.py +0 -0
  66. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/map_content.py +0 -0
  67. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/maps.py +0 -0
  68. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/network_info.py +0 -0
  69. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/routines.py +0 -0
  70. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  71. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/status.py +0 -0
  72. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  73. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/volume.py +0 -0
  74. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  75. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/transport/__init__.py +0 -0
  76. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/transport/channel.py +0 -0
  77. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/transport/local_channel.py +0 -0
  78. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/devices/transport/mqtt_channel.py +0 -0
  79. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/diagnostics.py +0 -0
  80. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/exceptions.py +0 -0
  81. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/map/__init__.py +0 -0
  82. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/map/map_parser.py +0 -0
  83. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/mqtt/__init__.py +0 -0
  84. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/mqtt/health_manager.py +0 -0
  85. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/mqtt/roborock_session.py +0 -0
  86. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/mqtt/session.py +0 -0
  87. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocol.py +0 -0
  88. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocols/__init__.py +0 -0
  89. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocols/a01_protocol.py +0 -0
  90. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocols/b01_q10_protocol.py +0 -0
  91. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocols/b01_q7_protocol.py +0 -0
  92. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/protocols/v1_protocol.py +0 -0
  93. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/py.typed +0 -0
  94. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/roborock_message.py +0 -0
  95. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/roborock_typing.py +0 -0
  96. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/util.py +0 -0
  97. {python_roborock-4.19.0 → python_roborock-4.20.0}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 4.19.0
3
+ Version: 4.20.0
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/humbertogontijo/python-roborock
6
6
  Project-URL: Documentation, https://python-roborock.readthedocs.io/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-roborock"
3
- version = "4.19.0"
3
+ version = "4.20.0"
4
4
  description = "A package to control Roborock vacuums."
5
5
  authors = [{ name = "humbertogontijo", email = "humbertogontijo@users.noreply.github.com" }, {name="Lash-L"}, {name="allenporter"}]
6
6
  requires-python = ">=3.11, <4"
@@ -301,6 +301,11 @@ class HomeDataRoom(RoborockBase):
301
301
  id: int
302
302
  name: str
303
303
 
304
+ @property
305
+ def iot_id(self) -> str:
306
+ """Return the room's ID as a string IOT ID."""
307
+ return str(self.id)
308
+
304
309
 
305
310
  @dataclass
306
311
  class HomeDataScene(RoborockBase):
@@ -352,6 +357,16 @@ class HomeData(RoborockBase):
352
357
  if (product := product_map.get(device.product_id)) is not None
353
358
  }
354
359
 
360
+ @property
361
+ def rooms_map(self) -> dict[str, HomeDataRoom]:
362
+ """Returns a dictionary of Room iot_id to rooms"""
363
+ return {room.iot_id: room for room in self.rooms}
364
+
365
+ @property
366
+ def rooms_name_map(self) -> dict[str, str]:
367
+ """Returns a dictionary of Room iot_id to room names."""
368
+ return {room.iot_id: room.name for room in self.rooms}
369
+
355
370
 
356
371
  @dataclass
357
372
  class LoginData(RoborockBase):
@@ -388,8 +403,13 @@ class NamedRoomMapping(RoomMapping):
388
403
  from the HomeData based on the iot_id from the room.
389
404
  """
390
405
 
391
- name: str
392
- """The human-readable name of the room, if available."""
406
+ @property
407
+ def name(self) -> str:
408
+ """The human-readable name of the room, or a default name if not available."""
409
+ return self.raw_name or f"Room {self.segment_id}"
410
+
411
+ raw_name: str | None = None
412
+ """The raw name of the room, as provided by the device."""
393
413
 
394
414
 
395
415
  @dataclass
@@ -409,6 +429,11 @@ class CombinedMapInfo(RoborockBase):
409
429
  rooms: list[NamedRoomMapping]
410
430
  """The list of rooms in the map."""
411
431
 
432
+ @property
433
+ def rooms_map(self) -> dict[int, NamedRoomMapping]:
434
+ """Returns a mapping of segment_id to NamedRoomMapping."""
435
+ return {room.segment_id: room for room in self.rooms}
436
+
412
437
 
413
438
  @dataclass
414
439
  class BroadcastMessage(RoborockBase):
@@ -38,7 +38,7 @@ from roborock.const import (
38
38
  )
39
39
  from roborock.exceptions import RoborockException
40
40
 
41
- from ..containers import RoborockBase, RoborockBaseTimer, _attr_repr
41
+ from ..containers import NamedRoomMapping, RoborockBase, RoborockBaseTimer, _attr_repr
42
42
  from .v1_code_mappings import (
43
43
  CleanFluidStatus,
44
44
  ClearWaterBoxStatus,
@@ -400,6 +400,7 @@ class StatusV2(RoborockBase):
400
400
  value = (self.dss >> 10) & 3
401
401
  if value == 0:
402
402
  return None # Feature not supported by this device
403
+ return CleanFluidStatus(value)
403
404
  return None
404
405
 
405
406
  @property
@@ -686,6 +687,17 @@ class MultiMapsListRoom(RoborockBase):
686
687
  iot_name_id: str | None = None
687
688
  iot_name: str | None = None
688
689
 
690
+ @property
691
+ def named_room_mapping(self) -> NamedRoomMapping | None:
692
+ """Returns a NamedRoomMapping object if valid."""
693
+ if self.id is None or self.iot_name_id is None:
694
+ return None
695
+ return NamedRoomMapping(
696
+ segment_id=self.id,
697
+ iot_id=self.iot_name_id,
698
+ raw_name=self.iot_name,
699
+ )
700
+
689
701
 
690
702
  @dataclass
691
703
  class MultiMapsListMapInfoBakMaps(RoborockBase):
@@ -707,6 +719,15 @@ class MultiMapsListMapInfo(RoborockBase):
707
719
  """Alias for map_flag, returns the map flag as an integer."""
708
720
  return self.map_flag
709
721
 
722
+ @property
723
+ def rooms_map(self) -> dict[int, NamedRoomMapping]:
724
+ """Returns a dictionary of room mappings by segment id."""
725
+ return {
726
+ room.id: mapping
727
+ for room in self.rooms or ()
728
+ if room.id is not None and (mapping := room.named_room_mapping) is not None
729
+ }
730
+
710
731
 
711
732
  @dataclass
712
733
  class MultiMapsList(RoborockBase):
@@ -20,7 +20,7 @@ import base64
20
20
  import logging
21
21
  from typing import Self
22
22
 
23
- from roborock.data import CombinedMapInfo, NamedRoomMapping, RoborockBase
23
+ from roborock.data import CombinedMapInfo, MultiMapsListMapInfo, NamedRoomMapping, RoborockBase
24
24
  from roborock.data.v1.v1_code_mappings import RoborockStateCode
25
25
  from roborock.devices.cache import DeviceCache
26
26
  from roborock.devices.traits.v1 import common
@@ -114,35 +114,24 @@ class HomeTrait(RoborockBase, common.V1TraitMixin):
114
114
  self._discovery_completed = True
115
115
  await self._update_home_cache(home_map_info, home_map_content)
116
116
 
117
- async def _refresh_map_info(self, map_info) -> CombinedMapInfo:
117
+ async def _refresh_map_info(self, map_info: MultiMapsListMapInfo) -> CombinedMapInfo:
118
118
  """Collect room data for a specific map and return CombinedMapInfo."""
119
119
  await self._rooms_trait.refresh()
120
120
 
121
- rooms: dict[int, NamedRoomMapping] = {}
122
- if map_info.rooms:
123
- # Not all vacuums respond with rooms inside map_info.
124
- # If we can determine if all vacuums will return everything with get_rooms, we could remove this step.
125
- for room in map_info.rooms:
126
- if room.id is not None and room.iot_name_id is not None:
127
- rooms[room.id] = NamedRoomMapping(
128
- segment_id=room.id,
129
- iot_id=room.iot_name_id,
130
- name=room.iot_name or f"Room {room.id}",
131
- )
132
-
133
- # Add rooms from rooms_trait.
134
- # Keep existing names from map_info unless they are fallback names.
135
- if self._rooms_trait.rooms:
136
- for room in self._rooms_trait.rooms:
137
- if room.segment_id is not None and room.name:
138
- existing_room = rooms.get(room.segment_id)
139
- if existing_room is None or existing_room.name == f"Room {room.segment_id}":
140
- rooms[room.segment_id] = room
141
-
121
+ # We have room names from multiple sources:
122
+ # - The map_info.rooms which we just received from the MultiMapsList
123
+ # - RoomsTrait rooms come from the GET_ROOM_MAPPING command for the current device (only)
124
+ # - RoomsTrait rooms that are pulled from the cloud API
125
+ # We always prefer the RoomsTrait room names since they are always newer and
126
+ # just refreshed above.
127
+ rooms_map: dict[int, NamedRoomMapping] = {
128
+ **map_info.rooms_map,
129
+ **{room.segment_id: room for room in self._rooms_trait.rooms or ()},
130
+ }
142
131
  return CombinedMapInfo(
143
132
  map_flag=map_info.map_flag,
144
133
  name=map_info.name,
145
- rooms=list(rooms.values()),
134
+ rooms=list(rooms_map.values()),
146
135
  )
147
136
 
148
137
  async def _refresh_map_content(self) -> MapContent:
@@ -232,6 +221,13 @@ class HomeTrait(RoborockBase, common.V1TraitMixin):
232
221
  return None
233
222
  return self._home_map_info.get(current_map_flag)
234
223
 
224
+ @property
225
+ def current_rooms(self) -> list[NamedRoomMapping]:
226
+ """Returns the room names for the current map."""
227
+ if self.current_map_data is None:
228
+ return []
229
+ return self.current_map_data.rooms
230
+
235
231
  @property
236
232
  def home_map_content(self) -> dict[int, MapContent] | None:
237
233
  """Returns the map content for all cached maps."""
@@ -3,7 +3,7 @@
3
3
  import logging
4
4
  from dataclasses import dataclass
5
5
 
6
- from roborock.data import HomeData, NamedRoomMapping, RoborockBase
6
+ from roborock.data import HomeData, HomeDataRoom, NamedRoomMapping, RoborockBase
7
7
  from roborock.devices.traits.v1 import common
8
8
  from roborock.roborock_typing import RoborockCommand
9
9
  from roborock.web_api import UserWebApiClient
@@ -36,7 +36,7 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
36
36
  super().__init__()
37
37
  self._home_data = home_data
38
38
  self._web_api = web_api
39
- self._seen_unknown_room_iot_ids: set[str] = set()
39
+ self._discovered_iot_ids: set[str] = set()
40
40
 
41
41
  async def refresh(self) -> None:
42
42
  """Refresh room mappings and backfill unknown room names from the web API."""
@@ -45,47 +45,39 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
45
45
  raise ValueError(f"Unexpected RoomsTrait response format: {response!r}")
46
46
 
47
47
  segment_map = _extract_segment_map(response)
48
- await self._populate_missing_home_data_rooms(segment_map)
49
-
50
- new_data = self._parse_response(response, segment_map)
48
+ # Track all iot ids seen before. Refresh the room list when new ids are found.
49
+ new_iot_ids = set(segment_map.values()) - set(self._home_data.rooms_map.keys())
50
+ if new_iot_ids - self._discovered_iot_ids:
51
+ _LOGGER.debug("Refreshing room list to discover new room names")
52
+ if updated_rooms := await self._refresh_rooms():
53
+ _LOGGER.debug("Updating rooms: %s", list(updated_rooms))
54
+ self._home_data.rooms = updated_rooms
55
+ self._discovered_iot_ids.update(new_iot_ids)
56
+
57
+ new_data = self._parse_rooms(segment_map, self._home_data.rooms_name_map)
51
58
  self._update_trait_values(new_data)
52
59
  _LOGGER.debug("Refreshed %s: %s", self.__class__.__name__, new_data)
53
60
 
54
- @property
55
- def _iot_id_room_name_map(self) -> dict[str, str]:
56
- """Returns a dictionary of Room IOT IDs to room names."""
57
- return {str(room.id): room.name for room in self._home_data.rooms or ()}
58
-
59
- def _parse_response(self, response: common.V1ResponseData, segment_map: dict[int, str] | None = None) -> Rooms:
61
+ @staticmethod
62
+ def _parse_rooms(
63
+ segment_map: dict[int, str],
64
+ name_map: dict[str, str],
65
+ ) -> Rooms:
60
66
  """Parse the response from the device into a list of NamedRoomMapping."""
61
- if not isinstance(response, list):
62
- raise ValueError(f"Unexpected RoomsTrait response format: {response!r}")
63
- if segment_map is None:
64
- segment_map = _extract_segment_map(response)
65
- name_map = self._iot_id_room_name_map
66
67
  return Rooms(
67
68
  rooms=[
68
- NamedRoomMapping(segment_id=segment_id, iot_id=iot_id, name=name_map.get(iot_id, f"Room {segment_id}"))
69
+ NamedRoomMapping(segment_id=segment_id, iot_id=iot_id, raw_name=name_map.get(iot_id))
69
70
  for segment_id, iot_id in segment_map.items()
70
71
  ]
71
72
  )
72
73
 
73
- async def _populate_missing_home_data_rooms(self, segment_map: dict[int, str]) -> None:
74
- """Load missing room names into home data for newly-seen unknown room ids."""
75
- missing_room_iot_ids = set(segment_map.values()) - set(self._iot_id_room_name_map.keys())
76
- new_missing_room_iot_ids = missing_room_iot_ids - self._seen_unknown_room_iot_ids
77
- if not new_missing_room_iot_ids:
78
- return
79
-
74
+ async def _refresh_rooms(self) -> list[HomeDataRoom]:
75
+ """Fetch the latest rooms from the web API."""
80
76
  try:
81
- web_rooms = await self._web_api.get_rooms()
77
+ return await self._web_api.get_rooms()
82
78
  except Exception:
83
79
  _LOGGER.debug("Failed to fetch rooms from web API", exc_info=True)
84
- else:
85
- if isinstance(web_rooms, list) and web_rooms:
86
- self._home_data.rooms = web_rooms
87
-
88
- self._seen_unknown_room_iot_ids.update(missing_room_iot_ids)
80
+ return []
89
81
 
90
82
 
91
83
  def _extract_segment_map(response: list) -> dict[int, str]: