python-roborock 3.9.2__tar.gz → 3.10.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 (96) hide show
  1. {python_roborock-3.9.2 → python_roborock-3.10.0}/PKG-INFO +1 -1
  2. {python_roborock-3.9.2 → python_roborock-3.10.0}/pyproject.toml +1 -1
  3. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/local_channel.py +31 -0
  4. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/clean_summary.py +1 -1
  5. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/protocols/v1_protocol.py +1 -1
  6. {python_roborock-3.9.2 → python_roborock-3.10.0}/.gitignore +0 -0
  7. {python_roborock-3.9.2 → python_roborock-3.10.0}/LICENSE +0 -0
  8. {python_roborock-3.9.2 → python_roborock-3.10.0}/README.md +0 -0
  9. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/__init__.py +0 -0
  10. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/api.py +0 -0
  11. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/broadcast_protocol.py +0 -0
  12. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/callbacks.py +0 -0
  13. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/cli.py +0 -0
  14. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/cloud_api.py +0 -0
  15. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/command_cache.py +0 -0
  16. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/const.py +0 -0
  17. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/__init__.py +0 -0
  18. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q10/__init__.py +0 -0
  19. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  20. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  21. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q7/__init__.py +0 -0
  22. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  23. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  24. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/code_mappings.py +0 -0
  25. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/containers.py +0 -0
  26. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/dyad/__init__.py +0 -0
  27. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  28. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/dyad/dyad_containers.py +0 -0
  29. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/v1/__init__.py +0 -0
  30. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/v1/v1_clean_modes.py +0 -0
  31. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/v1/v1_code_mappings.py +0 -0
  32. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/v1/v1_containers.py +0 -0
  33. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/zeo/__init__.py +0 -0
  34. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  35. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/data/zeo/zeo_containers.py +0 -0
  36. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/device_features.py +0 -0
  37. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/README.md +0 -0
  38. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/__init__.py +0 -0
  39. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/a01_channel.py +0 -0
  40. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/b01_channel.py +0 -0
  41. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/cache.py +0 -0
  42. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/channel.py +0 -0
  43. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/device.py +0 -0
  44. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/device_manager.py +0 -0
  45. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/file_cache.py +0 -0
  46. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/mqtt_channel.py +0 -0
  47. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/__init__.py +0 -0
  48. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/a01/__init__.py +0 -0
  49. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/b01/__init__.py +0 -0
  50. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/traits_mixin.py +0 -0
  51. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/__init__.py +0 -0
  52. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/child_lock.py +0 -0
  53. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/command.py +0 -0
  54. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/common.py +0 -0
  55. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/consumeable.py +0 -0
  56. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/device_features.py +0 -0
  57. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  58. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  59. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  60. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/home.py +0 -0
  61. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/led_status.py +0 -0
  62. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/map_content.py +0 -0
  63. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/maps.py +0 -0
  64. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/network_info.py +0 -0
  65. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/rooms.py +0 -0
  66. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/routines.py +0 -0
  67. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  68. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/status.py +0 -0
  69. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  70. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/volume.py +0 -0
  71. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  72. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/devices/v1_channel.py +0 -0
  73. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/exceptions.py +0 -0
  74. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/map/__init__.py +0 -0
  75. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/map/map_parser.py +0 -0
  76. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/mqtt/__init__.py +0 -0
  77. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/mqtt/health_manager.py +0 -0
  78. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/mqtt/roborock_session.py +0 -0
  79. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/mqtt/session.py +0 -0
  80. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/protocol.py +0 -0
  81. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/protocols/__init__.py +0 -0
  82. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/protocols/a01_protocol.py +0 -0
  83. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/protocols/b01_protocol.py +0 -0
  84. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/py.typed +0 -0
  85. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/roborock_future.py +0 -0
  86. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/roborock_message.py +0 -0
  87. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/roborock_typing.py +0 -0
  88. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/util.py +0 -0
  89. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_1_apis/__init__.py +0 -0
  90. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
  91. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
  92. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
  93. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_a01_apis/__init__.py +0 -0
  94. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
  95. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
  96. {python_roborock-3.9.2 → python_roborock-3.10.0}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 3.9.2
3
+ Version: 3.10.0
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 = "3.9.2"
3
+ version = "3.10.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"
@@ -17,6 +17,7 @@ from .channel import Channel
17
17
  _LOGGER = logging.getLogger(__name__)
