python-roborock 2.58.1__tar.gz → 3.10.8__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-2.58.1 → python_roborock-3.10.8}/PKG-INFO +29 -26
- {python_roborock-2.58.1 → python_roborock-3.10.8}/README.md +28 -25
- {python_roborock-2.58.1 → python_roborock-3.10.8}/pyproject.toml +18 -10
- python_roborock-3.10.8/roborock/__init__.py +30 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/api.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/broadcast_protocol.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/cli.py +76 -40
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/cloud_api.py +1 -1
- python_roborock-3.10.8/roborock/data/__init__.py +9 -0
- python_roborock-3.10.8/roborock/data/b01_q10/__init__.py +2 -0
- python_roborock-3.10.8/roborock/data/b01_q10/b01_q10_code_mappings.py +213 -0
- python_roborock-3.10.8/roborock/data/b01_q10/b01_q10_containers.py +53 -0
- python_roborock-3.10.8/roborock/data/b01_q7/__init__.py +2 -0
- python_roborock-2.58.1/roborock/b01_containers.py → python_roborock-3.10.8/roborock/data/b01_q7/b01_q7_code_mappings.py +1 -130
- python_roborock-3.10.8/roborock/data/b01_q7/b01_q7_containers.py +130 -0
- python_roborock-3.10.8/roborock/data/code_mappings.py +146 -0
- python_roborock-3.10.8/roborock/data/containers.py +450 -0
- python_roborock-3.10.8/roborock/data/dyad/__init__.py +2 -0
- python_roborock-3.10.8/roborock/data/dyad/dyad_code_mappings.py +102 -0
- python_roborock-3.10.8/roborock/data/dyad/dyad_containers.py +28 -0
- python_roborock-3.10.8/roborock/data/v1/__init__.py +3 -0
- python_roborock-2.58.1/roborock/clean_modes.py → python_roborock-3.10.8/roborock/data/v1/v1_clean_modes.py +6 -2
- python_roborock-2.58.1/roborock/code_mappings.py → python_roborock-3.10.8/roborock/data/v1/v1_code_mappings.py +147 -528
- python_roborock-2.58.1/roborock/containers.py → python_roborock-3.10.8/roborock/data/v1/v1_containers.py +51 -495
- python_roborock-3.10.8/roborock/data/zeo/__init__.py +2 -0
- python_roborock-3.10.8/roborock/data/zeo/zeo_code_mappings.py +136 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/device_features.py +26 -3
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/README.md +5 -3
- python_roborock-3.10.8/roborock/devices/__init__.py +11 -0
- python_roborock-3.10.8/roborock/devices/cache.py +143 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/channel.py +5 -0
- python_roborock-3.10.8/roborock/devices/device.py +223 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/device_manager.py +61 -32
- python_roborock-3.10.8/roborock/devices/file_cache.py +77 -0
- python_roborock-3.10.8/roborock/devices/local_channel.py +290 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/mqtt_channel.py +11 -2
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/a01/__init__.py +3 -3
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/b01/__init__.py +1 -2
- python_roborock-3.10.8/roborock/devices/traits/v1/__init__.py +293 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/child_lock.py +11 -2
- python_roborock-3.10.8/roborock/devices/traits/v1/clean_summary.py +83 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/command.py +9 -2
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/common.py +30 -7
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/consumeable.py +2 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/device_features.py +15 -12
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/do_not_disturb.py +17 -15
- python_roborock-3.10.8/roborock/devices/traits/v1/dust_collection_mode.py +13 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/flow_led_status.py +11 -2
- python_roborock-3.10.8/roborock/devices/traits/v1/home.py +262 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/led_status.py +11 -2
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/map_content.py +34 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/maps.py +1 -1
- python_roborock-3.10.8/roborock/devices/traits/v1/network_info.py +55 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/rooms.py +1 -1
- python_roborock-3.10.8/roborock/devices/traits/v1/routines.py +26 -0
- python_roborock-3.10.8/roborock/devices/traits/v1/smart_wash_params.py +13 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/status.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/valley_electricity_timer.py +16 -12
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/v1/volume.py +1 -0
- python_roborock-3.10.8/roborock/devices/traits/v1/wash_towel_mode.py +13 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/v1_channel.py +223 -53
- python_roborock-3.10.8/roborock/mqtt/health_manager.py +51 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/mqtt/roborock_session.py +131 -57
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/mqtt/session.py +4 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/protocol.py +1 -1
- python_roborock-3.10.8/roborock/protocols/__init__.py +3 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/protocols/v1_protocol.py +50 -6
- python_roborock-3.10.8/roborock/py.typed +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/roborock_typing.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_1_apis/roborock_client_v1.py +4 -13
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_1_apis/roborock_local_client_v1.py +2 -10
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_1_apis/roborock_mqtt_client_v1.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_a01_apis/roborock_client_a01.py +5 -3
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +1 -1
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/web_api.py +27 -1
- python_roborock-2.58.1/roborock/__init__.py +0 -39
- python_roborock-2.58.1/roborock/devices/__init__.py +0 -7
- python_roborock-2.58.1/roborock/devices/cache.py +0 -64
- python_roborock-2.58.1/roborock/devices/device.py +0 -105
- python_roborock-2.58.1/roborock/devices/local_channel.py +0 -131
- python_roborock-2.58.1/roborock/devices/traits/v1/__init__.py +0 -163
- python_roborock-2.58.1/roborock/devices/traits/v1/clean_summary.py +0 -29
- python_roborock-2.58.1/roborock/devices/traits/v1/home.py +0 -174
- python_roborock-2.58.1/roborock/devices/v1_rpc_channel.py +0 -211
- {python_roborock-2.58.1 → python_roborock-3.10.8}/.gitignore +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/LICENSE +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/callbacks.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/command_cache.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/const.py +0 -0
- /python_roborock-2.58.1/roborock/py.typed → /python_roborock-3.10.8/roborock/data/zeo/zeo_containers.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/a01_channel.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/b01_channel.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/__init__.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/devices/traits/traits_mixin.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/exceptions.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/map/__init__.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/map/map_parser.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/protocols/a01_protocol.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/protocols/b01_protocol.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/roborock_future.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/roborock_message.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/util.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-2.58.1 → python_roborock-3.10.8}/roborock/version_a01_apis/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-roborock
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.10.8
|
|
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/
|
|
@@ -35,8 +35,12 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
</a>
|
|
36
36
|
<img src="https://img.shields.io/pypi/pyversions/python-roborock.svg?style=flat-square&logo=python&logoColor=fff" alt="Supported Python versions">
|
|
37
37
|
<img src="https://img.shields.io/pypi/l/python-roborock.svg?style=flat-square" alt="License">
|
|
38
|
+
<a href="https://codecov.io/github/Python-roborock/python-roborock" >
|
|
39
|
+
<img src="https://codecov.io/github/Python-roborock/python-roborock/graph/badge.svg?token=KEK4S3FPSZ" alt="Code Coverage"/>
|
|
40
|
+
</a>
|
|
38
41
|
</p>
|
|
39
42
|
|
|
43
|
+
|
|
40
44
|
Roborock library for online and offline control of your vacuums.
|
|
41
45
|
|
|
42
46
|
## Installation
|
|
@@ -49,16 +53,14 @@ Install this via pip (or your favourite package manager):
|
|
|
49
53
|
|
|
50
54
|
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
51
55
|
|
|
52
|
-
##
|
|
56
|
+
## Example Usage
|
|
53
57
|
|
|
54
|
-
Here is an example that requires no manual intervention and can be done all automatically. You can skip some steps by
|
|
55
|
-
caching values or looking at them and grabbing them manually.
|
|
56
58
|
```python
|
|
57
59
|
import asyncio
|
|
58
60
|
|
|
59
|
-
from roborock import HomeDataProduct, DeviceData, RoborockCommand
|
|
60
|
-
from roborock.version_1_apis import RoborockMqttClientV1, RoborockLocalClientV1
|
|
61
61
|
from roborock.web_api import RoborockApiClient
|
|
62
|
+
from roborock.devices.device_manager import create_device_manager, UserParams
|
|
63
|
+
|
|
62
64
|
|
|
63
65
|
async def main():
|
|
64
66
|
web_api = RoborockApiClient(username="youremailhere")
|
|
@@ -69,30 +71,31 @@ async def main():
|
|
|
69
71
|
code = input("What is the code?")
|
|
70
72
|
user_data = await web_api.code_login(code)
|
|
71
73
|
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
status = await local_client.send_command(RoborockCommand.GET_STATUS)
|
|
90
|
-
# Or use existing functions that will give you data classes
|
|
91
|
-
status = await local_client.get_status()
|
|
74
|
+
# Create a device manager that can discover devices.
|
|
75
|
+
user_params = UserParams(
|
|
76
|
+
username="youremailhere",
|
|
77
|
+
user_data=user_data,
|
|
78
|
+
)
|
|
79
|
+
device_manager = await create_device_manager(user_params)
|
|
80
|
+
devices = await device_manager.get_devices()
|
|
81
|
+
|
|
82
|
+
# Get all vacuum devices that support the v1 PropertiesApi
|
|
83
|
+
for device in devices:
|
|
84
|
+
if not device.v1_properties:
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
# Refresh the current device status
|
|
88
|
+
status_trait = device.v1_properties.status
|
|
89
|
+
await status_trait.refresh()
|
|
90
|
+
print(status_trait)
|
|
92
91
|
|
|
93
92
|
asyncio.run(main())
|
|
94
93
|
```
|
|
95
94
|
|
|
95
|
+
See [examples/example.py](examples/example.py) for a more full featured example
|
|
96
|
+
that has performance improvements to cache cloud information to prefer
|
|
97
|
+
connections over the local network.
|
|
98
|
+
|
|
96
99
|
## Supported devices
|
|
97
100
|
|
|
98
101
|
You can find what devices are supported
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
</a>
|
|
7
7
|
<img src="https://img.shields.io/pypi/pyversions/python-roborock.svg?style=flat-square&logo=python&logoColor=fff" alt="Supported Python versions">
|
|
8
8
|
<img src="https://img.shields.io/pypi/l/python-roborock.svg?style=flat-square" alt="License">
|
|
9
|
+
<a href="https://codecov.io/github/Python-roborock/python-roborock" >
|
|
10
|
+
<img src="https://codecov.io/github/Python-roborock/python-roborock/graph/badge.svg?token=KEK4S3FPSZ" alt="Code Coverage"/>
|
|
11
|
+
</a>
|
|
9
12
|
</p>
|
|
10
13
|
|
|
14
|
+
|
|
11
15
|
Roborock library for online and offline control of your vacuums.
|
|
12
16
|
|
|
13
17
|
## Installation
|
|
@@ -20,16 +24,14 @@ Install this via pip (or your favourite package manager):
|
|
|
20
24
|
|
|
21
25
|
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
22
26
|
|
|
23
|
-
##
|
|
27
|
+
## Example Usage
|
|
24
28
|
|
|
25
|
-
Here is an example that requires no manual intervention and can be done all automatically. You can skip some steps by
|
|
26
|
-
caching values or looking at them and grabbing them manually.
|
|
27
29
|
```python
|
|
28
30
|
import asyncio
|
|
29
31
|
|
|
30
|
-
from roborock import HomeDataProduct, DeviceData, RoborockCommand
|
|
31
|
-
from roborock.version_1_apis import RoborockMqttClientV1, RoborockLocalClientV1
|
|
32
32
|
from roborock.web_api import RoborockApiClient
|
|
33
|
+
from roborock.devices.device_manager import create_device_manager, UserParams
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
async def main():
|
|
35
37
|
web_api = RoborockApiClient(username="youremailhere")
|
|
@@ -40,30 +42,31 @@ async def main():
|
|
|
40
42
|
code = input("What is the code?")
|
|
41
43
|
user_data = await web_api.code_login(code)
|
|
42
44
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
status = await local_client.send_command(RoborockCommand.GET_STATUS)
|
|
61
|
-
# Or use existing functions that will give you data classes
|
|
62
|
-
status = await local_client.get_status()
|
|
45
|
+
# Create a device manager that can discover devices.
|
|
46
|
+
user_params = UserParams(
|
|
47
|
+
username="youremailhere",
|
|
48
|
+
user_data=user_data,
|
|
49
|
+
)
|
|
50
|
+
device_manager = await create_device_manager(user_params)
|
|
51
|
+
devices = await device_manager.get_devices()
|
|
52
|
+
|
|
53
|
+
# Get all vacuum devices that support the v1 PropertiesApi
|
|
54
|
+
for device in devices:
|
|
55
|
+
if not device.v1_properties:
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
# Refresh the current device status
|
|
59
|
+
status_trait = device.v1_properties.status
|
|
60
|
+
await status_trait.refresh()
|
|
61
|
+
print(status_trait)
|
|
63
62
|
|
|
64
63
|
asyncio.run(main())
|
|
65
64
|
```
|
|
66
65
|
|
|
66
|
+
See [examples/example.py](examples/example.py) for a more full featured example
|
|
67
|
+
that has performance improvements to cache cloud information to prefer
|
|
68
|
+
connections over the local network.
|
|
69
|
+
|
|
67
70
|
## Supported devices
|
|
68
71
|
|
|
69
72
|
You can find what devices are supported
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-roborock"
|
|
3
|
-
version = "
|
|
3
|
+
version = "3.10.8"
|
|
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"
|
|
@@ -44,7 +44,7 @@ dev = [
|
|
|
44
44
|
"pytest",
|
|
45
45
|
"pre-commit>=3.5,<5.0",
|
|
46
46
|
"mypy",
|
|
47
|
-
"ruff==0.14.
|
|
47
|
+
"ruff==0.14.6",
|
|
48
48
|
"codespell",
|
|
49
49
|
"pyshark>=0.6,<0.7",
|
|
50
50
|
"aioresponses>=0.7.7,<0.8",
|
|
@@ -52,6 +52,9 @@ dev = [
|
|
|
52
52
|
"pytest-timeout>=2.3.1,<3",
|
|
53
53
|
"syrupy>=4.9.1,<5",
|
|
54
54
|
"pdoc>=15.0.4,<16",
|
|
55
|
+
"pyyaml>=6.0.3",
|
|
56
|
+
"pyshark>=0.6",
|
|
57
|
+
"pytest-cov>=7.0.0",
|
|
55
58
|
]
|
|
56
59
|
|
|
57
60
|
[tool.hatch.build.targets.sdist]
|
|
@@ -66,8 +69,19 @@ build-backend = "hatchling.build"
|
|
|
66
69
|
|
|
67
70
|
[tool.semantic_release]
|
|
68
71
|
branch = "main"
|
|
69
|
-
version_toml = ["pyproject.toml:
|
|
70
|
-
build_command = "pip install
|
|
72
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
73
|
+
build_command = "pip install uv && uv lock --upgrade-package python-roborock && git add uv.lock && uv build"
|
|
74
|
+
changelog_file = 'CHANGELOG.md'
|
|
75
|
+
commit = true
|
|
76
|
+
|
|
77
|
+
[tool.semantic_release.branches.main]
|
|
78
|
+
match = "main"
|
|
79
|
+
prerelease = false
|
|
80
|
+
|
|
81
|
+
[tool.semantic_release.branches.temp-main-branch]
|
|
82
|
+
match = "temp-main-branch"
|
|
83
|
+
prerelease = false
|
|
84
|
+
|
|
71
85
|
|
|
72
86
|
[tool.semantic_release.commit_parser_options]
|
|
73
87
|
allowed_tags = [
|
|
@@ -92,9 +106,3 @@ asyncio_mode = "auto"
|
|
|
92
106
|
asyncio_default_fixture_loop_scope = "function"
|
|
93
107
|
timeout = 30
|
|
94
108
|
log_format = "%(asctime)s.%(msecs)03d %(levelname)s (%(threadName)s) [%(name)s] %(message)s"
|
|
95
|
-
|
|
96
|
-
[tool.uv]
|
|
97
|
-
dev-dependencies = [
|
|
98
|
-
"pyyaml>=6.0.3",
|
|
99
|
-
"pyshark>=0.6",
|
|
100
|
-
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Roborock API.
|
|
2
|
+
|
|
3
|
+
.. include:: ../README.md
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from roborock.data import *
|
|
7
|
+
from roborock.exceptions import *
|
|
8
|
+
from roborock.roborock_typing import *
|
|
9
|
+
|
|
10
|
+
from . import (
|
|
11
|
+
cloud_api,
|
|
12
|
+
const,
|
|
13
|
+
data,
|
|
14
|
+
devices,
|
|
15
|
+
exceptions,
|
|
16
|
+
roborock_typing,
|
|
17
|
+
version_1_apis,
|
|
18
|
+
version_a01_apis,
|
|
19
|
+
web_api,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"devices",
|
|
24
|
+
"data",
|
|
25
|
+
"map",
|
|
26
|
+
"web_api",
|
|
27
|
+
"roborock_typing",
|
|
28
|
+
"exceptions",
|
|
29
|
+
"const",
|
|
30
|
+
]
|
|
@@ -19,7 +19,7 @@ from construct import ( # type: ignore
|
|
|
19
19
|
from Crypto.Cipher import AES
|
|
20
20
|
|
|
21
21
|
from roborock import RoborockException
|
|
22
|
-
from roborock.
|
|
22
|
+
from roborock.data import BroadcastMessage
|
|
23
23
|
from roborock.protocol import EncryptionAdapter, Utils, _Parser
|
|
24
24
|
|
|
25
25
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -42,11 +42,11 @@ from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException
|
|
|
42
42
|
from pyshark.packet.packet import Packet # type: ignore
|
|
43
43
|
|
|
44
44
|
from roborock import SHORT_MODEL_TO_ENUM, RoborockCommand
|
|
45
|
-
from roborock.
|
|
45
|
+
from roborock.data import DeviceData, RoborockBase, UserData
|
|
46
46
|
from roborock.device_features import DeviceFeatures
|
|
47
47
|
from roborock.devices.cache import Cache, CacheData
|
|
48
48
|
from roborock.devices.device import RoborockDevice
|
|
49
|
-
from roborock.devices.device_manager import DeviceManager,
|
|
49
|
+
from roborock.devices.device_manager import DeviceManager, UserParams, create_device_manager
|
|
50
50
|
from roborock.devices.traits import Trait
|
|
51
51
|
from roborock.devices.traits.v1 import V1TraitMixin
|
|
52
52
|
from roborock.devices.traits.v1.consumeable import ConsumableAttribute
|
|
@@ -116,9 +116,8 @@ class ConnectionCache(RoborockBase):
|
|
|
116
116
|
|
|
117
117
|
user_data: UserData
|
|
118
118
|
email: str
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
home_cache: dict[int, CombinedMapInfo] | None = None
|
|
119
|
+
# TODO: Used new APIs for cache file storage
|
|
120
|
+
cache_data: CacheData | None = None
|
|
122
121
|
|
|
123
122
|
|
|
124
123
|
class DeviceConnectionManager:
|
|
@@ -133,9 +132,12 @@ class DeviceConnectionManager:
|
|
|
133
132
|
async def ensure_device_manager(self) -> DeviceManager:
|
|
134
133
|
"""Ensure device manager is initialized."""
|
|
135
134
|
if self.device_manager is None:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
connection_cache = self.context.connection_cache()
|
|
136
|
+
user_params = UserParams(
|
|
137
|
+
username=connection_cache.email,
|
|
138
|
+
user_data=connection_cache.user_data,
|
|
139
|
+
)
|
|
140
|
+
self.device_manager = await create_device_manager(user_params, cache=self.context)
|
|
139
141
|
# Cache devices for quick lookup
|
|
140
142
|
devices = await self.device_manager.get_devices()
|
|
141
143
|
self._devices = {device.duid: device for device in devices}
|
|
@@ -160,7 +162,8 @@ class RoborockContext(Cache):
|
|
|
160
162
|
"""Context that handles both CLI and session modes internally."""
|
|
161
163
|
|
|
162
164
|
roborock_file = Path("~/.roborock").expanduser()
|
|
163
|
-
|
|
165
|
+
roborock_cache_file = Path("~/.roborock.cache").expanduser()
|
|
166
|
+
_connection_cache: ConnectionCache | None = None
|
|
164
167
|
|
|
165
168
|
def __init__(self):
|
|
166
169
|
self.reload()
|
|
@@ -173,22 +176,22 @@ class RoborockContext(Cache):
|
|
|
173
176
|
with open(self.roborock_file) as f:
|
|
174
177
|
data = json.load(f)
|
|
175
178
|
if data:
|
|
176
|
-
self.
|
|
179
|
+
self._connection_cache = ConnectionCache.from_dict(data)
|
|
177
180
|
|
|
178
|
-
def update(self,
|
|
179
|
-
data = json.dumps(
|
|
181
|
+
def update(self, connection_cache: ConnectionCache):
|
|
182
|
+
data = json.dumps(connection_cache.as_dict(), default=vars, indent=4)
|
|
180
183
|
with open(self.roborock_file, "w") as f:
|
|
181
184
|
f.write(data)
|
|
182
185
|
self.reload()
|
|
183
186
|
|
|
184
187
|
def validate(self):
|
|
185
|
-
if self.
|
|
188
|
+
if self._connection_cache is None:
|
|
186
189
|
raise RoborockException("You must login first")
|
|
187
190
|
|
|
188
|
-
def
|
|
191
|
+
def connection_cache(self) -> ConnectionCache:
|
|
189
192
|
"""Get the cache data."""
|
|
190
193
|
self.validate()
|
|
191
|
-
return cast(ConnectionCache, self.
|
|
194
|
+
return cast(ConnectionCache, self._connection_cache)
|
|
192
195
|
|
|
193
196
|
def start_session_mode(self):
|
|
194
197
|
"""Start session mode with a background event loop."""
|
|
@@ -225,19 +228,21 @@ class RoborockContext(Cache):
|
|
|
225
228
|
|
|
226
229
|
async def refresh_devices(self) -> ConnectionCache:
|
|
227
230
|
"""Refresh device data from server (always fetches fresh data)."""
|
|
228
|
-
|
|
229
|
-
client = RoborockApiClient(
|
|
230
|
-
home_data = await client.get_home_data_v3(
|
|
231
|
-
cache_data
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
connection_cache = self.connection_cache()
|
|
232
|
+
client = RoborockApiClient(connection_cache.email)
|
|
233
|
+
home_data = await client.get_home_data_v3(connection_cache.user_data)
|
|
234
|
+
if connection_cache.cache_data is None:
|
|
235
|
+
connection_cache.cache_data = CacheData()
|
|
236
|
+
connection_cache.cache_data.home_data = home_data
|
|
237
|
+
self.update(connection_cache)
|
|
238
|
+
return connection_cache
|
|
234
239
|
|
|
235
240
|
async def get_devices(self) -> ConnectionCache:
|
|
236
241
|
"""Get device data (uses cache if available, fetches if needed)."""
|
|
237
|
-
|
|
238
|
-
if
|
|
239
|
-
|
|
240
|
-
return
|
|
242
|
+
connection_cache = self.connection_cache()
|
|
243
|
+
if (connection_cache.cache_data is None) or (connection_cache.cache_data.home_data is None):
|
|
244
|
+
connection_cache = await self.refresh_devices()
|
|
245
|
+
return connection_cache
|
|
241
246
|
|
|
242
247
|
async def cleanup(self):
|
|
243
248
|
"""Clean up resources (mainly for session mode)."""
|
|
@@ -262,20 +267,16 @@ class RoborockContext(Cache):
|
|
|
262
267
|
async def get(self) -> CacheData:
|
|
263
268
|
"""Get cached value."""
|
|
264
269
|
_LOGGER.debug("Getting cache data")
|
|
265
|
-
connection_cache = self.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
home_cache=connection_cache.home_cache,
|
|
270
|
-
)
|
|
270
|
+
connection_cache = self.connection_cache()
|
|
271
|
+
if connection_cache.cache_data is not None:
|
|
272
|
+
return connection_cache.cache_data
|
|
273
|
+
return CacheData()
|
|
271
274
|
|
|
272
275
|
async def set(self, value: CacheData) -> None:
|
|
273
276
|
"""Set value in the cache."""
|
|
274
277
|
_LOGGER.debug("Setting cache data")
|
|
275
|
-
connection_cache = self.
|
|
276
|
-
connection_cache.
|
|
277
|
-
connection_cache.network_info = value.network_info
|
|
278
|
-
connection_cache.home_cache = value.home_cache
|
|
278
|
+
connection_cache = self.connection_cache()
|
|
279
|
+
connection_cache.cache_data = value
|
|
279
280
|
self.update(connection_cache)
|
|
280
281
|
|
|
281
282
|
|
|
@@ -361,9 +362,9 @@ async def discover(ctx):
|
|
|
361
362
|
@async_command
|
|
362
363
|
async def list_devices(ctx):
|
|
363
364
|
context: RoborockContext = ctx.obj
|
|
364
|
-
|
|
365
|
+
connection_cache = await context.get_devices()
|
|
365
366
|
|
|
366
|
-
home_data = cache_data.home_data
|
|
367
|
+
home_data = connection_cache.cache_data.home_data
|
|
367
368
|
|
|
368
369
|
device_name_id = {device.name: device.duid for device in home_data.get_all_devices()}
|
|
369
370
|
click.echo(json.dumps(device_name_id, indent=4))
|
|
@@ -401,9 +402,11 @@ async def _v1_trait(context: RoborockContext, device_id: str, display_func: Call
|
|
|
401
402
|
device_manager = await context.get_device_manager()
|
|
402
403
|
device = await device_manager.get_device(device_id)
|
|
403
404
|
if device.v1_properties is None:
|
|
404
|
-
raise
|
|
405
|
+
raise RoborockUnsupportedFeature(f"Device {device.name} does not support V1 protocol")
|
|
405
406
|
await device.v1_properties.discover_features()
|
|
406
407
|
trait = display_func(device.v1_properties)
|
|
408
|
+
if trait is None:
|
|
409
|
+
raise RoborockUnsupportedFeature("Trait not supported by device")
|
|
407
410
|
await trait.refresh()
|
|
408
411
|
return trait
|
|
409
412
|
|
|
@@ -440,6 +443,26 @@ async def clean_summary(ctx, device_id: str):
|
|
|
440
443
|
await _display_v1_trait(context, device_id, lambda v1: v1.clean_summary)
|
|
441
444
|
|
|
442
445
|
|
|
446
|
+
@session.command()
|
|
447
|
+
@click.option("--device_id", required=True)
|
|
448
|
+
@click.pass_context
|
|
449
|
+
@async_command
|
|
450
|
+
async def clean_record(ctx, device_id: str):
|
|
451
|
+
"""Get device last clean record."""
|
|
452
|
+
context: RoborockContext = ctx.obj
|
|
453
|
+
await _display_v1_trait(context, device_id, lambda v1: v1.clean_record)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@session.command()
|
|
457
|
+
@click.option("--device_id", required=True)
|
|
458
|
+
@click.pass_context
|
|
459
|
+
@async_command
|
|
460
|
+
async def dock_summary(ctx, device_id: str):
|
|
461
|
+
"""Get device dock summary."""
|
|
462
|
+
context: RoborockContext = ctx.obj
|
|
463
|
+
await _display_v1_trait(context, device_id, lambda v1: v1.dock_summary)
|
|
464
|
+
|
|
465
|
+
|
|
443
466
|
@session.command()
|
|
444
467
|
@click.option("--device_id", required=True)
|
|
445
468
|
@click.pass_context
|
|
@@ -692,20 +715,30 @@ async def home(ctx, device_id: str, refresh: bool):
|
|
|
692
715
|
await home_trait.refresh()
|
|
693
716
|
|
|
694
717
|
# Display the discovered home cache
|
|
695
|
-
if home_trait.
|
|
718
|
+
if home_trait.home_map_info:
|
|
696
719
|
cache_summary = {
|
|
697
720
|
map_flag: {
|
|
698
721
|
"name": map_data.name,
|
|
699
722
|
"room_count": len(map_data.rooms),
|
|
700
723
|
"rooms": [{"segment_id": room.segment_id, "name": room.name} for room in map_data.rooms],
|
|
701
724
|
}
|
|
702
|
-
for map_flag, map_data in home_trait.
|
|
725
|
+
for map_flag, map_data in home_trait.home_map_info.items()
|
|
703
726
|
}
|
|
704
727
|
click.echo(dump_json(cache_summary))
|
|
705
728
|
else:
|
|
706
729
|
click.echo("No maps discovered")
|
|
707
730
|
|
|
708
731
|
|
|
732
|
+
@session.command()
|
|
733
|
+
@click.option("--device_id", required=True)
|
|
734
|
+
@click.pass_context
|
|
735
|
+
@async_command
|
|
736
|
+
async def network_info(ctx, device_id: str):
|
|
737
|
+
"""Get device network information."""
|
|
738
|
+
context: RoborockContext = ctx.obj
|
|
739
|
+
await _display_v1_trait(context, device_id, lambda v1: v1.network_info)
|
|
740
|
+
|
|
741
|
+
|
|
709
742
|
@click.command()
|
|
710
743
|
@click.option("--device_id", required=True)
|
|
711
744
|
@click.option("--cmd", required=True)
|
|
@@ -938,6 +971,8 @@ cli.add_command(session)
|
|
|
938
971
|
cli.add_command(get_device_info)
|
|
939
972
|
cli.add_command(update_docs)
|
|
940
973
|
cli.add_command(clean_summary)
|
|
974
|
+
cli.add_command(clean_record)
|
|
975
|
+
cli.add_command(dock_summary)
|
|
941
976
|
cli.add_command(volume)
|
|
942
977
|
cli.add_command(set_volume)
|
|
943
978
|
cli.add_command(maps)
|
|
@@ -952,6 +987,7 @@ cli.add_command(child_lock)
|
|
|
952
987
|
cli.add_command(dnd)
|
|
953
988
|
cli.add_command(flow_led_status)
|
|
954
989
|
cli.add_command(led_status)
|
|
990
|
+
cli.add_command(network_info)
|
|
955
991
|
|
|
956
992
|
|
|
957
993
|
def main():
|
|
@@ -14,7 +14,7 @@ from paho.mqtt.enums import MQTTErrorCode
|
|
|
14
14
|
from paho.mqtt.reasoncodes import ReasonCode # type: ignore
|
|
15
15
|
|
|
16
16
|
from .api import KEEPALIVE, RoborockClient
|
|
17
|
-
from .
|
|
17
|
+
from .data import DeviceData, UserData
|
|
18
18
|
from .exceptions import RoborockException, VacuumError
|
|
19
19
|
from .protocol import (
|
|
20
20
|
Decoder,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""This module is meant to hold dataclasses and codemappings for various devices and protocols."""
|
|
2
|
+
|
|
3
|
+
from .b01_q7 import *
|
|
4
|
+
from .b01_q10 import *
|
|
5
|
+
from .code_mappings import *
|
|
6
|
+
from .containers import *
|
|
7
|
+
from .dyad import *
|
|
8
|
+
from .v1 import *
|
|
9
|
+
from .zeo import *
|