python-roborock 7.3.0__tar.gz → 7.4.1__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 (132) hide show
  1. {python_roborock-7.3.0 → python_roborock-7.4.1}/PKG-INFO +1 -1
  2. {python_roborock-7.3.0 → python_roborock-7.4.1}/pyproject.toml +1 -1
  3. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/containers.py +18 -0
  4. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/a01/device_feature.py +18 -0
  5. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/web_api.py +68 -1
  6. {python_roborock-7.3.0 → python_roborock-7.4.1}/.gitignore +0 -0
  7. {python_roborock-7.3.0 → python_roborock-7.4.1}/LICENSE +0 -0
  8. {python_roborock-7.3.0 → python_roborock-7.4.1}/README.md +0 -0
  9. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/__init__.py +0 -0
  10. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/broadcast_protocol.py +0 -0
  11. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/callbacks.py +0 -0
  12. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/cli.py +0 -0
  13. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/const.py +0 -0
  14. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/__init__.py +0 -0
  15. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q10/__init__.py +0 -0
  16. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  17. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  18. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q7/__init__.py +0 -0
  19. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  20. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  21. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/code_mappings.py +0 -0
  22. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/dyad/__init__.py +0 -0
  23. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  24. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/dyad/dyad_containers.py +0 -0
  25. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/mower/__init__.py +0 -0
  26. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/mower/mower_code_mappings.py +0 -0
  27. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/mower/mower_containers.py +0 -0
  28. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/v1/__init__.py +0 -0
  29. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/v1/v1_clean_modes.py +0 -0
  30. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/v1/v1_code_mappings.py +0 -0
  31. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/v1/v1_containers.py +0 -0
  32. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/zeo/__init__.py +0 -0
  33. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  34. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/data/zeo/zeo_containers.py +0 -0
  35. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/device_features.py +0 -0
  36. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/README.md +0 -0
  37. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/__init__.py +0 -0
  38. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/cache.py +0 -0
  39. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/device.py +0 -0
  40. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/device_manager.py +0 -0
  41. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/file_cache.py +0 -0
  42. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/rpc/__init__.py +0 -0
  43. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/rpc/a01_channel.py +0 -0
  44. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  45. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  46. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/rpc/v1_channel.py +0 -0
  47. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/__init__.py +0 -0
  48. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/a01/__init__.py +0 -0
  49. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/__init__.py +0 -0
  50. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  51. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/button_light.py +0 -0
  52. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/child_lock.py +0 -0
  53. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/clean_history.py +0 -0
  54. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/command.py +0 -0
  55. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/common.py +0 -0
  56. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/consumable.py +0 -0
  57. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/do_not_disturb.py +0 -0
  58. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/dust_collection.py +0 -0
  59. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/map.py +0 -0
  60. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/maps.py +0 -0
  61. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/network_info.py +0 -0
  62. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/remote.py +0 -0
  63. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/status.py +0 -0
  64. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
  65. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q10/volume.py +0 -0
  66. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  67. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
  68. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q7/map.py +0 -0
  69. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/b01/q7/map_content.py +0 -0
  70. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/common.py +0 -0
  71. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/traits_mixin.py +0 -0
  72. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/__init__.py +0 -0
  73. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/child_lock.py +0 -0
  74. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/clean_summary.py +0 -0
  75. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/command.py +0 -0
  76. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/common.py +0 -0
  77. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/consumeable.py +0 -0
  78. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/device_features.py +0 -0
  79. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  80. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  81. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  82. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/home.py +0 -0
  83. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/led_status.py +0 -0
  84. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/map_content.py +0 -0
  85. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/maps.py +0 -0
  86. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/network_info.py +0 -0
  87. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/obstacle_photos.py +0 -0
  88. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/rooms.py +0 -0
  89. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/routines.py +0 -0
  90. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  91. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/status.py +0 -0
  92. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  93. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/volume.py +0 -0
  94. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  95. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/transport/__init__.py +0 -0
  96. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/transport/channel.py +0 -0
  97. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/transport/local_channel.py +0 -0
  98. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/devices/transport/mqtt_channel.py +0 -0
  99. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/diagnostics.py +0 -0
  100. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/exceptions.py +0 -0
  101. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/__init__.py +0 -0
  102. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/b01_grid_layers.py +0 -0
  103. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/b01_map_parser.py +0 -0
  104. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/b01_q10_map_parser.py +0 -0
  105. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/b01_q10_overlays.py +0 -0
  106. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/b01_q10_render.py +0 -0
  107. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/map_parser.py +0 -0
  108. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/proto/__init__.py +0 -0
  109. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/proto/b01_scmap.proto +0 -0
  110. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/proto/b01_scmap_pb2.py +0 -0
  111. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/map/room_colors.py +0 -0
  112. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/mqtt/__init__.py +0 -0
  113. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/mqtt/health_manager.py +0 -0
  114. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/mqtt/roborock_session.py +0 -0
  115. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/mqtt/session.py +0 -0
  116. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocol.py +0 -0
  117. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocols/__init__.py +0 -0
  118. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocols/a01_protocol.py +0 -0
  119. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocols/b01_q10_protocol.py +0 -0
  120. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocols/b01_q7_protocol.py +0 -0
  121. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/protocols/v1_protocol.py +0 -0
  122. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/py.typed +0 -0
  123. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/roborock_message.py +0 -0
  124. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/roborock_typing.py +0 -0
  125. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/__init__.py +0 -0
  126. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/a01_simulator.py +0 -0
  127. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/b01_q10_simulator.py +0 -0
  128. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/channel.py +0 -0
  129. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/cloud.py +0 -0
  130. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/simulator.py +0 -0
  131. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/testing/v1_simulator.py +0 -0
  132. {python_roborock-7.3.0 → python_roborock-7.4.1}/roborock/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-roborock
