python-roborock 5.14.2__tar.gz → 5.15.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 (104) hide show
  1. {python_roborock-5.14.2 → python_roborock-5.15.0}/PKG-INFO +1 -1
  2. {python_roborock-5.14.2 → python_roborock-5.15.0}/pyproject.toml +1 -1
  3. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/__init__.py +1 -1
  4. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/rooms.py +20 -4
  5. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/web_api.py +31 -0
  6. {python_roborock-5.14.2 → python_roborock-5.15.0}/.gitignore +0 -0
  7. {python_roborock-5.14.2 → python_roborock-5.15.0}/LICENSE +0 -0
  8. {python_roborock-5.14.2 → python_roborock-5.15.0}/README.md +0 -0
  9. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/__init__.py +0 -0
  10. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/broadcast_protocol.py +0 -0
  11. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/callbacks.py +0 -0
  12. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/cli.py +0 -0
  13. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/const.py +0 -0
  14. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/__init__.py +0 -0
  15. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q10/__init__.py +0 -0
  16. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  17. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  18. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q7/__init__.py +0 -0
  19. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  20. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  21. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/code_mappings.py +0 -0
  22. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/containers.py +0 -0
  23. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/dyad/__init__.py +0 -0
  24. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  25. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/dyad/dyad_containers.py +0 -0
  26. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/v1/__init__.py +0 -0
  27. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/v1/v1_clean_modes.py +0 -0
  28. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/v1/v1_code_mappings.py +0 -0
  29. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/v1/v1_containers.py +0 -0
  30. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/zeo/__init__.py +0 -0
  31. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  32. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/data/zeo/zeo_containers.py +0 -0
  33. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/device_features.py +0 -0
  34. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/README.md +0 -0
  35. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/__init__.py +0 -0
  36. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/cache.py +0 -0
  37. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/device.py +0 -0
  38. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/device_manager.py +0 -0
  39. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/file_cache.py +0 -0
  40. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/rpc/__init__.py +0 -0
  41. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/rpc/a01_channel.py +0 -0
  42. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  43. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  44. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/rpc/v1_channel.py +0 -0
  45. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/__init__.py +0 -0
  46. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/a01/__init__.py +0 -0
  47. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/__init__.py +0 -0
  48. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  49. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q10/command.py +0 -0
  50. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q10/remote.py +0 -0
  51. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q10/status.py +0 -0
  52. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
  53. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  54. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
  55. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q7/map.py +0 -0
  56. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/b01/q7/map_content.py +0 -0
  57. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/common.py +0 -0
  58. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/traits_mixin.py +0 -0
  59. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/child_lock.py +0 -0
  60. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
  61. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/command.py +0 -0
  62. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/common.py +0 -0
  63. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/consumeable.py +0 -0
  64. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/device_features.py +0 -0
  65. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  66. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  67. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  68. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/home.py +0 -0
  69. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/led_status.py +0 -0
  70. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/map_content.py +0 -0
  71. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/maps.py +0 -0
  72. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/network_info.py +0 -0
  73. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/routines.py +0 -0
  74. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  75. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/status.py +0 -0
  76. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  77. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/volume.py +0 -0
  78. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  79. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/transport/__init__.py +0 -0
  80. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/transport/channel.py +0 -0
  81. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/transport/local_channel.py +0 -0
  82. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/devices/transport/mqtt_channel.py +0 -0
  83. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/diagnostics.py +0 -0
  84. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/exceptions.py +0 -0
  85. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/__init__.py +0 -0
  86. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/b01_map_parser.py +0 -0
  87. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/map_parser.py +0 -0
  88. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/proto/__init__.py +0 -0
  89. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/proto/b01_scmap.proto +0 -0
  90. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/map/proto/b01_scmap_pb2.py +0 -0
  91. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/mqtt/__init__.py +0 -0
  92. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/mqtt/health_manager.py +0 -0
  93. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/mqtt/roborock_session.py +0 -0
  94. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/mqtt/session.py +0 -0
  95. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocol.py +0 -0
  96. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocols/__init__.py +0 -0
  97. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocols/a01_protocol.py +0 -0
  98. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocols/b01_q10_protocol.py +0 -0
  99. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocols/b01_q7_protocol.py +0 -0
  100. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/protocols/v1_protocol.py +0 -0
  101. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/py.typed +0 -0
  102. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/roborock_message.py +0 -0
  103. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/roborock_typing.py +0 -0
  104. {python_roborock-5.14.2 → python_roborock-5.15.0}/roborock/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 5.14.2
3
+ Version: 5.15.0
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/python-roborock/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 = "5.14.2"
3
+ version = "5.15.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"
@@ -199,7 +199,7 @@ class PropertiesApi(Trait):
199
199
  self.device_features = DeviceFeaturesTrait(product, self._device_cache)
200
200
  self.status = StatusTrait(self.device_features, region=self._region)
201
201
  self.consumables = ConsumableTrait()
202
- self.rooms = RoomsTrait(home_data, web_api)
202
+ self.rooms = RoomsTrait(home_data, device_uid, web_api)
203
203
  self.maps = MapsTrait(self.status)
204
204
  self.map_content = MapContentTrait(map_parser_config)
205
205
  self.home = HomeTrait(self.status, self.maps, self.map_content, self.rooms, self._device_cache)
