python-roborock 7.4.2__tar.gz → 7.4.3__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.4.2 → python_roborock-7.4.3}/PKG-INFO +1 -1
  2. {python_roborock-7.4.2 → python_roborock-7.4.3}/pyproject.toml +29 -3
  3. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/broadcast_protocol.py +2 -2
  4. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/cli.py +11 -11
  5. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q7/b01_q7_code_mappings.py +5 -1
  6. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q7/b01_q7_containers.py +2 -2
  7. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/code_mappings.py +1 -1
  8. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/containers.py +5 -5
  9. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/v1/v1_code_mappings.py +1 -1
  10. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/device_features.py +1 -1
  11. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/rpc/b01_q7_channel.py +1 -1
  12. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/__init__.py +1 -1
  13. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q7/map_content.py +4 -0
  14. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/clean_summary.py +1 -1
  15. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/rooms.py +1 -1
  16. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/transport/local_channel.py +1 -1
  17. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/b01_grid_layers.py +1 -1
  18. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/b01_q10_map_parser.py +2 -2
  19. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/mqtt/roborock_session.py +1 -1
  20. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocol.py +3 -3
  21. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocols/a01_protocol.py +5 -3
  22. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocols/b01_q7_protocol.py +4 -2
  23. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/v1_simulator.py +2 -2
  24. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/util.py +1 -1
  25. {python_roborock-7.4.2 → python_roborock-7.4.3}/.gitignore +0 -0
  26. {python_roborock-7.4.2 → python_roborock-7.4.3}/LICENSE +0 -0
  27. {python_roborock-7.4.2 → python_roborock-7.4.3}/README.md +0 -0
  28. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/__init__.py +0 -0
  29. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/callbacks.py +0 -0
  30. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/const.py +0 -0
  31. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/__init__.py +0 -0
  32. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q10/__init__.py +0 -0
  33. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  34. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  35. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/b01_q7/__init__.py +0 -0
  36. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/dyad/__init__.py +0 -0
  37. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  38. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/dyad/dyad_containers.py +0 -0
  39. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/mower/__init__.py +0 -0
  40. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/mower/mower_code_mappings.py +0 -0
  41. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/mower/mower_containers.py +0 -0
  42. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/v1/__init__.py +0 -0
  43. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/v1/v1_clean_modes.py +0 -0
  44. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/v1/v1_containers.py +0 -0
  45. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/zeo/__init__.py +0 -0
  46. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  47. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/data/zeo/zeo_containers.py +0 -0
  48. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/README.md +0 -0
  49. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/__init__.py +0 -0
  50. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/cache.py +0 -0
  51. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/device.py +0 -0
  52. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/device_manager.py +0 -0
  53. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/file_cache.py +0 -0
  54. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/rpc/__init__.py +0 -0
  55. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/rpc/a01_channel.py +0 -0
  56. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  57. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/rpc/v1_channel.py +0 -0
  58. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/a01/__init__.py +0 -0
  59. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/a01/device_feature.py +0 -0
  60. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/__init__.py +0 -0
  61. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  62. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/button_light.py +0 -0
  63. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/child_lock.py +0 -0
  64. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/clean_history.py +0 -0
  65. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/command.py +0 -0
  66. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/common.py +0 -0
  67. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/consumable.py +0 -0
  68. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/do_not_disturb.py +0 -0
  69. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/dust_collection.py +0 -0
  70. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/map.py +0 -0
  71. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/maps.py +0 -0
  72. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/network_info.py +0 -0
  73. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/remote.py +0 -0
  74. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/status.py +0 -0
  75. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
  76. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q10/volume.py +0 -0
  77. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  78. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
  79. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/b01/q7/map.py +0 -0
  80. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/common.py +0 -0
  81. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/traits_mixin.py +0 -0
  82. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/__init__.py +0 -0
  83. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/child_lock.py +0 -0
  84. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/command.py +0 -0
  85. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/common.py +0 -0
  86. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/consumeable.py +0 -0
  87. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/device_features.py +0 -0
  88. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  89. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  90. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  91. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/home.py +0 -0
  92. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/led_status.py +0 -0
  93. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/map_content.py +0 -0
  94. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/maps.py +0 -0
  95. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/network_info.py +0 -0
  96. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/obstacle_photos.py +0 -0
  97. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/routines.py +0 -0
  98. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  99. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/status.py +0 -0
  100. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  101. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/volume.py +0 -0
  102. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  103. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/transport/__init__.py +0 -0
  104. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/transport/channel.py +0 -0
  105. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/devices/transport/mqtt_channel.py +0 -0
  106. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/diagnostics.py +0 -0
  107. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/exceptions.py +0 -0
  108. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/__init__.py +0 -0
  109. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/b01_map_parser.py +0 -0
  110. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/b01_q10_overlays.py +0 -0
  111. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/b01_q10_render.py +0 -0
  112. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/map_parser.py +0 -0
  113. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/proto/__init__.py +0 -0
  114. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/proto/b01_scmap.proto +0 -0
  115. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/proto/b01_scmap_pb2.py +0 -0
  116. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/map/room_colors.py +0 -0
  117. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/mqtt/__init__.py +0 -0
  118. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/mqtt/health_manager.py +0 -0
  119. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/mqtt/session.py +0 -0
  120. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocols/__init__.py +0 -0
  121. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocols/b01_q10_protocol.py +0 -0
  122. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/protocols/v1_protocol.py +0 -0
  123. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/py.typed +0 -0
  124. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/roborock_message.py +0 -0
  125. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/roborock_typing.py +0 -0
  126. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/__init__.py +0 -0
  127. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/a01_simulator.py +0 -0
  128. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/b01_q10_simulator.py +0 -0
  129. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/channel.py +0 -0
  130. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/cloud.py +0 -0
  131. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/testing/simulator.py +0 -0
  132. {python_roborock-7.4.2 → python_roborock-7.4.3}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-roborock