3
- Version: 7.3.0
3
+ Version: 7.4.1
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 = "7.3.0"
3
+ version = "7.4.1"
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"
@@ -348,6 +348,24 @@ class HomeDataScene(RoborockBase):
348
348
  name: str
349
349
 
350
350
 
351
+ @dataclass
352
+ class FirmwareInfo(RoborockBase):
353
+ """Firmware/OTA info from the cloud (`ota/firmware/{duid}/updatev2`)."""
354
+
355
+ version: str | None = None
356
+ """Latest available firmware version."""
357
+ current_version: str | None = None
358
+ """Currently installed firmware version."""
359
+ updatable: bool | None = None
360
+ """Whether a newer firmware is available to install."""
361
+ desc: str | None = None
362
+ """Release notes / description."""
363
+ release_time: str | None = None
364
+ """Release date of the available firmware as an ISO-8601 date (``YYYY-MM-DD``)."""
365
+ force_update: bool | None = None
366
+ """Whether the update is mandatory (cannot be skipped)."""
367
+
368
+
351
369
  @dataclass
352
370
  class HomeDataSchedule(RoborockBase):
353
371
  id: int
@@ -143,6 +143,13 @@ _UNSUPPORTED_FEATURE_BITS: frozenset[str] = frozenset(
143
143
  }
144
144
  )
145
145
 
146
+ # Devices known to lack DEFAULT_SETTING (DP 225).
147
+ _UNSUPPORTED_DEFAULT_SETTING: frozenset[str] = frozenset(
148
+ {
149
+ "roborock.wm.a63", # H1
150
+ }
151
+ )
152
+
146
153
  # Series that support UV light (DP 228).
