Skip to content

Commit 6d0f502

Browse files
committed
chore: add dataclasses for Roborock mower
1 parent 7888a6d commit 6d0f502

5 files changed

Lines changed: 160 additions & 0 deletions

File tree

roborock/data/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
from .code_mappings import *
66
from .containers import *
77
from .dyad import *
8+
from .mower import *
89
from .v1 import *
910
from .zeo import *

roborock/data/mower/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Dataclasses for Roborock mower devices."""
2+
3+
from .mower_containers import *
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Data containers for Roborock mower devices."""
2+
3+
from dataclasses import dataclass, field
4+
from typing import Any
5+
6+
from roborock.data.containers import RoborockBase
7+
from roborock.roborock_message import RoborockMowerDataProtocol
8+
9+
10+
@dataclass
11+
class MowerStatus(RoborockBase):
12+
"""Core mower status backed by mower DPS updates."""
13+
14+
error_code: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.ERROR_CODE})
15+
battery: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.BATTERY})
16+
mow_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_TYPE})
17+
mow_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_STATE})
18+
mapping_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MAPPING_TYPE})
19+
mapping_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MAPPING_STATE})
20+
ota_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.OTA_STATE})
21+
charge_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.CHARGE_STATE})
22+
dock_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.DOCK_STATE})
23+
charge_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.CHARGE_TYPE})
24+
pend_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.PEND_TYPE})
25+
remote_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.REMOTE_STATE})
26+
mow_start_type: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_START_TYPE})
27+
mow_eff_mode: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_EFF_MODE})
28+
mow_height: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_HEIGHT})
29+
mow_direction_angle: int | None = field(
30+
default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_DIRECTION_ANGLE}
31+
)
32+
mow_patten: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_PATTEN})
33+
mow_conf_mode: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_CONF_MODE})
34+
offline_status: Any | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.OFFLINE_STATUS})
35+
mow_progress: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.MOW_PROGRESS})
36+
blade_lifespan: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.BLADE_LIFESPAN})
37+
fc_state: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.FC_STATE})
38+
gps_coordinate: Any | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.GPS_COORDINATE})
39+
off_dock_no_task_status: int | None = field(
40+
default=None, metadata={"dps": RoborockMowerDataProtocol.OFF_DOCK_NO_TASK_STATUS}
41+
)
42+
afs_status: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.AFS_STATUS})
43+
network_channel: int | None = field(default=None, metadata={"dps": RoborockMowerDataProtocol.NETWORK_CHANNEL})

roborock/roborock_message.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,45 @@ def _missing_(cls: type[Self], key) -> Self:
4040
raise ValueError(f"{key} not a valid key for Data Protocol")
4141

4242

