python-roborock 2.48.0__tar.gz → 2.49.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-2.48.0 → python_roborock-2.49.0}/PKG-INFO +1 -1
- {python_roborock-2.48.0 → python_roborock-2.49.0}/pyproject.toml +1 -1
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/clean_modes.py +50 -10
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/device_features.py +52 -7
- python_roborock-2.49.0/roborock/map/map_parser.py +106 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/LICENSE +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/README.md +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/api.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/b01_containers.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/broadcast_protocol.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/callbacks.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/cli.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/cloud_api.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/code_mappings.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/command_cache.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/const.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/containers.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/README.md +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/a01_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/b01_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/cache.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/device.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/device_manager.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/local_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/mqtt_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/a01/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/b01/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/traits_mixin.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/common.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/status.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/volume.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/v1_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/v1_rpc_channel.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/exceptions.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/mqtt/roborock_session.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/mqtt/session.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/protocol.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/protocols/a01_protocol.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/protocols/b01_protocol.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/protocols/v1_protocol.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/py.typed +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/roborock_future.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/roborock_message.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/util.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
- {python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/web_api.py +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from roborock import DeviceFeatures
|
|
4
|
-
|
|
5
3
|
from .code_mappings import RoborockModeEnum
|
|
4
|
+
from .device_features import DeviceFeatures
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
class
|
|
7
|
+
class VacuumModes(RoborockModeEnum):
|
|
9
8
|
GENTLE = ("gentle", 105)
|
|
10
9
|
OFF = ("off", 105)
|
|
11
10
|
QUIET = ("quiet", 101)
|
|
@@ -27,7 +26,7 @@ class CleanRoutes(RoborockModeEnum):
|
|
|
27
26
|
CUSTOMIZED = ("custom", 302)
|
|
28
27
|
|
|
29
28
|
|
|
30
|
-
class
|
|
29
|
+
class VacuumModesOld(RoborockModeEnum):
|
|
31
30
|
QUIET = ("quiet", 38)
|
|
32
31
|
BALANCED = ("balanced", 60)
|
|
33
32
|
TURBO = ("turbo", 75)
|
|
@@ -48,18 +47,40 @@ class WaterModes(RoborockModeEnum):
|
|
|
48
47
|
SMART_MODE = ("smart_mode", 209)
|
|
49
48
|
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
class WashTowelModes(RoborockModeEnum):
|
|
51
|
+
SMART = ("smart", 10)
|
|
52
|
+
LIGHT = ("light", 0)
|
|
53
|
+
BALANCED = ("balanced", 1)
|
|
54
|
+
DEEP = ("deep", 2)
|
|
55
|
+
SUPER_DEEP = ("super_deep", 8)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_wash_towel_modes(features: DeviceFeatures) -> list[WashTowelModes]:
|
|
59
|
+
"""Get the valid wash towel modes for the device"""
|
|
60
|
+
modes = [WashTowelModes.LIGHT, WashTowelModes.BALANCED, WashTowelModes.DEEP]
|
|
61
|
+
if features.is_super_deep_wash_supported and not features.is_dirty_replenish_clean_supported:
|
|
62
|
+
modes.append(WashTowelModes.SUPER_DEEP)
|
|
63
|
+
elif features.is_dirty_replenish_clean_supported:
|
|
64
|
+
modes.append(WashTowelModes.SMART)
|
|
65
|
+
return modes
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_clean_modes(features: DeviceFeatures) -> list[VacuumModes]:
|
|
52
69
|
"""Get the valid clean modes for the device - also known as 'fan power' or 'suction mode'"""
|
|
53
|
-
modes = [
|
|
70
|
+
modes = [VacuumModes.QUIET, VacuumModes.BALANCED, VacuumModes.TURBO, VacuumModes.MAX]
|
|
54
71
|
if features.is_max_plus_mode_supported or features.is_none_pure_clean_mop_with_max_plus:
|
|
55
72
|
# If the vacuum has max plus mode supported
|
|
56
|
-
modes.append(
|
|
73
|
+
modes.append(VacuumModes.MAX_PLUS)
|
|
57
74
|
if features.is_pure_clean_mop_supported:
|
|
58
75
|
# If the vacuum is capable of 'pure mop clean' aka no vacuum
|
|
59
|
-
modes.append(
|
|
76
|
+
modes.append(VacuumModes.OFF)
|
|
60
77
|
else:
|
|
61
78
|
# If not, we can add gentle
|
|
62
|
-
modes.append(
|
|
79
|
+
modes.append(VacuumModes.GENTLE)
|
|
80
|
+
if features.is_smart_clean_mode_set_supported:
|
|
81
|
+
modes.append(VacuumModes.SMART_MODE)
|
|
82
|
+
if features.is_customized_clean_supported:
|
|
83
|
+
modes.append(VacuumModes.CUSTOMIZED)
|
|
63
84
|
return modes
|
|
64
85
|
|
|
65
86
|
|
|
@@ -72,7 +93,7 @@ def get_clean_routes(features: DeviceFeatures, region: str) -> list[CleanRoutes]
|
|
|
72
93
|
if not (
|
|
73
94
|
features.is_corner_clean_mode_supported
|
|
74
95
|
and features.is_clean_route_deep_slow_plus_supported
|
|
75
|
-
and region == "
|
|
96
|
+
and region == "cn"
|
|
76
97
|
):
|
|
77
98
|
# for some reason there is a china specific deep plus mode
|
|
78
99
|
supported.append(CleanRoutes.DEEP_PLUS_CN)
|
|
@@ -81,6 +102,11 @@ def get_clean_routes(features: DeviceFeatures, region: str) -> list[CleanRoutes]
|
|
|
81
102
|
|
|
82
103
|
if features.is_clean_route_fast_mode_supported:
|
|
83
104
|
supported.append(CleanRoutes.FAST)
|
|
105
|
+
if features.is_smart_clean_mode_set_supported:
|
|
106
|
+
supported.append(CleanRoutes.SMART_MODE)
|
|
107
|
+
if features.is_customized_clean_supported:
|
|
108
|
+
supported.append(CleanRoutes.CUSTOMIZED)
|
|
109
|
+
|
|
84
110
|
return supported
|
|
85
111
|
|
|
86
112
|
|
|
@@ -97,4 +123,18 @@ def get_water_modes(features: DeviceFeatures) -> list[WaterModes]:
|
|
|
97
123
|
supported_modes.append(WaterModes.CUSTOM)
|
|
98
124
|
if features.is_mop_shake_module_supported and features.is_mop_shake_water_max_supported:
|
|
99
125
|
supported_modes.append(WaterModes.EXTREME)
|
|
126
|
+
if features.is_smart_clean_mode_set_supported:
|
|
127
|
+
supported_modes.append(WaterModes.SMART_MODE)
|
|
128
|
+
if features.is_customized_clean_supported:
|
|
129
|
+
supported_modes.append(WaterModes.CUSTOMIZED)
|
|
130
|
+
|
|
100
131
|
return supported_modes
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def is_smart_mode_set(water_mode: WaterModes, clean_mode: VacuumModes, mop_mode: CleanRoutes) -> bool:
|
|
135
|
+
"""Check if the smart mode is set for the given water mode and clean mode"""
|
|
136
|
+
return (
|
|
137
|
+
water_mode == WaterModes.SMART_MODE
|
|
138
|
+
or clean_mode == VacuumModes.SMART_MODE
|
|
139
|
+
or mop_mode == CleanRoutes.SMART_MODE
|
|
140
|
+
)
|
|
@@ -116,14 +116,45 @@ DUAL_LINE_CAMERA_FEATURES = [
|
|
|
116
116
|
NEW_DEFAULT_FEATURES = [ProductFeatures.REMOTE_BACK, ProductFeatures.CLEANMODE_MAXPLUS]
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
PEARL_FEATURES =
|
|
119
|
+
PEARL_FEATURES = SINGLE_LINE_CAMERA_FEATURES + [ProductFeatures.CLEANMODE_MAXPLUS, ProductFeatures.MOP_SPIN_MODULE]
|
|
120
120
|
PEARL_PLUS_FEATURES = NEW_DEFAULT_FEATURES + RGB_CAMERA_FEATURES + [ProductFeatures.MOP_SPIN_MODULE]
|
|
121
121
|
ULTRON_FEATURES = NEW_DEFAULT_FEATURES + DUAL_LINE_CAMERA_FEATURES + [ProductFeatures.MOP_SHAKE_MODULE]
|
|
122
122
|
ULTRONSV_FEATURES = NEW_DEFAULT_FEATURES + RGB_CAMERA_FEATURES + [ProductFeatures.MOP_SHAKE_MODULE]
|
|
123
|
-
TANOSS_FEATURES =
|
|
124
|
-
TOPAZSPOWER_FEATURES =
|
|
123
|
+
TANOSS_FEATURES = [ProductFeatures.REMOTE_BACK, ProductFeatures.MOP_SHAKE_MODULE]
|
|
124
|
+
TOPAZSPOWER_FEATURES = [ProductFeatures.CLEANMODE_MAXPLUS, ProductFeatures.MOP_SHAKE_MODULE]
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
PRODUCTS_WITHOUT_CUSTOM_CLEAN: set[RoborockProductNickname] = {
|
|
127
|
+
RoborockProductNickname.TANOS,
|
|
128
|
+
RoborockProductNickname.RUBYPLUS,
|
|
129
|
+
RoborockProductNickname.RUBYSC,
|
|
130
|
+
RoborockProductNickname.RUBYSE,
|
|
131
|
+
}
|
|
132
|
+
PRODUCTS_WITHOUT_DEFAULT_3D_MAP: set[RoborockProductNickname] = {
|
|
133
|
+
RoborockProductNickname.TANOS,
|
|
134
|
+
RoborockProductNickname.TANOSSPLUS,
|
|
135
|
+
RoborockProductNickname.TANOSE,
|
|
136
|
+
RoborockProductNickname.TANOSV,
|
|
137
|
+
RoborockProductNickname.RUBYPLUS,
|
|
138
|
+
RoborockProductNickname.RUBYSC,
|
|
139
|
+
RoborockProductNickname.RUBYSE,
|
|
140
|
+
}
|
|
141
|
+
PRODUCTS_WITHOUT_PURE_CLEAN_MOP: set[RoborockProductNickname] = {
|
|
142
|
+
RoborockProductNickname.TANOS,
|
|
143
|
+
RoborockProductNickname.TANOSE,
|
|
144
|
+
RoborockProductNickname.TANOSV,
|
|
145
|
+
RoborockProductNickname.TANOSSLITE,
|
|
146
|
+
RoborockProductNickname.TANOSSE,
|
|
147
|
+
RoborockProductNickname.TANOSSC,
|
|
148
|
+
RoborockProductNickname.ULTRONLITE,
|
|
149
|
+
RoborockProductNickname.ULTRONE,
|
|
150
|
+
RoborockProductNickname.RUBYPLUS,
|
|
151
|
+
RoborockProductNickname.RUBYSLITE,
|
|
152
|
+
RoborockProductNickname.RUBYSC,
|
|
153
|
+
RoborockProductNickname.RUBYSE,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Base map containing the initial, unconditional features for each product.
|
|
157
|
+
_BASE_PRODUCT_FEATURE_MAP: dict[RoborockProductNickname, list[ProductFeatures]] = {
|
|
127
158
|
RoborockProductNickname.PEARL: PEARL_FEATURES,
|
|
128
159
|
RoborockProductNickname.PEARLS: PEARL_FEATURES,
|
|
129
160
|
RoborockProductNickname.PEARLPLUS: PEARL_PLUS_FEATURES,
|
|
@@ -139,7 +170,8 @@ product_feature_map = {
|
|
|
139
170
|
RoborockProductNickname.PEARLSLITE: PEARL_FEATURES,
|
|
140
171
|
RoborockProductNickname.PEARLE: PEARL_FEATURES,
|
|
141
172
|
RoborockProductNickname.PEARLELITE: PEARL_FEATURES,
|
|
142
|
-
RoborockProductNickname.VIVIANC:
|
|
173
|
+
RoborockProductNickname.VIVIANC: [ProductFeatures.CLEANMODE_MAXPLUS, ProductFeatures.MOP_SPIN_MODULE]
|
|
174
|
+
+ SINGLE_LINE_CAMERA_FEATURES,
|
|
143
175
|
RoborockProductNickname.CORALPRO: PEARL_PLUS_FEATURES,
|
|
144
176
|
RoborockProductNickname.ULTRONLITE: SINGLE_LINE_CAMERA_FEATURES
|
|
145
177
|
+ [ProductFeatures.CLEANMODE_NONE_PURECLEANMOP_WITH_MAXPLUS, ProductFeatures.MOP_ELECTRONIC_MODULE],
|
|
@@ -150,7 +182,7 @@ product_feature_map = {
|
|
|
150
182
|
],
|
|
151
183
|
RoborockProductNickname.ULTRONSPLUS: ULTRON_FEATURES,
|
|
152
184
|
RoborockProductNickname.VERDELITE: ULTRONSV_FEATURES,
|
|
153
|
-
RoborockProductNickname.TOPAZS:
|
|
185
|
+
RoborockProductNickname.TOPAZS: [ProductFeatures.REMOTE_BACK, ProductFeatures.MOP_SHAKE_MODULE],
|
|
154
186
|
RoborockProductNickname.TOPAZSPLUS: NEW_DEFAULT_FEATURES
|
|
155
187
|
+ DUAL_LINE_CAMERA_FEATURES
|
|
156
188
|
+ [ProductFeatures.MOP_SHAKE_MODULE],
|
|
@@ -173,6 +205,16 @@ product_feature_map = {
|
|
|
173
205
|
RoborockProductNickname.RUBYSLITE: [ProductFeatures.MOP_ELECTRONIC_MODULE],
|
|
174
206
|
}
|
|
175
207
|
|
|
208
|
+
PRODUCT_FEATURE_MAP: dict[RoborockProductNickname, list[ProductFeatures]] = {
|
|
209
|
+
product: (
|
|
210
|
+
features
|
|
211
|
+
+ ([ProductFeatures.DEFAULT_CLEANMODECUSTOM] if product not in PRODUCTS_WITHOUT_CUSTOM_CLEAN else [])
|
|
212
|
+
+ ([ProductFeatures.DEFAULT_MAP3D] if product not in PRODUCTS_WITHOUT_DEFAULT_3D_MAP else [])
|
|
213
|
+
+ ([ProductFeatures.CLEANMODE_PURECLEANMOP] if product not in PRODUCTS_WITHOUT_PURE_CLEAN_MOP else [])
|
|
214
|
+
)
|
|
215
|
+
for product, features in _BASE_PRODUCT_FEATURE_MAP.items()
|
|
216
|
+
}
|
|
217
|
+
|
|
176
218
|
|
|
177
219
|
@dataclass
|
|
178
220
|
class DeviceFeatures:
|
|
@@ -424,6 +466,9 @@ class DeviceFeatures:
|
|
|
424
466
|
metadata={"product_features": [ProductFeatures.MOP_SHAKE_MODULE, ProductFeatures.MOP_SPIN_MODULE]}
|
|
425
467
|
)
|
|
426
468
|
is_mop_shake_module_supported: bool = field(metadata={"product_features": [ProductFeatures.MOP_SHAKE_MODULE]})
|
|
469
|
+
is_customized_clean_supported: bool = field(
|
|
470
|
+
metadata={"product_features": [ProductFeatures.MOP_SHAKE_MODULE, ProductFeatures.MOP_SPIN_MODULE]}
|
|
471
|
+
)
|
|
427
472
|
|
|
428
473
|
@classmethod
|
|
429
474
|
def from_feature_flags(
|
|
@@ -493,7 +538,7 @@ class DeviceFeatures:
|
|
|
493
538
|
kwargs[f.name] = product_nickname not in blacklist
|
|
494
539
|
elif (product_features := f.metadata.get("product_features")) is not None:
|
|
495
540
|
if product_nickname is not None:
|
|
496
|
-
available_features =
|
|
541
|
+
available_features = PRODUCT_FEATURE_MAP.get(product_nickname, [])
|
|
497
542
|
if any(feat in available_features for feat in product_features): # type: ignore
|
|
498
543
|
kwargs[f.name] = True
|
|
499
544
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Module for parsing v1 Roborock map content."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import logging
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
from vacuum_map_parser_base.config.color import ColorsPalette, SupportedColor
|
|
8
|
+
from vacuum_map_parser_base.config.drawable import Drawable
|
|
9
|
+
from vacuum_map_parser_base.config.image_config import ImageConfig
|
|
10
|
+
from vacuum_map_parser_base.config.size import Size, Sizes
|
|
11
|
+
from vacuum_map_parser_base.map_data import MapData
|
|
12
|
+
from vacuum_map_parser_roborock.map_data_parser import RoborockMapDataParser
|
|
13
|
+
|
|
14
|
+
from roborock.exceptions import RoborockException
|
|
15
|
+
|
|
16
|
+
_LOGGER = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
DEFAULT_DRAWABLES = {
|
|
19
|
+
Drawable.CHARGER: True,
|
|
20
|
+
Drawable.CLEANED_AREA: False,
|
|
21
|
+
Drawable.GOTO_PATH: False,
|
|
22
|
+
Drawable.IGNORED_OBSTACLES: False,
|
|
23
|
+
Drawable.IGNORED_OBSTACLES_WITH_PHOTO: False,
|
|
24
|
+
Drawable.MOP_PATH: False,
|
|
25
|
+
Drawable.NO_CARPET_AREAS: False,
|
|
26
|
+
Drawable.NO_GO_AREAS: False,
|
|
27
|
+
Drawable.NO_MOPPING_AREAS: False,
|
|
28
|
+
Drawable.OBSTACLES: False,
|
|
29
|
+
Drawable.OBSTACLES_WITH_PHOTO: False,
|
|
30
|
+
Drawable.PATH: True,
|
|
31
|
+
Drawable.PREDICTED_PATH: False,
|
|
32
|
+
Drawable.VACUUM_POSITION: True,
|
|
33
|
+
Drawable.VIRTUAL_WALLS: False,
|
|
34
|
+
Drawable.ZONES: False,
|
|
35
|
+
}
|
|
36
|
+
DEFAULT_MAP_SCALE = 4
|
|
37
|
+
MAP_FILE_FORMAT = "PNG"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _default_drawable_factory() -> list[Drawable]:
|
|
41
|
+
return [drawable for drawable, default_value in DEFAULT_DRAWABLES.items() if default_value]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class MapParserConfig:
|
|
46
|
+
"""Configuration for the Roborock map parser."""
|
|
47
|
+
|
|
48
|
+
drawables: list[Drawable] = field(default_factory=_default_drawable_factory)
|
|
49
|
+
"""List of drawables to include in the map rendering."""
|
|
50
|
+
|
|
51
|
+
show_background: bool = True
|
|
52
|
+
"""Whether to show the background of the map."""
|
|
53
|
+
|
|
54
|
+
map_scale: int = DEFAULT_MAP_SCALE
|
|
55
|
+
"""Scale factor for the map."""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ParsedMapData:
|
|
60
|
+
"""Roborock Map Data.
|
|
61
|
+
|
|
62
|
+
This class holds the parsed map data and the rendered image.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
image_content: bytes | None
|
|
66
|
+
"""The rendered image of the map in PNG format."""
|
|
67
|
+
|
|
68
|
+
map_data: MapData | None
|
|
69
|
+
"""The parsed map data which contains metadata for points on the map."""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class MapParser:
|
|
73
|
+
"""Roborock Map Parser.
|
|
74
|
+
|
|
75
|
+
This class is used to parse the map data from the device and render it into an image.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(self, config: MapParserConfig) -> None:
|
|
79
|
+
"""Initialize the MapParser."""
|
|
80
|
+
self._map_parser = _create_map_data_parser(config)
|
|
81
|
+
|
|
82
|
+
def parse(self, map_bytes: bytes) -> ParsedMapData | None:
|
|
83
|
+
"""Parse map_bytes and return MapData and the image."""
|
|
84
|
+
try:
|
|
85
|
+
parsed_map = self._map_parser.parse(map_bytes)
|
|
86
|
+
except (IndexError, ValueError) as err:
|
|
87
|
+
raise RoborockException("Failed to parse map data") from err
|
|
88
|
+
if parsed_map.image is None:
|
|
89
|
+
raise RoborockException("Failed to render map image")
|
|
90
|
+
img_byte_arr = io.BytesIO()
|
|
91
|
+
parsed_map.image.data.save(img_byte_arr, format=MAP_FILE_FORMAT)
|
|
92
|
+
return ParsedMapData(image_content=img_byte_arr.getvalue(), map_data=parsed_map)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _create_map_data_parser(config: MapParserConfig) -> RoborockMapDataParser:
|
|
96
|
+
"""Create a RoborockMapDataParser based on the config entry."""
|
|
97
|
+
colors = ColorsPalette()
|
|
98
|
+
if not config.show_background:
|
|
99
|
+
colors = ColorsPalette({SupportedColor.MAP_OUTSIDE: (0, 0, 0, 0)})
|
|
100
|
+
return RoborockMapDataParser(
|
|
101
|
+
colors,
|
|
102
|
+
Sizes({k: v * config.map_scale for k, v in Sizes.SIZES.items() if k != Size.MOP_PATH_WIDTH}),
|
|
103
|
+
config.drawables,
|
|
104
|
+
ImageConfig(scale=config.map_scale),
|
|
105
|
+
[],
|
|
106
|
+
)
|
|
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-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/clean_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/devices/traits/v1/do_not_disturb.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-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.48.0 → python_roborock-2.49.0}/roborock/version_a01_apis/roborock_client_a01.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|