147
154
  _UV_LIGHT_SERIES: frozenset[str] = (
148
155
  _H1_LITE_SERIES # a90, a91, a237
@@ -242,6 +249,13 @@ def supports_feature_bits(model: str | None) -> bool:
242
249
  return model not in _UNSUPPORTED_FEATURE_BITS
243
250
 
244
251
 
252
+ def supports_default_setting(model: str | None) -> bool:
253
+ """H1 (a63) does not support DP 225 even though it has a softener compartment."""
254
+ if model is None:
255
+ return True # conservative: assume yes
256
+ return model not in _UNSUPPORTED_DEFAULT_SETTING
257
+
258
+
245
259
  def supports_remote_control(model: str | None) -> bool:
246
260
  """Remote control (DP 232) is supported on all overseas models."""
247
261
  if model is None:
@@ -309,6 +323,10 @@ def build_force_load_dp_list(model: str | None) -> list[RoborockZeoProtocol]:
309
323
  if not supports_feature_bits(model):
310
324
  base = [dp for dp in base if dp != RoborockZeoProtocol.FEATURE_BITS]
311
325
 
326
+ # ── Strip unsupported DEFAULT_SETTING ──
327
+ if not supports_default_setting(model):
328
+ base = [dp for dp in base if dp != RoborockZeoProtocol.DEFAULT_SETTING]
329
+
312
330
  return base
313
331
 
314
332
 
@@ -15,7 +15,7 @@ from aiohttp import ContentTypeError, FormData
15
15
  from pyrate_limiter import Duration, Limiter, Rate
16
16
 
17
17
  from roborock import HomeDataSchedule
18
- from roborock.data import HomeData, HomeDataRoom, HomeDataScene, ProductResponse, RRiot, UserData
18
+ from roborock.data import FirmwareInfo, HomeData, HomeDataRoom, HomeDataScene, ProductResponse, RRiot, UserData
19
19
  from roborock.exceptions import (
20
20
  RoborockAccountDoesNotExist,
21
21
  RoborockException,
@@ -608,6 +608,73 @@ class RoborockApiClient:
608
608
  else:
609
609
  raise RoborockException("scene_response result was an unexpected type")
610
610
 
611
+ async def get_firmware_info(self, user_data: UserData, device_id: str) -> FirmwareInfo:
612
+ """Get firmware/OTA info for a device (latest version + updatable flag)."""
613
+ rriot = user_data.rriot
614
+ if rriot is None:
615
+ raise RoborockException("rriot is none")
616
+ if rriot.r.a is None:
617
+ raise RoborockException("Missing field 'a' in rriot reference")
618
+ path = f"/ota/firmware/{device_id}/updatev2"
619
+ params = {"lang": "en"}
620
+ firmware_request = PreparedRequest(
621
+ rriot.r.a,
622
+ self.session,
623
+ {
624
+ "Authorization": _get_hawk_authentication(rriot, path, params=params),
625
+ },
626
+ )
627
+ firmware_response = await firmware_request.request("get", path, params=params)
628
+ if not firmware_response or not firmware_response.get("success"):
629
+ raise RoborockException(firmware_response)
630
+ return FirmwareInfo.from_dict(firmware_response.get("result") or {})
631
+
632
+ async def start_firmware_update(self, user_data: UserData, device_id: str) -> None:
633
+ """Trigger the (irreversible) firmware update for a device.
634
+
635
+ The device downloads and flashes the latest firmware reported by
636
+ :meth:`get_firmware_info`.
637
+ """
638
+ rriot = user_data.rriot
639
+ if rriot is None:
640
+ raise RoborockException("rriot is none")
641
+ if rriot.r.a is None:
642
+ raise RoborockException("Missing field 'a' in rriot reference")
643
+ path = f"/ota/device/{device_id}/upgrade"
644
+ upgrade_request = PreparedRequest(
645
+ rriot.r.a,
646
+ self.session,
647
+ {
648
+ "Authorization": _get_hawk_authentication(rriot, path),
649
+ },
650
+ )
651
+ upgrade_response = await upgrade_request.request("post", path)
652
+ if not upgrade_response or not upgrade_response.get("success"):
653
+ raise RoborockException(upgrade_response)
654
+
655
+ async def set_silent_ota(self, user_data: UserData, device_id: str, enabled: bool) -> None:
656
+ """Enable/disable automatic (silent) firmware updates for a device.
657
+
658
+ The current value is reported as ``silent_ota_switch`` on the home-data device.
659
+ """
660
+ rriot = user_data.rriot
661
+ if rriot is None:
662
+ raise RoborockException("rriot is none")
663
+ if rriot.r.a is None:
664
+ raise RoborockException("Missing field 'a' in rriot reference")
665
+ path = f"/user/devices/{device_id}"
666
+ formdata = {"silentOtaSwitch": "true" if enabled else "false"}
667
+ silent_ota_request = PreparedRequest(
668
+ rriot.r.a,
669
+ self.session,
670
+ {
671
+ "Authorization": _get_hawk_authentication(rriot, path, formdata=formdata),
672
+ },
673
+ )
674
+ silent_ota_response = await silent_ota_request.request("put", path, data=formdata)
675
+ if not silent_ota_response or not silent_ota_response.get("success"):
676
+ raise RoborockException(silent_ota_response)
677
+
611
678
  async def execute_scene(self, user_data: UserData, scene_id: int) -> None:
612
679
  rriot = user_data.rriot
613
680
  if rriot is None:
File without changes