python-roborock 4.7.1__tar.gz → 4.7.2__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 (93) hide show
  1. {python_roborock-4.7.1 → python_roborock-4.7.2}/PKG-INFO +1 -1
  2. {python_roborock-4.7.1 → python_roborock-4.7.2}/pyproject.toml +1 -1
  3. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/home.py +7 -2
  4. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/exceptions.py +4 -0
  5. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocols/v1_protocol.py +42 -12
  6. {python_roborock-4.7.1 → python_roborock-4.7.2}/.gitignore +0 -0
  7. {python_roborock-4.7.1 → python_roborock-4.7.2}/LICENSE +0 -0
  8. {python_roborock-4.7.1 → python_roborock-4.7.2}/README.md +0 -0
  9. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/__init__.py +0 -0
  10. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/broadcast_protocol.py +0 -0
  11. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/callbacks.py +0 -0
  12. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/cli.py +0 -0
  13. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/const.py +0 -0
  14. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/__init__.py +0 -0
  15. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q10/__init__.py +0 -0
  16. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  17. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  18. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q7/__init__.py +0 -0
  19. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  20. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  21. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/code_mappings.py +0 -0
  22. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/containers.py +0 -0
  23. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/dyad/__init__.py +0 -0
  24. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  25. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/dyad/dyad_containers.py +0 -0
  26. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/v1/__init__.py +0 -0
  27. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/v1/v1_clean_modes.py +0 -0
  28. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/v1/v1_code_mappings.py +0 -0
  29. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/v1/v1_containers.py +0 -0
  30. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/zeo/__init__.py +0 -0
  31. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  32. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/data/zeo/zeo_containers.py +0 -0
  33. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/device_features.py +0 -0
  34. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/README.md +0 -0
  35. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/__init__.py +0 -0
  36. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/cache.py +0 -0
  37. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/device.py +0 -0
  38. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/device_manager.py +0 -0
  39. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/file_cache.py +0 -0
  40. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/rpc/__init__.py +0 -0
  41. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/rpc/a01_channel.py +0 -0
  42. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  43. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  44. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/rpc/v1_channel.py +0 -0
  45. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/__init__.py +0 -0
  46. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/a01/__init__.py +0 -0
  47. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/b01/__init__.py +0 -0
  48. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  49. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/b01/q10/command.py +0 -0
  50. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  51. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/traits_mixin.py +0 -0
  52. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/__init__.py +0 -0
  53. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/child_lock.py +0 -0
  54. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/clean_summary.py +0 -0
  55. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/command.py +0 -0
  56. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/common.py +0 -0
  57. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/consumeable.py +0 -0
  58. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/device_features.py +0 -0
  59. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  60. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  61. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  62. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/led_status.py +0 -0
  63. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/map_content.py +0 -0
  64. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/maps.py +0 -0
  65. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/network_info.py +0 -0
  66. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/rooms.py +0 -0
  67. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/routines.py +0 -0
  68. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  69. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/status.py +0 -0
  70. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  71. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/volume.py +0 -0
  72. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  73. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/transport/__init__.py +0 -0
  74. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/transport/channel.py +0 -0
  75. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/transport/local_channel.py +0 -0
  76. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/devices/transport/mqtt_channel.py +0 -0
  77. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/diagnostics.py +0 -0
  78. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/map/__init__.py +0 -0
  79. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/map/map_parser.py +0 -0
  80. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/mqtt/__init__.py +0 -0
  81. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/mqtt/health_manager.py +0 -0
  82. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/mqtt/roborock_session.py +0 -0
  83. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/mqtt/session.py +0 -0
  84. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocol.py +0 -0
  85. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocols/__init__.py +0 -0
  86. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocols/a01_protocol.py +0 -0
  87. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocols/b01_q10_protocol.py +0 -0
  88. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/protocols/b01_q7_protocol.py +0 -0
  89. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/py.typed +0 -0
  90. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/roborock_message.py +0 -0
  91. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/roborock_typing.py +0 -0
  92. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/util.py +0 -0
  93. {python_roborock-4.7.1 → python_roborock-4.7.2}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 4.7.1
3
+ Version: 4.7.2
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.7.1"
3
+ version = "4.7.2"
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"
@@ -24,7 +24,7 @@ from roborock.data import CombinedMapInfo, 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
27
- from roborock.exceptions import RoborockDeviceBusy, RoborockException
27
+ from roborock.exceptions import RoborockDeviceBusy, RoborockException, RoborockInvalidStatus
28
28
  from roborock.roborock_typing import RoborockCommand
29
29
 
30
30
  from .map_content import MapContent, MapContentTrait
@@ -171,7 +171,12 @@ class HomeTrait(RoborockBase, common.V1TraitMixin):
171
171
  # We need to load each map to get its room data
172
172
  if len(sorted_map_infos) > 1:
173
173
  _LOGGER.debug("Loading map %s", map_info.map_flag)