18
18
  _PORT = 58867
19
19
  _TIMEOUT = 5.0
20
+ _PING_INTERVAL = 10
20
21
 
21
22
 
22
23
  @dataclass
@@ -58,6 +59,7 @@ class LocalChannel(Channel):
58
59
  self._subscribers: CallbackList[RoborockMessage] = CallbackList(_LOGGER)
59
60
  self._is_connected = False
60
61
  self._local_protocol_version: LocalProtocolVersion | None = None
62
+ self._keep_alive_task: asyncio.Task[None] | None = None
61
63
  self._update_encoder_decoder(
62
64
  LocalChannelParams(local_key=local_key, connect_nonce=get_next_int(10000, 32767), ack_nonce=None)
63
65
  )
@@ -132,6 +134,28 @@ class LocalChannel(Channel):
132
134
 
133
135
  raise RoborockException("Failed to connect to device with any known protocol")
134
136
 
137
+ async def _ping(self) -> None:
138
+ ping_message = RoborockMessage(
139
+ protocol=RoborockMessageProtocol.PING_REQUEST, version=self.protocol_version.encode()
140
+ )
141
+ await self._send_message(
142
+ roborock_message=ping_message,
143
+ request_id=ping_message.seq,
144
+ response_protocol=RoborockMessageProtocol.PING_RESPONSE,
145
+ )
146
+
147
+ async def _keep_alive_loop(self) -> None:
148
+ while self._is_connected:
149
+ try:
150
+ await asyncio.sleep(_PING_INTERVAL)
151
+ if self._is_connected:
152
+ await self._ping()
153
+ except asyncio.CancelledError:
154
+ break
155
+ except Exception:
156
+ _LOGGER.debug("Keep-alive ping failed", exc_info=True)
157
+ # Retry next interval
158
+
135
159
  @property
136
160
  def protocol_version(self) -> LocalProtocolVersion:
137
161
  """Return the negotiated local protocol version, or a sensible default."""
@@ -166,6 +190,7 @@ class LocalChannel(Channel):
166
190
  # Perform protocol negotiation
167
191
  try:
168
192
  await self._hello()
193
+ self._keep_alive_task = asyncio.create_task(self._keep_alive_loop())
169
194
  except RoborockException:
170
195
  # If protocol negotiation fails, clean up the connection state
171
196
  self.close()
@@ -177,6 +202,9 @@ class LocalChannel(Channel):
177
202
 
178
203
  def close(self) -> None:
179
204
  """Disconnect from the device."""
205
+ if self._keep_alive_task:
206
+ self._keep_alive_task.cancel()
207
+ self._keep_alive_task = None
180
208
  if self._transport:
181
209
  self._transport.close()
182
210
  else:
@@ -187,6 +215,9 @@ class LocalChannel(Channel):
187
215
  def _connection_lost(self, exc: Exception | None) -> None:
188
216
  """Handle connection loss."""
189
217
  _LOGGER.warning("Connection lost to %s", self._host, exc_info=exc)
218
+ if self._keep_alive_task:
219
+ self._keep_alive_task.cancel()
220
+ self._keep_alive_task = None
190
221
  self._transport = None
191
222
  self._is_connected = False
192
223
 
@@ -24,7 +24,7 @@ class CleanSummaryTrait(CleanSummaryWithDetail, common.V1TraitMixin):
24
24
  _LOGGER.debug("No clean records available in clean summary.")
25
25
  self.last_clean_record = None
26
26
  return
27
- last_record_id = self.records[-1]
27
+ last_record_id = self.records[0]
28
28
  self.last_clean_record = await self.get_clean_record(last_record_id)
29
29
 
30
30
  @classmethod
@@ -135,7 +135,7 @@ def decode_rpc_response(message: RoborockMessage) -> ResponseMessage:
135
135
  return ResponseMessage(request_id=message.seq, data={})
136
136
  try:
137
137
  payload = json.loads(message.payload.decode())
138
- except (json.JSONDecodeError, TypeError) as e:
138
+ except (json.JSONDecodeError, TypeError, UnicodeDecodeError) as e:
139
139
  raise RoborockException(f"Invalid V1 message payload: {e} for {message.payload!r}") from e
140
140
 
141
141
  _LOGGER.debug("Decoded V1 message payload: %s", payload)