python-roborock 3.7.4__tar.gz → 3.8.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-3.7.4 → python_roborock-3.8.0}/PKG-INFO +25 -26
- {python_roborock-3.7.4 → python_roborock-3.8.0}/README.md +24 -25
- {python_roborock-3.7.4 → python_roborock-3.8.0}/pyproject.toml +1 -1
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/__init__.py +5 -6
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/README.md +5 -3
- python_roborock-3.8.0/roborock/devices/__init__.py +11 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/device.py +47 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/device_manager.py +1 -1
- python_roborock-3.8.0/roborock/devices/file_cache.py +70 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/b01/__init__.py +1 -2
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/__init__.py +20 -20
- python_roborock-3.8.0/roborock/protocols/__init__.py +3 -0
- python_roborock-3.7.4/roborock/devices/__init__.py +0 -7
- {python_roborock-3.7.4 → python_roborock-3.8.0}/.gitignore +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/LICENSE +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/api.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/broadcast_protocol.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/callbacks.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/cli.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/cloud_api.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/command_cache.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/const.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q10/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q7/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/dyad/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/dyad/dyad_containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/v1/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/v1/v1_clean_modes.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/v1/v1_code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/v1/v1_containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/zeo/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/zeo/zeo_containers.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/device_features.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/a01_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/b01_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/cache.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/local_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/mqtt_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/a01/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/traits_mixin.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/child_lock.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/command.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/common.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/consumeable.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/device_features.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/home.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/led_status.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/map_content.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/maps.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/network_info.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/rooms.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/routines.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/status.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/volume.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/v1_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/v1_rpc_channel.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/exceptions.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/map/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/map/map_parser.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/mqtt/roborock_session.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/mqtt/session.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/protocol.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/protocols/a01_protocol.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/protocols/b01_protocol.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/protocols/v1_protocol.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/py.typed +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/roborock_future.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/roborock_message.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/util.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
- {python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/web_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-roborock
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.0
|
|
4
4
|
Summary: A package to control Roborock vacuums.
|
|
5
5
|
Project-URL: Repository, https://github.com/humbertogontijo/python-roborock
|
|
6
6
|
Project-URL: Documentation, https://python-roborock.readthedocs.io/
|
|
@@ -49,16 +49,14 @@ Install this via pip (or your favourite package manager):
|
|
|
49
49
|
|
|
50
50
|
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
51
51
|
|
|
52
|
-
##
|
|
52
|
+
## Example Usage
|
|
53
53
|
|
|
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
54
|
```python
|
|
57
55
|
import asyncio
|
|
58
56
|
|
|
59
|
-
from roborock import HomeDataProduct, DeviceData, RoborockCommand
|
|
60
|
-
from roborock.version_1_apis import RoborockMqttClientV1, RoborockLocalClientV1
|
|
61
57
|
from roborock.web_api import RoborockApiClient
|
|
58
|
+
from roborock.devices.device_manager import create_device_manager, UserParams
|
|
59
|
+
|
|
62
60
|
|
|
63
61
|
async def main():
|
|
64
62
|
web_api = RoborockApiClient(username="youremailhere")
|
|
@@ -69,30 +67,31 @@ async def main():
|
|
|
69
67
|
code = input("What is the code?")
|
|
70
68
|
user_data = await web_api.code_login(code)
|
|
71
69
|
|
|
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()
|
|
70
|
+
# Create a device manager that can discover devices.
|
|
71
|
+
user_params = UserParams(
|
|
72
|
+
username="youremailhere",
|
|
73
|
+
user_data=user_data,
|
|
74
|
+
)
|
|
75
|
+
device_manager = await create_device_manager(user_params)
|
|
76
|
+
devices = await device_manager.get_devices()
|
|
77
|
+
|
|
78
|
+
# Get all vacuum devices that support the v1 PropertiesApi
|
|
79
|
+
for device in devices:
|
|
80
|
+
if not device.v1_properties:
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
# Refresh the current device status
|
|
84
|
+
status_trait = device.v1_properties.status
|
|
85
|
+
await status_trait.refresh()
|
|
86
|
+
print(status_trait)
|
|
92
87
|
|
|
93
88
|
asyncio.run(main())
|
|
94
89
|
```
|
|
95
90
|
|
|
91
|
+
See [examples/example.py](examples/example.py) for a more full featured example
|
|
92
|
+
that has performance improvements to cache cloud information to prefer
|
|
93
|
+
connections over the local network.
|
|
94
|
+
|
|
96
95
|
## Supported devices
|
|
97
96
|
|
|
98
97
|
You can find what devices are supported
|
|
@@ -20,16 +20,14 @@ Install this via pip (or your favourite package manager):
|
|
|
20
20
|
|
|
21
21
|
You can see all of the commands supported [here](https://python-roborock.readthedocs.io/en/latest/api_commands.html)
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Example Usage
|
|
24
24
|
|
|
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
25
|
```python
|
|
28
26
|
import asyncio
|
|
29
27
|
|
|
30
|
-
from roborock import HomeDataProduct, DeviceData, RoborockCommand
|
|
31
|
-
from roborock.version_1_apis import RoborockMqttClientV1, RoborockLocalClientV1
|
|
32
28
|
from roborock.web_api import RoborockApiClient
|
|
29
|
+
from roborock.devices.device_manager import create_device_manager, UserParams
|
|
30
|
+
|
|
33
31
|
|
|
34
32
|
async def main():
|
|
35
33
|
web_api = RoborockApiClient(username="youremailhere")
|
|
@@ -40,30 +38,31 @@ async def main():
|
|
|
40
38
|
code = input("What is the code?")
|
|
41
39
|
user_data = await web_api.code_login(code)
|
|
42
40
|
|
|
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()
|
|
41
|
+
# Create a device manager that can discover devices.
|
|
42
|
+
user_params = UserParams(
|
|
43
|
+
username="youremailhere",
|
|
44
|
+
user_data=user_data,
|
|
45
|
+
)
|
|
46
|
+
device_manager = await create_device_manager(user_params)
|
|
47
|
+
devices = await device_manager.get_devices()
|
|
48
|
+
|
|
49
|
+
# Get all vacuum devices that support the v1 PropertiesApi
|
|
50
|
+
for device in devices:
|
|
51
|
+
if not device.v1_properties:
|
|
52
|
+
continue
|
|
53
|
+
|
|
54
|
+
# Refresh the current device status
|
|
55
|
+
status_trait = device.v1_properties.status
|
|
56
|
+
await status_trait.refresh()
|
|
57
|
+
print(status_trait)
|
|
63
58
|
|
|
64
59
|
asyncio.run(main())
|
|
65
60
|
```
|
|
66
61
|
|
|
62
|
+
See [examples/example.py](examples/example.py) for a more full featured example
|
|
63
|
+
that has performance improvements to cache cloud information to prefer
|
|
64
|
+
connections over the local network.
|
|
65
|
+
|
|
67
66
|
## Supported devices
|
|
68
67
|
|
|
69
68
|
You can find what devices are supported
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-roborock"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.8.0"
|
|
4
4
|
description = "A package to control Roborock vacuums."
|
|
5
5
|
authors = [{ name = "humbertogontijo", email = "humbertogontijo@users.noreply.github.com" }, {name="Lash-L"}, {name="allenporter"}]
|
|
6
6
|
requires-python = ">=3.11, <4"
|
|
@@ -11,6 +11,7 @@ from . import (
|
|
|
11
11
|
cloud_api,
|
|
12
12
|
const,
|
|
13
13
|
data,
|
|
14
|
+
devices,
|
|
14
15
|
exceptions,
|
|
15
16
|
roborock_typing,
|
|
16
17
|
version_1_apis,
|
|
@@ -19,13 +20,11 @@ from . import (
|
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
__all__ = [
|
|
23
|
+
"devices",
|
|
24
|
+
"data",
|
|
25
|
+
"map",
|
|
22
26
|
"web_api",
|
|
23
|
-
"version_1_apis",
|
|
24
|
-
"version_a01_apis",
|
|
25
|
-
"const",
|
|
26
|
-
"cloud_api",
|
|
27
27
|
"roborock_typing",
|
|
28
28
|
"exceptions",
|
|
29
|
-
"
|
|
30
|
-
# Add new APIs here in the future when they are public e.g. devices/
|
|
29
|
+
"const",
|
|
31
30
|
]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# Roborock
|
|
1
|
+
# Roborock Devices & Discovery
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The devices module provides functionality to discover Roborock devices on the
|
|
4
|
+
network. This section documents the full lifecycle of device discovery across
|
|
5
|
+
Cloud and Network.
|
|
4
6
|
|
|
5
7
|
## Init account setup
|
|
6
8
|
|
|
@@ -61,7 +63,7 @@ that a newer version of the API should be used.
|
|
|
61
63
|
|
|
62
64
|
## Design
|
|
63
65
|
|
|
64
|
-
###
|
|
66
|
+
### Prior API Issues
|
|
65
67
|
|
|
66
68
|
- Complex Inheritance Hierarchy: Multiple inheritance with classes like RoborockMqttClientV1 inheriting from both RoborockMqttClient and RoborockClientV1
|
|
67
69
|
|
|
@@ -4,12 +4,15 @@ This interface is experimental and subject to breaking changes without notice
|
|
|
4
4
|
until the API is stable.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import asyncio
|
|
8
|
+
import datetime
|
|
7
9
|
import logging
|
|
8
10
|
from abc import ABC
|
|
9
11
|
from collections.abc import Callable, Mapping
|
|
10
12
|
from typing import Any, TypeVar, cast
|
|
11
13
|
|
|
12
14
|
from roborock.data import HomeDataDevice, HomeDataProduct
|
|
15
|
+
from roborock.exceptions import RoborockException
|
|
13
16
|
from roborock.roborock_message import RoborockMessage
|
|
14
17
|
|
|
15
18
|
from .channel import Channel
|
|
@@ -22,6 +25,11 @@ __all__ = [
|
|
|
22
25
|
"RoborockDevice",
|
|
23
26
|
]
|
|
24
27
|
|
|
28
|
+
# Exponential backoff parameters
|
|
29
|
+
MIN_BACKOFF_INTERVAL = datetime.timedelta(seconds=10)
|
|
30
|
+
MAX_BACKOFF_INTERVAL = datetime.timedelta(minutes=30)
|
|
31
|
+
BACKOFF_MULTIPLIER = 1.5
|
|
32
|
+
|
|
25
33
|
|
|
26
34
|
class RoborockDevice(ABC, TraitsMixin):
|
|
27
35
|
"""A generic channel for establishing a connection with a Roborock device.
|
|
@@ -54,6 +62,7 @@ class RoborockDevice(ABC, TraitsMixin):
|
|
|
54
62
|
self._device_info = device_info
|
|
55
63
|
self._product = product
|
|
56
64
|
self._channel = channel
|
|
65
|
+
self._connect_task: asyncio.Task[None] | None = None
|
|
57
66
|
self._unsub: Callable[[], None] | None = None
|
|
58
67
|
|
|
59
68
|
@property
|
|
@@ -98,6 +107,38 @@ class RoborockDevice(ABC, TraitsMixin):
|
|
|
98
107
|
"""
|
|
99
108
|
return self._channel.is_local_connected
|
|
100
109
|
|
|
110
|
+
def start_connect(self) -> None:
|
|
111
|
+
"""Start a background task to connect to the device.
|
|
112
|
+
|
|
113
|
+
This will attempt to connect to the device using the appropriate protocol
|
|
114
|
+
channel. If the connection fails, it will retry with exponential backoff.
|
|
115
|
+
|
|
116
|
+
Once connected, the device will remain connected until `close()` is
|
|
117
|
+
called. The device will automatically attempt to reconnect if the connection
|
|
118
|
+
is lost.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
async def connect_loop() -> None:
|
|
122
|
+
backoff = MIN_BACKOFF_INTERVAL
|
|
123
|
+
try:
|
|
124
|
+
while True:
|
|
125
|
+
try:
|
|
126
|
+
await self.connect()
|
|
127
|
+
return
|
|
128
|
+
except RoborockException as e:
|
|
129
|
+
_LOGGER.info("Failed to connect to device %s: %s", self.name, e)
|
|
130
|
+
_LOGGER.info(
|
|
131
|
+
"Retrying connection to device %s in %s seconds", self.name, backoff.total_seconds()
|
|
132
|
+
)
|
|
133
|
+
await asyncio.sleep(backoff.total_seconds())
|
|
134
|
+
backoff = min(backoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_INTERVAL)
|
|
135
|
+
except asyncio.CancelledError:
|
|
136
|
+
_LOGGER.info("connect_loop for device %s was cancelled", self.name)
|
|
137
|
+
# Clean exit on cancellation
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
self._connect_task = asyncio.create_task(connect_loop())
|
|
141
|
+
|
|
101
142
|
async def connect(self) -> None:
|
|
102
143
|
"""Connect to the device using the appropriate protocol channel."""
|
|
103
144
|
if self._unsub:
|
|
@@ -107,6 +148,12 @@ class RoborockDevice(ABC, TraitsMixin):
|
|
|
107
148
|
|
|
108
149
|
async def close(self) -> None:
|
|
109
150
|
"""Close all connections to the device."""
|
|
151
|
+
if self._connect_task:
|
|
152
|
+
self._connect_task.cancel()
|
|
153
|
+
try:
|
|
154
|
+
await self._connect_task
|
|
155
|
+
except asyncio.CancelledError:
|
|
156
|
+
pass
|
|
110
157
|
if self._unsub:
|
|
111
158
|
self._unsub()
|
|
112
159
|
self._unsub = None
|
|
@@ -86,7 +86,7 @@ class DeviceManager:
|
|
|
86
86
|
if duid in self._devices:
|
|
87
87
|
continue
|
|
88
88
|
new_device = self._device_creator(home_data, device, product)
|
|
89
|
-
|
|
89
|
+
new_device.start_connect()
|
|
90
90
|
new_devices[duid] = new_device
|
|
91
91
|
|
|
92
92
|
self._devices.update(new_devices)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""This module implements a file-backed cache for device information.
|
|
2
|
+
|
|
3
|
+
This module provides a `FileCache` class that implements the `Cache` protocol
|
|
4
|
+
to store and retrieve cached device information from a file on disk. This allows
|
|
5
|
+
persistent caching of device data across application restarts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import pathlib
|
|
10
|
+
import pickle
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from .cache import Cache, CacheData
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FileCache(Cache):
|
|
18
|
+
"""File backed cache implementation."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, file_path: pathlib.Path, init_fn: Callable[[], CacheData] = CacheData) -> None:
|
|
21
|
+
"""Initialize the file cache with the given file path."""
|
|
22
|
+
self._init_fn = init_fn
|
|
23
|
+
self._file_path = file_path
|
|
24
|
+
self._cache_data: CacheData | None = None
|
|
25
|
+
|
|
26
|
+
async def get(self) -> CacheData:
|
|
27
|
+
"""Get cached value."""
|
|
28
|
+
if self._cache_data is not None:
|
|
29
|
+
return self._cache_data
|
|
30
|
+
|
|
31
|
+
data = await load_value(self._file_path)
|
|
32
|
+
if data is not None and not isinstance(data, CacheData):
|
|
33
|
+
raise TypeError(f"Invalid cache data loaded from {self._file_path}")
|
|
34
|
+
|
|
35
|
+
self._cache_data = data or self._init_fn()
|
|
36
|
+
return self._cache_data
|
|
37
|
+
|
|
38
|
+
async def set(self, value: CacheData) -> None: # type: ignore[override]
|
|
39
|
+
"""Set value in the cache."""
|
|
40
|
+
self._cache_data = value
|
|
41
|
+
|
|
42
|
+
async def flush(self) -> None:
|
|
43
|
+
"""Flush the cache to disk."""
|
|
44
|
+
if self._cache_data is None:
|
|
45
|
+
return
|
|
46
|
+
await store_value(self._file_path, self._cache_data)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async def store_value(file_path: pathlib.Path, value: Any) -> None:
|
|
50
|
+
"""Store a value to the given file path."""
|
|
51
|
+
|
|
52
|
+
def _store_to_disk(file_path: pathlib.Path, value: Any) -> None:
|
|
53
|
+
with open(file_path, "wb") as f:
|
|
54
|
+
data = pickle.dumps(value)
|
|
55
|
+
f.write(data)
|
|
56
|
+
|
|
57
|
+
await asyncio.to_thread(_store_to_disk, file_path, value)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def load_value(file_path: pathlib.Path) -> Any | None:
|
|
61
|
+
"""Load a value from the given file path."""
|
|
62
|
+
|
|
63
|
+
def _load_from_disk(file_path: pathlib.Path) -> Any | None:
|
|
64
|
+
if not file_path.exists():
|
|
65
|
+
return None
|
|
66
|
+
with open(file_path, "rb") as f:
|
|
67
|
+
data = f.read()
|
|
68
|
+
return pickle.loads(data)
|
|
69
|
+
|
|
70
|
+
return await asyncio.to_thread(_load_from_disk, file_path)
|
|
@@ -67,27 +67,27 @@ from .wash_towel_mode import WashTowelModeTrait
|
|
|
67
67
|
_LOGGER = logging.getLogger(__name__)
|
|
68
68
|
|
|
69
69
|
__all__ = [
|
|
70
|
-
"create",
|
|
71
70
|
"PropertiesApi",
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
71
|
+
"child_lock",
|
|
72
|
+
"clean_summary",
|
|
73
|
+
"common",
|
|
74
|
+
"consumeable",
|
|
75
|
+
"device_features",
|
|
76
|
+
"do_not_disturb",
|
|
77
|
+
"dust_collection_mode",
|
|
78
|
+
"flow_led_status",
|
|
79
|
+
"home",
|
|
80
|
+
"led_status",
|
|
81
|
+
"map_content",
|
|
82
|
+
"maps",
|
|
83
|
+
"network_info",
|
|
84
|
+
"rooms",
|
|
85
|
+
"routines",
|
|
86
|
+
"smart_wash_params",
|
|
87
|
+
"status",
|
|
88
|
+
"valley_electricity_timer",
|
|
89
|
+
"volume",
|
|
90
|
+
"wash_towel_mode",
|
|
91
91
|
]
|
|
92
92
|
|
|
93
93
|
|
|
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-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q10/b01_q10_code_mappings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/data/b01_q7/b01_q7_code_mappings.py
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/device_features.py
RENAMED
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/do_not_disturb.py
RENAMED
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/dust_collection_mode.py
RENAMED
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/flow_led_status.py
RENAMED
|
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-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/smart_wash_params.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/devices/traits/v1/wash_towel_mode.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_local_client_v1.py
RENAMED
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-3.7.4 → python_roborock-3.8.0}/roborock/version_a01_apis/roborock_client_a01.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|