174
- await self._maps_trait.set_current_map(map_info.map_flag)
174
+ try:
175
+ await self._maps_trait.set_current_map(map_info.map_flag)
176
+ except RoborockInvalidStatus as ex:
177
+ # Device is in a state that forbids map switching. Translate to
178
+ # "busy" so callers can fall back to refreshing the current map only.
179
+ raise RoborockDeviceBusy("Cannot switch maps right now (device action locked)") from ex
175
180
  await asyncio.sleep(MAP_SLEEP)
176
181
 
177
182
  map_content = await self._refresh_map_content()
@@ -87,5 +87,9 @@ class RoborockDeviceBusy(RoborockException):
87
87
  """Class for Roborock device busy exceptions."""
88
88
 
89
89
 
90
+ class RoborockInvalidStatus(RoborockException):
91
+ """Class for Roborock invalid status exceptions (device action locked)."""
92
+
93
+
90
94
  class RoborockUnsupportedFeature(RoborockException):
91
95
  """Class for Roborock unsupported feature exceptions."""
@@ -13,7 +13,7 @@ from enum import StrEnum
13
13
  from typing import Any, Protocol, TypeVar, overload
14
14
 
15
15
  from roborock.data import RoborockBase, RRiot
16
- from roborock.exceptions import RoborockException, RoborockUnsupportedFeature
16
+ from roborock.exceptions import RoborockException, RoborockInvalidStatus, RoborockUnsupportedFeature
17
17
  from roborock.protocol import Utils
18
18
  from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol
19
19
  from roborock.roborock_typing import RoborockCommand
@@ -106,6 +106,24 @@ class RequestMessage:
106
106
 
107
107
  ResponseData = dict[str, Any] | list | int
108
108
 
109
+ # V1 RPC error code mappings to specific exception types
110
+ _V1_ERROR_CODE_EXCEPTIONS: dict[int, type[RoborockException]] = {
111
+ -10007: RoborockInvalidStatus, # "invalid status" - device action locked
112
+ }
113
+
114
+
115
+ def _create_api_error(error: Any) -> RoborockException:
116
+ """Create an appropriate exception for a V1 RPC error response.
117
+
118
+ Maps known error codes to specific exception types for easier handling
119
+ at higher levels.
120
+ """
121
+ if isinstance(error, dict):
122
+ code = error.get("code")
123
+ if isinstance(code, int) and (exc_type := _V1_ERROR_CODE_EXCEPTIONS.get(code)):
124
+ return exc_type(error)
125
+ return RoborockException(error)
126
+
109
127
 
110
128
  @dataclass(kw_only=True, frozen=True)
111
129
  class ResponseMessage:
@@ -154,26 +172,38 @@ def decode_rpc_response(message: RoborockMessage) -> ResponseMessage:
154
172
  ) from e
155
173
 
156
174
  request_id: int | None = data_point_response.get("id")
157
- exc: RoborockException | None = None
175
+ api_error: RoborockException | None = None
158
176
  if error := data_point_response.get("error"):
159
- exc = RoborockException(error)
177
+ api_error = _create_api_error(error)
178
+
160
179
  if (result := data_point_response.get("result")) is None:
161
- exc = RoborockException(f"Invalid V1 message format: missing 'result' in data point for {message.payload!r}")
180
+ # Some firmware versions return an error-only response (no "result" key).
181
+ # Preserve that error instead of overwriting it with a parsing exception.
182
+ if api_error is None:
183
+ api_error = RoborockException(
184
+ f"Invalid V1 message format: missing 'result' in data point for {message.payload!r}"
185
+ )
186
+ result = {}
162
187
  else:
163
188
  _LOGGER.debug("Decoded V1 message result: %s", result)
164
189
  if isinstance(result, str):
165
190
  if result == "unknown_method":
166
- exc = RoborockUnsupportedFeature("The method called is not recognized by the device.")
191
+ api_error = RoborockUnsupportedFeature("The method called is not recognized by the device.")
167
192
  elif result != "ok":
168
- exc = RoborockException(f"Unexpected API Result: {result}")
193
+ api_error = RoborockException(f"Unexpected API Result: {result}")
169
194
  result = {}
170
195
  if not isinstance(result, dict | list | int):
171
- raise RoborockException(
172
- f"Invalid V1 message format: 'result' was unexpected type {type(result)}. {message.payload!r}"
173
- )
174
- if not request_id and exc:
175
- raise exc
176
- return ResponseMessage(request_id=request_id, data=result, api_error=exc)
196
+ # If we already have an API error, prefer returning a response object
197
+ # rather than failing to decode the message entirely.
198
+ if api_error is None:
199
+ raise RoborockException(
200
+ f"Invalid V1 message format: 'result' was unexpected type {type(result)}. {message.payload!r}"
201
+ )
202
+ result = {}
203
+
204
+ if not request_id and api_error:
205
+ raise api_error
206
+ return ResponseMessage(request_id=request_id, data=result, api_error=api_error)
177
207
 
178
208
 
179
209
  @dataclass
File without changes