python-roborock 5.7.0__py3-none-any.whl → 5.8.0__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 5.7.0
3
+ Version: 5.8.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/
@@ -21,7 +21,7 @@ Requires-Dist: click-shell~=2.1
21
21
  Requires-Dist: click>=8
22
22
  Requires-Dist: construct<3,>=2.10.57
23
23
  Requires-Dist: paho-mqtt<3.0.0,>=1.6.1
24
- Requires-Dist: protobuf<7,>=6.31.1
24
+ Requires-Dist: protobuf<8,>=6.31.1
25
25
  Requires-Dist: pycryptodomex~=3.18; sys_platform == 'darwin'
26
26
  Requires-Dist: pycryptodome~=3.18
27
27
  Requires-Dist: pyrate-limiter<5,>=4.0.0
@@ -5,7 +5,7 @@ roborock/cli.py,sha256=tCxPgdBBME1ZlOgU9_-Y4i7EXC_le1amW9spFqW7fmk,50628
5
5
  roborock/const.py,sha256=fWpgUPrCgLnaXmncgjCLZET-t7wHWQlpyzV8qHtTjb4,2860
6
6
  roborock/device_features.py,sha256=uhzhVbiltYybGZGzRTpmnizmILIOeY9cavwn8gzpXWM,35879
7
7
  roborock/diagnostics.py,sha256=YIc7BhC6Cy6W2a6hykvfSRPG8NpLrPZCc_7jTX2Zdho,5091
8
- roborock/exceptions.py,sha256=2zvuNrtrnrkYXNcwIWvE2Liv_01bJIwgxenHHmliUck,2608
8
+ roborock/exceptions.py,sha256=t2YvfSRMymZPtdPV238itjxVJTaTq5-uBL_EM5FTlfg,3159
9
9
  roborock/protocol.py,sha256=eNUL6UGmtSdfsGM1mlYjmorukGGudV45iKXUA7a-Qa8,20193
10
10
  roborock/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  roborock/roborock_message.py,sha256=BPDT_uzCeD4L_4LottCMeft1kYmYPoG9ktcqqj0SYhQ,6466
@@ -27,7 +27,7 @@ roborock/data/dyad/dyad_containers.py,sha256=klJD2wV-2McjAoSN8Bthuyeid59L7M8nzSv
27
27
  roborock/data/v1/__init__.py,sha256=Lx_D6baZrCMxp57D0NcdiA8rssJ5NnInZwUwrT79XOI,91
28
28
  roborock/data/v1/v1_clean_modes.py,sha256=pJBwykCToEKZv9zs11x45Jjq3giUKfp0zibAjQ_LuOQ,7194
29
29
  roborock/data/v1/v1_code_mappings.py,sha256=qyCTWxnlyBMy8ZuoCRLR43fyLxjl_b6IfarG-M8GY-8,15251
30
- roborock/data/v1/v1_containers.py,sha256=yrv5uOdlZ1-iN8GamWajFKk7cpUTEyF8FqLTYoBW-_Y,26291
30
+ roborock/data/v1/v1_containers.py,sha256=UM8hL2xKIx1u_L-tCxjapr0lV69fzxZxIOjxpUf9ASI,26295
31
31
  roborock/data/zeo/__init__.py,sha256=VxG5qG4M24DGOq2YAaxownWp6bEfj9DEOgOMHmTpcqY,63
32
32
  roborock/data/zeo/zeo_code_mappings.py,sha256=aj-TBjLWzxSBzpBESOtwNeFwD2rv-Jj95RZidO28szA,2319
33
33
  roborock/data/zeo/zeo_containers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -57,9 +57,9 @@ roborock/devices/traits/b01/q7/map.py,sha256=Zrvj8LNctIFksCBoiZVQ1x4hgG3wwp1jqPY
57
57
  roborock/devices/traits/b01/q7/map_content.py,sha256=rI21-kMmIgf1TY98HXrWG_4rEEs9qzdYBm7RTU47yN4,3519
58
58
  roborock/devices/traits/v1/__init__.py,sha256=BIuc4Vh2aPQg8st2piHltG7mxWcGwgSwOtV1V9ftLSM,14201
59
59
  roborock/devices/traits/v1/child_lock.py,sha256=NeaPqcEoBRXvEzKZGonkyINkwCBOK3xa4zSWvJW66kA,1161
60
- roborock/devices/traits/v1/clean_summary.py,sha256=b0o_U-cGlhp1EwQ7e6SH5WzpshsuDkT2nqe7UWBt5r4,4264
60
+ roborock/devices/traits/v1/clean_summary.py,sha256=2uDl3Tg6H9INf7HTEPPat_PBgodoWeX_ko5MJgWggn8,4625
61
61
  roborock/devices/traits/v1/command.py,sha256=2yNyCF_EDPkLE_vK6IN5VB8ZVypwrrwKTByCdQzJs3c,1494
