python-roborock 5.34.0__tar.gz → 5.36.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-5.34.0 → python_roborock-5.36.0}/PKG-INFO +1 -1
- {python_roborock-5.34.0 → python_roborock-5.36.0}/pyproject.toml +1 -1
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/rpc/a01_channel.py +13 -2
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/__init__.py +8 -3
- python_roborock-5.36.0/roborock/devices/traits/b01/q10/map.py +151 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/mqtt_channel.py +7 -3
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/mqtt/roborock_session.py +12 -6
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/mqtt/session.py +25 -1
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocols/a01_protocol.py +5 -1
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/channel.py +6 -1
- python_roborock-5.34.0/roborock/devices/traits/b01/q10/map.py +0 -110
- {python_roborock-5.34.0 → python_roborock-5.36.0}/.gitignore +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/LICENSE +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/README.md +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/broadcast_protocol.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/callbacks.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/cli.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/const.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q10/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q7/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/dyad/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/dyad/dyad_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/mower/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/mower/mower_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/v1/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/v1/v1_clean_modes.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/v1/v1_code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/v1/v1_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/zeo/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/zeo/zeo_containers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/device_features.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/README.md +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/cache.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/device.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/device_manager.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/file_cache.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/rpc/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/rpc/v1_channel.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/a01/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/button_light.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/child_lock.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/clean_history.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/command.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/common.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/consumable.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/do_not_disturb.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/dust_collection.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/network_info.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/remote.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/status.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/volume.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/map.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/map_content.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/common.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/traits_mixin.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/child_lock.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/command.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/common.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/consumeable.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/device_features.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/home.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/led_status.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/map_content.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/maps.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/network_info.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/rooms.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/routines.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/status.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/volume.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/channel.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/local_channel.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/diagnostics.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/exceptions.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/b01_grid_layers.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/b01_map_parser.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/b01_q10_map_parser.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/b01_q10_overlays.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/b01_q10_render.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/map_parser.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/proto/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/proto/b01_scmap.proto +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/map/proto/b01_scmap_pb2.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/mqtt/health_manager.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocol.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocols/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocols/b01_q10_protocol.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocols/b01_q7_protocol.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/protocols/v1_protocol.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/py.typed +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/roborock_message.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/__init__.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/b01_q10_simulator.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/cloud.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/simulator.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/testing/v1_simulator.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/util.py +0 -0
- {python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/web_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-roborock
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.36.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,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-roborock"
|
|
3
|
-
version = "5.
|
|
3
|
+
version = "5.36.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"
|
|
@@ -7,6 +7,7 @@ from typing import Any, overload
|
|
|
7
7
|
|
|
8
8
|
from roborock.devices.transport.mqtt_channel import MqttChannel
|
|
9
9
|
from roborock.exceptions import RoborockException
|
|
10
|
+
from roborock.mqtt.session import MqttQos
|
|
10
11
|
from roborock.protocols.a01_protocol import (
|
|
11
12
|
decode_rpc_response,
|
|
12
13
|
encode_mqtt_payload,
|
|
@@ -30,6 +31,7 @@ async def send_decoded_command(
|
|
|
30
31
|
mqtt_channel: MqttChannel,
|
|
31
32
|
params: dict[RoborockDyadDataProtocol, Any],
|
|
32
33
|
value_encoder: Callable[[Any], Any] | None = None,
|
|
34
|
+
qos: MqttQos = MqttQos.AT_MOST_ONCE,
|
|
33
35
|
) -> dict[RoborockDyadDataProtocol, Any]: ...
|
|
34
36
|
|
|
35
37
|
|
|
@@ -38,6 +40,7 @@ async def send_decoded_command(
|
|
|
38
40
|
mqtt_channel: MqttChannel,
|
|
39
41
|
params: dict[RoborockZeoProtocol, Any],
|
|
40
42
|
value_encoder: Callable[[Any], Any] | None = None,
|
|
43
|
+
qos: MqttQos = MqttQos.AT_MOST_ONCE,
|
|
41
44
|
) -> dict[RoborockZeoProtocol, Any]: ...
|
|
42
45
|
|
|
43
46
|
|
|
@@ -45,8 +48,16 @@ async def send_decoded_command(
|
|
|
45
48
|
mqtt_channel: MqttChannel,
|
|
46
49
|
params: dict[RoborockDyadDataProtocol, Any] | dict[RoborockZeoProtocol, Any],
|
|
47
50
|
value_encoder: Callable[[Any], Any] | None = None,
|
|
51
|
+
qos: MqttQos = MqttQos.AT_MOST_ONCE,
|
|
48
52
|
) -> dict[RoborockDyadDataProtocol, Any] | dict[RoborockZeoProtocol, Any]:
|
|
49
|
-
"""Send a command on the MQTT channel and get a decoded response.
|
|
53
|
+
"""Send a command on the MQTT channel and get a decoded response.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
mqtt_channel: The MQTT channel to send the command on.
|
|
57
|
+
params: The parameters to send.
|
|
58
|
+
value_encoder: A function to encode the values of the dictionary.
|
|
59
|
+
qos: The MQTT QoS level. Defaults to AT_MOST_ONCE.
|
|
60
|
+
"""
|
|
50
61
|
_LOGGER.debug("Sending MQTT command: %s", params)
|
|
51
62
|
roborock_message = encode_mqtt_payload(params, value_encoder)
|
|
52
63
|
|
|
@@ -54,7 +65,7 @@ async def send_decoded_command(
|
|
|
54
65
|
# block waiting for a response. Queries are handled below.
|
|
55
66
|
param_values = {int(k): v for k, v in params.items()}
|
|
56
67
|
if not (query_values := param_values.get(_ID_QUERY)):
|
|
57
|
-
await mqtt_channel.publish(roborock_message)
|
|
68
|
+
await mqtt_channel.publish(roborock_message, qos=qos)
|
|
58
69
|
return {}
|
|
59
70
|
|
|
60
71
|
# Merge any results together than contain the requested data. This
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/__init__.py
RENAMED
|
@@ -16,7 +16,7 @@ from .command import CommandTrait
|
|
|
16
16
|
from .consumable import ConsumableTrait
|
|
17
17
|
from .do_not_disturb import DoNotDisturbTrait
|
|
18
18
|
from .dust_collection import DustCollectionTrait
|
|
19
|
-
from .map import MapContentTrait
|
|
19
|
+
from .map import MapContentTrait, MapDpsTrait
|
|
20
20
|
from .network_info import NetworkInfoTrait
|
|
21
21
|
from .remote import RemoteTrait
|
|
22
22
|
from .status import StatusTrait
|
|
@@ -77,7 +77,10 @@ class Q10PropertiesApi(Trait):
|
|
|
77
77
|
"""Trait exposing remaining life of consumables."""
|
|
78
78
|
|
|
79
79
|
map: MapContentTrait
|
|
80
|
-
"""
|
|
80
|
+
"""Composed map image plus caller-facing map and trace data."""
|
|
81
|
+
|
|
82
|
+
_map_dps: MapDpsTrait
|
|
83
|
+
"""Private source of restricted zones and virtual walls received through DPS."""
|
|
81
84
|
|
|
82
85
|
clean_history: CleanHistoryTrait
|
|
83
86
|
"""Trait for fetching the device clean-record history (``dpCleanRecord``)."""
|
|
@@ -96,7 +99,8 @@ class Q10PropertiesApi(Trait):
|
|
|
96
99
|
self.button_light = ButtonLightTrait(self.command)
|
|
97
100
|
self.network_info = NetworkInfoTrait()
|
|
98
101
|
self.consumable = ConsumableTrait()
|
|
99
|
-
self.
|
|
102
|
+
self._map_dps = MapDpsTrait()
|
|
103
|
+
self.map = MapContentTrait(self._map_dps)
|
|
100
104
|
self.clean_history = CleanHistoryTrait(self.command)
|
|
101
105
|
# Read-model traits updated from the device's DPS push stream.
|
|
102
106
|
self._updatable_traits = [
|
|
@@ -108,6 +112,7 @@ class Q10PropertiesApi(Trait):
|
|
|
108
112
|
self.network_info,
|
|
109
113
|
self.consumable,
|
|
110
114
|
self.clean_history,
|
|
115
|
+
self._map_dps,
|
|
111
116
|
]
|
|
112
117
|
self._subscribe_task: asyncio.Task[None] | None = None
|
|
113
118
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Push-driven map traits for B01 Q10 devices.
|
|
2
|
+
|
|
3
|
+
Map-related state arrives on three independent streams:
|
|
4
|
+
|
|
5
|
+
* map packets are decoded from map-protocol responses;
|
|
6
|
+
* trace packets are decoded from trace-protocol responses;
|
|
7
|
+
* restricted zones and virtual walls arrive as ordinary DPS values.
|
|
8
|
+
|
|
9
|
+
``MapDpsTrait`` owns the low-level DPS read model. ``MapContentTrait`` depends
|
|
10
|
+
on it and combines that state with the latest map/trace packets through the pure
|
|
11
|
+
functions in :mod:`roborock.map.b01_q10_render`. The high-level trait keeps only
|
|
12
|
+
the latest value from each source and one replace-whole rendered image;
|
|
13
|
+
calibration, path placement and overlay placement remain inside the renderer.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from roborock.data import RoborockBase
|
|
21
|
+
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
|
|
22
|
+
from roborock.devices.traits.common import DpsDataConverter, TraitUpdateListener
|
|
23
|
+
from roborock.exceptions import RoborockException
|
|
24
|
+
from roborock.map.b01_q10_map_parser import (
|
|
25
|
+
B01Q10MapParserConfig,
|
|
26
|
+
Q10MapPacket,
|
|
27
|
+
Q10Point,
|
|
28
|
+
Q10Room,
|
|
29
|
+
Q10TracePacket,
|
|
30
|
+
)
|
|
31
|
+
from roborock.map.b01_q10_overlays import parse_virtual_wall_blob, parse_zone_blob
|
|
32
|
+
from roborock.map.b01_q10_render import Q10MapOverlays, render_q10_map
|
|
33
|
+
|
|
34
|
+
from .common import UpdatableTrait
|
|
35
|
+
|
|
36
|
+
_LOGGER = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class MapDps(RoborockBase):
|
|
41
|
+
"""Low-level map values delivered in the Q10 DPS stream."""
|
|
42
|
+
|
|
43
|
+
restricted_zone_up: str | None = field(default=None, metadata={"dps": B01_Q10_DP.RESTRICTED_ZONE_UP})
|
|
44
|
+
virtual_wall_up: str | None = field(default=None, metadata={"dps": B01_Q10_DP.VIRTUAL_WALL_UP})
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MapDpsTrait(MapDps, UpdatableTrait):
|
|
48
|
+
"""Private read model for map-related DPS values and decoded overlays."""
|
|
49
|
+
|
|
50
|
+
_CONVERTER = DpsDataConverter.from_dataclass(MapDps)
|
|
51
|
+
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
MapDps.__init__(self)
|
|
54
|
+
UpdatableTrait.__init__(self, command=None, logger=_LOGGER)
|
|
55
|
+
self._overlays = Q10MapOverlays()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def overlays(self) -> Q10MapOverlays:
|
|
59
|
+
"""Overlays decoded once from the latest relevant DPS update."""
|
|
60
|
+
return self._overlays
|
|
61
|
+
|
|
62
|
+
def update_from_dps(self, decoded_dps: dict[B01_Q10_DP, Any]) -> None:
|
|
63
|
+
"""Decode overlay blobs when they arrive, then notify dependents."""
|
|
64
|
+
if not self._CONVERTER.update_from_dps(self, decoded_dps):
|
|
65
|
+
return
|
|
66
|
+
self._overlays = Q10MapOverlays(
|
|
67
|
+
zones=tuple(parse_zone_blob(self.restricted_zone_up)),
|
|
68
|
+
virtual_walls=tuple(parse_virtual_wall_blob(self.virtual_wall_up)),
|
|
69
|
+
)
|
|
70
|
+
self._notify_update()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class MapContentTrait(TraitUpdateListener):
|
|
74
|
+
"""High-level composed Q10 map view.
|
|
75
|
+
|
|
76
|
+
The latest map and trace packets are combined with the injected
|
|
77
|
+
:class:`MapDpsTrait` whenever any of those three sources changes.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
map_dps: MapDpsTrait,
|
|
83
|
+
*,
|
|
84
|
+
map_parser_config: B01Q10MapParserConfig | None = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
TraitUpdateListener.__init__(self, logger=_LOGGER)
|
|
87
|
+
self._config = map_parser_config or B01Q10MapParserConfig()
|
|
88
|
+
self._map_dps = map_dps
|
|
89
|
+
self._map_packet: Q10MapPacket | None = None
|
|
90
|
+
self._trace_packet: Q10TracePacket | None = None
|
|
91
|
+
self._image_content: bytes | None = None
|
|
92
|
+
self._map_dps.add_update_listener(self._map_dps_updated)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def image_content(self) -> bytes | None:
|
|
96
|
+
"""The composed map PNG, if the latest map rendered successfully."""
|
|
97
|
+
return self._image_content
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def rooms(self) -> list[Q10Room]:
|
|
101
|
+
"""Rooms reported by the device."""
|
|
102
|
+
return self._map_packet.rooms if self._map_packet else []
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def path(self) -> list[Q10Point]:
|
|
106
|
+
"""Full path for live status and callers drawing their own map overlay."""
|
|
107
|
+
return self._trace_packet.points if self._trace_packet else []
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def robot_position(self) -> Q10Point | None:
|
|
111
|
+
"""Current position for live status and caller-rendered map overlays."""
|
|
112
|
+
return self._trace_packet.robot_position if self._trace_packet else None
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def robot_heading(self) -> int | None:
|
|
116
|
+
"""Current heading for orienting a robot marker on a caller-rendered map."""
|
|
117
|
+
return self._trace_packet.heading if self._trace_packet else None
|
|
118
|
+
|
|
119
|
+
def update_from_map_packet(self, packet: Q10MapPacket) -> None:
|
|
120
|
+
"""Store a map-protocol update and render the latest sources."""
|
|
121
|
+
self._map_packet = packet
|
|
122
|
+
self._render()
|
|
123
|
+
self._notify_update()
|
|
124
|
+
|
|
125
|
+
def update_from_trace_packet(self, packet: Q10TracePacket) -> None:
|
|
126
|
+
"""Store a trace-protocol update and render the latest sources."""
|
|
127
|
+
self._trace_packet = packet
|
|
128
|
+
self._render()
|
|
129
|
+
self._notify_update()
|
|
130
|
+
|
|
131
|
+
def _map_dps_updated(self) -> None:
|
|
132
|
+
"""Render after the low-level DPS source changes."""
|
|
133
|
+
if self._map_packet is None:
|
|
134
|
+
return
|
|
135
|
+
self._render()
|
|
136
|
+
self._notify_update()
|
|
137
|
+
|
|
138
|
+
def _render(self) -> None:
|
|
139
|
+
"""Render the required map with the latest optional trace and overlays."""
|
|
140
|
+
if self._map_packet is None:
|
|
141
|
+
return
|
|
142
|
+
try:
|
|
143
|
+
self._image_content = render_q10_map(
|
|
144
|
+
self._map_packet,
|
|
145
|
+
self._trace_packet,
|
|
146
|
+
self._map_dps.overlays,
|
|
147
|
+
config=self._config,
|
|
148
|
+
)
|
|
149
|
+
except RoborockException as ex:
|
|
150
|
+
_LOGGER.debug("Failed to render Q10 map packet: %s", ex)
|
|
151
|
+
self._image_content = None
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/mqtt_channel.py
RENAMED
|
@@ -8,7 +8,7 @@ from roborock.callbacks import decoder_callback
|
|
|
8
8
|
from roborock.data import HomeDataDevice, RRiot, UserData
|
|
9
9
|
from roborock.exceptions import RoborockException
|
|
10
10
|
from roborock.mqtt.health_manager import HealthManager
|
|
11
|
-
from roborock.mqtt.session import MqttParams, MqttSession, MqttSessionException
|
|
11
|
+
from roborock.mqtt.session import MqttParams, MqttQos, MqttSession, MqttSessionException
|
|
12
12
|
from roborock.protocol import create_mqtt_decoder, create_mqtt_encoder
|
|
13
13
|
from roborock.roborock_message import RoborockMessage
|
|
14
14
|
from roborock.util import RoborockLoggerAdapter
|
|
@@ -89,11 +89,15 @@ class MqttChannel(Channel):
|
|
|
89
89
|
finally:
|
|
90
90
|
unsub()
|
|
91
91
|
|
|
92
|
-
async def publish(self, message: RoborockMessage) -> None:
|
|
92
|
+
async def publish(self, message: RoborockMessage, qos: MqttQos = MqttQos.AT_MOST_ONCE) -> None:
|
|
93
93
|
"""Publish a command message.
|
|
94
94
|
|
|
95
95
|
The caller is responsible for handling any responses and associating them
|
|
96
96
|
with the incoming request.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
message: The message to publish.
|
|
100
|
+
qos: The MQTT QoS level. Defaults to AT_MOST_ONCE.
|
|
97
101
|
"""
|
|
98
102
|
try:
|
|
99
103
|
encoded_msg = self._encoder(message)
|
|
@@ -101,7 +105,7 @@ class MqttChannel(Channel):
|
|
|
101
105
|
self._logger.exception("Error encoding MQTT message: %s", e)
|
|
102
106
|
raise RoborockException(f"Failed to encode MQTT message: {e}") from e
|
|
103
107
|
try:
|
|
104
|
-
return await self._mqtt_session.publish(self._publish_topic, encoded_msg)
|
|
108
|
+
return await self._mqtt_session.publish(self._publish_topic, encoded_msg, qos=qos)
|
|
105
109
|
except MqttSessionException as e:
|
|
106
110
|
self._logger.debug("Error publishing MQTT message: %s", e)
|
|
107
111
|
raise RoborockException(f"Failed to publish MQTT message: {e}") from e
|
|
@@ -22,7 +22,7 @@ from roborock.callbacks import CallbackMap
|
|
|
22
22
|
from roborock.diagnostics import Diagnostics, redact_topic_name
|
|
23
23
|
|
|
24
24
|
from .health_manager import HealthManager
|
|
25
|
-
from .session import MqttParams, MqttSession, MqttSessionException, MqttSessionUnauthorized
|
|
25
|
+
from .session import MqttParams, MqttQos, MqttSession, MqttSessionException, MqttSessionUnauthorized
|
|
26
26
|
|
|
27
27
|
_LOGGER = logging.getLogger(__name__)
|
|
28
28
|
_MQTT_LOGGER = logging.getLogger(f"{__name__}.aiomqtt")
|
|
@@ -361,8 +361,14 @@ class RoborockMqttSession(MqttSession):
|
|
|
361
361
|
|
|
362
362
|
return delayed_unsub
|
|
363
363
|
|
|
364
|
-
async def publish(self, topic: str, message: bytes) -> None:
|
|
365
|
-
"""Publish a message on the topic.
|
|
364
|
+
async def publish(self, topic: str, message: bytes, qos: MqttQos = MqttQos.AT_MOST_ONCE) -> None:
|
|
365
|
+
"""Publish a message on the topic.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
topic: The MQTT topic to publish to.
|
|
369
|
+
message: The message payload.
|
|
370
|
+
qos: The MQTT QoS level. Defaults to AT_MOST_ONCE.
|
|
371
|
+
"""
|
|
366
372
|
_LOGGER.debug("Sending message to topic %s: %s", topic, message)
|
|
367
373
|
client: aiomqtt.Client
|
|
368
374
|
async with self._client_lock:
|
|
@@ -371,7 +377,7 @@ class RoborockMqttSession(MqttSession):
|
|
|
371
377
|
client = self._client
|
|
372
378
|
try:
|
|
373
379
|
with self._diagnostics.timer("publish"):
|
|
374
|
-
await client.publish(topic, message)
|
|
380
|
+
await client.publish(topic, message, qos=qos)
|
|
375
381
|
except MqttError as err:
|
|
376
382
|
raise MqttSessionException(f"Error publishing message: {err}") from err
|
|
377
383
|
|
|
@@ -417,13 +423,13 @@ class LazyMqttSession(MqttSession):
|
|
|
417
423
|
await self._maybe_start()
|
|
418
424
|
return await self._session.subscribe(device_id, callback)
|
|
419
425
|
|
|
420
|
-
async def publish(self, topic: str, message: bytes) -> None:
|
|
426
|
+
async def publish(self, topic: str, message: bytes, qos: MqttQos = MqttQos.AT_MOST_ONCE) -> None:
|
|
421
427
|
"""Publish a message on the specified topic.
|
|
422
428
|
|
|
423
429
|
This will raise an exception if the message could not be sent.
|
|
424
430
|
"""
|
|
425
431
|
await self._maybe_start()
|
|
426
|
-
return await self._session.publish(topic, message)
|
|
432
|
+
return await self._session.publish(topic, message, qos=qos)
|
|
427
433
|
|
|
428
434
|
async def close(self) -> None:
|
|
429
435
|
"""Cancels the mqtt loop.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
|
+
from enum import IntEnum
|
|
6
7
|
|
|
7
8
|
from roborock.diagnostics import Diagnostics
|
|
8
9
|
from roborock.exceptions import RoborockException
|
|
@@ -10,6 +11,24 @@ from roborock.mqtt.health_manager import HealthManager
|
|
|
10
11
|
|
|
11
12
|
DEFAULT_TIMEOUT = 30.0
|
|
12
13
|
|
|
14
|
+
|
|
15
|
+
class MqttQos(IntEnum):
|
|
16
|
+
"""MQTT Quality of Service levels.
|
|
17
|
+
|
|
18
|
+
A01 devices (Zeo, Dyad) require ``AT_LEAST_ONCE`` for DP200 (start)
|
|
19
|
+
commands. Other protocol versions use ``AT_MOST_ONCE``.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
AT_MOST_ONCE = 0
|
|
23
|
+
"""Fire-and-forget. No acknowledgment required."""
|
|
24
|
+
|
|
25
|
+
AT_LEAST_ONCE = 1
|
|
26
|
+
"""Guaranteed delivery with possible duplicates. Broker sends PUBACK."""
|
|
27
|
+
|
|
28
|
+
EXACTLY_ONCE = 2
|
|
29
|
+
"""Guaranteed delivery with no duplicates. Broker sends PUBREC/PUBREL/PUBCOMP."""
|
|
30
|
+
|
|
31
|
+
|
|
13
32
|
SessionUnauthorizedHook = Callable[[], None]
|
|
14
33
|
|
|
15
34
|
|
|
@@ -76,10 +95,15 @@ class MqttSession(ABC):
|
|
|
76
95
|
"""
|
|
77
96
|
|
|
78
97
|
@abstractmethod
|
|
79
|
-
async def publish(self, topic: str, message: bytes) -> None:
|
|
98
|
+
async def publish(self, topic: str, message: bytes, qos: MqttQos = MqttQos.AT_MOST_ONCE) -> None:
|
|
80
99
|
"""Publish a message on the specified topic.
|
|
81
100
|
|
|
82
101
|
This will raise an exception if the message could not be sent.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
topic: The MQTT topic to publish to.
|
|
105
|
+
message: The message payload.
|
|
106
|
+
qos: The MQTT QoS level. Defaults to AT_MOST_ONCE.
|
|
83
107
|
"""
|
|
84
108
|
|
|
85
109
|
@abstractmethod
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
import time
|
|
5
6
|
from collections.abc import Callable
|
|
6
7
|
from typing import Any
|
|
7
8
|
|
|
@@ -42,7 +43,10 @@ def encode_mqtt_payload(
|
|
|
42
43
|
"""
|
|
43
44
|
if value_encoder is None:
|
|
44
45
|
value_encoder = _no_encode
|
|
45
|
-
dps_data = {
|
|
46
|
+
dps_data = {
|
|
47
|
+
"dps": {key: value_encoder(value) for key, value in data.items()},
|
|
48
|
+
"t": int(time.time()),
|
|
49
|
+
}
|
|
46
50
|
payload = pad(json.dumps(dps_data).encode("utf-8"), AES.block_size)
|
|
47
51
|
return RoborockMessage(
|
|
48
52
|
protocol=RoborockMessageProtocol.RPC_REQUEST,
|
|
@@ -12,6 +12,7 @@ from unittest.mock import AsyncMock, MagicMock
|
|
|
12
12
|
|
|
13
13
|
from roborock.devices.transport.channel import Channel
|
|
14
14
|
from roborock.mqtt.health_manager import HealthManager
|
|
15
|
+
from roborock.mqtt.session import MqttQos
|
|
15
16
|
from roborock.protocols.v1_protocol import LocalProtocolVersion
|
|
16
17
|
from roborock.roborock_message import RoborockMessage
|
|
17
18
|
|
|
@@ -83,6 +84,7 @@ class FakeChannel(Channel):
|
|
|
83
84
|
self.close = MagicMock(side_effect=self._close)
|
|
84
85
|
|
|
85
86
|
self.protocol_version = LocalProtocolVersion.V1
|
|
87
|
+
|
|
86
88
|
self.restart = AsyncMock()
|
|
87
89
|
self.health_manager = HealthManager(self.restart)
|
|
88
90
|
|
|
@@ -102,10 +104,13 @@ class FakeChannel(Channel):
|
|
|
102
104
|
"""Return true if locally connected."""
|
|
103
105
|
return self._is_connected and self._is_local
|
|
104
106
|
|
|
105
|
-
async def _publish(self, message: RoborockMessage) -> None:
|
|
107
|
+
async def _publish(self, message: RoborockMessage, qos: MqttQos = MqttQos.AT_MOST_ONCE) -> None:
|
|
106
108
|
"""Default publish implementation.
|
|
107
109
|
|
|
108
110
|
Records the message in ``published_messages`` and executes ``publish_handler``.
|
|
111
|
+
|
|
112
|
+
The ``qos`` parameter is accepted for compatibility with
|
|
113
|
+
``MqttChannel.publish`` but not simulated by the fake channel.
|
|
109
114
|
"""
|
|
110
115
|
self.published_messages.append(message)
|
|
111
116
|
if self.publish_side_effect:
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"""Map content trait for B01 Q10 devices.
|
|
2
|
-
|
|
3
|
-
Unlike the v1 / Q7 maps, the Q10 has no synchronous "get map" command, so this
|
|
4
|
-
trait is purely push-driven and mirrors the Q10 ``StatusTrait`` contract:
|
|
5
|
-
|
|
6
|
-
- The device pushes its current map/path as protocol-301 ``MAP_RESPONSE``
|
|
7
|
-
messages (a ``dpRequestDps`` nudges it to do so). The protocol layer decodes
|
|
8
|
-
those into :class:`Q10MapPacket` / :class:`Q10TracePacket` objects and the
|
|
9
|
-
``Q10PropertiesApi`` subscribe loop routes them to
|
|
10
|
-
:meth:`MapContentTrait.update_from_map_packet` /
|
|
11
|
-
:meth:`MapContentTrait.update_from_trace_packet`.
|
|
12
|
-
- Those methods render/cache the content and notify update listeners (register
|
|
13
|
-
via :meth:`add_update_listener`).
|
|
14
|
-
- ``image_content``, ``map_data``, ``rooms``, ``path`` and ``robot_position``
|
|
15
|
-
are readable and reflect the most recently pushed map.
|
|
16
|
-
|
|
17
|
-
Unlike the Q7, the Q10 map payload is unencrypted, so no map key is required.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import logging
|
|
21
|
-
from dataclasses import dataclass, field
|
|
22
|
-
|
|
23
|
-
from vacuum_map_parser_base.map_data import MapData
|
|
24
|
-
|
|
25
|
-
from roborock.data import RoborockBase
|
|
26
|
-
from roborock.devices.traits.common import TraitUpdateListener
|
|
27
|
-
from roborock.map.b01_q10_map_parser import (
|
|
28
|
-
B01Q10MapParser,
|
|
29
|
-
B01Q10MapParserConfig,
|
|
30
|
-
Q10MapPacket,
|
|
31
|
-
Q10Point,
|
|
32
|
-
Q10Room,
|
|
33
|
-
Q10TracePacket,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
_LOGGER = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
|
-
_TRUNCATE_LENGTH = 20
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@dataclass
|
|
42
|
-
class MapContent(RoborockBase):
|
|
43
|
-
"""Dataclass representing Q10 map content."""
|
|
44
|
-
|
|
45
|
-
image_content: bytes | None = None
|
|
46
|
-
"""The rendered image of the map in PNG format."""
|
|
47
|
-
|
|
48
|
-
map_data: MapData | None = None
|
|
49
|
-
"""Parsed map data (image metadata + room names)."""
|
|
50
|
-
|
|
51
|
-
rooms: list[Q10Room] = field(default_factory=list)
|
|
52
|
-
"""Rooms (segments) reported by the device, with ids and names."""
|
|
53
|
-
|
|
54
|
-
path: list[Q10Point] = field(default_factory=list)
|
|
55
|
-
"""Full path of the current cleaning session (oldest point first).
|
|
56
|
-
|
|
57
|
-
The robot accumulates this server-side and serves the whole trajectory so
|
|
58
|
-
far in one packet, so it is complete even if we connect mid-session. Only
|
|
59
|
-
populated while a cleaning session is active."""
|
|
60
|
-
|
|
61
|
-
robot_position: Q10Point | None = None
|
|
62
|
-
"""Current robot position (the most recent path point), if known."""
|
|
63
|
-
|
|
64
|
-
def __repr__(self) -> str:
|
|
65
|
-
img = self.image_content
|
|
66
|
-
if img and len(img) > _TRUNCATE_LENGTH:
|
|
67
|
-
img = img[: _TRUNCATE_LENGTH - 3] + b"..."
|
|
68
|
-
return f"MapContent(image_content={img!r}, rooms={self.rooms!r})"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
class MapContentTrait(MapContent, TraitUpdateListener):
|
|
72
|
-
"""Trait holding the most recently pushed parsed map content for Q10 devices.
|
|
73
|
-
|
|
74
|
-
The Q10 has no synchronous get-map request; the device pushes map and trace
|
|
75
|
-
packets, which the protocol layer decodes and the ``Q10PropertiesApi``
|
|
76
|
-
subscribe loop feeds into :meth:`update_from_map_packet` /
|
|
77
|
-
:meth:`update_from_trace_packet`. Consumers read the cached fields and/or
|
|
78
|
-
register a callback with :meth:`add_update_listener` to be notified when new
|
|
79
|
-
map content arrives.
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
def __init__(
|
|
83
|
-
self,
|
|
84
|
-
*,
|
|
85
|
-
map_parser_config: B01Q10MapParserConfig | None = None,
|
|
86
|
-
) -> None:
|
|
87
|
-
super().__init__()
|
|
88
|
-
TraitUpdateListener.__init__(self, logger=_LOGGER)
|
|
89
|
-
self._map_parser = B01Q10MapParser(map_parser_config)
|
|
90
|
-
|
|
91
|
-
def update_from_map_packet(self, packet: Q10MapPacket) -> None:
|
|
92
|
-
"""Render a pushed full-map packet into the cached image/rooms.
|
|
93
|
-
|
|
94
|
-
Rendering failures are logged and skipped (listeners are not notified) so
|
|
95
|
-
a single bad push cannot tear down the subscribe loop.
|
|
96
|
-
"""
|
|
97
|
-
parsed = self._map_parser.parse_packet(packet)
|
|
98
|
-
if parsed.image_content is None:
|
|
99
|
-
_LOGGER.debug("Failed to render Q10 map image")
|
|
100
|
-
return
|
|
101
|
-
self.image_content = parsed.image_content
|
|
102
|
-
self.map_data = parsed.map_data
|
|
103
|
-
self.rooms = packet.rooms
|
|
104
|
-
self._notify_update()
|
|
105
|
-
|
|
106
|
-
def update_from_trace_packet(self, packet: Q10TracePacket) -> None:
|
|
107
|
-
"""Cache the path/robot position from a pushed trace packet."""
|
|
108
|
-
self.path = packet.points
|
|
109
|
-
self.robot_position = packet.robot_position
|
|
110
|
-
self._notify_update()
|
|
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-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q10/b01_q10_code_mappings.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/data/b01_q10/b01_q10_containers.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.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
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/button_light.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/child_lock.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/clean_history.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/command.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/consumable.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/do_not_disturb.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/dust_collection.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q10/network_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/__init__.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/clean_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/b01/q7/map_content.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/clean_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/device_features.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/do_not_disturb.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/dust_collection_mode.py
RENAMED
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.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
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/network_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/smart_wash_params.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/traits/v1/wash_towel_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.34.0 → python_roborock-5.36.0}/roborock/devices/transport/local_channel.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
|
|
File without changes
|