Skip to content

Commit 5bae2d0

Browse files
committed
Add initial support for Goat A1600 RTK (#852)
1 parent 5830188 commit 5bae2d0

7 files changed

Lines changed: 227 additions & 2 deletions

File tree

deebot_client/commands/json/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .clear_map import ClearMap
2020
from .continuous_cleaning import GetContinuousCleaning, SetContinuousCleaning
2121
from .cross_map_border_warning import GetCrossMapBorderWarning, SetCrossMapBorderWarning
22+
from .custom_cut_mode import GetCustomCutMode, SetCustomCutMode
2223
from .cut_direction import GetCutDirection, SetCutDirection
2324
from .efficiency import GetEfficiencyMode, SetEfficiencyMode
2425
from .error import GetError
@@ -74,6 +75,7 @@
7475
"GetCleanPreference",
7576
"GetContinuousCleaning",
7677
"GetCrossMapBorderWarning",
78+
"GetCustomCutMode",
7779
"GetCutDirection",
7880
"GetEfficiencyMode",
7981
"GetError",
@@ -110,6 +112,7 @@
110112
"SetCleanPreference",
111113
"SetContinuousCleaning",
112114
"SetCrossMapBorderWarning",
115+
"SetCustomCutMode",
113116
"SetCutDirection",
114117
"SetEfficiencyMode",
115118
"SetFanSpeed",
@@ -173,6 +176,9 @@
173176
GetCrossMapBorderWarning,
174177
SetCrossMapBorderWarning,
175178

179+
GetCustomCutMode,
180+
SetCustomCutMode,
181+
176182
GetEfficiencyMode,
177183
SetEfficiencyMode,
178184

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Advanced mode command module."""
2+
3+
from __future__ import annotations
4+
5+
from deebot_client.events import CustomCutModeEvent
6+
7+
from .common import GetEnableCommand, SetEnableCommand
8+
9+
10+
class GetCustomCutMode(GetEnableCommand):
11+
"""Get custom cut mode command."""
12+
13+
NAME = "getCustomCutMode"
14+
EVENT_TYPE = CustomCutModeEvent
15+
16+
17+
class SetCustomCutMode(SetEnableCommand):
18+
"""Set custom cut mode command."""
19+
20+
NAME = "setCustomCutMode"
21+
get_command = GetCustomCutMode

deebot_client/events/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,8 @@ class FirmwareEvent(Event):
308308
"""Firmware event."""
309309

310310
version: str
311+
312+
@dataclass(frozen=True)
313+
class CustomCutModeEvent(EnableEvent):
314+
"""custom cut event."""
315+
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""DEEBOT GOAT A1600 RTK Capabilities."""
2+
3+
from __future__ import annotations
4+
5+
from deebot_client.capabilities import (
6+
Capabilities,
7+
CapabilityClean,
8+
CapabilityCleanAction,
9+
CapabilityCustomCommand,
10+
CapabilityEvent,
11+
CapabilityExecute,
12+
CapabilityLifeSpan,
13+
CapabilitySet,
14+
CapabilitySetEnable,
15+
CapabilitySettings,
16+
CapabilityStats,
17+
DeviceType,
18+
)
19+
from deebot_client.commands.json import (
20+
GetBorderSwitch,
21+
GetChildLock,
22+
GetCrossMapBorderWarning,
23+
GetCutDirection,
24+
GetMoveUpWarning,
25+
GetSafeProtect,
26+
SetBorderSwitch,
27+
SetChildLock,
28+
SetCrossMapBorderWarning,
29+
SetCutDirection,
30+
SetMoveUpWarning,
31+
SetSafeProtect,
32+
)
33+
from deebot_client.commands.json.battery import GetBattery
34+
from deebot_client.commands.json.charge import Charge
35+
from deebot_client.commands.json.charge_state import GetChargeState
36+
from deebot_client.commands.json.clean import CleanV2, GetCleanInfoV2
37+
from deebot_client.commands.json.custom import CustomCommand
38+
from deebot_client.commands.json.custom_cut_mode import GetCustomCutMode, SetCustomCutMode
39+
from deebot_client.commands.json.error import GetError
40+
from deebot_client.commands.json.life_span import GetLifeSpan, ResetLifeSpan
41+
from deebot_client.commands.json.network import GetNetInfo
42+
from deebot_client.commands.json.play_sound import PlaySound
43+
from deebot_client.commands.json.stats import GetStats, GetTotalStats
44+
from deebot_client.commands.json.true_detect import GetTrueDetect, SetTrueDetect
45+
from deebot_client.commands.json.volume import GetVolume, SetVolume
46+
from deebot_client.const import DataType
47+
from deebot_client.events import (
48+
AvailabilityEvent,
49+
BatteryEvent,
50+
BorderSwitchEvent,
51+
ChildLockEvent,
52+
CrossMapBorderWarningEvent,
53+
CustomCommandEvent,
54+
CustomCutModeEvent,
55+
CutDirectionEvent,
56+
ErrorEvent,
57+
LifeSpan,
58+
LifeSpanEvent,
59+
MoveUpWarningEvent,
60+
NetworkInfoEvent,
61+
ReportStatsEvent,
62+
SafeProtectEvent,
63+
StateEvent,
64+
StatsEvent,
65+
TotalStatsEvent,
66+
TrueDetectEvent,
67+
VolumeEvent,
68+
)
69+
from deebot_client.models import StaticDeviceInfo
70+
from deebot_client.util import short_name
71+
72+
from . import DEVICES
73+
74+
DEVICES[short_name(__name__)] = StaticDeviceInfo(
75+
DataType.JSON,
76+
Capabilities(
77+
device_type=DeviceType.MOWER,
78+
availability=CapabilityEvent(
79+
AvailabilityEvent, [GetBattery(is_available_check=True)]
80+
),
81+
battery=CapabilityEvent(BatteryEvent, [GetBattery()]),
82+
charge=CapabilityExecute(Charge),
83+
clean=CapabilityClean(
84+
action=CapabilityCleanAction(command=CleanV2),
85+
),
86+
custom=CapabilityCustomCommand(
87+
event=CustomCommandEvent, get=[], set=CustomCommand
88+
),
89+
error=CapabilityEvent(ErrorEvent, [GetError()]),
90+
life_span=CapabilityLifeSpan(
91+
types=(LifeSpan.BLADE, LifeSpan.LENS_BRUSH),
92+
event=LifeSpanEvent,
93+
get=[
94+
GetLifeSpan(
95+
[
96+
LifeSpan.BLADE,
97+
LifeSpan.LENS_BRUSH,
98+
]
99+
)
100+
],
101+
reset=ResetLifeSpan,
102+
),
103+
network=CapabilityEvent(NetworkInfoEvent, [GetNetInfo()]),
104+
play_sound=CapabilityExecute(PlaySound),
105+
settings=CapabilitySettings(
106+
border_switch=CapabilitySetEnable(
107+
BorderSwitchEvent, [GetBorderSwitch()], SetBorderSwitch
108+
),
109+
cut_direction=CapabilitySet(
110+
CutDirectionEvent, [GetCutDirection()], SetCutDirection
111+
),
112+
custom_cut_mode =CapabilitySetEnable(
113+
CustomCutModeEvent, [GetCustomCutMode()], SetCustomCutMode
114+
),
115+
child_lock=CapabilitySetEnable(
116+
ChildLockEvent, [GetChildLock()], SetChildLock
117+
),
118+
moveup_warning=CapabilitySetEnable(
119+
MoveUpWarningEvent, [GetMoveUpWarning()], SetMoveUpWarning
120+
),
121+
cross_map_border_warning=CapabilitySetEnable(
122+
CrossMapBorderWarningEvent,
123+
[GetCrossMapBorderWarning()],
124+
SetCrossMapBorderWarning,
125+
),
126+
safe_protect=CapabilitySetEnable(
127+
SafeProtectEvent, [GetSafeProtect()], SetSafeProtect
128+
),
129+
true_detect=CapabilitySetEnable(
130+
TrueDetectEvent, [GetTrueDetect()], SetTrueDetect
131+
),
132+
volume=CapabilitySet(VolumeEvent, [GetVolume()], SetVolume),
133+
),
134+
state=CapabilityEvent(StateEvent, [GetChargeState(), GetCleanInfoV2()]),
135+
stats=CapabilityStats(
136+
clean=CapabilityEvent(StatsEvent, [GetStats()]),
137+
report=CapabilityEvent(ReportStatsEvent, []),
138+
total=CapabilityEvent(TotalStatsEvent, [GetTotalStats()]),
139+
),
140+
),
141+
)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ classifiers = [
2424
"Topic :: Home Automation",
2525
"Topic :: Software Development :: Libraries :: Python Modules",
2626
]
27-
requires-python = ">=3.13.0"
27+
requires-python = ">=3.13.0,<4.0"
2828
dependencies = [
2929
"aiohttp~=3.10",
3030
"aiomqtt>=2.0.0,<3.0",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from deebot_client.commands.json import GetCustomCutMode, SetCustomCutMode
6+
from deebot_client.events import CustomCutModeEvent
7+
from tests.helpers import get_request_json, get_success_body
8+
9+
from . import assert_command, assert_set_enable_command
10+
11+
12+
@pytest.mark.parametrize("value", [False, True])
13+
async def test_GetCustomCutMode(*, value: bool) -> None:
14+
json, firmware_event = get_request_json(
15+
get_success_body({"enable": 1 if value else 0})
16+
)
17+
await assert_command(
18+
GetCustomCutMode(), json, (firmware_event, CustomCutModeEvent(value))
19+
)
20+
21+
22+
@pytest.mark.parametrize("value", [False, True])
23+
async def test_SetCustomCutMode(*, value: bool) -> None:
24+
await assert_set_enable_command(
25+
SetCustomCutMode(value), CustomCutModeEvent, enabled=value
26+
)

tests/hardware/test_init.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from deebot_client.commands.json.cross_map_border_warning import (
2424
GetCrossMapBorderWarning,
2525
)
26+
from deebot_client.commands.json.custom_cut_mode import GetCustomCutMode
2627
from deebot_client.commands.json.efficiency import GetEfficiencyMode
2728
from deebot_client.commands.json.error import GetError
2829
from deebot_client.commands.json.fan_speed import GetFanSpeed
@@ -54,6 +55,7 @@
5455
ContinuousCleaningEvent,
5556
CrossMapBorderWarningEvent,
5657
CustomCommandEvent,
58+
CustomCutModeEvent,
5759
CutDirectionEvent,
5860
ErrorEvent,
5961
LifeSpan,
@@ -238,8 +240,32 @@ async def test_get_static_device_info(
238240
WaterAmountEvent: [GetWaterInfo()],
239241
},
240242
),
243+
(
244+
"xmp9ds",
245+
{
246+
AvailabilityEvent: [GetBattery(is_available_check=True)],
247+
BatteryEvent: [GetBattery()],
248+
BorderSwitchEvent: [GetBorderSwitch()],
249+
CustomCutModeEvent: [GetCustomCutMode()],
250+
CutDirectionEvent: [GetCutDirection()],
251+
ChildLockEvent: [GetChildLock()],
252+
CrossMapBorderWarningEvent: [GetCrossMapBorderWarning()],
253+
CustomCommandEvent: [],
254+
ErrorEvent: [GetError()],
255+
LifeSpanEvent: [GetLifeSpan([LifeSpan.BLADE, LifeSpan.LENS_BRUSH])],
256+
MoveUpWarningEvent: [GetMoveUpWarning()],
257+
NetworkInfoEvent: [GetNetInfo()],
258+
ReportStatsEvent: [],
259+
SafeProtectEvent: [GetSafeProtect()],
260+
StateEvent: [GetChargeState(), GetCleanInfoV2()],
261+
StatsEvent: [GetStats()],
262+
TotalStatsEvent: [GetTotalStats()],
263+
TrueDetectEvent: [GetTrueDetect()],
264+
VolumeEvent: [GetVolume()],
265+
},
266+
),
241267
],
242-
ids=["5xu9h3", "itk04l", "yna5xi", "p95mgv"],
268+
ids=["5xu9h3", "itk04l", "yna5xi", "p95mgv", "xmp9ds"],
243269
)
244270
async def test_capabilities_event_extraction(
245271
class_: str, expected: dict[type[Event], list[Command]]

0 commit comments

Comments
 (0)