62
- roborock/devices/traits/v1/common.py,sha256=XDY-14Tx3Kgt0nlzgPXWyWXpFVzFrv4W-jUqEtAiZ_Y,6240
62
+ roborock/devices/traits/v1/common.py,sha256=1KOZImteAABc-pS1l0LGwsWPAIXakj6EYHRAAusVVm4,6602
63
63
  roborock/devices/traits/v1/consumeable.py,sha256=63Jpq_z1tAxfLnr_hgEZmQ0IBpdQbbhgeYZBPTUNgmw,1686
64
64
  roborock/devices/traits/v1/device_features.py,sha256=VKHs4gc6OJyk7f_-5uc6QdveLC20zzKNSYCt7-jyS0c,3766
65
65
  roborock/devices/traits/v1/do_not_disturb.py,sha256=_pJ-DS9r9h9eoTx1MW2MZ0RcrEh9J9gbSUPMQKoMSnE,1661
@@ -70,7 +70,7 @@ roborock/devices/traits/v1/led_status.py,sha256=qUY6GgC-RSXCAKlL2D0_FBO-1xwi2eU3
70
70
  roborock/devices/traits/v1/map_content.py,sha256=w_34H6ItiYm98QFOmEDCP0AvTBWAFVuB-uz5rmgBRwI,3175
71
71
  roborock/devices/traits/v1/maps.py,sha256=JdOjJCeJ6iAH85pNHKHbVGlD-zOrha9h6XAh7IDeQr8,3468
72
72
  roborock/devices/traits/v1/network_info.py,sha256=CX9-ye2Zb_8lAWPGvegXWSOguxMY2K0xO-2OmWmE67o,2291
73
- roborock/devices/traits/v1/rooms.py,sha256=md1J3h0Vx2UZK_10QlXWuTk1wFEtD7BEEYtFQMP2Zis,4850
73
+ roborock/devices/traits/v1/rooms.py,sha256=o1VEb2OxedhCHxfKYZLhoBBvNZpsVuzqYUUap3DgGrA,5353
74
74
  roborock/devices/traits/v1/routines.py,sha256=BfktlpnyDjD2DB3zBDS5BnmjZPE38aHa-wjMontPnik,931
75
75
  roborock/devices/traits/v1/smart_wash_params.py,sha256=fAhJpMgUUP1kJcfEAAPeD3anMmCsuX7I1SEoUrUgfjE,504
76
76
  roborock/devices/traits/v1/status.py,sha256=F-2WyGv2xT6PM_dD7dyepZ-mvma9dBvNN5F5A1IVEhA,3158
@@ -96,8 +96,8 @@ roborock/protocols/a01_protocol.py,sha256=JCIhUuVNamcENu0gtZR2x8rBz6dpAZLcbA-NQg
96
96
  roborock/protocols/b01_q10_protocol.py,sha256=SimfXpQotkEkb58ThZq7xa7fCxPxF-hrpAJcRKI-yZE,3407
97
97
  roborock/protocols/b01_q7_protocol.py,sha256=o8repRrxhxknzspsg1K27ds643rs87ilWXbj8RJtOCs,4619
98
98
  roborock/protocols/v1_protocol.py,sha256=bSWqNJYL9feHmWch4OxoL6fVZwXf_YOjt3QnvdNsC24,9635
99
- python_roborock-5.7.0.dist-info/METADATA,sha256=oYDzsKNa6WzIyn3_cMEuFrgl95lRRO4IFneUUABIuxo,4962
100
- python_roborock-5.7.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
101
- python_roborock-5.7.0.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
102
- python_roborock-5.7.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
103
- python_roborock-5.7.0.dist-info/RECORD,,
99
+ python_roborock-5.8.0.dist-info/METADATA,sha256=nZkO5gqv23iCmcvNjDPgRJWwv09BRQWC92_lCI3hsoY,4962
100
+ python_roborock-5.8.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
101
+ python_roborock-5.8.0.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
102
+ python_roborock-5.8.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
103
+ python_roborock-5.8.0.dist-info/RECORD,,
@@ -792,7 +792,7 @@ class AppInitStatusLocalInfo(RoborockBase):
792
792
  class AppInitStatus(RoborockBase):
793
793
  local_info: AppInitStatusLocalInfo
794
794
  feature_info: list[int]
795
- new_feature_info: int
795
+ new_feature_info: int = 0
796
796
  new_feature_info_str: str = ""
797
797
  new_feature_info_2: int | None = None
798
798
  carriage_type: int | None = None
@@ -2,6 +2,7 @@ import logging
2
2
 
3
3
  from roborock.data import CleanRecord, CleanSummaryWithDetail, RoborockBase
4
4
  from roborock.devices.traits.v1 import common
5
+ from roborock.exceptions import RoborockParsingException
5
6
  from roborock.roborock_typing import RoborockCommand
6
7
  from roborock.util import unpack_list
7
8
 
@@ -87,4 +88,12 @@ class CleanSummaryTrait(CleanSummaryWithDetail, common.V1TraitMixin):
87
88
  async def get_clean_record(self, record_id: int) -> CleanRecord:
88
89
  """Load a specific clean record by ID."""
89
90
  response = await self.rpc_channel.send_command(RoborockCommand.GET_CLEAN_RECORD, params=[record_id])
90
- return self.clean_record_converter.convert(response)
91
+ try:
92
+ return self.clean_record_converter.convert(response)
93
+ except (TypeError, ValueError) as err:
94
+ raise RoborockParsingException(
95
+ trait_name=type(self).__name__,
96
+ command=RoborockCommand.GET_CLEAN_RECORD,
97
+ payload=response,
98
+ inner_error=err,
99
+ ) from err
@@ -9,6 +9,7 @@ from dataclasses import fields
9
9
  from typing import ClassVar
10
10
 
11
11
  from roborock.data import RoborockBase
12
+ from roborock.exceptions import RoborockParsingException
12
13
  from roborock.protocols.v1_protocol import V1RpcChannel
13
14
  from roborock.roborock_typing import RoborockCommand
14
15
 
@@ -63,7 +64,7 @@ class V1TraitMixin(ABC):
63
64
 
64
65
  def __init__(self) -> None:
65
66
  """Initialize the V1TraitMixin."""
66
- self._rpc_channel = None
67
+ self._rpc_channel: V1RpcChannel | None = None
67
68
 
68
69
  @property
69
70
  def rpc_channel(self) -> V1RpcChannel:
@@ -75,7 +76,15 @@ class V1TraitMixin(ABC):
75
76
  async def refresh(self) -> None:
76
77
  """Refresh the contents of this trait."""
77
78
  response = await self.rpc_channel.send_command(self.command)
78
- new_data = self.converter.convert(response)
79
+ try:
80
+ new_data = self.converter.convert(response)
81
+ except (TypeError, ValueError) as err:
82
+ raise RoborockParsingException(
83
+ trait_name=type(self).__name__,
84
+ command=self.command,
85
+ payload=response,
86
+ inner_error=err,
87
+ ) from err
79
88
  merge_trait_values(self, new_data) # type: ignore[arg-type]
80
89
 
81
90
 
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
 
6
6
  from roborock.data import HomeData, HomeDataRoom, NamedRoomMapping, RoborockBase
7
7
  from roborock.devices.traits.v1 import common
8
+ from roborock.exceptions import RoborockParsingException
8
9
  from roborock.roborock_typing import RoborockCommand
9
10
  from roborock.web_api import UserWebApiClient
10
11
 
@@ -94,7 +95,12 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
94
95
  """Refresh room mappings and backfill unknown room names from the web API."""
95
96
  response = await self.rpc_channel.send_command(self.command)
96
97
  if not isinstance(response, list):
97
- raise ValueError(f"Unexpected RoomsTrait response format: {response!r}")
98
+ raise RoborockParsingException(
99
+ trait_name=type(self).__name__,
100
+ command=self.command,
101
+ payload=response,
102
+ inner_error="Unexpected RoomsTrait response format",
103
+ )
98
104
 
99
105
  segment_map = RoomsConverter.extract_segment_map(response)
100
106
  # Track all iot ids seen before. Refresh the room list when new ids are found.
@@ -105,8 +111,16 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
105
111
  _LOGGER.debug("Updating rooms: %s", list(updated_rooms))
106
112
  self._home_data.rooms = updated_rooms
107
113
  self._discovered_iot_ids.update(new_iot_ids)
114
+ try:
115
+ rooms = self.converter.convert(response)
116
+ except (TypeError, ValueError) as err:
117
+ raise RoborockParsingException(
118
+ trait_name=type(self).__name__,
119
+ command=self.command,
120
+ payload=response,
121
+ inner_error=err,
122
+ ) from err
108
123
 
109
- rooms = self.converter.convert(response)
110
124
  rooms = rooms.with_room_names(self._home_data.rooms_name_map)
111
125
  common.merge_trait_values(self, rooms)
112
126
 
roborock/exceptions.py CHANGED
@@ -1,5 +1,8 @@
1
1
  """Roborock exceptions."""
2
2
 
3
+ from enum import Enum
4
+ from typing import Any
5
+
3
6
 
4
7
  class RoborockException(Exception):
5
8
  """Class for Roborock exceptions."""
@@ -91,3 +94,14 @@ class RoborockInvalidStatus(RoborockException):
91
94
 
92
95
  class RoborockUnsupportedFeature(RoborockException):
93
96
  """Class for Roborock unsupported feature exceptions."""
97
+
98
+
99
+ class RoborockParsingException(RoborockException):
100
+ """Class for Roborock exceptions when parsing device responses."""
101
+
102
+ def __init__(self, trait_name: str, command: Enum | str, payload: Any, inner_error: Exception | str) -> None:
103
+ cmd_name = command.name if isinstance(command, Enum) else str(command)
104
+ self.message = (
105
+ f"Failed to parse {cmd_name} response for {trait_name}. Payload: {payload!r} Error: {inner_error!r}"
106
+ )
107
+ super().__init__(self.message)