python-roborock 5.28.1__tar.gz → 5.30.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.28.1 → python_roborock-5.30.0}/PKG-INFO +1 -1
- {python_roborock-5.28.1 → python_roborock-5.30.0}/pyproject.toml +1 -1
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/containers.py +19 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/v1/v1_containers.py +27 -7
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/__init__.py +1 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/device_features.py +45 -18
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/roborock_message.py +18 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/.gitignore +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/LICENSE +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/README.md +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/broadcast_protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/callbacks.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/cli.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/const.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q10/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q7/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/dyad/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/dyad/dyad_containers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/mower/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/mower/mower_containers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/v1/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/v1/v1_clean_modes.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/v1/v1_code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/zeo/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/zeo/zeo_containers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/device_features.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/README.md +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/cache.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/device.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/device_manager.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/file_cache.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/rpc/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/rpc/a01_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/rpc/v1_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/a01/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/button_light.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/child_lock.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/clean_history.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/command.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/common.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/consumable.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/do_not_disturb.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/dust_collection.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/map.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/network_info.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/remote.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/status.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/volume.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/map.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/map_content.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/common.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/traits_mixin.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/child_lock.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/command.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/common.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/consumeable.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/home.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/led_status.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/map_content.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/maps.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/network_info.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/rooms.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/routines.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/status.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/volume.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/local_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/mqtt_channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/diagnostics.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/exceptions.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/b01_grid_layers.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/b01_map_parser.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/b01_q10_map_parser.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/b01_q10_overlays.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/map_parser.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/proto/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/proto/b01_scmap.proto +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/map/proto/b01_scmap_pb2.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/mqtt/health_manager.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/mqtt/roborock_session.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/mqtt/session.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocols/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocols/a01_protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocols/b01_q10_protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocols/b01_q7_protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/protocols/v1_protocol.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/py.typed +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/testing/__init__.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/testing/channel.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/testing/cloud.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/testing/simulator.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/testing/v1_simulator.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/util.py +0 -0
- {python_roborock-5.28.1 → python_roborock-5.30.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.30.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.30.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"
|
|
@@ -60,6 +60,25 @@ def _attr_repr(obj: Any) -> str:
|
|
|
60
60
|
return f"{type(obj).__name__}({', '.join(parts)})"
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def field_metadata(**kwargs):
|
|
64
|
+
"""Decorator to attach capability check metadata to a property.
|
|
65
|
+
|
|
66
|
+
This attaches a `_field_metadata` dictionary to the underlying getter function,
|
|
67
|
+
which is then preserved when decorated with `@property`.
|
|
68
|
+
|
|
69
|
+
Supported metadata keys:
|
|
70
|
+
- `feature` (str): Name of a capability property on `DeviceFeaturesTrait`.
|
|
71
|
+
- `dock_feature` (str): Name of a capability property on `RoborockDockFeatures`.
|
|
72
|
+
- `dps` (str/int): RoborockDataProtocol ID to check against supported schema IDs.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def decorator(func):
|
|
76
|
+
func._field_metadata = kwargs
|
|
77
|
+
return func
|
|
78
|
+
|
|
79
|
+
return decorator
|
|
80
|
+
|
|
81
|
+
|
|
63
82
|
@dataclass(repr=False)
|
|
64
83
|
class RoborockBase:
|
|
65
84
|
"""Base class for all Roborock data classes."""
|
|
@@ -39,7 +39,7 @@ from roborock.const import (
|
|
|
39
39
|
from roborock.exceptions import RoborockException
|
|
40
40
|
from roborock.roborock_message import RoborockDataProtocol
|
|
41
41
|
|
|
42
|
-
from ..containers import NamedRoomMapping, RoborockBase, RoborockBaseTimer, _attr_repr
|
|
42
|
+
from ..containers import NamedRoomMapping, RoborockBase, RoborockBaseTimer, _attr_repr, field_metadata
|
|
43
43
|
from .v1_clean_modes import WashTowelModes
|
|
44
44
|
from .v1_code_mappings import (
|
|
45
45
|
CleanFluidStatus,
|
|
@@ -117,6 +117,15 @@ class StatusField(FieldNameBase):
|
|
|
117
117
|
CHARGE_STATUS = "charge_status"
|
|
118
118
|
DRY_STATUS = "dry_status"
|
|
119
119
|
ERROR_CODE = "error_code"
|
|
120
|
+
WATER_BOX_CARRIAGE_STATUS = "water_box_carriage_status"
|
|
121
|
+
WATER_BOX_STATUS = "water_box_status"
|
|
122
|
+
WATER_SHORTAGE_STATUS = "water_shortage_status"
|
|
123
|
+
DIRTY_WATER_BOX_STATUS = "dirty_water_box_status"
|
|
124
|
+
CLEAR_WATER_BOX_STATUS = "clear_water_box_status"
|
|
125
|
+
CLEAN_FLUID_STATUS = "clean_fluid_status"
|
|
126
|
+
CLEAN_PERCENT = "clean_percent"
|
|
127
|
+
DOCK_ERROR_STATUS = "dock_error_status"
|
|
128
|
+
RDT = "rdt"
|
|
120
129
|
|
|
121
130
|
|
|
122
131
|
@dataclass
|
|
@@ -246,12 +255,14 @@ class Status(RoborockBase):
|
|
|
246
255
|
return (self.dss & 3) == 2
|
|
247
256
|
|
|
248
257
|
@property
|
|
258
|
+
@field_metadata(dock_feature="is_washable")
|
|
249
259
|
def clear_water_box_status(self) -> ClearWaterBoxStatus | None:
|
|
250
260
|
if self.dss:
|
|
251
261
|
return ClearWaterBoxStatus((self.dss >> 2) & 3)
|
|
252
262
|
return None
|
|
253
263
|
|
|
254
264
|
@property
|
|
265
|
+
@field_metadata(dock_feature="is_washable")
|
|
255
266
|
def dirty_water_box_status(self) -> DirtyWaterBoxStatus | None:
|
|
256
267
|
if self.dss:
|
|
257
268
|
return DirtyWaterBoxStatus((self.dss >> 4) & 3)
|
|
@@ -270,6 +281,9 @@ class Status(RoborockBase):
|
|
|
270
281
|
return None
|
|
271
282
|
|
|
272
283
|
@property
|
|
284
|
+
@field_metadata(
|
|
285
|
+
dock_feature="is_clean_fluid_auto_delivery_supported",
|
|
286
|
+
)
|
|
273
287
|
def clean_fluid_status(self) -> CleanFluidStatus | None:
|
|
274
288
|
if self.dss:
|
|
275
289
|
value = (self.dss >> 10) & 3
|
|
@@ -313,7 +327,7 @@ class StatusV2(RoborockBase):
|
|
|
313
327
|
in_returning: int | None = None
|
|
314
328
|
in_fresh_state: int | None = None
|
|
315
329
|
lab_status: int | None = None
|
|
316
|
-
water_box_status: int | None = None
|
|
330
|
+
water_box_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
|
|
317
331
|
back_type: int | None = None
|
|
318
332
|
wash_phase: int | None = None
|
|
319
333
|
wash_ready: int | None = None
|
|
@@ -323,14 +337,14 @@ class StatusV2(RoborockBase):
|
|
|
323
337
|
is_locating: int | None = None
|
|
324
338
|
lock_status: int | None = None
|
|
325
339
|
water_box_mode: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.WATER_BOX_MODE})
|
|
326
|
-
water_box_carriage_status: int | None = None
|
|
340
|
+
water_box_carriage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
|
|
327
341
|
mop_forbidden_enable: int | None = None
|
|
328
342
|
camera_status: int | None = None
|
|
329
343
|
is_exploring: int | None = None
|
|
330
344
|
home_sec_status: int | None = None
|
|
331
345
|
home_sec_enable_password: int | None = None
|
|
332
346
|
adbumper_status: list[int] | None = None
|
|
333
|
-
water_shortage_status: int | None = None
|
|
347
|
+
water_shortage_status: int | None = field(default=None, metadata={"feature": "is_support_water_mode"})
|
|
334
348
|
dock_type: RoborockDockTypeCode | None = None
|
|
335
349
|
dust_collection_status: int | None = None
|
|
336
350
|
auto_dust_collection: int | None = None
|
|
@@ -339,7 +353,8 @@ class StatusV2(RoborockBase):
|
|
|
339
353
|
debug_mode: int | None = None
|
|
340
354
|
collision_avoid_status: int | None = None
|
|
341
355
|
switch_map_mode: int | None = None
|
|
342
|
-
dock_error_status: RoborockDockErrorCode | None = None
|
|
356
|
+
dock_error_status: RoborockDockErrorCode | None = field(default=None, metadata={"dock_feature": "has_dock"})
|
|
357
|
+
|
|
343
358
|
charge_status: RoborockChargeStatus | None = field(
|
|
344
359
|
default=None, metadata={"dps": RoborockDataProtocol.CHARGE_STATUS}
|
|
345
360
|
)
|
|
@@ -349,8 +364,8 @@ class StatusV2(RoborockBase):
|
|
|
349
364
|
distance_off: int | None = None
|
|
350
365
|
in_warmup: int | None = None
|
|
351
366
|
dry_status: int | None = field(default=None, metadata={"dps": RoborockDataProtocol.DRYING_STATUS})
|
|
352
|
-
rdt: int | None = None
|
|
353
|
-
clean_percent: int | None = None
|
|
367
|
+
rdt: int | None = field(default=None, metadata={"feature": "is_supported_drying"})
|
|
368
|
+
clean_percent: int | None = field(default=None, metadata={"feature": "is_support_clean_estimate"})
|
|
354
369
|
rss: int | None = None
|
|
355
370
|
dss: int | None = None
|
|
356
371
|
common_status: int | None = None
|
|
@@ -389,12 +404,14 @@ class StatusV2(RoborockBase):
|
|
|
389
404
|
return (self.dss & 3) == 2
|
|
390
405
|
|
|
391
406
|
@property
|
|
407
|
+
@field_metadata(dock_feature="is_washable")
|
|
392
408
|
def clear_water_box_status(self) -> ClearWaterBoxStatus | None:
|
|
393
409
|
if self.dss:
|
|
394
410
|
return ClearWaterBoxStatus((self.dss >> 2) & 3)
|
|
395
411
|
return None
|
|
396
412
|
|
|
397
413
|
@property
|
|
414
|
+
@field_metadata(dock_feature="is_washable")
|
|
398
415
|
def dirty_water_box_status(self) -> DirtyWaterBoxStatus | None:
|
|
399
416
|
if self.dss:
|
|
400
417
|
return DirtyWaterBoxStatus((self.dss >> 4) & 3)
|
|
@@ -413,6 +430,9 @@ class StatusV2(RoborockBase):
|
|
|
413
430
|
return None
|
|
414
431
|
|
|
415
432
|
@property
|
|
433
|
+
@field_metadata(
|
|
434
|
+
dock_feature="is_clean_fluid_auto_delivery_supported",
|
|
435
|
+
)
|
|
416
436
|
def clean_fluid_status(self) -> CleanFluidStatus | None:
|
|
417
437
|
if self.dss:
|
|
418
438
|
value = (self.dss >> 10) & 3
|
|
@@ -264,6 +264,7 @@ class PropertiesApi(Trait):
|
|
|
264
264
|
# Dock type also acts like a device feature for some traits.
|
|
265
265
|
dock_type = await self._dock_type()
|
|
266
266
|
dock_features = RoborockDockFeatures.from_dock_type(dock_type, has_am=self.status.has_am)
|
|
267
|
+
self.device_features.dock_features = dock_features
|
|
267
268
|
|
|
268
269
|
# Initialize traits with special arguments before the generic loop
|
|
269
270
|
if self.wash_towel_mode is None and self._is_supported(WashTowelModeTrait, "wash_towel_mode", dock_features):
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/device_features.py
RENAMED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
from dataclasses import
|
|
1
|
+
from dataclasses import fields
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from roborock.data import AppInitStatus, HomeDataProduct, RoborockBase
|
|
5
|
+
from roborock.data.v1 import RoborockDockTypeCode
|
|
4
6
|
from roborock.data.v1.v1_containers import FieldNameBase
|
|
5
|
-
from roborock.device_features import DeviceFeatures
|
|
7
|
+
from roborock.device_features import DeviceFeatures, RoborockDockFeatures
|
|
6
8
|
from roborock.devices.cache import DeviceCache
|
|
7
9
|
from roborock.devices.traits.v1 import common
|
|
8
10
|
from roborock.roborock_typing import RoborockCommand
|
|
9
11
|
|
|
12
|
+
# Cache of metadata for each trait class
|
|
13
|
+
_metadata_cache: dict[type[RoborockBase], dict[str, dict[str, Any]]] = {}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _get_field_metadata(cls: type[RoborockBase]) -> dict[str, Any]:
|
|
17
|
+
"""Helper to get metadata from either class properties or dataclass fields."""
|
|
18
|
+
if cls not in _metadata_cache:
|
|
19
|
+
metadata_map = {}
|
|
20
|
+
# Inspect properties with @field_metadata
|
|
21
|
+
for name in dir(cls):
|
|
22
|
+
prop = getattr(cls, name, None)
|
|
23
|
+
if isinstance(prop, property):
|
|
24
|
+
metadata_map[name] = getattr(prop.fget, "_field_metadata", {})
|
|
25
|
+
# Inspect dataclass fields metadata
|
|
26
|
+
for f in fields(cls):
|
|
27
|
+
metadata_map[f.name] = f.metadata
|
|
28
|
+
_metadata_cache[cls] = metadata_map
|
|
29
|
+
return _metadata_cache[cls]
|
|
30
|
+
|
|
10
31
|
|
|
11
32
|
class DeviceTraitsConverter(common.V1TraitDataConverter):
|
|
12
33
|
"""Converter for APP_GET_INIT_STATUS responses into DeviceFeatures."""
|
|
@@ -40,31 +61,37 @@ class DeviceFeaturesTrait(DeviceFeatures, common.V1TraitMixin):
|
|
|
40
61
|
self.converter = DeviceTraitsConverter(product)
|
|
41
62
|
self._product = product
|
|
42
63
|
self._device_cache = device_cache
|
|
64
|
+
# Dock features are populated after device feature discovery
|
|
65
|
+
# is triggered.
|
|
66
|
+
self.dock_features: RoborockDockFeatures = RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.o0_dock)
|
|
43
67
|
# All fields of DeviceFeatures are required. Initialize them to False
|
|
44
68
|
# so we have some known state.
|
|
45
69
|
for field in fields(self):
|
|
46
70
|
setattr(self, field.name, False)
|
|
47
71
|
|
|
48
|
-
@staticmethod
|
|
49
|
-
def _get_dataclass_field(cls: type[RoborockBase], field_name: FieldNameBase) -> Field:
|
|
50
|
-
"""Look up a dataclass field by its FieldNameBase name."""
|
|
51
|
-
for f in fields(cls):
|
|
52
|
-
if f.name == field_name:
|
|
53
|
-
return f
|
|
54
|
-
raise ValueError(f"Field {field_name!r} not found in {cls}")
|
|
55
|
-
|
|
56
72
|
def is_field_supported(self, cls: type[RoborockBase], field_name: FieldNameBase) -> bool:
|
|
57
73
|
"""Determines if the specified field is supported by this device.
|
|
58
74
|
|
|
59
|
-
We
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
We inspect the metadata defined for the field (either via dataclass field metadata
|
|
76
|
+
or the `@field_metadata` decorator on properties). Supported checks include:
|
|
77
|
+
|
|
78
|
+
- `feature`: Maps to a boolean capability property on `DeviceFeatures` / `DeviceFeaturesTrait`
|
|
79
|
+
(e.g. `is_support_water_mode`).
|
|
80
|
+
- `dock_feature`: Maps to a boolean capability property on `RoborockDockFeatures` (e.g. `is_washable`).
|
|
81
|
+
- `dps`: Maps to a `RoborockDataProtocol` ID checked against the product's supported schema IDs.
|
|
62
82
|
"""
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
83
|
+
if self.dock_features is None:
|
|
84
|
+
raise ValueError("DeviceFeaturesTrait was invoked but was not fully initialized")
|
|
85
|
+
metadata_map = _get_field_metadata(cls)
|
|
86
|
+
if (field_metadata := metadata_map.get(field_name)) is not None:
|
|
87
|
+
if (feature := field_metadata.get("feature")) is not None:
|
|
88
|
+
return getattr(self, feature, False)
|
|
89
|
+
if (dock_feature := field_metadata.get("dock_feature")) is not None:
|
|
90
|
+
return getattr(self.dock_features, dock_feature, False)
|
|
91
|
+
if (dps := field_metadata.get("dps")) is not None:
|
|
92
|
+
return int(dps) in self._product.supported_schema_ids
|
|
93
|
+
# No metadata, field is assumed always supported
|
|
94
|
+
return True
|
|
68
95
|
|
|
69
96
|
async def refresh(self) -> None:
|
|
70
97
|
"""Refresh the contents of this trait.
|
|
@@ -274,6 +274,9 @@ ROBOROCK_DATA_CONSUMABLE_PROTOCOL = [
|
|
|
274
274
|
]
|
|
275
275
|
|
|
276
276
|
|
|
277
|
+
MAX_PAYLOAD_REPR_LEN = 1024
|
|
278
|
+
|
|
279
|
+
|
|
277
280
|
@dataclass
|
|
278
281
|
class RoborockMessage:
|
|
279
282
|
protocol: RoborockMessageProtocol
|
|
@@ -282,3 +285,18 @@ class RoborockMessage:
|
|
|
282
285
|
version: bytes = b"1.0"
|
|
283
286
|
random: int = field(default_factory=lambda: get_next_int(10000, 99999))
|
|
284
287
|
timestamp: int = field(default_factory=lambda: get_timestamp())
|
|
288
|
+
|
|
289
|
+
def __repr__(self) -> str:
|
|
290
|
+
payload_repr = "None"
|
|
291
|
+
if self.payload is not None:
|
|
292
|
+
if isinstance(self.payload, (bytes, bytearray, str)) and len(self.payload) > MAX_PAYLOAD_REPR_LEN:
|
|
293
|
+
r = repr(self.payload[:MAX_PAYLOAD_REPR_LEN])
|
|
294
|
+
quote = r[-1]
|
|
295
|
+
payload_repr = f"{r[:-1]}...{quote} (length: {len(self.payload)})"
|
|
296
|
+
else:
|
|
297
|
+
payload_repr = repr(self.payload)
|
|
298
|
+
return (
|
|
299
|
+
f"RoborockMessage(protocol={self.protocol}, payload={payload_repr}, "
|
|
300
|
+
f"seq={self.seq}, version={self.version!r}, random={self.random}, "
|
|
301
|
+
f"timestamp={self.timestamp})"
|
|
302
|
+
)
|
|
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.28.1 → python_roborock-5.30.0}/roborock/data/b01_q10/b01_q10_code_mappings.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/data/b01_q10/b01_q10_containers.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.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-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/__init__.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/button_light.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/child_lock.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/clean_history.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/command.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/consumable.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/do_not_disturb.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q10/dust_collection.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.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.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/__init__.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/clean_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/b01/q7/map_content.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/clean_summary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/do_not_disturb.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/dust_collection_mode.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.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.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/network_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.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.28.1 → python_roborock-5.30.0}/roborock/devices/traits/v1/wash_towel_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/local_channel.py
RENAMED
|
File without changes
|
{python_roborock-5.28.1 → python_roborock-5.30.0}/roborock/devices/transport/mqtt_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
|
|
File without changes
|