3
- Version: 7.4.2
3
+ Version: 7.4.3
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.4.2"
3
+ version = "7.4.3"
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"
@@ -106,14 +106,40 @@ allowed_tags = [
106
106
  major_tags= ["refactor"]
107
107
 
108
108
  [tool.ruff]
109
- lint.ignore = ["F403", "E741"]
110
- lint.select=["E", "F", "UP", "I"]
109
+ lint.ignore = []
110
+ # TODO: Enable ASYNC (flake8-async) in a dedicated follow-up PR once async open() and timeout parameters are refactored.
111
+ lint.select = [
112
+ "A",
113
+ "B",
114
+ "BLE",
115
+ "C4",
116
+ "E",
117
+ "F",
118
+ "FA",
119
+ "I",
120
+ "ICN",
121
+ "ISC",
122
+ "PGH",
123
+ "PIE",
124
+ "UP",
125
+ "W",
126
+ "YTT",
127
+ ]
111
128
  line-length = 120
112
129
  extend-exclude = ["roborock/map/proto/*_pb2.py"]
113
130
 
114
131
  [tool.ruff.lint.per-file-ignores]
115
132
  "*/__init__.py" = ["F401"]
133
+ "roborock/__init__.py" = ["F403"]
134
+ "roborock/data/__init__.py" = ["F403"]
135
+ "roborock/data/b01_q7/__init__.py" = ["F403"]
136
+ "roborock/data/b01_q10/__init__.py" = ["F403"]
137
+ "roborock/data/dyad/__init__.py" = ["F403"]
138
+ "roborock/data/mower/__init__.py" = ["F403"]
139
+ "roborock/data/v1/__init__.py" = ["F403"]
140
+ "roborock/data/zeo/__init__.py" = ["F403"]
116
141
  "roborock/map/proto/*_pb2.py" = ["E501", "I001", "UP009"]
142
+ "tests/*" = ["B010"]
117
143
 
118
144
  [[tool.mypy.overrides]]
119
145
  module = ["roborock.map.proto.*"]
@@ -4,7 +4,7 @@ import json
4
4
  import logging
5
5
  from asyncio import BaseTransport, Lock
6
6
 
7
- from construct import ( # type: ignore
7
+ from construct import ( # type: ignore[import-untyped]
8
8
  Bytes,
9
9
  Checksum,
10
10
  GreedyBytes,
@@ -63,7 +63,7 @@ class RoborockProtocol(asyncio.DatagramProtocol):
63
63
  parsed_message = BroadcastMessage(duid=json_payload["duid"], ip=json_payload["ip"], version=version)
64
64
  _LOGGER.debug(f"Received broadcast: {parsed_message}")
65
65
  self.devices_found.append(parsed_message)
66
- except Exception as e:
66
+ except Exception as e: # noqa: BLE001
67
67
  _LOGGER.warning(f"Failed to decode message: {data!r}. Error: {e}")
68
68
 
69
69
  async def discover(self) -> list[BroadcastMessage]:
@@ -22,6 +22,8 @@ roborock> status --device_id <device_id>
22
22
  ```
23
23
  """
24
24
 
25
+ # ruff: noqa: BLE001
26
+
25
27
  import asyncio
26
28
  import datetime
27
29
  import functools
@@ -38,9 +40,9 @@ try:
38
40
  import click
39
41
  import click_shell
40
42
  import yaml
41
- from pyshark import FileCapture # type: ignore
42
- from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException # type: ignore
43
- from pyshark.packet.packet import Packet # type: ignore
43
+ from pyshark import FileCapture # type: ignore[import-untyped]
44
+ from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException # type: ignore[import-untyped]
45
+ from pyshark.packet.packet import Packet # type: ignore[import-untyped]
44
46
  except ImportError as err:
45
47
  raise SystemExit(
46
48
  f"The 'roborock' command line tool requires extra dependencies that are not installed ({err.name}).\n"
@@ -307,7 +309,7 @@ class RoborockContext(Cache):
307
309
  @click.pass_context
308
310
  def cli(ctx, debug: int):
309
311
  logging_config: dict[str, Any] = {"level": logging.DEBUG if debug > 0 else logging.INFO}
310
- logging.basicConfig(**logging_config) # type: ignore
312
+ logging.basicConfig(**logging_config) # type: ignore[call-overload]
311
313
  ctx.obj = RoborockContext()
312
314
 
313
315
 
@@ -988,9 +990,8 @@ async def parser(_, local_key, device_ip, file):
988
990
  local_key,
989
991
  )
990
992
  print(f"Received request: {f}")
991
- except BaseException as e:
993
+ except Exception as e:
992
994
  print(e)
993
- pass
994
995
  elif packet.ip.src == device_ip:
995
996
  try:
996
997
  f, buffer["data"] = MessageParser.parse(
@@ -998,16 +999,15 @@ async def parser(_, local_key, device_ip, file):
998
999
  local_key,
999
1000
  )
1000
1001
  print(f"Received response: {f}")
1001
- except BaseException as e:
1002
+ except Exception as e:
1002
1003
  print(e)
1003
- pass
1004
1004
 
1005
1005
  try:
1006
1006
  await capture.packets_from_tshark(on_package, close_tshark=not file_provided)
1007
- except UnknownInterfaceException:
1007
+ except UnknownInterfaceException as err:
1008
1008
  raise RoborockException(
1009
1009
  "You need to run 'rvictl -s XXXXXXXX-XXXXXXXXXXXXXXXX' first, with an iPhone connected to usb port"
1010
- )
1010
+ ) from err
1011
1011
 
1012
1012
 
1013
1013
  def _parse_diagnostic_file(diagnostic_path: Path) -> dict[str, dict[str, Any]]:
@@ -1319,7 +1319,7 @@ def update_docs(data_file: str, output_file: str):
1319
1319
  ]
1320
1320
  # Regular features are the remaining keys, sorted alphabetically
1321
1321
  # We filter out the special rows to avoid duplicating them.
1322
- sorted_features = sorted(list(all_features - set(special_rows)))
1322
+ sorted_features = sorted(all_features - set(special_rows))
1323
1323
 
1324
1324
  header = ["Feature"] + sorted_products
1325
1325
 
@@ -302,7 +302,11 @@ class B01Fault(RoborockModeEnum):
302
302
  # charging.
303
303
  F_2101 = ("fault_2101", 2101)
304
304
  F_2102 = ("cleaning_complete", 2102) # Cleaning completed. Returning to the dock.
305
- F_2103 = ("fault_2103", 2103)
305
+ F_2103 = (
306
+ "cleaning_complete_docked",
307
+ 2103,
308
+ ) # Task finished and robot docked. Follows 2102 once docking and any auto-empty complete; persists
309
+ # while docked-idle. Not an error (hw-confirmed on a Q7 M5+).
306
310
  F_2104 = ("fault_2104", 2104)
307
311
  F_2105 = ("fault_2105", 2105)
308
312
  F_2108 = ("fault_2108", 2108)
@@ -137,11 +137,11 @@ class B01Props(RoborockBase):
137
137
  custom_type: int | None = None
138
138
  sound: int | None = None
139
139
  work_mode: WorkModeMapping | None = None
140
- station_act: int | None = None
140
+ station_act: int | None = None # dock activity; 3 while collecting dust, 0 idle. hw-confirmed (Q7 M5+)
141
141
  charge_state: int | None = None
142
142
  current_map_id: int | None = None
143
143
  map_num: int | None = None
144
- dust_action: int | None = None
144
+ dust_action: int | None = None # 1 while the dock is collecting dust; read-only (prop.set rejected, code 1)
145
145
  quiet_is_open: int | None = None
146
146
  quiet_begin_time: int | None = None
147
147
  quiet_end_time: int | None = None
@@ -33,7 +33,7 @@ class RoborockEnum(IntEnum):
33
33
  if warning not in completed_warnings:
34
34
  completed_warnings.add(warning)
35
35
  _LOGGER.warning(warning)
36
- return cls.unknown # type: ignore
36
+ return cls.unknown # type: ignore[attr-defined]
37
37
  default_value = next(item for item in cls)
38
38
  warning = f"Missing {cls.__name__} code: {key} - defaulting to {default_value}"
39
39
  if warning not in completed_warnings:
@@ -52,7 +52,7 @@ def _attr_repr(obj: Any) -> str:
52
52
  continue
53
53
  try:
54
54
  v = getattr(obj, k)
55
- except (RuntimeError, Exception):
55
+ except Exception: # noqa: BLE001
56
56
  continue
57
57
  if callable(v):
58
58
  continue
@@ -210,7 +210,7 @@ class Reference(RoborockBase):
210
210
  r: str | None = None
211
211
  a: str | None = None
212
212
  m: str | None = None
213
- l: str | None = None
213
+ l: str | None = None # noqa: E741
214
214
 
215
215
 
216
216
  @dataclass
@@ -379,9 +379,9 @@ class HomeDataSchedule(RoborockBase):
379
379
  class HomeData(RoborockBase):
380
380
  id: int
381
381
  name: str
382
- products: list[HomeDataProduct] = field(default_factory=lambda: [])
383
- devices: list[HomeDataDevice] = field(default_factory=lambda: [])
384
- received_devices: list[HomeDataDevice] = field(default_factory=lambda: [])
382
+ products: list[HomeDataProduct] = field(default_factory=list)
383
+ devices: list[HomeDataDevice] = field(default_factory=list)
384
+ received_devices: list[HomeDataDevice] = field(default_factory=list)
385
385
  lon: Any | None = None
386
386
  lat: Any | None = None
387
387
  geo_name: Any | None = None
@@ -151,7 +151,7 @@ class RoborockDssCodes(RoborockEnum):
151
151
  def _missing_(cls: type[Self], key) -> Self:
152
152
  # If the calculated value is not provided, then it should be viewed as okay.
153
153
  # As the math will sometimes result in you getting numbers that don't matter.
154
- return cls.okay # type: ignore
154
+ return cls.okay # type: ignore[attr-defined]
155
155
 
156
156
 
157
157
  class ClearWaterBoxStatus(RoborockDssCodes):
@@ -643,7 +643,7 @@ class DeviceFeatures(RoborockBase):
643
643
  elif (product_features := f.metadata.get("product_features")) is not None:
644
644
  if product_nickname is not None:
645
645
  available_features = PRODUCT_FEATURE_MAP.get(product_nickname, [])
646
- if any(feat in available_features for feat in product_features): # type: ignore
646
+ if any(feat in available_features for feat in product_features):
647
647
  kwargs[f.name] = True
648
648
 
649
649
  # The app combines runtime shake-mop, model shake/spin, and roller-mop
@@ -84,7 +84,7 @@ async def _send_command(
84
84
  return
85
85
  try:
86
86
  response = response_matcher(response_message)
87
- except Exception as ex:
87
+ except Exception as ex: # noqa: BLE001
88
88
  future.set_exception(ex)
89
89
  return
90
90
  if response is not None:
@@ -24,5 +24,5 @@ __all__ = [
24
24
  ]
25
25
 
26
26
 
27
- class Trait(ABC):
27
+ class Trait(ABC): # noqa: B024
28
28
  """Base class for all traits."""
@@ -6,6 +6,10 @@ This intentionally mirrors the v1 `MapContentTrait` contract:
6
6
  - fields `image_content`, `map_data`, and `raw_api_response` are then readable
7
7
 
8
8
  For B01/Q7 devices, the underlying raw map payload is retrieved via `MapTrait`.
9
+
10
+ Q7 devices additionally stream map frames unprompted while cleaning; those arrive
11
+ through `update_from_push()`, which keeps the same cached fields current and
12
+ notifies registered update listeners.
9
13
  """
10
14
 
11
15
  import asyncio
@@ -56,7 +56,7 @@ class CleanRecordConverter(common.V1TraitDataConverter):
56
56
  rec.square_meter_area or 0
57
57
  )
58
58
  return final_record
59
- except Exception:
59
+ except Exception: # noqa: BLE001
60
60
  # Return final record when an exception occurred
61
61
  return final_record
62
62
  # There are still a few unknown variables in this.
@@ -144,6 +144,6 @@ class RoomsTrait(Rooms, common.V1TraitMixin):
144
144
  rooms_by_id.update({room.iot_id: room for room in shared_rooms})
145
145
  return list(rooms_by_id.values())
146
146
  return await self._web_api.get_rooms()
147
- except Exception:
147
+ except Exception: # noqa: BLE001
148
148
  _LOGGER.debug("Failed to fetch rooms from web API", exc_info=True)
149
149
  return []
@@ -158,7 +158,7 @@ class LocalChannel(Channel):
158
158
  await self._ping()
159
159
  except asyncio.CancelledError:
160
160
  break
161
- except Exception:
161
+ except Exception: # noqa: BLE001
162
162
  self._logger.debug("Keep-alive ping failed", exc_info=True)
163
163
  # Retry next interval
164
164
 
@@ -198,7 +198,7 @@ def solve_calibration(
198
198
  min_sx, max_sx, min_sy, max_sy = min(sx), max(sx), min(sy), max(sy)
199
199
  if (max_sx - min_sx) >= w or (max_sy - min_sy) >= h:
200
200
  continue # path wider/taller than the map at this resolution
201
- pts = list(zip(sx, sy))
201
+ pts = list(zip(sx, sy, strict=True))
202
202
  # Slide so every point stays in-bounds: px = px_f + ox in [0, w), py = oy - py_f in [0, h).
203
203
  for ox in range(ceil(-min_sx), ceil(w - max_sx)):
204
204
  for oy in range(ceil(max_sy), ceil(h + min_sy)):
@@ -341,7 +341,7 @@ def _drop_stray_leading_point(points: list[Q10Point]) -> list[Q10Point]:
341
341
  """
342
342
  if len(points) < 3:
343
343
  return points
344
- steps = [math.hypot(b.x - a.x, b.y - a.y) for a, b in zip(points, points[1:])]
344
+ steps = [math.hypot(b.x - a.x, b.y - a.y) for a, b in zip(points, points[1:], strict=False)]
345
345
  median_rest = statistics.median(steps[1:])
346
346
  if median_rest > 0 and steps[0] > _STRAY_POINT_STEP_RATIO * median_rest:
347
347
  return points[1:]
@@ -425,7 +425,7 @@ def _infer_layout(decoded: bytes, width: int) -> tuple[int, bytes, bytes]:
425
425
  up with the marker. Used as a fallback when the header carries no usable
426
426
  height.
427
427
  """
428
- for room_count in range(0, _MAX_ROOMS + 1):
428
+ for room_count in range(_MAX_ROOMS + 1):
429
429
  room_data_length = 2 + room_count * _ROOM_RECORD_LENGTH
430
430
  area = len(decoded) - room_data_length
431
431
  if area <= 0 or area % width:
@@ -165,7 +165,7 @@ class RoborockMqttSession(MqttSession):
165
165
  await self._connection_task
166
166
  except asyncio.CancelledError:
167
167
  _LOGGER.debug("MQTT connection task cancelled")
168
- except Exception:
168
+ except Exception: # noqa: BLE001
169
169
  # Exceptions are logged and handled in _run_connection.
170
170
  # There is a special case for exceptions on startup where we return
171
171
  # immediately. Otherwise, we let the reconnect loop retry with
@@ -5,7 +5,7 @@ import logging
5
5
  from collections.abc import Callable
6
6
  from urllib.parse import urlparse
7
7
 
8
- from construct import ( # type: ignore
8
+ from construct import ( # type: ignore[import-untyped]
9
9
  Bytes,
10
10
  Checksum,
11
11
  ChecksumError,
@@ -65,7 +65,7 @@ class Utils:
65
65
  @staticmethod
66
66
  def encode_timestamp(_timestamp: int) -> bytes:
67
67
  hex_value = f"{_timestamp:x}".zfill(8)
68
- return "".join(list(map(lambda idx: hex_value[idx], [5, 6, 3, 7, 1, 2, 0, 4]))).encode()
68
+ return "".join([hex_value[idx] for idx in [5, 6, 3, 7, 1, 2, 0, 4]]).encode()
69
69
 
70
70
  @staticmethod
71
71
  def md5(data: bytes) -> bytes:
@@ -470,7 +470,7 @@ class _Parser:
470
470
  }
471
471
  )
472
472
  return self.con.build(
473
- {"messages": [message for message in messages], "remaining": b""},
473
+ {"messages": list(messages), "remaining": b""},
474
474
  local_key=local_key,
475
475
  prefixed=prefixed,
476
476
  connect_nonce=connect_nonce,
@@ -62,7 +62,7 @@ def decode_rpc_response(message: RoborockMessage) -> dict[int, Any]:
62
62
  try:
63
63
  unpadded = unpad(message.payload, AES.block_size)
64
64
  except ValueError as err:
65
- raise RoborockException(f"Unable to unpad A01 payload: {err}")
65
+ raise RoborockException(f"Unable to unpad A01 payload: {err}") from err
66
66
 
67
67
  try:
68
68
  payload = json.loads(unpadded.decode())
@@ -74,5 +74,7 @@ def decode_rpc_response(message: RoborockMessage) -> dict[int, Any]:
74
74
  raise RoborockException(f"Invalid A01 message format: 'dps' should be a dictionary for {message.payload!r}")
75
75
  try:
76
76
  return {int(key): value for key, value in datapoints.items()}
77
- except ValueError:
78
- raise RoborockException(f"Invalid A01 message format: 'dps' key should be an integer for {message.payload!r}")
77
+ except ValueError as err:
78
+ raise RoborockException(
79
+ f"Invalid A01 message format: 'dps' key should be an integer for {message.payload!r}"
80
+ ) from err
@@ -83,8 +83,10 @@ def decode_rpc_response(message: RoborockMessage) -> dict[int, Any]:
83
83
  raise RoborockException(f"Invalid B01 message format: 'dps' should be a dictionary for {message.payload!r}")
84
84
  try:
85
85
  return {int(key): value for key, value in datapoints.items()}
86
- except ValueError:
87
- raise RoborockException(f"Invalid B01 message format: 'dps' key should be an integer for {message.payload!r}")
86
+ except ValueError as err:
87
+ raise RoborockException(
88
+ f"Invalid B01 message format: 'dps' key should be an integer for {message.payload!r}"
89
+ ) from err
88
90
 
89
91
 
90
92
  @dataclass
@@ -346,7 +346,7 @@ class V1VacuumSimulator(RoborockDeviceSimulator):
346
346
  msg_id = inner["id"]
347
347
  method = inner["method"]
348
348
  params = inner.get("params", [])
349
- except Exception as e:
349
+ except Exception as e: # noqa: BLE001
350
350
  _LOGGER.debug("Failed to parse plaintext JSON RPC payload: %s", e, exc_info=True)
351
351
  return
352
352
 
@@ -358,7 +358,7 @@ class V1VacuumSimulator(RoborockDeviceSimulator):
358
358
  if handler:
359
359
  try:
360
360
  result = handler(params)
361
- except Exception as e:
361
+ except Exception as e: # noqa: BLE001
362
362
  error = str(e)
363
363
  _LOGGER.debug("Error executing command handler for %s: %s", method, e, exc_info=True)
364
364
  else:
@@ -10,7 +10,7 @@ T = TypeVar("T")
10
10
 
11
11
 
12
12
  def unpack_list(value: list[T], size: int) -> list[T | None]:
13
- return (value + [None] * size)[:size] # type: ignore
13
+ return (value + [None] * size)[:size]
14
14
 
15
15
 
16
16
  class RoborockLoggerAdapter(logging.LoggerAdapter):
File without changes