python-roborock 6.2.1__py3-none-any.whl → 7.2.0__py3-none-any.whl

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 (34) hide show
  1. {python_roborock-6.2.1.dist-info → python_roborock-7.2.0.dist-info}/METADATA +2 -2
  2. {python_roborock-6.2.1.dist-info → python_roborock-7.2.0.dist-info}/RECORD +34 -30
  3. {python_roborock-6.2.1.dist-info → python_roborock-7.2.0.dist-info}/WHEEL +1 -1
  4. roborock/cli.py +29 -12
  5. roborock/data/b01_q10/b01_q10_containers.py +22 -1
  6. roborock/data/b01_q7/b01_q7_code_mappings.py +12 -0
  7. roborock/data/code_mappings.py +10 -3
  8. roborock/data/containers.py +3 -2
  9. roborock/data/mower/__init__.py +1 -0
  10. roborock/data/mower/mower_code_mappings.py +72 -0
  11. roborock/data/mower/mower_containers.py +29 -3
  12. roborock/data/v1/v1_clean_modes.py +12 -18
  13. roborock/data/zeo/zeo_code_mappings.py +11 -12
  14. roborock/device_features.py +8 -0
  15. roborock/devices/device.py +10 -0
  16. roborock/devices/rpc/a01_channel.py +2 -0
  17. roborock/devices/rpc/b01_q7_channel.py +23 -0
  18. roborock/devices/traits/a01/__init__.py +132 -6
  19. roborock/devices/traits/a01/device_feature.py +396 -0
  20. roborock/devices/traits/b01/q10/__init__.py +24 -7
  21. roborock/devices/traits/b01/q10/map.py +43 -6
  22. roborock/devices/traits/b01/q10/maps.py +58 -0
  23. roborock/devices/traits/b01/q7/__init__.py +14 -0
  24. roborock/devices/traits/b01/q7/map_content.py +36 -3
  25. roborock/devices/traits/v1/status.py +1 -1
  26. roborock/diagnostics.py +1 -0
  27. roborock/map/b01_map_parser.py +9 -0
  28. roborock/map/b01_q10_map_parser.py +5 -4
  29. roborock/roborock_message.py +3 -0
  30. roborock/testing/__init__.py +20 -0
  31. roborock/testing/a01_simulator.py +287 -0
  32. roborock/testing/cloud.py +7 -1
  33. {python_roborock-6.2.1.dist-info → python_roborock-7.2.0.dist-info}/entry_points.txt +0 -0
  34. {python_roborock-6.2.1.dist-info → python_roborock-7.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: python-roborock
3
- Version: 6.2.1
3
+ Version: 7.2.0
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,55 +1,57 @@
1
1
  roborock/__init__.py,sha256=jpp3MEmevRvoJ5tq2waCDGH5VfJk--Lv1DmrwEdDyEQ,375
2
2
  roborock/broadcast_protocol.py,sha256=fjNQW7NdBKRzSy6126TfCSoYGpT2Esj9Jd-t7tXFc_E,4015
3
3
  roborock/callbacks.py,sha256=w2yPXtWFH7zfoFsLPYoCTbfwbE9p1ivA7iDcw20lJQI,4300
4
- roborock/cli.py,sha256=3AZHW8Co1H0Bqi7o1nMKA2MkfPuld_OdbPHQh_sNzCA,63478
4
+ roborock/cli.py,sha256=3OrJAmd9c52cyKLC9jF4-O5UkVXJAWZilOzvnxP7jyc,64097
5
5
  roborock/const.py,sha256=fWpgUPrCgLnaXmncgjCLZET-t7wHWQlpyzV8qHtTjb4,2860
6
- roborock/device_features.py,sha256=MGpyUPFkAD4ntYS9RbZoYaojy26XQZvbAWrWmAnrMv4,45433
7
- roborock/diagnostics.py,sha256=YIc7BhC6Cy6W2a6hykvfSRPG8NpLrPZCc_7jTX2Zdho,5091
6
+ roborock/device_features.py,sha256=i4YrJUfS8ZPB8azK8grAiBxoLS2MyGJcdwOvGtnUuFg,45866
7
+ roborock/diagnostics.py,sha256=OVfPCjBVidAlQtFz-WRlgCWOBIaXlO-73xQloXJaLwI,5107
8
8
  roborock/exceptions.py,sha256=t2YvfSRMymZPtdPV238itjxVJTaTq5-uBL_EM5FTlfg,3159
9
9
  roborock/protocol.py,sha256=eNUL6UGmtSdfsGM1mlYjmorukGGudV45iKXUA7a-Qa8,20193
10
10
  roborock/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- roborock/roborock_message.py,sha256=-y66O_JapRoHEyhKd5kyogCpE3d9TSuKysVLnxQ6Fd4,11678
11
+ roborock/roborock_message.py,sha256=VWsytnm7nQqOMBj7oYbiqPPqwE9qClDSI03CFuHXsds,11822
12
12
  roborock/roborock_typing.py,sha256=xppavdf57-Cu6elj3MP403uT75Tjw5Zs6bLGPLQmZf4,15483
13
13
  roborock/util.py,sha256=mjw329ujLjoWPPAr9mG0VZstaVL06dmVvNnYACB-Pxk,1650
14
14
  roborock/web_api.py,sha256=M_A4PiRK5cwkoT3oS8fvglOU97s1jpWKuuCxeeCiF_E,37507
15
15
  roborock/data/__init__.py,sha256=jSZHOrd-LfVN-TdBkjNW334ef99rGBz4-hPT_7KvoLs,278
16
- roborock/data/code_mappings.py,sha256=5c7hW3nN8uad8j3fyv8upYoIAfGlOsaZDeivpL4VAWc,9450
17
- roborock/data/containers.py,sha256=zgT2lm4NIz5_og8wmdgg2PREPN4PIuZ_BI-Z8JdGey0,17129
16
+ roborock/data/code_mappings.py,sha256=SGLJvHSdibUsXqCbQcqCGKm3x09JqhRKLoCgMCN1_s0,9769
17
+ roborock/data/containers.py,sha256=r46o2Xf6gfpw2SHBZnkVbfJIYYbpgTPYWDmAHWdgL8E,17228
18
18
  roborock/data/b01_q10/__init__.py,sha256=E4lwJcz4AI1z92FcYOJ-cY3fcfHSoXqvYVgfA-TgaRk,71
19
19
  roborock/data/b01_q10/b01_q10_code_mappings.py,sha256=UBFkxCWLYCGQatENmNwR0owkXrcB8AosnD-hICfS2AY,15203
20
- roborock/data/b01_q10/b01_q10_containers.py,sha256=jieHxHeWIRm2NHVdv15J6kYSeHjAZunGrvZsob-RIH8,11130
20
+ roborock/data/b01_q10/b01_q10_containers.py,sha256=HE1qAhYKDTz35oRgekYItNfD1iWTi7605-wpETcDzxU,11823
21
21
  roborock/data/b01_q7/__init__.py,sha256=D-Cd8eB0njf1PQPM6Exl_9A0AhpzIjrL0hapGOCEkkA,69
22
- roborock/data/b01_q7/b01_q7_code_mappings.py,sha256=EHSCZSv_Os049NcenKo4tkPjDOB4vpmQ2p2Psr9FRCc,10698
22
+ roborock/data/b01_q7/b01_q7_code_mappings.py,sha256=aOJqNFrJWqRSvgruVIpuaB6tP7gwvr-sSGHVsCOJAHk,11072
23
23
  roborock/data/b01_q7/b01_q7_containers.py,sha256=jNEHoNEdq276XJZGGUmtSyJ81cSIzJwem-O_NOgmfdQ,10270
24
24
  roborock/data/dyad/__init__.py,sha256=Ksx7Ri1alsAYAyILOpj9iNbCC_6sF7xvETFRnTO4rdM,65
25
25
  roborock/data/dyad/dyad_code_mappings.py,sha256=PGzEpkdc1jsR5RLRnjVnI2Y87O_HFAFulwOjjjbT4B0,2872
26
26
  roborock/data/dyad/dyad_containers.py,sha256=klJD2wV-2McjAoSN8Bthuyeid59L7M8nzSvc3MtmqOI,434
27
- roborock/data/mower/__init__.py,sha256=v-bMapgWFzlb0jJVJBmsnmDfgnER7oTjP0OH3ikwGdE,79
28
- roborock/data/mower/mower_containers.py,sha256=mCsRFTE2AZ2wC9wzrzsr-3z7T2M63CH5ax9kPqPygIY,3194
27
+ roborock/data/mower/__init__.py,sha256=RXFcOE0-rchWViq3F-cLXB9Jnx4nKrn98TUR917szWM,114
28
+ roborock/data/mower/mower_code_mappings.py,sha256=T3NJEjgkYv3svIt7-gqFgrnNmVeBOkqit8_D52vSIao,1741
29
+ roborock/data/mower/mower_containers.py,sha256=PYNVhbGCafkchenBlBmG_fUnIC-9WfxF8gNB0C4_9Yo,4106
29
30
  roborock/data/v1/__init__.py,sha256=Lx_D6baZrCMxp57D0NcdiA8rssJ5NnInZwUwrT79XOI,91
30
- roborock/data/v1/v1_clean_modes.py,sha256=71_olE6rsdx_UwxkBEPlcHTz0vnyKSnURGxIwuqhOwM,14056
31
+ roborock/data/v1/v1_clean_modes.py,sha256=ZUhMqrM9MwnXFl3btZj9_LEAOmhNIl80krW-AiuWouk,13866
31
32
  roborock/data/v1/v1_code_mappings.py,sha256=_2ycHU9VH86SayZXPLXY1Ej6bJxRvOT_GDIdHsNUR04,12934
32
33
  roborock/data/v1/v1_containers.py,sha256=UBScIG6VKziEAC0FaQRHnfrGWDY06nITY8NkFJEzhiE,17256
33
34
  roborock/data/zeo/__init__.py,sha256=VxG5qG4M24DGOq2YAaxownWp6bEfj9DEOgOMHmTpcqY,63
34
- roborock/data/zeo/zeo_code_mappings.py,sha256=MaTs9UqvwC2t2eaLRpeTT2RkP1TYNLVcxe5iJBfzLHw,8364
35
+ roborock/data/zeo/zeo_code_mappings.py,sha256=mfm2xoI8RllPZfyZE0HmUhUhLECwRD0llkMNWfaEHvw,8057
35
36
  roborock/data/zeo/zeo_containers.py,sha256=huDeisutagKz1rzsLZr_tGAietec_qOd0KB3i09YGgo,4339
36
37
  roborock/devices/README.md,sha256=zjssyRIlFWTgQz8hLdsJC9_stlHdUQybz7r2af_8q1k,2186
37
38
  roborock/devices/__init__.py,sha256=yOWuncnp5wwKPLzcnblsBMGD0v8hcDDDC_x7YdSrN70,129
38
39
  roborock/devices/cache.py,sha256=V3KC16LzTEAp_cdAirNtWPjZAgz6ugn3zfsYPyrbWsE,4633
39
- roborock/devices/device.py,sha256=8lHdjLlHhrENPjrZxllpYU0CEh7Os9rp9spnwhdUOoc,9678
40
+ roborock/devices/device.py,sha256=bhRvHsZC2yhNiwg2yBJVjC8ZO_BJ_NkZMajuABXMHuo,10122
40
41
  roborock/devices/device_manager.py,sha256=RPuvbhYxLjdCBrsjYP91dvHTnO8inODsa26m5987VR4,11777
41
42
  roborock/devices/file_cache.py,sha256=-G2Bm4ra8K_DvSBjntv5hGaRDB-VzSoKWcI0Y_kK6jw,2724
42
43
  roborock/devices/rpc/__init__.py,sha256=MDtZovvHi3F4Wbgyzu6gyjAjkZ6xYGU1LRQmtiIapuU,561
43
- roborock/devices/rpc/a01_channel.py,sha256=cUwxaG3DdCDZrKDXNqbtKrgd8pFybeGrql_xwPNk5DY,3776
44
+ roborock/devices/rpc/a01_channel.py,sha256=R33NQ3hK6pWjPzF2kaWVv93r9RrTWskg6_YWi3Oiiq4,3886
44
45
  roborock/devices/rpc/b01_q10_channel.py,sha256=nT7fsTtti37alm68CHzId8Wy3GMd6npiSNB8Gjegy3I,3494
45
- roborock/devices/rpc/b01_q7_channel.py,sha256=cxJR_DjJobP6SsAch_O3tNcJdiQGMIwpxH8Wx8bb9xA,7689
46
+ roborock/devices/rpc/b01_q7_channel.py,sha256=sE3U5r8RlSqSCXxSdd_a_4nPkOSkIPFvCTwxKMtcOnU,8738
46
47
  roborock/devices/rpc/v1_channel.py,sha256=xCQ9YqgTFteU-ptc9-H0w6HtZK3OyH8GBS4QNsxi18w,24365
47
48
  roborock/devices/traits/__init__.py,sha256=YaL9qoxG6IBG0XXDP0HMTvoc0Jkmq7AF6iH2oYWNtcg,765
48
49
  roborock/devices/traits/common.py,sha256=n3fHK4i4bkTU1QL7skMStJiUPIDlpN37z0T9mPQYoOY,4588
49
50
  roborock/devices/traits/traits_mixin.py,sha256=7t15l_Ty1cN-3-fKNtRH1XR6-mfadPnTBCQRZP4rAtc,2092
50
- roborock/devices/traits/a01/__init__.py,sha256=i-us9zLPWPfSQ5XWq8t0MiYLYe5NkcLvk3aEQTYT7E0,8104
51
+ roborock/devices/traits/a01/__init__.py,sha256=GKu_SWJ9l57u0DU_vd8ec4j6smwrR9s4gUF0yMB-xWA,13284
52
+ roborock/devices/traits/a01/device_feature.py,sha256=6--fV8kRv4nxWIaQlxHt0XFyovhqk6dGeVm-E1n5y_U,13514
51
53
  roborock/devices/traits/b01/__init__.py,sha256=pGN6wEocE6Fr2BTasG8Z_75crD6OdTwpju59Vw7eTDk,202
52
- roborock/devices/traits/b01/q10/__init__.py,sha256=ZFQw1_fwTyjOpJ6ggeFl4JTutleu8R7sCK-j6OYD_UI,6212
54
+ roborock/devices/traits/b01/q10/__init__.py,sha256=BpeCO7vrM11ISy8JZwBiSkHsTs5-vp68c9YwnWKEIDk,6747
53
55
  roborock/devices/traits/b01/q10/button_light.py,sha256=_CCWSjFe_iZnnSXgBHOju31VUmwG1KKd_jGkmSpLew4,994
54
56
  roborock/devices/traits/b01/q10/child_lock.py,sha256=bTsbAMxn7AF1zpWteyZCkQm4jj3NiWD8ddZTM3tlG_0,1131
55
57
  roborock/devices/traits/b01/q10/clean_history.py,sha256=OsuzliXtWl2RDMAdKElCaebp9Pr2czVOex180k4jzVs,6672
@@ -58,16 +60,17 @@ roborock/devices/traits/b01/q10/common.py,sha256=Qxl3zBAUulqdrjFZJ0DPEFEIJLvlPqU
58
60
  roborock/devices/traits/b01/q10/consumable.py,sha256=MbtMgYKqzNdVn6M1iyOAqZPCYTbN_Q_Pr4h8EYGEiuY,669
59
61
  roborock/devices/traits/b01/q10/do_not_disturb.py,sha256=klyGQZ_nHyO6bhPlwBl8vElTnMwPf4A8VXwxkU8rMlM,1157
60
62
  roborock/devices/traits/b01/q10/dust_collection.py,sha256=LM-0YH4pMrEqLUCFP2g-DymhL5ZUQ4bHd-2EyKHmucY,1582
61
- roborock/devices/traits/b01/q10/map.py,sha256=2feJhw2N7j1niGheTDvgHrxXFW94GeGpRiWoK-DO4Ss,6064
63
+ roborock/devices/traits/b01/q10/map.py,sha256=1_gFfiSTgJ0XbdfBsiH6QM2Nh6aF25i-IElojEf85v4,7541
64
+ roborock/devices/traits/b01/q10/maps.py,sha256=qWk1K47aIf3iJead3A2zQ3Lo0wZ1wcS2mo4qVfiiTDw,2101
62
65
  roborock/devices/traits/b01/q10/network_info.py,sha256=XiCr6YPu7xkvhgeaGwXli-_4SB88QW63ykiegyaau2k,656
63
66
  roborock/devices/traits/b01/q10/remote.py,sha256=8-fg4SA5M-tdMufHPeD9hIcax7y9Qh7pzcE7rBBVW_o,1267
64
67
  roborock/devices/traits/b01/q10/status.py,sha256=JAPixbsQ8jfN3OvI7o_NxISXFk8l7rGHFYcL4pH97Jk,859
65
68
  roborock/devices/traits/b01/q10/vacuum.py,sha256=w2FftNH5n-Tb-9drR3-5OiMy85FJfTDNmtt34LklC8w,4374
66
69
  roborock/devices/traits/b01/q10/volume.py,sha256=UnT0yYDQntxYwnpv4_NVychm0FnGAYRAWA_FJR4yJag,1001
67
- roborock/devices/traits/b01/q7/__init__.py,sha256=y3NV-DYHyQoPcpWnmGppX5Y1GjF9MylVxyoIVldKFCA,7935
70
+ roborock/devices/traits/b01/q7/__init__.py,sha256=wHe2uncF49MlfPwyIgs0xbwnQo8q0eDEyHTh33iHq80,8549
68
71
  roborock/devices/traits/b01/q7/clean_summary.py,sha256=M43iJVeYjrkBV6ZxXdHtn4Rd5Mx-KAK7WLU5fABiN8I,2742
69
72
  roborock/devices/traits/b01/q7/map.py,sha256=NfPQAEwNCUsb0SYGMxmGeq4q4rEHqDJK0zTD5cE-ESs,1299
70
- roborock/devices/traits/b01/q7/map_content.py,sha256=5l7WJSDEfUzXkwXYcvTWhuNz3mlXvA_u2o5Pnh6f5kE,3372
73
+ roborock/devices/traits/b01/q7/map_content.py,sha256=M0anKPY82kN3wZZAu-vVWqpq_Cw-FA5YJ6QsMef9YPo,4722
71
74
  roborock/devices/traits/v1/__init__.py,sha256=gzp5b2aJCugHF_9jqEZG7ycsv_xCMZa8ymhtm3Nqofg,16986
72
75
  roborock/devices/traits/v1/child_lock.py,sha256=NeaPqcEoBRXvEzKZGonkyINkwCBOK3xa4zSWvJW66kA,1161
73
76
  roborock/devices/traits/v1/clean_summary.py,sha256=2uDl3Tg6H9INf7HTEPPat_PBgodoWeX_ko5MJgWggn8,4625
@@ -87,7 +90,7 @@ roborock/devices/traits/v1/obstacle_photos.py,sha256=Aul1sOxJ6AxLWqI5AbeHHSzxfUP
87
90
  roborock/devices/traits/v1/rooms.py,sha256=PKNEvzL_Pk5pxGpiMC-XgGpgWVRjivMw_yv7vpGlz3s,6221
88
91
  roborock/devices/traits/v1/routines.py,sha256=BfktlpnyDjD2DB3zBDS5BnmjZPE38aHa-wjMontPnik,931
89
92
  roborock/devices/traits/v1/smart_wash_params.py,sha256=6K3XrF5SRS39BWaMjjtGJgKX3lZ24jPsb6Nia4a9GVM,634
90
- roborock/devices/traits/v1/status.py,sha256=Y5VBJPZQhmlGDPQvPIp8mFCFsUf4hheZ5k_nnxOoXHI,5071
93
+ roborock/devices/traits/v1/status.py,sha256=HPEUnpCbOxoZ6O_Dz3C3mJpYiIiq9vs8zvrzc78oxAw,5078
91
94
  roborock/devices/traits/v1/valley_electricity_timer.py,sha256=vE9bLJe8TdFGVh_9mDRkEoC3_DTBkDcdlSMSiYq0YTw,1863
92
95
  roborock/devices/traits/v1/volume.py,sha256=etRIYE0ynZZLEo2ez7Dm7_JbijmElrdjpn59hyLWqsQ,814
93
96
  roborock/devices/traits/v1/wash_towel_mode.py,sha256=bSXtaJ0ObDlXsJYuCHWCN3J0GyHEibPsDvOqBCxQW3Q,2039
@@ -97,8 +100,8 @@ roborock/devices/transport/local_channel.py,sha256=kU49v6v3wsT6MQeN4wN-XkTxr-zBy
97
100
  roborock/devices/transport/mqtt_channel.py,sha256=dpL1mZIoI4Glk3hfUO9JweWFHG1tZWLrWbt9f4RbvhQ,4789
98
101
  roborock/map/__init__.py,sha256=L3WHujuxUHCTTPaOElkJsTN_FkYhw01drfR-W4blgFc,146
99
102
  roborock/map/b01_grid_layers.py,sha256=VluAmKEIBTsvzGB5pUrr8iYFiyEx5siyDwBKft1C2vA,12290
100
- roborock/map/b01_map_parser.py,sha256=UacKI3qfPvjEX3zkSq360lMukitFdMhlB24IyLQR8Dw,4160
101
- roborock/map/b01_q10_map_parser.py,sha256=qR1So58HrrO2GxCr1CWY_GlUQBJcOldRYd03jGQXEOw,29923
103
+ roborock/map/b01_map_parser.py,sha256=tTeeWH4fA4Pv4DvqN7PBQs92DuWTaD2rvD44Mo_t3OY,4433
104
+ roborock/map/b01_q10_map_parser.py,sha256=EQMx2ZNVjHKsmKr6vR8JS7o86IZu85dNg3bKi5S0ZYw,29985
102
105
  roborock/map/b01_q10_overlays.py,sha256=JmriUbT4-oe6NiE94VttMplFc1HHQrAGNQIiZHj5QKk,6640
103
106
  roborock/map/b01_q10_render.py,sha256=0K7x5AErSaowAH3ZUkStUXFgH4GM0debu0jIEJhlgVk,13360
104
107
  roborock/map/map_parser.py,sha256=2Rse_VhC2HEfjO2aXw7p-QhYN3NLl9JoRbxqxGGPR64,7275
@@ -115,14 +118,15 @@ roborock/protocols/a01_protocol.py,sha256=LpFsrZ9epwuTNsPprYGL0KgQD37DfvXfFrNuc_
115
118
  roborock/protocols/b01_q10_protocol.py,sha256=Ac3_VHJ2DAwBiXFMPYOHExEV0prxS9Ju0djiC8nKtiI,4935
116
119
  roborock/protocols/b01_q7_protocol.py,sha256=o8repRrxhxknzspsg1K27ds643rs87ilWXbj8RJtOCs,4619
117
120
  roborock/protocols/v1_protocol.py,sha256=ntFQoGn1IF7v_BwjiGow478SJHBSKr6jq6M2s01OdaI,12918
118
- roborock/testing/__init__.py,sha256=cveoyU-mQVQ2TezMEHc_OT5ga-7QIKY7ew-Xs_0AOz8,4581
121
+ roborock/testing/__init__.py,sha256=rji4a-JBIWC_I6SUTG9j4r2bGxfhYUoopdDAzYQ1tmA,5086
122
+ roborock/testing/a01_simulator.py,sha256=M4R0ATgebIva6Jl0BPKfwdGqdZjmjGZHlozAVVteJ5I,10477
119
123
  roborock/testing/b01_q10_simulator.py,sha256=7k2poUIDI0akTw0rEcCpTUZq0gjr8z3kfTkgA33fFis,7004
120
124
  roborock/testing/channel.py,sha256=vjulT5MHBe8lAq6XITUqcxJVcCILWx7ZEcw5imTx0Tk,7243
121
- roborock/testing/cloud.py,sha256=tAZ8oT8UX5w1OziY1kSGQ4Q6-erTQH9IG2bZC1ih_7w,11566
125
+ roborock/testing/cloud.py,sha256=L2L0KlZDYaMuoV19KUQUoq5EAUDeNQ1lJ8Ew5YaOgjo,11946
122
126
  roborock/testing/simulator.py,sha256=g8ZUWVSjgAzuRRxWOCeOq-7deodyEItwUpqEw9RzCmQ,4347
123
127
  roborock/testing/v1_simulator.py,sha256=TQ2PsRoP_4kJvVn-Tm532ByHuaCKltsVjvTa2Ju4PAo,14407
124
- python_roborock-6.2.1.dist-info/METADATA,sha256=Se_oCY7u4yDt8OSULGKisD3C8594Yvic4oHzKKHTYQ8,5278
125
- python_roborock-6.2.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
126
- python_roborock-6.2.1.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
127
- python_roborock-6.2.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
128
- python_roborock-6.2.1.dist-info/RECORD,,
128
+ python_roborock-7.2.0.dist-info/METADATA,sha256=FIUbTM4uQDYeOtX_WjwGgRQz7MqfiYsDlQFlNGQsZoM,5278
129
+ python_roborock-7.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
130
+ python_roborock-7.2.0.dist-info/entry_points.txt,sha256=EvC1nMqi9ZXKgZnqlNXA33v_3nzgPNjnM0mzWlrehnY,47
131
+ python_roborock-7.2.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
132
+ python_roborock-7.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.31.0
2
+ Generator: hatchling 1.32.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
roborock/cli.py CHANGED
@@ -594,9 +594,9 @@ async def maps(ctx, device_id: str):
594
594
  await _display_v1_trait(context, device_id, lambda v1: v1.maps)
595
595
 
596
596
 
597
- # The Q10 pushes its map ~9s after a dpRequestDps; firmware throttles pushes to
598
- # ~once per 60-70s, so a single request is answered quickly but rapid re-requests
599
- # may not be. This bounds how long a one-shot CLI command waits for that push.
597
+ # The Q10 publishes its map asynchronously after a dpMultiMap list/get request.
598
+ # Firmware throttles pushes to ~once per 60-70s, so rapid re-requests may not be
599
+ # answered immediately. This bounds how long a one-shot CLI command waits.
600
600
  _Q10_MAP_PUSH_TIMEOUT = 30.0
601
601
 
602
602
 
@@ -607,13 +607,12 @@ async def _await_q10_map_push(
607
607
  timeout: float = _Q10_MAP_PUSH_TIMEOUT,
608
608
  allow_cached_on_timeout: bool = False,
609
609
  ) -> bool:
610
- """Nudge a Q10 to push its map/trace and wait for a fresh update.
610
+ """Request Q10 map content and wait for usable map-trait state.
611
611
 
612
- The Q10 map API is entirely push-driven: there is no synchronous get-map
613
- request. A ``dpRequestDps`` causes the device to publish a ``MAP_RESPONSE``,
614
- which the device's subscribe loop feeds into the map trait. Here we register
615
- an update listener, send the request, and wait for a newly pushed update to
616
- satisfy ``predicate``. Returns whether it did within ``timeout``.
612
+ A Q10 needs a saved-map ID before it can request content. The map list and
613
+ content have independent refresh schedules, so the list is requested only
614
+ when no ID is stored. The content then arrives as a later ``MAP_RESPONSE``
615
+ and is published through the standard trait update interface.
617
616
  """
618
617
  loop = asyncio.get_running_loop()
619
618
  updated: asyncio.Future[None] = loop.create_future()
@@ -624,8 +623,23 @@ async def _await_q10_map_push(
624
623
 
625
624
  unsub = properties.map.add_update_listener(on_update)
626
625
  try:
627
- await properties.refresh()
628
- await asyncio.wait_for(updated, timeout=timeout)
626
+ async with asyncio.timeout(timeout):
627
+ if properties.maps.current_map_id is None:
628
+ map_list_updated: asyncio.Future[None] = loop.create_future()
629
+
630
+ def on_map_list_update() -> None:
631
+ if properties.maps.current_map_id is not None and not map_list_updated.done():
632
+ map_list_updated.set_result(None)
633
+
634
+ unsub_maps = properties.maps.add_update_listener(on_map_list_update)
635
+ try:
636
+ await properties.maps.refresh()
637
+ if properties.maps.current_map_id is None:
638
+ await map_list_updated
639
+ finally:
640
+ unsub_maps()
641
+ await properties.map.refresh()
642
+ await updated
629
643
  return True
630
644
  except TimeoutError:
631
645
  return allow_cached_on_timeout and predicate()
@@ -706,7 +720,10 @@ async def q10_position(ctx, device_id: str, include_path: bool):
706
720
  click.echo("Feature not supported by device")
707
721
  return
708
722
  properties = device.b01_q10_properties
709
- got_trace = await _await_q10_map_push(properties, lambda: bool(properties.map.path))
723
+ got_trace = await _await_q10_map_push(
724
+ properties,
725
+ lambda: bool(properties.map.path),
726
+ )
710
727
  if not got_trace:
711
728
  click.echo("No live trace available (the robot only reports position while cleaning).")
712
729
  return
@@ -83,11 +83,32 @@ class Q10CleanRecord(RoborockBase):
83
83
  return None
84
84
 
85
85
 
86
+ @dataclass
87
+ class Q10MapInfo(RoborockBase):
88
+ """A saved map reported by ``dpMultiMap``.
89
+
90
+ Q10 firmware represents the map identifier as a string on the wire. The
91
+ value is sent back unchanged in a subsequent ``{"op": "get"}`` request.
92
+ """
93
+
94
+ id: str
95
+ name: str | None = None
96
+ timestamp: int | None = None
97
+
98
+
86
99
  @dataclass
87
100
  class dpMultiMap(RoborockBase):
101
+ """Response envelope for the Q10 ``dpMultiMap`` data point."""
102
+
88
103
  op: str
89
104
  result: int
90
- data: list
105
+ data: list[Q10MapInfo] = field(default_factory=list)
106
+
107
+ @property
108
+ def current_map_id(self) -> str | None:
109
+ """Return the first saved-map identifier, if one was reported."""
110
+ first = next((map_info for map_info in self.data if map_info.id), None)
111
+ return first.id if first else None
91
112
 
92
113
 
93
114
  @dataclass
@@ -1,3 +1,5 @@
1
+ from typing import Self, cast
2
+
1
3
  from ..code_mappings import RoborockModeEnum
2
4
 
3
5
 
@@ -15,6 +17,16 @@ class WorkStatusMapping(RoborockModeEnum):
15
17
  UPDATING = ("updating", 8)
16
18
  MOP_CLEANING = ("mop_cleaning", 9)
17
19
  MOP_AIRDRYING = ("mop_airdrying", 10)
20
+ WORKING_SLEEP = ("working_sleep", 11)
21
+ UNKNOWN = ("unknown", -1)
22
+
23
+ @classmethod
24
+ def from_code(cls, code: int) -> Self:
25
+ """Map unrecognized Q7 statuses to UNKNOWN without failing the response."""
26
+ try:
27
+ return super().from_code(code)
28
+ except ValueError:
29
+ return cast(Self, cls.UNKNOWN)
18
30
 
19
31
 
20
32
  class SCWindMapping(RoborockModeEnum):
@@ -72,14 +72,21 @@ class RoborockModeEnum(StrEnum):
72
72
 
73
73
  code: int
74
74
  """The integer code associated with the enum member."""
75
+ _display_name_: str | None
75
76
 
76
- def __new__(cls, value: str, code: int) -> Self:
77
+ def __new__(cls, value: str, code: int, display_name: str | None = None) -> Self:
77
78
  """Creates a new enum member."""
78
79
  member = str.__new__(cls, value)
79
80
  member._value_ = value
80
81
  member.code = code
82
+ member._display_name_ = display_name
81
83
  return member
82
84
 
85
+ @property
86
+ def display_name(self) -> str:
87
+ """Return the canonical user-facing name for the mode."""
88
+ return self._display_name_ or self.value
89
+
83
90
  @classmethod
84
91
  def from_code(cls, code: int) -> Self:
85
92
  for member in cls:
@@ -149,8 +156,8 @@ class RoborockModeEnum(StrEnum):
149
156
 
150
157
  @classmethod
151
158
  def keys(cls) -> list[str]:
152
- """Returns a list of all member values."""
153
- return [member.value for member in cls]
159
+ """Returns a de-duplicated list of canonical member names."""
160
+ return list(dict.fromkeys(member.display_name for member in cls))
154
161
 
155
162
  def __eq__(self, other: Any) -> bool:
156
163
  if isinstance(other, str):
@@ -162,13 +162,14 @@ class RoborockBase:
162
162
 
163
163
  return result
164
164
 
165
- def as_dict(self) -> dict:
165
+ def as_dict(self, exclude: set[str] | None = None) -> dict:
166
+ exclude_set = exclude or set()
166
167
  return asdict(
167
168
  self,
168
169
  dict_factory=lambda _fields: {
169
170
  _camelize(key): value.value if isinstance(value, Enum) else value
170
171
  for (key, value) in _fields
171
- if value is not None
172
+ if value is not None and key not in exclude_set
172
173
  },
173
174
  )
174
175
 
@@ -1,3 +1,4 @@
1
1
  """Dataclasses for Roborock mower devices."""
2
2
 
3
+ from .mower_code_mappings import *
3
4
  from .mower_containers import *
@@ -0,0 +1,72 @@
1
+ """Code mappings for Roborock mower devices."""
2
+
3
+ from roborock.data.code_mappings import RoborockEnum
4
+
5
+
6
+ class RoborockMowerStateCode(RoborockEnum):
7
+ """Detailed mower operating state reported by DPS 123."""
8
+
9
+ unknown = -999
10
+ idle = 0
11
+
12
+ map_initializing = 1
13
+ map_undocking = 2
14
+ map_undock_fault = 3
15
+ map_locating = 4
16
+ map_prepare_boundary = 5
17
+ map_prepare_island = 6
18
+ map_prepare_path = 7
19
+ map_boundary = 8
20
+ map_island = 9
21
+ map_path = 10
22
+ map_boundary_auto = 11
23
+ map_erasing = 12
24
+ map_save = 13
25
+ map_wait = 14
26
+ map_recoverable_fault = 15
27
+ map_fault = 16
28
+ map_emergency_stop = 17
29
+ map_waiting_fault = 18
30
+
31
+ mow_initializing = 51
32
+ mow_undocking = 52
33
+ mow_locating = 53
34
+ mow_adjust_cutter = 54
35
+ mow_zig_zag = 55
36
+ mow_edge = 56
37
+ mow_goto = 57
38
+ mow_suspend = 58
39
+ mow_recoverable_fault = 59
40
+ mow_fault = 60
41
+ mow_docked_rainfall = 61
42
+ mow_docked_do_not_disturb = 62
43
+ mow_docked_low_battery = 63
44
+ mow_wait = 64
45
+ mow_prepare_remote = 65
46
+ mow_remote = 66
47
+ mow_emergency_stop = 67
48
+ mow_docked_manual = 68
49
+ mow_dock_fault = 69
50
+ mow_remote_undocking = 70
51
+ mow_to_dock_initializing = 71
52
+ mow_to_dock_locating = 72
53
+ mow_to_dock_recoverable_fault = 73
54
+ mow_to_dock_fault = 74
55
+ mow_to_dock_emergency_stop = 75
56
+ mow_to_dock_charging = 76
57
+ mow_to_dock_charge_completed = 77
58
+
59
+ free = 101
60
+ free_initializing = 102
61
+ free_locating = 103
62
+ free_docked_manual = 104
63
+ free_docked_mow_end = 105
64
+ free_docked_plan_end = 106
65
+ free_emergency_stop = 107
66
+ free_recoverable_fault = 108
67
+ free_fault = 109
68
+
69
+ charge_charging = 151
70
+ charge_completed = 152
71
+ charge_waiting = 153
72
+ charge_fault = 154
@@ -1,11 +1,13 @@
1
1
  """Data containers for Roborock mower devices."""
2
2
 
3
- from dataclasses import dataclass, field
4
- from typing import Any
3
+ from dataclasses import dataclass, field, fields
4
+ from typing import Any, Self
5
5
 
6
6
  from roborock.data.containers import RoborockBase
7
7
  from roborock.roborock_message import RoborockMowerDataProtocol
8
8
 
9
+ from .mower_code_mappings import RoborockMowerStateCode
10
+
9
11
 
10
12
  @dataclass
11
13
  class MowerStatus(RoborockBase):
@@ -14,7 +16,9 @@ class MowerStatus(RoborockBase):
14
16
  error_code: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.ERROR_CODE})
15
17
  battery: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.BATTERY})
16
18
  mow_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_TYPE})
17
- mow_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_STATE})
19
+ mow_state: RoborockMowerStateCode | None = field(
20
+ default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_STATE}
21
+ )
18
22
  mapping_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MAPPING_TYPE})
19
23
  mapping_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MAPPING_STATE})
20
24
  ota_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.OTA_STATE})
@@ -41,3 +45,25 @@ class MowerStatus(RoborockBase):
41
45
  )
42
46
  afs_status: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.AFS_STATUS})
43
47
  network_channel: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.NETWORK_CHANNEL})
48
+
49
+ @classmethod
50
+ def from_dps(cls, dps: dict[int | str, Any] | None) -> Self:
51
+ """Create mower status from raw DPS data.
52
+
53
+ Cloud snapshots use string DPS keys while decoded MQTT messages may use
54
+ integer keys. Unknown and malformed keys are ignored.
55
+ """
56
+ field_by_dps = {
57
+ int(field_info.metadata["dps"]): field_info.name
58
+ for field_info in fields(cls)
59
+ if "dps" in field_info.metadata
60
+ }
61
+ values: dict[str, Any] = {}
62
+ for key, value in (dps or {}).items():
63
+ try:
64
+ dps_id = int(key)
65
+ except (TypeError, ValueError):
66
+ continue
67
+ if field_name := field_by_dps.get(dps_id):
68
+ values[field_name] = value
69
+ return cls.from_dict(values)
@@ -29,7 +29,7 @@ class CleanRoutes(RoborockModeEnum):
29
29
  DEEP = ("deep", 301)
30
30
  DEEP_PLUS = ("deep_plus", 303)
31
31
  FAST = ("fast", 304)
32
- DEEP_PLUS_CN = ("deep_plus", 305)
32
+ DEEP_PLUS_CN = ("deep_plus_cn", 305, "deep_plus")
33
33
  SMART_MODE = ("smart_mode", 306)
34
34
  CUSTOMIZED = ("custom", 302)
35
35
 
@@ -118,10 +118,7 @@ def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]:
118
118
  modes.append(VacuumModes.MAX_PLUS)
119
119
  if features.is_pure_clean_mop_supported:
120
120
  # If the vacuum is capable of 'pure mop clean' aka no vacuum
121
- if features.is_support_main_brush_up_down_supported:
122
- modes.append(VacuumModes.OFF_RAISE_MAIN_BRUSH)
123
- else:
124
- modes.append(VacuumModes.OFF)
121
+ modes.append(VacuumModes.OFF)
125
122
  else:
126
123
  # If not, we can add gentle
127
124
  modes.append(VacuumModes.GENTLE)
@@ -134,16 +131,19 @@ def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]:
134
131
 
135
132
  def get_clean_routes(features: DeviceFeatures, region: str) -> list[CleanRoutes]:
136
133
  """The routes that the vacuum will take while mopping"""
134
+ if not features.is_clean_route_setting_supported:
135
+ return []
137
136
  if features.is_none_pure_clean_mop_with_max_plus:
138
137
  return [CleanRoutes.FAST, CleanRoutes.STANDARD]
139
- supported = [CleanRoutes.STANDARD, CleanRoutes.DEEP]
138
+ supported = [CleanRoutes.STANDARD]
139
+ if not features.is_clean_efficiency_supported:
140
+ supported.append(CleanRoutes.DEEP)
140
141
  if features.is_careful_slow_mop_supported:
141
- if not (
142
- features.is_corner_clean_mode_supported
142
+ if (
143
+ not features.is_corner_clean_mode_supported
143
144
  and features.is_clean_route_deep_slow_plus_supported
144
145
  and region == "cn"
145
146
  ):
146
- # for some reason there is a china specific deep plus mode
147
147
  supported.append(CleanRoutes.DEEP_PLUS_CN)
148
148
  else:
149
149
  supported.append(CleanRoutes.DEEP_PLUS)
@@ -218,17 +218,11 @@ def get_cleaning_mode_options(features: DeviceFeatures) -> list[CleaningMode]:
218
218
 
219
219
 
220
220
  def get_mop_only_vacuum_mode(features: DeviceFeatures) -> VacuumModes:
221
- """Determine the vacuum mode to use when you just want to mop.
222
-
223
- There are three cases that must be handled:
224
- 1. The device does not support only mopping.
225
- 2. The device supports raising the vacuum brush while mopping
226
- 3. All other cases.
227
- """
221
+ """Return the vacuum mode used by the app for mop-only cleaning."""
228
222
  if not features.is_pure_clean_mop_supported:
229
223
  raise RoborockUnsupportedFeature("Mop-only cleaning is not supported")
230
- if features.is_support_main_brush_up_down_supported:
231
- return VacuumModes.OFF_RAISE_MAIN_BRUSH
224
+ # Main-brush lift is a device capability, not an alternate fan-power
225
+ # command. The app still sends CleanModeZero (105) for mop-only cleaning.
232
226
  return VacuumModes.OFF
233
227
 
234
228
 
@@ -1,8 +1,5 @@
1
1
  """Zeo (washing machine) device enums.
2
2
 
3
- Member-level comments show the manufacturer's official identifiers
4
- extracted from the React Native app plugin bundle.
5
-
6
3
  For enums that map between protocol-level positions and physical units
7
4
  (e.g. spin speed, temperature), the comment format is
8
5
  ``# L<N>, <physical-value>`` where ``L<N>`` is the protocol position
@@ -18,12 +15,7 @@ from ..code_mappings import RoborockEnum
18
15
 
19
16
 
20
17
  class ZeoFeatureBits(RoborockEnum):
21
- """Bit positions in DP 237 (FEATURE_BITS).
22
-
23
- Extracted from the official Roborock Washer app plugin bundle
24
- (index.ios.bundle, module 726). Each member's integer value
25
- is the exact bit offset the device reports at DP 237.
26
- """
18
+ """Bit positions in DP 237 (FEATURE_BITS)."""
27
19
 
28
20
  smart_hosting = 0
29
21
  silent_mode = 1
@@ -52,7 +44,7 @@ class ZeoFeatureBits(RoborockEnum):
52
44
 
53
45
 
54
46
  class ZeoMode(RoborockEnum):
55
- null = 0 # (not found in app bundle)
47
+ null = 0
56
48
  wash = 1
57
49
  wash_and_dry = 2
58
50
  dry = 3
@@ -60,6 +52,7 @@ class ZeoMode(RoborockEnum):
60
52
 
61
53
 
62
54
  class ZeoState(RoborockEnum):
55
+ null = 0
63
56
  standby = 1
64
57
  weighing = 2 # Checking
65
58
  soaking = 3
@@ -83,7 +76,7 @@ class ZeoState(RoborockEnum):
83
76
 
84
77
 
85
78
  class ZeoProgram(RoborockEnum):
86
- null = 0 # (not found in app bundle)
79
+ null = 0
87
80
  standard = 1 # Mixed
88
81
  quick = 2
89
82
  sanitize = 3 # Sterilization
@@ -152,6 +145,7 @@ class ZeoSoak(RoborockEnum):
152
145
 
153
146
 
154
147
  class ZeoTemperature(RoborockEnum):
148
+ null = 0
155
149
  normal = 1 # L1, 0 C
156
150
  low = 2 # L2, 30 C
157
151
  medium = 3 # L3, 40 C
@@ -203,11 +197,13 @@ class ZeoSoftenerType(RoborockEnum):
203
197
 
204
198
 
205
199
  class ZeoDetergentExpansionType(RoborockEnum):
200
+ null = 0
206
201
  concentrated_detergent = 1
207
202
  detergent = 2
208
203
 
209
204
 
210
205
  class ZeoSoftenerExpansionType(RoborockEnum):
206
+ null = 0
211
207
  softener = 1
212
208
  softener_expansion = 2
213
209
  wool_detergent = 3
@@ -241,6 +237,7 @@ class ZeoError(RoborockEnum):
241
237
 
242
238
 
243
239
  class ZeoDryingMethod(RoborockEnum):
240
+ null = 0
244
241
  l1 = 1 # L1, Saving
245
242
  l2 = 2 # L2, Standard
246
243
  l3 = 3 # L3, SuperFast
@@ -255,11 +252,13 @@ class ZeoSteamVolume(RoborockEnum):
255
252
 
256
253
 
257
254
  class ZeoDryAndCare(RoborockEnum):
255
+ null = 0
258
256
  soft = 1
259
257
  normal = 2
260
258
 
261
259
 
262
260
  class ZeoDryerStartError(RoborockEnum):
261
+ null = 0
263
262
  dryer_running = 1 # Washer-Dryer Pairing cannot start: Dryer is running.
264
263
  dryer_error = 2 # Washer-Dryer Pairing cannot start: Dryer has an error.
265
264
  dryer_done = 3 # Dryer drying is complete, please remove the clothes first.
@@ -269,7 +268,7 @@ class ZeoDryerStartError(RoborockEnum):
269
268
  dryer_network_fail = 7 # Please check the dryer network connection.
270
269
 
271
270
 
272
- # The following are App-internal lookup tables extracted from the bundle.
271
+ # The following are App-internal lookup tables.
273
272
  # They are NOT DP protocol enums — the device never receives these values.
274
273
  # They control how the official app adjusts recommended dosages or UI visibility.
275
274
  #