Skip to content

Commit 9f34308

Browse files
authored
Merge branch 'main' into add-qrevo-curv
2 parents eb415ea + 2d24a66 commit 9f34308

File tree

9 files changed

+2269
-486
lines changed

9 files changed

+2269
-486
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
actions: write
6969
packages: write
7070
environment:
71-
name: pypi
71+
name: release
7272

7373
steps:
7474
- uses: actions/checkout@v4
@@ -79,7 +79,7 @@ jobs:
7979
id: release
8080
uses: python-semantic-release/python-semantic-release@v9.14.0
8181
with:
82-
github_token: ${{ secrets.GITHUB_TOKEN }}
82+
github_token: ${{ secrets.GH_TOKEN }}
8383

8484
- name: Publish package distributions to PyPI
8585
uses: pypa/gh-action-pypi-publish@v1.12.2
@@ -92,4 +92,4 @@ jobs:
9292
uses: python-semantic-release/upload-to-gh-release@v8.7.0
9393
if: steps.release.outputs.released == 'true'
9494
with:
95-
github_token: ${{ secrets.GITHUB_TOKEN }}
95+
github_token: ${{ secrets.GH_TOKEN }}

CHANGELOG.md

Lines changed: 2225 additions & 459 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "python-roborock"
3-
version = "2.8.0"
3+
version = "2.8.5"
44
description = "A package to control Roborock vacuums."
55
authors = ["humbertogontijo <humbertogontijo@users.noreply.github.com>"]
66
license = "GPL-3.0-only"

roborock/api.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import logging
88
import secrets
99
import time
10-
from collections.abc import Callable, Coroutine
10+
from collections.abc import Coroutine
1111
from typing import Any
1212

1313
from .containers import (
@@ -36,8 +36,8 @@ def __init__(self, endpoint: str, device_info: DeviceData, queue_timeout: int =
3636
self._endpoint = endpoint
3737
self._nonce = secrets.token_bytes(16)
3838
self._waiting_queue: dict[int, RoborockFuture] = {}
39-
self._last_device_msg_in = self.time_func()
40-
self._last_disconnection = self.time_func()
39+
self._last_device_msg_in = time.monotonic()
40+
self._last_disconnection = time.monotonic()
4141
self.keep_alive = KEEPALIVE
4242
self._diagnostic_data: dict[str, dict[str, Any]] = {
4343
"misc_info": {"Nonce": base64.b64encode(self._nonce).decode("utf-8")}
@@ -59,15 +59,6 @@ async def async_release(self) -> None:
5959
def diagnostic_data(self) -> dict:
6060
return self._diagnostic_data
6161

62-
@property
63-
def time_func(self) -> Callable[[], float]:
64-
try:
65-
# Use monotonic clock if available
66-
time_func = time.monotonic
67-
except AttributeError:
68-
time_func = time.time
69-
return time_func
70-
7162
async def async_connect(self):
7263
raise NotImplementedError
7364

@@ -81,13 +72,13 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
8172
raise NotImplementedError
8273

8374
def on_connection_lost(self, exc: Exception | None) -> None:
84-
self._last_disconnection = self.time_func()
75+
self._last_disconnection = time.monotonic()
8576
self._logger.info("Roborock client disconnected")
8677
if exc is not None:
8778
self._logger.warning(exc)
8879

8980
def should_keepalive(self) -> bool:
90-
now = self.time_func()
81+
now = time.monotonic()
9182
# noinspection PyUnresolvedReferences
9283
if now - self._last_disconnection > self.keep_alive**2 and now - self._last_device_msg_in > self.keep_alive:
9384
return False
@@ -116,8 +107,11 @@ def _async_response(
116107
if request_id in self._waiting_queue:
117108
new_id = get_next_int(10000, 32767)
118109
_LOGGER.warning(
119-
f"Attempting to create a future with an existing request_id... New id is {new_id}. "
120-
f"Code may not function properly."
110+
"Attempting to create a future with an existing id %s (%s)... New id is %s. "
111+
"Code may not function properly.",
112+
request_id,
113+
protocol_id,
114+
new_id,
121115
)
122116
request_id = new_id
123117
self._waiting_queue[request_id] = queue

roborock/code_mappings.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,14 @@ class RoborockFanSpeedQ7Max(RoborockFanPowerCode):
244244

245245

246246
class RoborockFanSpeedQRevoMaster(RoborockFanPowerCode):
247+
off = 105
247248
quiet = 101
248249
balanced = 102
249250
turbo = 103
250251
max = 104
251-
max_plus = 105
252-
custom = 110 # Smartplan
252+
custom = 106
253+
max_plus = 108
254+
smart_mode = 110
253255

254256

255257
class RoborockFanSpeedQRevoCurv(RoborockFanPowerCode):
@@ -321,6 +323,15 @@ class RoborockMopModeS8MaxVUltra(RoborockMopModeCode):
321323
smart_mode = 306
322324

323325

326+
class RoborockMopModeQRevoMaster(RoborockMopModeCode):
327+
standard = 300
328+
deep = 301
329+
custom = 302
330+
deep_plus = 303
331+
fast = 304
332+
smart_mode = 306
333+
334+
324335
class RoborockMopIntensityCode(RoborockEnum):
325336
"""Describes the mop intensity of the vacuum cleaner."""
326337

@@ -352,8 +363,9 @@ class RoborockMopIntensityQRevoMaster(RoborockMopIntensityCode):
352363
low = 201
353364
medium = 202
354365
high = 203
366+
custom = 204
355367
custom_water_flow = 207
356-
custom = 209 # SmartPlan
368+
smart_mode = 209
357369

358370

359371
class RoborockMopIntensityQRevoCurv(RoborockMopIntensityCode):
@@ -443,6 +455,7 @@ class RoborockDockTypeCode(RoborockEnum):
443455
p10_dock = 8
444456
p10_pro_dock = 9
445457
s8_maxv_ultra_dock = 10
458+
qrevo_master_dock = 14
446459
qrevo_s_dock = 15
447460
qrevo_curv_dock = 17
448461

roborock/containers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
RoborockMopIntensityS8MaxVUltra,
4040
RoborockMopModeCode,
4141
RoborockMopModeQRevoCurv,
42+
RoborockMopModeQRevoMaster,
4243
RoborockMopModeS7,
4344
RoborockMopModeS8MaxVUltra,
4445
RoborockMopModeS8ProUltra,
@@ -145,12 +146,12 @@ def from_dict(cls, data: dict[str, Any]):
145146
cls_annotations.update(getattr(base, "__annotations__", {}))
146147
remove_keys = []
147148
for key, value in data.items():
148-
if value == "None" or value is None:
149-
data[key] = None
150-
continue
151149
if key not in cls_annotations:
152150
remove_keys.append(key)
153151
continue
152+
if value == "None" or value is None:
153+
data[key] = None
154+
continue
154155
field_type: str = cls_annotations[key]
155156
if "|" in field_type:
156157
# It's a union
@@ -581,6 +582,7 @@ class Q7MaxStatus(Status):
581582
class QRevoMasterStatus(Status):
582583
fan_power: RoborockFanSpeedQRevoMaster | None = None
583584
water_box_mode: RoborockMopIntensityQRevoMaster | None = None
585+
mop_mode: RoborockMopModeQRevoMaster | None = None
584586

585587

586588
@dataclass

roborock/version_1_apis/roborock_client_v1.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def _get_payload(
362362

363363
def on_message_received(self, messages: list[RoborockMessage]) -> None:
364364
try:
365-
self._last_device_msg_in = self.time_func()
365+
self._last_device_msg_in = time.monotonic()
366366
for data in messages:
367367
protocol = data.protocol
368368
if data.payload and protocol in [
@@ -392,6 +392,8 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
392392
if isinstance(result, list) and len(result) == 1:
393393
result = result[0]
394394
queue.resolve((result, None))
395+
else:
396+
self._logger.debug("Received response for unknown request id %s", request_id)
395397
else:
396398
try:
397399
data_protocol = RoborockDataProtocol(int(data_point_number))
@@ -444,10 +446,14 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
444446
if isinstance(decompressed, list):
445447
decompressed = decompressed[0]
446448
queue.resolve((decompressed, None))
449+
else:
450+
self._logger.debug("Received response for unknown request id %s", request_id)
447451
else:
448452
queue = self._waiting_queue.get(data.seq)
449453
if queue:
450454
queue.resolve((data.payload, None))
455+
else:
456+
self._logger.debug("Received response for unknown request id %s", data.seq)
451457
except Exception as ex:
452458
self._logger.exception(ex)
453459

roborock/version_1_apis/roborock_local_client_v1.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def build_roborock_message(
1818
) -> RoborockMessage:
1919
secured = True if method in COMMANDS_SECURED else False
2020
request_id, timestamp, payload = self._get_payload(method, params, secured)
21+
self._logger.debug("Building message id %s for method %s", request_id, method)
2122
request_protocol = RoborockMessageProtocol.GENERAL_REQUEST
2223
message_retry: MessageRetry | None = None
2324
if method == RoborockCommand.RETRY_REQUEST and isinstance(params, dict):

roborock/version_1_apis/roborock_mqtt_client_v1.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ async def _send_command(
7474
# When we have more custom commands do something more complicated here
7575
return await self._get_calibration_points()
7676
request_id, timestamp, payload = self._get_payload(method, params, True)
77+
self._logger.debug("Building message id %s for method %s", request_id, method)
7778
request_protocol = RoborockMessageProtocol.RPC_REQUEST
7879
roborock_message = RoborockMessage(timestamp=timestamp, protocol=request_protocol, payload=payload)
7980
return await self.send_message(roborock_message)

0 commit comments

Comments
 (0)