python-roborock 1.0.0__tar.gz → 2.1.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.
- {python_roborock-1.0.0 → python_roborock-2.1.0}/PKG-INFO +1 -1
- {python_roborock-1.0.0 → python_roborock-2.1.0}/pyproject.toml +1 -1
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/api.py +0 -9
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/code_mappings.py +172 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/const.py +1 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/containers.py +12 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/protocol.py +2 -3
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/roborock_message.py +42 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/roborock_typing.py +29 -0
- python_roborock-2.1.0/roborock/version_a01_apis/roborock_client_a01.py +142 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +21 -8
- python_roborock-1.0.0/roborock/version_a01_apis/roborock_client_a01.py +0 -100
- {python_roborock-1.0.0 → python_roborock-2.1.0}/LICENSE +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/README.md +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/__init__.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/cli.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/cloud_api.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/command_cache.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/exceptions.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/local_api.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/py.typed +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/roborock_future.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/util.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/web_api.py +0 -0
|
@@ -12,9 +12,6 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
from .containers import (
|
|
14
14
|
DeviceData,
|
|
15
|
-
ModelStatus,
|
|
16
|
-
S7MaxVStatus,
|
|
17
|
-
Status,
|
|
18
15
|
)
|
|
19
16
|
from .exceptions import (
|
|
20
17
|
RoborockTimeout,
|
|
@@ -48,16 +45,10 @@ class RoborockClient:
|
|
|
48
45
|
self._logger = RoborockLoggerAdapter(device_info.device.name, _LOGGER)
|
|
49
46
|
self.is_available: bool = True
|
|
50
47
|
self.queue_timeout = queue_timeout
|
|
51
|
-
self._status_type: type[Status] = ModelStatus.get(self.device_info.model, S7MaxVStatus)
|
|
52
48
|
|
|
53
49
|
def __del__(self) -> None:
|
|
54
50
|
self.release()
|
|
55
51
|
|
|
56
|
-
@property
|
|
57
|
-
def status_type(self) -> type[Status]:
|
|
58
|
-
"""Gets the status type for this device"""
|
|
59
|
-
return self._status_type
|
|
60
|
-
|
|
61
52
|
def release(self):
|
|
62
53
|
self.sync_disconnect()
|
|
63
54
|
|
|
@@ -65,10 +65,12 @@ class RoborockStateCode(RoborockEnum):
|
|
|
65
65
|
segment_cleaning = 18
|
|
66
66
|
emptying_the_bin = 22 # on s7+
|
|
67
67
|
washing_the_mop = 23 # on a46
|
|
68
|
+
washing_the_mop_2 = 25
|
|
68
69
|
going_to_wash_the_mop = 26 # on a46
|
|
69
70
|
in_call = 28
|
|
70
71
|
mapping = 29
|
|
71
72
|
egg_attack = 30
|
|
73
|
+
patrol = 32
|
|
72
74
|
charging_complete = 100
|
|
73
75
|
device_offline = 101
|
|
74
76
|
locked = 103
|
|
@@ -126,6 +128,7 @@ class RoborockErrorCode(RoborockEnum):
|
|
|
126
128
|
side_brush_error = 17
|
|
127
129
|
fan_error = 18
|
|
128
130
|
dock = 19 # Dock not connected to power
|
|
131
|
+
optical_flow_sensor_dirt = 20
|
|
129
132
|
vertical_bumper_pressed = 21
|
|
130
133
|
dock_locator_error = 22
|
|
131
134
|
return_to_dock_fail = 23
|
|
@@ -150,7 +153,14 @@ class RoborockErrorCode(RoborockEnum):
|
|
|
150
153
|
clear_brush_exception_2 = 43 # Positioning button error
|
|
151
154
|
filter_screen_exception = 44 # Clean the dock water filter
|
|
152
155
|
mopping_roller_2 = 45 # Wash roller may be jammed
|
|
156
|
+
up_water_exception = 48
|
|
157
|
+
drain_water_exception = 49
|
|
153
158
|
temperature_protection = 51 # Unit temperature protection
|
|
159
|
+
clean_carousel_exception = 52
|
|
160
|
+
clean_carousel_water_full = 53
|
|
161
|
+
water_carriage_drop = 54
|
|
162
|
+
check_clean_carouse = 55
|
|
163
|
+
audio_error = 56
|
|
154
164
|
|
|
155
165
|
|
|
156
166
|
class RoborockFanPowerCode(RoborockEnum):
|
|
@@ -236,6 +246,14 @@ class RoborockFanSpeedP10(RoborockFanPowerCode):
|
|
|
236
246
|
max_plus = 108
|
|
237
247
|
|
|
238
248
|
|
|
249
|
+
class RoborockFanSpeedS8MaxVUltra(RoborockFanPowerCode):
|
|
250
|
+
off = 105
|
|
251
|
+
balanced = 102
|
|
252
|
+
custom = 106
|
|
253
|
+
max_plus = 108
|
|
254
|
+
smart_mode = 110
|
|
255
|
+
|
|
256
|
+
|
|
239
257
|
class RoborockMopModeCode(RoborockEnum):
|
|
240
258
|
"""Describes the mop mode of the vacuum cleaner."""
|
|
241
259
|
|
|
@@ -257,6 +275,15 @@ class RoborockMopModeS8ProUltra(RoborockMopModeCode):
|
|
|
257
275
|
custom = 302
|
|
258
276
|
|
|
259
277
|
|
|
278
|
+
class RoborockMopModeS8MaxVUltra(RoborockMopModeCode):
|
|
279
|
+
standard = 300
|
|
280
|
+
deep = 301
|
|
281
|
+
deep_plus = 303
|
|
282
|
+
fast = 304
|
|
283
|
+
deep_plus_pearl = 305
|
|
284
|
+
smart_mode = 306
|
|
285
|
+
|
|
286
|
+
|
|
260
287
|
class RoborockMopIntensityCode(RoborockEnum):
|
|
261
288
|
"""Describes the mop intensity of the vacuum cleaner."""
|
|
262
289
|
|
|
@@ -292,6 +319,14 @@ class RoborockMopIntensityP10(RoborockMopIntensityCode):
|
|
|
292
319
|
custom_water_flow = 207
|
|
293
320
|
|
|
294
321
|
|
|
322
|
+
class RoborockMopIntensityS8MaxVUltra(RoborockMopIntensityCode):
|
|
323
|
+
off = 200
|
|
324
|
+
low = 201
|
|
325
|
+
medium = 202
|
|
326
|
+
smart_mode = 209
|
|
327
|
+
custom_water_flow = 207
|
|
328
|
+
|
|
329
|
+
|
|
295
330
|
class RoborockMopIntensityS5Max(RoborockMopIntensityCode):
|
|
296
331
|
"""Describes the mop intensity of the vacuum cleaner."""
|
|
297
332
|
|
|
@@ -321,6 +356,7 @@ class RoborockDockErrorCode(RoborockEnum):
|
|
|
321
356
|
duct_blockage = 34
|
|
322
357
|
water_empty = 38
|
|
323
358
|
waste_water_tank_full = 39
|
|
359
|
+
maintenance_brush_jammed = 42
|
|
324
360
|
dirty_tank_latch_open = 44
|
|
325
361
|
no_dustbin = 46
|
|
326
362
|
cleaning_tank_full_or_blocked = 53
|
|
@@ -335,6 +371,7 @@ class RoborockDockTypeCode(RoborockEnum):
|
|
|
335
371
|
s7_max_ultra_dock = 6
|
|
336
372
|
s8_dock = 7
|
|
337
373
|
p10_dock = 8
|
|
374
|
+
s8_maxv_ultra_dock = 10
|
|
338
375
|
|
|
339
376
|
|
|
340
377
|
class RoborockDockDustCollectionModeCode(RoborockEnum):
|
|
@@ -450,3 +487,138 @@ class DyadError(RoborockEnum):
|
|
|
450
487
|
dirty_charging_contacts = 10007 # Disconnection between the device and dock. Wipe charging contacts.
|
|
451
488
|
low_battery = 20017 # Low battery level. Charge before starting self-cleaning.
|
|
452
489
|
battery_under_10 = 20018 # Charge until the battery level exceeds 10% before manually starting self-cleaning.
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class ZeoMode(RoborockEnum):
|
|
493
|
+
wash = 1
|
|
494
|
+
wash_and_dry = 2
|
|
495
|
+
dry = 3
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class ZeoState(RoborockEnum):
|
|
499
|
+
standby = 1
|
|
500
|
+
weighing = 2
|
|
501
|
+
soaking = 3
|
|
502
|
+
washing = 4
|
|
503
|
+
rinsing = 5
|
|
504
|
+
spinning = 6
|
|
505
|
+
drying = 7
|
|
506
|
+
cooling = 8
|
|
507
|
+
under_delay_start = 9
|
|
508
|
+
done = 10
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
class ZeoProgram(RoborockEnum):
|
|
512
|
+
standard = 1
|
|
513
|
+
quick = 2
|
|
514
|
+
sanitize = 3
|
|
515
|
+
wool = 4
|
|
516
|
+
air_refresh = 5
|
|
517
|
+
custom = 6
|
|
518
|
+
bedding = 7
|
|
519
|
+
down = 8
|
|
520
|
+
silk = 9
|
|
521
|
+
rinse_and_spin = 10
|
|
522
|
+
spin = 11
|
|
523
|
+
down_clean = 12
|
|
524
|
+
baby_care = 13
|
|
525
|
+
anti_allergen = 14
|
|
526
|
+
sportswear = 15
|
|
527
|
+
night = 16
|
|
528
|
+
new_clothes = 17
|
|
529
|
+
shirts = 18
|
|
530
|
+
synthetics = 19
|
|
531
|
+
underwear = 20
|
|
532
|
+
gentle = 21
|
|
533
|
+
intensive = 22
|
|
534
|
+
cotton_linen = 23
|
|
535
|
+
season = 24
|
|
536
|
+
warming = 25
|
|
537
|
+
bra = 26
|
|
538
|
+
panties = 27
|
|
539
|
+
boiling_wash = 28
|
|
540
|
+
socks = 30
|
|
541
|
+
towels = 31
|
|
542
|
+
anti_mite = 32
|
|
543
|
+
exo_40_60 = 33
|
|
544
|
+
twenty_c = 34
|
|
545
|
+
t_shirts = 35
|
|
546
|
+
stain_removal = 36
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
class ZeoSoak(RoborockEnum):
|
|
550
|
+
normal = 0
|
|
551
|
+
low = 1
|
|
552
|
+
medium = 2
|
|
553
|
+
high = 3
|
|
554
|
+
max = 4
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
class ZeoTemperature(RoborockEnum):
|
|
558
|
+
normal = 1
|
|
559
|
+
low = 2
|
|
560
|
+
medium = 3
|
|
561
|
+
high = 4
|
|
562
|
+
max = 5
|
|
563
|
+
twenty_c = 6
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
class ZeoRinse(RoborockEnum):
|
|
567
|
+
none = 0
|
|
568
|
+
min = 1
|
|
569
|
+
low = 2
|
|
570
|
+
mid = 3
|
|
571
|
+
high = 4
|
|
572
|
+
max = 5
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
class ZeoSpin(RoborockEnum):
|
|
576
|
+
none = 1
|
|
577
|
+
very_low = 2
|
|
578
|
+
low = 3
|
|
579
|
+
mid = 4
|
|
580
|
+
high = 5
|
|
581
|
+
very_high = 6
|
|
582
|
+
max = 7
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
class ZeoDryingMode(RoborockEnum):
|
|
586
|
+
none = 0
|
|
587
|
+
quick = 1
|
|
588
|
+
iron = 2
|
|
589
|
+
store = 3
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
class ZeoDetergentType(RoborockEnum):
|
|
593
|
+
empty = 0
|
|
594
|
+
low = 1
|
|
595
|
+
medium = 2
|
|
596
|
+
high = 3
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
class ZeoSoftenerType(RoborockEnum):
|
|
600
|
+
empty = 0
|
|
601
|
+
low = 1
|
|
602
|
+
medium = 2
|
|
603
|
+
high = 3
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class ZeoError(RoborockEnum):
|
|
607
|
+
none = 0
|
|
608
|
+
refill_error = 1
|
|
609
|
+
drain_error = 2
|
|
610
|
+
door_lock_error = 3
|
|
611
|
+
water_level_error = 4
|
|
612
|
+
inverter_error = 5
|
|
613
|
+
heating_error = 6
|
|
614
|
+
temperature_error = 7
|
|
615
|
+
communication_error = 10
|
|
616
|
+
drying_error = 11
|
|
617
|
+
drying_error_e_12 = 12
|
|
618
|
+
drying_error_e_13 = 13
|
|
619
|
+
drying_error_e_14 = 14
|
|
620
|
+
drying_error_e_15 = 15
|
|
621
|
+
drying_error_e_16 = 16
|
|
622
|
+
drying_error_water_flow = 17 # Check for normal water flow
|
|
623
|
+
drying_error_restart = 18 # Restart the washer and try again
|
|
624
|
+
spin_error = 19 # re-arrange clothes
|
|
@@ -43,6 +43,7 @@ ROBOROCK_C1 = "roborock.vacuum.c1"
|
|
|
43
43
|
ROBOROCK_S8_PRO_ULTRA = "roborock.vacuum.a70"
|
|
44
44
|
ROBOROCK_S8 = "roborock.vacuum.a51"
|
|
45
45
|
ROBOROCK_P10 = "roborock.vacuum.a75"
|
|
46
|
+
ROBOROCK_S8_MAXV_ULTRA = "roborock.vacuum.a97"
|
|
46
47
|
|
|
47
48
|
ROBOROCK_DYAD_AIR = "roborock.wetdryvac.a107"
|
|
48
49
|
ROBOROCK_DYAD_PRO_COMBO = "roborock.wetdryvac.a83"
|
|
@@ -24,14 +24,17 @@ from .code_mappings import (
|
|
|
24
24
|
RoborockFanSpeedS6Pure,
|
|
25
25
|
RoborockFanSpeedS7,
|
|
26
26
|
RoborockFanSpeedS7MaxV,
|
|
27
|
+
RoborockFanSpeedS8MaxVUltra,
|
|
27
28
|
RoborockMopIntensityCode,
|
|
28
29
|
RoborockMopIntensityP10,
|
|
29
30
|
RoborockMopIntensityS5Max,
|
|
30
31
|
RoborockMopIntensityS6MaxV,
|
|
31
32
|
RoborockMopIntensityS7,
|
|
33
|
+
RoborockMopIntensityS8MaxVUltra,
|
|
32
34
|
RoborockMopIntensityV2,
|
|
33
35
|
RoborockMopModeCode,
|
|
34
36
|
RoborockMopModeS7,
|
|
37
|
+
RoborockMopModeS8MaxVUltra,
|
|
35
38
|
RoborockMopModeS8ProUltra,
|
|
36
39
|
RoborockStateCode,
|
|
37
40
|
)
|
|
@@ -52,6 +55,7 @@ from .const import (
|
|
|
52
55
|
ROBOROCK_S7,
|
|
53
56
|
ROBOROCK_S7_MAXV,
|
|
54
57
|
ROBOROCK_S8,
|
|
58
|
+
ROBOROCK_S8_MAXV_ULTRA,
|
|
55
59
|
ROBOROCK_S8_PRO_ULTRA,
|
|
56
60
|
SENSOR_DIRTY_REPLACE_TIME,
|
|
57
61
|
SIDE_BRUSH_REPLACE_TIME,
|
|
@@ -550,6 +554,13 @@ class P10Status(Status):
|
|
|
550
554
|
mop_mode: RoborockMopModeS8ProUltra | None = None
|
|
551
555
|
|
|
552
556
|
|
|
557
|
+
@dataclass
|
|
558
|
+
class S8MaxvUltraStatus(Status):
|
|
559
|
+
fan_power: RoborockFanSpeedS8MaxVUltra | None = None
|
|
560
|
+
water_box_mode: RoborockMopIntensityS8MaxVUltra | None = None
|
|
561
|
+
mop_mode: RoborockMopModeS8MaxVUltra | None = None
|
|
562
|
+
|
|
563
|
+
|
|
553
564
|
ModelStatus: dict[str, type[Status]] = {
|
|
554
565
|
ROBOROCK_S4_MAX: S4MaxStatus,
|
|
555
566
|
ROBOROCK_S5_MAX: S5MaxStatus,
|
|
@@ -563,6 +574,7 @@ ModelStatus: dict[str, type[Status]] = {
|
|
|
563
574
|
ROBOROCK_S8_PRO_ULTRA: S8ProUltraStatus,
|
|
564
575
|
ROBOROCK_G10S_PRO: S7MaxVStatus,
|
|
565
576
|
ROBOROCK_P10: P10Status,
|
|
577
|
+
ROBOROCK_S8_MAXV_ULTRA: S8MaxvUltraStatus,
|
|
566
578
|
}
|
|
567
579
|
|
|
568
580
|
|
|
@@ -36,7 +36,6 @@ from roborock.roborock_message import RoborockMessage
|
|
|
36
36
|
_LOGGER = logging.getLogger(__name__)
|
|
37
37
|
SALT = b"TXdfu$jyZ#TZHsg4"
|
|
38
38
|
A01_HASH = "726f626f726f636b2d67a6d6da"
|
|
39
|
-
A01_AES_DECIPHER = "ELSYN0wTI4AUm7C4"
|
|
40
39
|
BROADCAST_TOKEN = b"qWKYcdQWrbm9hPqe"
|
|
41
40
|
AP_CONFIG = 1
|
|
42
41
|
SOCK_DISCOVERY = 2
|
|
@@ -208,7 +207,7 @@ class EncryptionAdapter(Construct):
|
|
|
208
207
|
"""
|
|
209
208
|
if context.version == b"A01":
|
|
210
209
|
iv = md5hex(format(context.random, "08x") + A01_HASH)[8:24]
|
|
211
|
-
decipher = AES.new(bytes(
|
|
210
|
+
decipher = AES.new(bytes(context.search("local_key"), "utf-8"), AES.MODE_CBC, bytes(iv, "utf-8"))
|
|
212
211
|
f = decipher.encrypt(obj)
|
|
213
212
|
return f
|
|
214
213
|
token = self.token_func(context)
|
|
@@ -219,7 +218,7 @@ class EncryptionAdapter(Construct):
|
|
|
219
218
|
"""Decrypts the given payload with the token stored in the context."""
|
|
220
219
|
if context.version == b"A01":
|
|
221
220
|
iv = md5hex(format(context.random, "08x") + A01_HASH)[8:24]
|
|
222
|
-
decipher = AES.new(bytes(
|
|
221
|
+
decipher = AES.new(bytes(context.search("local_key"), "utf-8"), AES.MODE_CBC, bytes(iv, "utf-8"))
|
|
223
222
|
f = decipher.decrypt(obj)
|
|
224
223
|
return f
|
|
225
224
|
token = self.token_func(context)
|
|
@@ -87,6 +87,48 @@ class RoborockDyadDataProtocol(RoborockEnum):
|
|
|
87
87
|
RPC_RESPONSE = 10102
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
class RoborockZeoProtocol(RoborockEnum):
|
|
91
|
+
START = 200 # rw
|
|
92
|
+
PAUSE = 201 # rw
|
|
93
|
+
SHUTDOWN = 202 # rw
|
|
94
|
+
STATE = 203 # ro
|
|
95
|
+
MODE = 204 # rw
|
|
96
|
+
PROGRAM = 205 # rw
|
|
97
|
+
CHILD_LOCK = 206 # rw
|
|
98
|
+
TEMP = 207 # rw
|
|
99
|
+
RINSE_TIMES = 208 # rw
|
|
100
|
+
SPIN_LEVEL = 209 # rw
|
|
101
|
+
DRYING_MODE = 210 # rw
|
|
102
|
+
DETERGENT_SET = 211 # rw
|
|
103
|
+
SOFTENER_SET = 212 # rw
|
|
104
|
+
DETERGENT_TYPE = 213 # rw
|
|
105
|
+
SOFTENER_TYPE = 214 # rw
|
|
106
|
+
COUNTDOWN = 217 # rw
|
|
107
|
+
WASHING_LEFT = 218 # ro
|
|
108
|
+
DOORLOCK_STATE = 219 # ro
|
|
109
|
+
ERROR = 220 # ro
|
|
110
|
+
CUSTOM_PARAM_SAVE = 221 # rw
|
|
111
|
+
CUSTOM_PARAM_GET = 222 # ro
|
|
112
|
+
SOUND_SET = 223 # rw
|
|
113
|
+
TIMES_AFTER_CLEAN = 224 # ro
|
|
114
|
+
DEFAULT_SETTING = 225 # rw
|
|
115
|
+
DETERGENT_EMPTY = 226 # ro
|
|
116
|
+
SOFTENER_EMPTY = 227 # ro
|
|
117
|
+
LIGHT_SETTING = 229 # rw
|
|
118
|
+
DETERGENT_VOLUME = 230 # rw
|
|
119
|
+
SOFTENER_VOLUME = 231 # rw
|
|
120
|
+
APP_AUTHORIZATION = 232 # rw
|
|
121
|
+
ID_QUERY = 10000
|
|
122
|
+
F_C = 10001
|
|
123
|
+
SND_STATE = 10004
|
|
124
|
+
PRODUCT_INFO = 10005
|
|
125
|
+
PRIVACY_INFO = 10006
|
|
126
|
+
OTA_NFO = 10007
|
|
127
|
+
WASHING_LOG = 10008
|
|
128
|
+
RPC_REQ = 10101
|
|
129
|
+
RPC_RESp = 10102
|
|
130
|
+
|
|
131
|
+
|
|
90
132
|
ROBOROCK_DATA_STATUS_PROTOCOL = [
|
|
91
133
|
RoborockDataProtocol.ERROR_CODE,
|
|
92
134
|
RoborockDataProtocol.STATE,
|
|
@@ -35,10 +35,13 @@ class RoborockCommand(str, Enum):
|
|
|
35
35
|
APP_RC_START = "app_rc_start"
|
|
36
36
|
APP_RC_STOP = "app_rc_stop"
|
|
37
37
|
APP_RESUME_BUILD_MAP = "app_resume_build_map"
|
|
38
|
+
APP_RESUME_PATROL = "app_resume_patrol"
|
|
38
39
|
APP_SEGMENT_CLEAN = "app_segment_clean"
|
|
39
40
|
APP_SET_AMETHYST_STATUS = "app_set_amethyst_status"
|
|
40
41
|
APP_SET_CARPET_DEEP_CLEAN_STATUS = "app_set_carpet_deep_clean_status"
|
|
42
|
+
APP_SET_CROSS_CARPET_CLEANING_STATUS = "app_set_cross_carpet_cleaning_status"
|
|
41
43
|
APP_SET_DOOR_SILL_BLOCKS = "app_set_door_sill_blocks"
|
|
44
|
+
APP_SET_DIRTY_REPLENISH_CLEAN_STATUS = "app_set_dirty_replenish_clean_status"
|
|
42
45
|
APP_SET_DRYER_SETTING = "app_set_dryer_setting"
|
|
43
46
|
APP_SET_DRYER_STATUS = "app_set_dryer_status"
|
|
44
47
|
APP_SET_DYNAMIC_CONFIG = "app_set_dynamic_config"
|
|
@@ -50,6 +53,8 @@ class RoborockCommand(str, Enum):
|
|
|
50
53
|
APP_START_BUILD_MAP = "app_start_build_map"
|
|
51
54
|
APP_START_COLLECT_DUST = "app_start_collect_dust"
|
|
52
55
|
APP_START_EASTER_EGG = "app_start_easter_egg"
|
|
56
|
+
APP_START_PATROL = "app_start_patrol"
|
|
57
|
+
APP_START_PET_PATROL = "app_start_pet_patrol"
|
|
53
58
|
APP_START_WASH = "app_start_wash"
|
|
54
59
|
APP_STAT = "app_stat"
|
|
55
60
|
APP_STOP = "app_stop"
|
|
@@ -177,6 +182,7 @@ class RoborockCommand(str, Enum):
|
|
|
177
182
|
SET_CLEAN_FOLLOW_GROUND_MATERIAL_STATUS = "set_clean_follow_ground_material_status"
|
|
178
183
|
SET_CLEAN_MOTOR_MODE = "set_clean_motor_mode"
|
|
179
184
|
SET_CLEAN_SEQUENCE = "set_clean_sequence"
|
|
185
|
+
SET_CLEAN_REPEAT_TIMES = "set_clean_repeat_times"
|
|
180
186
|
SET_COLLISION_AVOID_STATUS = "set_collision_avoid_status"
|
|
181
187
|
SET_CUSTOM_MODE = "set_custom_mode"
|
|
182
188
|
SET_CUSTOMIZE_CLEAN_MODE = "set_customize_clean_mode"
|
|
@@ -239,6 +245,29 @@ class RoborockCommand(str, Enum):
|
|
|
239
245
|
USE_NEW_MAP = "use_new_map"
|
|
240
246
|
USE_OLD_MAP = "use_old_map"
|
|
241
247
|
USER_UPLOAD_LOG = "user_upload_log"
|
|
248
|
+
SET_STRETCH_TAG_STATUS = "set_stretch_tag_status"
|
|
249
|
+
GET_STRETCH_TAG_STATUS = "get_stretch_tag_status"
|
|
250
|
+
SET_RIGHT_BRUSH_STRETCH_STATUS = "set_right_brush_stretch_status"
|
|
251
|
+
GET_RIGHT_BRUSH_STRETCH_STATUS = "get_right_brush_stretch_status"
|
|
252
|
+
SET_DIRTY_OBJECT_DETECT_STATUS = "set_dirty_object_detect_status"
|
|
253
|
+
GET_DIRTY_OBJECT_DETECT_STATUS = "get_dirty_object_detect_status"
|
|
254
|
+
SET_WASH_WATER_TEMPERATURE = "set_wash_water_temperature"
|
|
255
|
+
GET_WASH_WATER_TEMPERATURE = "get_wash_water_temperature"
|
|
256
|
+
APP_EMPTY_RINSE_TANK_WATER = "app_empty_rinse_tank_water"
|
|
257
|
+
SET_PET_SUPPLIES_DEEP_CLEAN_STATUS = "set_pet_supplies_deep_clean_status"
|
|
258
|
+
GET_PET_SUPPLIES_DEEP_CLEAN_STATUS = "get_pet_supplies_deep_clean_status"
|
|
259
|
+
SET_AP_MIC_LED_STATUS = "set_ap_mic_led_status"
|
|
260
|
+
GET_AP_MIC_LED_STATUS = "get_ap_mic_led_status"
|
|
261
|
+
SET_HANDLE_LEAK_WATER_STATUS = "set_handle_leak_water_status"
|
|
262
|
+
GET_HANDLE_LEAK_WATER_STATUS = "get_handle_leak_water_status"
|
|
263
|
+
APP_IGNORE_DIRTY_OBJECTS = "app_ignore_dirty_objects"
|
|
264
|
+
MATTER_GET_STATUS = "matter.get_status"
|
|
265
|
+
MATTER_DNLD_KEY = "matter.dnld_key"
|
|
266
|
+
MATTER_RESET = "matter.reset"
|
|
267
|
+
SET_GAP_DEEP_CLEAN_STATUS = "set_gap_deep_clean_status"
|
|
268
|
+
GET_GAP_DEEP_CLEAN_STATUS = "get_gap_deep_clean_status"
|
|
269
|
+
APP_SET_ROBOT_SETTING = "app_set_robot_setting"
|
|
270
|
+
APP_GET_ROBOT_SETTING = "app_get_robot_setting"
|
|
242
271
|
|
|
243
272
|
|
|
244
273
|
@dataclass
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import json
|
|
3
|
+
import typing
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from datetime import time
|
|
6
|
+
|
|
7
|
+
from Crypto.Cipher import AES
|
|
8
|
+
from Crypto.Util.Padding import unpad
|
|
9
|
+
|
|
10
|
+
from roborock import DeviceData
|
|
11
|
+
from roborock.api import RoborockClient
|
|
12
|
+
from roborock.code_mappings import (
|
|
13
|
+
DyadBrushSpeed,
|
|
14
|
+
DyadCleanMode,
|
|
15
|
+
DyadError,
|
|
16
|
+
DyadSelfCleanLevel,
|
|
17
|
+
DyadSelfCleanMode,
|
|
18
|
+
DyadSuction,
|
|
19
|
+
DyadWarmLevel,
|
|
20
|
+
DyadWaterLevel,
|
|
21
|
+
RoborockDyadStateCode,
|
|
22
|
+
ZeoDetergentType,
|
|
23
|
+
ZeoDryingMode,
|
|
24
|
+
ZeoError,
|
|
25
|
+
ZeoMode,
|
|
26
|
+
ZeoProgram,
|
|
27
|
+
ZeoRinse,
|
|
28
|
+
ZeoSoftenerType,
|
|
29
|
+
ZeoSpin,
|
|
30
|
+
ZeoState,
|
|
31
|
+
ZeoTemperature,
|
|
32
|
+
)
|
|
33
|
+
from roborock.containers import DyadProductInfo, DyadSndState, RoborockCategory
|
|
34
|
+
from roborock.roborock_message import (
|
|
35
|
+
RoborockDyadDataProtocol,
|
|
36
|
+
RoborockMessage,
|
|
37
|
+
RoborockMessageProtocol,
|
|
38
|
+
RoborockZeoProtocol,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclasses.dataclass
|
|
43
|
+
class A01ProtocolCacheEntry:
|
|
44
|
+
post_process_fn: Callable
|
|
45
|
+
value: typing.Any | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Right now this cache is not active, it was too much complexity for the initial addition of dyad.
|
|
49
|
+
protocol_entries = {
|
|
50
|
+
RoborockDyadDataProtocol.STATUS: A01ProtocolCacheEntry(lambda val: RoborockDyadStateCode(val).name),
|
|
51
|
+
RoborockDyadDataProtocol.SELF_CLEAN_MODE: A01ProtocolCacheEntry(lambda val: DyadSelfCleanMode(val).name),
|
|
52
|
+
RoborockDyadDataProtocol.SELF_CLEAN_LEVEL: A01ProtocolCacheEntry(lambda val: DyadSelfCleanLevel(val).name),
|
|
53
|
+
RoborockDyadDataProtocol.WARM_LEVEL: A01ProtocolCacheEntry(lambda val: DyadWarmLevel(val).name),
|
|
54
|
+
RoborockDyadDataProtocol.CLEAN_MODE: A01ProtocolCacheEntry(lambda val: DyadCleanMode(val).name),
|
|
55
|
+
RoborockDyadDataProtocol.SUCTION: A01ProtocolCacheEntry(lambda val: DyadSuction(val).name),
|
|
56
|
+
RoborockDyadDataProtocol.WATER_LEVEL: A01ProtocolCacheEntry(lambda val: DyadWaterLevel(val).name),
|
|
57
|
+
RoborockDyadDataProtocol.BRUSH_SPEED: A01ProtocolCacheEntry(lambda val: DyadBrushSpeed(val).name),
|
|
58
|
+
RoborockDyadDataProtocol.POWER: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
59
|
+
RoborockDyadDataProtocol.AUTO_DRY: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
60
|
+
RoborockDyadDataProtocol.MESH_LEFT: A01ProtocolCacheEntry(lambda val: int(360000 - val * 60)),
|
|
61
|
+
RoborockDyadDataProtocol.BRUSH_LEFT: A01ProtocolCacheEntry(lambda val: int(360000 - val * 60)),
|
|
62
|
+
RoborockDyadDataProtocol.ERROR: A01ProtocolCacheEntry(lambda val: DyadError(val).name),
|
|
63
|
+
RoborockDyadDataProtocol.VOLUME_SET: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
64
|
+
RoborockDyadDataProtocol.STAND_LOCK_AUTO_RUN: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
65
|
+
RoborockDyadDataProtocol.AUTO_DRY_MODE: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
66
|
+
RoborockDyadDataProtocol.SILENT_DRY_DURATION: A01ProtocolCacheEntry(lambda val: int(val)), # in minutes
|
|
67
|
+
RoborockDyadDataProtocol.SILENT_MODE: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
68
|
+
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: A01ProtocolCacheEntry(
|
|
69
|
+
lambda val: time(hour=int(val / 60), minute=val % 60)
|
|
70
|
+
), # in minutes since 00:00
|
|
71
|
+
RoborockDyadDataProtocol.SILENT_MODE_END_TIME: A01ProtocolCacheEntry(
|
|
72
|
+
lambda val: time(hour=int(val / 60), minute=val % 60)
|
|
73
|
+
), # in minutes since 00:00
|
|
74
|
+
RoborockDyadDataProtocol.RECENT_RUN_TIME: A01ProtocolCacheEntry(
|
|
75
|
+
lambda val: [int(v) for v in val.split(",")]
|
|
76
|
+
), # minutes of cleaning in past few days.
|
|
77
|
+
RoborockDyadDataProtocol.TOTAL_RUN_TIME: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
78
|
+
RoborockDyadDataProtocol.SND_STATE: A01ProtocolCacheEntry(lambda val: DyadSndState.from_dict(val)),
|
|
79
|
+
RoborockDyadDataProtocol.PRODUCT_INFO: A01ProtocolCacheEntry(lambda val: DyadProductInfo.from_dict(val)),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
zeo_data_protocol_entries = {
|
|
83
|
+
# ro
|
|
84
|
+
RoborockZeoProtocol.STATE: A01ProtocolCacheEntry(lambda val: ZeoState(val).name),
|
|
85
|
+
RoborockZeoProtocol.COUNTDOWN: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
86
|
+
RoborockZeoProtocol.WASHING_LEFT: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
87
|
+
RoborockZeoProtocol.ERROR: A01ProtocolCacheEntry(lambda val: ZeoError(val).name),
|
|
88
|
+
RoborockZeoProtocol.TIMES_AFTER_CLEAN: A01ProtocolCacheEntry(lambda val: int(val)),
|
|
89
|
+
RoborockZeoProtocol.DETERGENT_EMPTY: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
90
|
+
RoborockZeoProtocol.SOFTENER_EMPTY: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
91
|
+
# rw
|
|
92
|
+
RoborockZeoProtocol.MODE: A01ProtocolCacheEntry(lambda val: ZeoMode(val).name),
|
|
93
|
+
RoborockZeoProtocol.PROGRAM: A01ProtocolCacheEntry(lambda val: ZeoProgram(val).name),
|
|
94
|
+
RoborockZeoProtocol.TEMP: A01ProtocolCacheEntry(lambda val: ZeoTemperature(val).name),
|
|
95
|
+
RoborockZeoProtocol.RINSE_TIMES: A01ProtocolCacheEntry(lambda val: ZeoRinse(val).name),
|
|
96
|
+
RoborockZeoProtocol.SPIN_LEVEL: A01ProtocolCacheEntry(lambda val: ZeoSpin(val).name),
|
|
97
|
+
RoborockZeoProtocol.DRYING_MODE: A01ProtocolCacheEntry(lambda val: ZeoDryingMode(val).name),
|
|
98
|
+
RoborockZeoProtocol.DETERGENT_TYPE: A01ProtocolCacheEntry(lambda val: ZeoDetergentType(val).name),
|
|
99
|
+
RoborockZeoProtocol.SOFTENER_TYPE: A01ProtocolCacheEntry(lambda val: ZeoSoftenerType(val).name),
|
|
100
|
+
RoborockZeoProtocol.SOUND_SET: A01ProtocolCacheEntry(lambda val: bool(val)),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class RoborockClientA01(RoborockClient):
|
|
105
|
+
def __init__(self, endpoint: str, device_info: DeviceData, category: RoborockCategory, queue_timeout: int = 4):
|
|
106
|
+
super().__init__(endpoint, device_info, queue_timeout)
|
|
107
|
+
self.category = category
|
|
108
|
+
|
|
109
|
+
def on_message_received(self, messages: list[RoborockMessage]) -> None:
|
|
110
|
+
for message in messages:
|
|
111
|
+
protocol = message.protocol
|
|
112
|
+
if message.payload and protocol in [
|
|
113
|
+
RoborockMessageProtocol.RPC_RESPONSE,
|
|
114
|
+
RoborockMessageProtocol.GENERAL_REQUEST,
|
|
115
|
+
]:
|
|
116
|
+
payload = message.payload
|
|
117
|
+
try:
|
|
118
|
+
payload = unpad(payload, AES.block_size)
|
|
119
|
+
except Exception:
|
|
120
|
+
continue
|
|
121
|
+
payload_json = json.loads(payload.decode())
|
|
122
|
+
for data_point_number, data_point in payload_json.get("dps").items():
|
|
123
|
+
data_point_protocol: RoborockDyadDataProtocol | RoborockZeoProtocol
|
|
124
|
+
entries: dict
|
|
125
|
+
if self.category == RoborockCategory.WET_DRY_VAC:
|
|
126
|
+
data_point_protocol = RoborockDyadDataProtocol(int(data_point_number))
|
|
127
|
+
entries = protocol_entries
|
|
128
|
+
elif self.category == RoborockCategory.WASHING_MACHINE:
|
|
129
|
+
data_point_protocol = RoborockZeoProtocol(int(data_point_number))
|
|
130
|
+
entries = zeo_data_protocol_entries
|
|
131
|
+
else:
|
|
132
|
+
continue
|
|
133
|
+
if data_point_protocol in entries:
|
|
134
|
+
# Auto convert into data struct we want.
|
|
135
|
+
converted_response = entries[data_point_protocol].post_process_fn(data_point)
|
|
136
|
+
queue = self._waiting_queue.get(int(data_point_number))
|
|
137
|
+
if queue and queue.protocol == protocol:
|
|
138
|
+
queue.resolve((converted_response, None))
|
|
139
|
+
|
|
140
|
+
async def update_values(self, dyad_data_protocols: list[RoborockDyadDataProtocol | RoborockZeoProtocol]):
|
|
141
|
+
"""This should handle updating for each given protocol."""
|
|
142
|
+
raise NotImplementedError
|
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import base64
|
|
3
3
|
import json
|
|
4
|
+
import typing
|
|
4
5
|
|
|
5
6
|
from Crypto.Cipher import AES
|
|
6
7
|
from Crypto.Util.Padding import pad, unpad
|
|
7
8
|
|
|
8
9
|
from roborock.cloud_api import RoborockMqttClient
|
|
9
|
-
from roborock.containers import DeviceData, UserData
|
|
10
|
+
from roborock.containers import DeviceData, RoborockCategory, UserData
|
|
10
11
|
from roborock.exceptions import RoborockException
|
|
11
12
|
from roborock.protocol import MessageParser, Utils
|
|
12
|
-
from roborock.roborock_message import
|
|
13
|
+
from roborock.roborock_message import (
|
|
14
|
+
RoborockDyadDataProtocol,
|
|
15
|
+
RoborockMessage,
|
|
16
|
+
RoborockMessageProtocol,
|
|
17
|
+
RoborockZeoProtocol,
|
|
18
|
+
)
|
|
13
19
|
|
|
14
20
|
from .roborock_client_a01 import RoborockClientA01
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
class RoborockMqttClientA01(RoborockMqttClient, RoborockClientA01):
|
|
18
|
-
def __init__(
|
|
24
|
+
def __init__(
|
|
25
|
+
self, user_data: UserData, device_info: DeviceData, category: RoborockCategory, queue_timeout: int = 10
|
|
26
|
+
) -> None:
|
|
19
27
|
rriot = user_data.rriot
|
|
20
28
|
if rriot is None:
|
|
21
29
|
raise RoborockException("Got no rriot data from user_data")
|
|
22
30
|
endpoint = base64.b64encode(Utils.md5(rriot.k.encode())[8:14]).decode()
|
|
23
31
|
|
|
24
32
|
RoborockMqttClient.__init__(self, user_data, device_info, queue_timeout)
|
|
25
|
-
RoborockClientA01.__init__(self, endpoint, device_info)
|
|
33
|
+
RoborockClientA01.__init__(self, endpoint, device_info, category, queue_timeout)
|
|
26
34
|
|
|
27
35
|
async def send_message(self, roborock_message: RoborockMessage):
|
|
28
36
|
await self.validate_connection()
|
|
@@ -37,14 +45,19 @@ class RoborockMqttClientA01(RoborockMqttClient, RoborockClientA01):
|
|
|
37
45
|
for dps in json.loads(payload["dps"]["10000"]):
|
|
38
46
|
futures.append(asyncio.ensure_future(self._async_response(dps, response_protocol)))
|
|
39
47
|
self._send_msg_raw(m)
|
|
40
|
-
responses = await asyncio.gather(*futures)
|
|
41
|
-
dps_responses = {}
|
|
48
|
+
responses = await asyncio.gather(*futures, return_exceptions=True)
|
|
49
|
+
dps_responses: dict[int, typing.Any] = {}
|
|
42
50
|
if "10000" in payload["dps"]:
|
|
43
51
|
for i, dps in enumerate(json.loads(payload["dps"]["10000"])):
|
|
44
|
-
|
|
52
|
+
response = responses[i]
|
|
53
|
+
if isinstance(response, BaseException):
|
|
54
|
+
self._logger.warning("Timed out get req for %s after %s s", dps, self.queue_timeout)
|
|
55
|
+
dps_responses[dps] = None
|
|
56
|
+
else:
|
|
57
|
+
dps_responses[dps] = response[0]
|
|
45
58
|
return dps_responses
|
|
46
59
|
|
|
47
|
-
async def update_values(self, dyad_data_protocols: list[RoborockDyadDataProtocol]):
|
|
60
|
+
async def update_values(self, dyad_data_protocols: list[RoborockDyadDataProtocol | RoborockZeoProtocol]):
|
|
48
61
|
payload = {"dps": {RoborockDyadDataProtocol.ID_QUERY: str([int(protocol) for protocol in dyad_data_protocols])}}
|
|
49
62
|
return await self.send_message(
|
|
50
63
|
RoborockMessage(
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
import json
|
|
3
|
-
import typing
|
|
4
|
-
from collections.abc import Callable
|
|
5
|
-
from datetime import time
|
|
6
|
-
|
|
7
|
-
from Crypto.Cipher import AES
|
|
8
|
-
from Crypto.Util.Padding import unpad
|
|
9
|
-
|
|
10
|
-
from roborock import DeviceData
|
|
11
|
-
from roborock.api import RoborockClient
|
|
12
|
-
from roborock.code_mappings import (
|
|
13
|
-
DyadBrushSpeed,
|
|
14
|
-
DyadCleanMode,
|
|
15
|
-
DyadError,
|
|
16
|
-
DyadSelfCleanLevel,
|
|
17
|
-
DyadSelfCleanMode,
|
|
18
|
-
DyadSuction,
|
|
19
|
-
DyadWarmLevel,
|
|
20
|
-
DyadWaterLevel,
|
|
21
|
-
RoborockDyadStateCode,
|
|
22
|
-
)
|
|
23
|
-
from roborock.containers import DyadProductInfo, DyadSndState
|
|
24
|
-
from roborock.roborock_message import (
|
|
25
|
-
RoborockDyadDataProtocol,
|
|
26
|
-
RoborockMessage,
|
|
27
|
-
RoborockMessageProtocol,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@dataclasses.dataclass
|
|
32
|
-
class DyadProtocolCacheEntry:
|
|
33
|
-
post_process_fn: Callable
|
|
34
|
-
value: typing.Any | None = None
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# Right now this cache is not active, it was too much complexity for the initial addition of dyad.
|
|
38
|
-
protocol_entries = {
|
|
39
|
-
RoborockDyadDataProtocol.STATUS: DyadProtocolCacheEntry(lambda val: RoborockDyadStateCode(val).name),
|
|
40
|
-
RoborockDyadDataProtocol.SELF_CLEAN_MODE: DyadProtocolCacheEntry(lambda val: DyadSelfCleanMode(val).name),
|
|
41
|
-
RoborockDyadDataProtocol.SELF_CLEAN_LEVEL: DyadProtocolCacheEntry(lambda val: DyadSelfCleanLevel(val).name),
|
|
42
|
-
RoborockDyadDataProtocol.WARM_LEVEL: DyadProtocolCacheEntry(lambda val: DyadWarmLevel(val).name),
|
|
43
|
-
RoborockDyadDataProtocol.CLEAN_MODE: DyadProtocolCacheEntry(lambda val: DyadCleanMode(val).name),
|
|
44
|
-
RoborockDyadDataProtocol.SUCTION: DyadProtocolCacheEntry(lambda val: DyadSuction(val).name),
|
|
45
|
-
RoborockDyadDataProtocol.WATER_LEVEL: DyadProtocolCacheEntry(lambda val: DyadWaterLevel(val).name),
|
|
46
|
-
RoborockDyadDataProtocol.BRUSH_SPEED: DyadProtocolCacheEntry(lambda val: DyadBrushSpeed(val).name),
|
|
47
|
-
RoborockDyadDataProtocol.POWER: DyadProtocolCacheEntry(lambda val: int(val)),
|
|
48
|
-
RoborockDyadDataProtocol.AUTO_DRY: DyadProtocolCacheEntry(lambda val: bool(val)),
|
|
49
|
-
RoborockDyadDataProtocol.MESH_LEFT: DyadProtocolCacheEntry(lambda val: int(360000 - val * 60)),
|
|
50
|
-
RoborockDyadDataProtocol.BRUSH_LEFT: DyadProtocolCacheEntry(lambda val: int(360000 - val * 60)),
|
|
51
|
-
RoborockDyadDataProtocol.ERROR: DyadProtocolCacheEntry(lambda val: DyadError(val).name),
|
|
52
|
-
RoborockDyadDataProtocol.VOLUME_SET: DyadProtocolCacheEntry(lambda val: int(val)),
|
|
53
|
-
RoborockDyadDataProtocol.STAND_LOCK_AUTO_RUN: DyadProtocolCacheEntry(lambda val: bool(val)),
|
|
54
|
-
RoborockDyadDataProtocol.AUTO_DRY_MODE: DyadProtocolCacheEntry(lambda val: bool(val)),
|
|
55
|
-
RoborockDyadDataProtocol.SILENT_DRY_DURATION: DyadProtocolCacheEntry(lambda val: int(val)), # in minutes
|
|
56
|
-
RoborockDyadDataProtocol.SILENT_MODE: DyadProtocolCacheEntry(lambda val: bool(val)),
|
|
57
|
-
RoborockDyadDataProtocol.SILENT_MODE_START_TIME: DyadProtocolCacheEntry(
|
|
58
|
-
lambda val: time(hour=int(val / 60), minute=val % 60)
|
|
59
|
-
), # in minutes since 00:00
|
|
60
|
-
RoborockDyadDataProtocol.SILENT_MODE_END_TIME: DyadProtocolCacheEntry(
|
|
61
|
-
lambda val: time(hour=int(val / 60), minute=val % 60)
|
|
62
|
-
), # in minutes since 00:00
|
|
63
|
-
RoborockDyadDataProtocol.RECENT_RUN_TIME: DyadProtocolCacheEntry(
|
|
64
|
-
lambda val: [int(v) for v in val.split(",")]
|
|
65
|
-
), # minutes of cleaning in past few days.
|
|
66
|
-
RoborockDyadDataProtocol.TOTAL_RUN_TIME: DyadProtocolCacheEntry(lambda val: int(val)),
|
|
67
|
-
RoborockDyadDataProtocol.SND_STATE: DyadProtocolCacheEntry(lambda val: DyadSndState.from_dict(val)),
|
|
68
|
-
RoborockDyadDataProtocol.PRODUCT_INFO: DyadProtocolCacheEntry(lambda val: DyadProductInfo.from_dict(val)),
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class RoborockClientA01(RoborockClient):
|
|
73
|
-
def __init__(self, endpoint: str, device_info: DeviceData):
|
|
74
|
-
super().__init__(endpoint, device_info)
|
|
75
|
-
|
|
76
|
-
def on_message_received(self, messages: list[RoborockMessage]) -> None:
|
|
77
|
-
for message in messages:
|
|
78
|
-
protocol = message.protocol
|
|
79
|
-
if message.payload and protocol in [
|
|
80
|
-
RoborockMessageProtocol.RPC_RESPONSE,
|
|
81
|
-
RoborockMessageProtocol.GENERAL_REQUEST,
|
|
82
|
-
]:
|
|
83
|
-
payload = message.payload
|
|
84
|
-
try:
|
|
85
|
-
payload = unpad(payload, AES.block_size)
|
|
86
|
-
except Exception:
|
|
87
|
-
continue
|
|
88
|
-
payload_json = json.loads(payload.decode())
|
|
89
|
-
for data_point_number, data_point in payload_json.get("dps").items():
|
|
90
|
-
data_point_protocol = RoborockDyadDataProtocol(int(data_point_number))
|
|
91
|
-
if data_point_protocol in protocol_entries:
|
|
92
|
-
# Auto convert into data struct we want.
|
|
93
|
-
converted_response = protocol_entries[data_point_protocol].post_process_fn(data_point)
|
|
94
|
-
queue = self._waiting_queue.get(int(data_point_number))
|
|
95
|
-
if queue and queue.protocol == protocol:
|
|
96
|
-
queue.resolve((converted_response, None))
|
|
97
|
-
|
|
98
|
-
async def update_values(self, dyad_data_protocols: list[RoborockDyadDataProtocol]):
|
|
99
|
-
"""This should handle updating for each given protocol."""
|
|
100
|
-
raise NotImplementedError
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
File without changes
|
{python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_local_client_v1.py
RENAMED
|
File without changes
|
{python_roborock-1.0.0 → python_roborock-2.1.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|