43+
class RoborockMowerDataProtocol(RoborockEnum):
44+
UNKNOWN = 0
45+
ERROR_CODE = 120
46+
BATTERY = 121
47+
MOW_TYPE = 122
48+
MOW_STATE = 123
49+
MAPPING_TYPE = 124
50+
MAPPING_STATE = 125
51+
OTA_STATE = 126
52+
CHARGE_STATE = 127
53+
DOCK_STATE = 128
54+
CHARGE_TYPE = 129
55+
PEND_TYPE = 130
56+
REMOTE_STATE = 131
57+
MOW_START_TYPE = 132
58+
MOW_EFF_MODE = 133
59+
MOW_HEIGHT = 134
60+
MOW_DIRECTION_ANGLE = 135
61+
MOW_PATTEN = 136
62+
MOW_CONF_MODE = 137
63+
OFFLINE_STATUS = 138
64+
MOW_PROGRESS = 139
65+
BLADE_LIFESPAN = 140
66+
FC_STATE = 141
67+
GPS_COORDINATE = 142
68+
OFF_DOCK_NO_TASK_STATUS = 143
69+
AFS_STATUS = 144
70+
NETWORK_CHANNEL = 145
71+
START = 201
72+
DOCK = 202
73+
PAUSE = 203
74+
RESUME = 204
75+
STOP = 205
76+
77+
@classmethod
78+
def _missing_(cls: type[Self], key) -> Self:
79+
raise ValueError(f"{key} not a valid key for Mower Data Protocol")
80+
81+
4382
class RoborockDyadDataProtocol(RoborockEnum):
4483
DRYING_STATUS = 134
4584
START = 200
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""Test mower data containers."""
2+
3+
import dataclasses
4+
5+
from roborock.data import MowerStatus
6+
from roborock.roborock_message import RoborockMowerDataProtocol
7+
8+
9+
def test_mower_status_from_dict() -> None:
10+
status = MowerStatus.from_dict(
11+
{
12+
"error_code": 0,
13+
"battery": 82,
14+
"mow_state": 3,
15+
"mowHeight": 70,
16+
"gpsCoordinate": {"latitude": 1, "longitude": 2},
17+
"unknown": "ignored",
18+
}
19+
)
20+
21+
assert status.error_code == 0
22+
assert status.battery == 82
23+
assert status.mow_state == 3
24+
assert status.mow_height == 70
25+
assert status.gps_coordinate == {"latitude": 1, "longitude": 2}
26+
27+
28+
def test_mower_status_dps_metadata() -> None:
29+
dps_by_field = {
30+
field.name: field.metadata["dps"]
31+
for field in dataclasses.fields(MowerStatus)
32+
if field.metadata and "dps" in field.metadata
33+
}
34+
35+
assert dps_by_field == {
36+
"error_code": RoborockMowerDataProtocol.ERROR_CODE,
37+
"battery": RoborockMowerDataProtocol.BATTERY,
38+
"mow_type": RoborockMowerDataProtocol.MOW_TYPE,
39+
"mow_state": RoborockMowerDataProtocol.MOW_STATE,
40+
"mapping_type": RoborockMowerDataProtocol.MAPPING_TYPE,
41+
"mapping_state": RoborockMowerDataProtocol.MAPPING_STATE,
42+
"ota_state": RoborockMowerDataProtocol.OTA_STATE,
43+
"charge_state": RoborockMowerDataProtocol.CHARGE_STATE,
44+
"dock_state": RoborockMowerDataProtocol.DOCK_STATE,
45+
"charge_type": RoborockMowerDataProtocol.CHARGE_TYPE,
46+
"pend_type": RoborockMowerDataProtocol.PEND_TYPE,
47+
"remote_state": RoborockMowerDataProtocol.REMOTE_STATE,
48+
"mow_start_type": RoborockMowerDataProtocol.MOW_START_TYPE,
49+
"mow_eff_mode": RoborockMowerDataProtocol.MOW_EFF_MODE,
50+
"mow_height": RoborockMowerDataProtocol.MOW_HEIGHT,
51+
"mow_direction_angle": RoborockMowerDataProtocol.MOW_DIRECTION_ANGLE,
52+
"mow_patten": RoborockMowerDataProtocol.MOW_PATTEN,
53+
"mow_conf_mode": RoborockMowerDataProtocol.MOW_CONF_MODE,
54+
"offline_status": RoborockMowerDataProtocol.OFFLINE_STATUS,
55+
"mow_progress": RoborockMowerDataProtocol.MOW_PROGRESS,
56+
"blade_lifespan": RoborockMowerDataProtocol.BLADE_LIFESPAN,
57+
"fc_state": RoborockMowerDataProtocol.FC_STATE,
58+
"gps_coordinate": RoborockMowerDataProtocol.GPS_COORDINATE,
59+
"off_dock_no_task_status": RoborockMowerDataProtocol.OFF_DOCK_NO_TASK_STATUS,
60+
"afs_status": RoborockMowerDataProtocol.AFS_STATUS,
61+
"network_channel": RoborockMowerDataProtocol.NETWORK_CHANNEL,
62+
}
63+
64+
65+
def test_mower_command_dps_are_not_status_fields() -> None:
66+
status_dps = {
67+
field.metadata["dps"] for field in dataclasses.fields(MowerStatus) if field.metadata and "dps" in field.metadata
68+
}
69+
70+
assert RoborockMowerDataProtocol.START not in status_dps
71+
assert RoborockMowerDataProtocol.DOCK not in status_dps
72+
assert RoborockMowerDataProtocol.PAUSE not in status_dps
73+
assert RoborockMowerDataProtocol.RESUME not in status_dps
74+
assert RoborockMowerDataProtocol.STOP not in status_dps

0 commit comments

Comments
 (0)