@@ -84,12 +84,21 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
84
84
  command = RoborockCommand.GET_ROOM_MAPPING
85
85
  converter = RoomsConverter()
86
86
 
87
- def __init__(self, home_data: HomeData, web_api: UserWebApiClient) -> None:
87
+ def __init__(self, home_data: HomeData, device_uid: str, web_api: UserWebApiClient) -> None:
88
88
  """Initialize the RoomsTrait."""
89
89
  super().__init__()
90
90
  self._home_data = home_data
91
+ self._device_uid = device_uid
92
+ self._shared_device_uid = next(
93
+ (device.duid for device in home_data.received_devices if device.duid == device_uid), None
94
+ )
91
95
  self._web_api = web_api
92
96
  self._discovered_iot_ids: set[str] = set()
97
+ self._room_names: dict[str, str] = dict(home_data.rooms_name_map)
98
+
99
+ @property
100
+ def _room_name_map(self) -> dict[str, str]:
101
+ return self._room_names
93
102
 
94
103
  async def refresh(self) -> None:
95
104
  """Refresh room mappings and backfill unknown room names from the web API."""
@@ -104,12 +113,14 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
104
113
 
105
114
  segment_map = RoomsConverter.extract_segment_map(response)
106
115
  # Track all iot ids seen before. Refresh the room list when new ids are found.
107
- new_iot_ids = set(segment_map.values()) - set(self._home_data.rooms_map.keys())
116
+ new_iot_ids = set(segment_map.values()) - set(self._room_name_map.keys())
108
117
  if new_iot_ids - self._discovered_iot_ids:
109
118
  _LOGGER.debug("Refreshing room list to discover new room names")
110
119
  if updated_rooms := await self._refresh_rooms():
111
120
  _LOGGER.debug("Updating rooms: %s", list(updated_rooms))
112
- self._home_data.rooms = updated_rooms
121
+ self._room_names = {room.iot_id: room.name for room in updated_rooms}
122
+ if self._shared_device_uid is None:
123
+ self._home_data.rooms = updated_rooms
113
124
  self._discovered_iot_ids.update(new_iot_ids)
114
125
  try:
115
126
  rooms = self.converter.convert(response)
@@ -121,12 +132,17 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
121
132
  inner_error=err,
122
133
  ) from err
123
134
 
124
- rooms = rooms.with_room_names(self._home_data.rooms_name_map)
135
+ rooms = rooms.with_room_names(self._room_name_map)
125
136
  common.merge_trait_values(self, rooms)
126
137
 
127
138
  async def _refresh_rooms(self) -> list[HomeDataRoom]:
128
139
  """Fetch the latest rooms from the web API."""
129
140
  try:
141
+ if self._shared_device_uid is not None:
142
+ rooms_by_id = {room.iot_id: room for room in self._home_data.rooms}
143
+ shared_rooms = await self._web_api.get_shared_device_rooms(self._shared_device_uid)
144
+ rooms_by_id.update({room.iot_id: room for room in shared_rooms})
145
+ return list(rooms_by_id.values())
130
146
  return await self._web_api.get_rooms()
131
147
  except Exception:
132
148
  _LOGGER.debug("Failed to fetch rooms from web API", exc_info=True)
@@ -558,6 +558,33 @@ class RoborockApiClient:
558
558
  else:
559
559
  raise RoborockException("home_response result was an unexpected type")
560
560
 
561
+ async def get_shared_device_rooms(self, user_data: UserData, device_id: str) -> list[HomeDataRoom]:
562
+ """Fetch room names for a shared (received) device."""
563
+ rriot = user_data.rriot
564
+ if rriot is None:
565
+ raise RoborockException("rriot is none")
566
+ if rriot.r.a is None:
567
+ raise RoborockException("Missing field 'a' in rriot reference")
568
+ path = f"/user/deviceshare/query/{device_id}/rooms"
569
+ room_request = PreparedRequest(
570
+ rriot.r.a,
571
+ self.session,
572
+ {"Authorization": _get_hawk_authentication(rriot, path)},
573
+ )
574
+ room_response = await room_request.request("get", path)
575
+ if not room_response.get("success"):
576
+ raise RoborockException(room_response)
577
+ rooms = room_response.get("result")
578
+ if isinstance(rooms, list):
579
+ output_list = []
580
+ for room in rooms:
581
+ normalized_room = room
582
+ if isinstance(room, dict) and "id" not in room and "roomId" in room:
583
+ normalized_room = {**room, "id": room["roomId"]}
584
+ output_list.append(HomeDataRoom.from_dict(normalized_room))
585
+ return output_list
586
+ raise RoborockException("get_shared_device_rooms result was an unexpected type")
587
+
561
588
  async def get_scenes(self, user_data: UserData, device_id: str) -> list[HomeDataScene]:
562
589
  rriot = user_data.rriot
563
590
  if rriot is None:
@@ -775,6 +802,10 @@ class UserWebApiClient:
775
802
  self._unauthorized_hook()
776
803
  raise
777
804
 
805
+ async def get_shared_device_rooms(self, device_id: str) -> list[HomeDataRoom]:
806
+ """Fetch shared-device rooms using the API client."""
807
+ return await self._web_api.get_shared_device_rooms(self._user_data, device_id)
808
+
778
809
  async def execute_routine(self, scene_id: int) -> None:
779
810
  """Execute a specific routine (scene) by its ID."""
780
811
  try: