Skip to content

Commit 86e11c7

Browse files
committed
Add first batch of XML Water related commands and messages
1 parent 1465b5c commit 86e11c7

5 files changed

Lines changed: 174 additions & 2 deletions

File tree

deebot_client/commands/xml/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .play_sound import PlaySound
1919
from .pos import GetChargerPos, GetPos
2020
from .stats import GetCleanSum
21+
from .water_info import GetWaterBoxInfo, GetWaterPermeability, SetWaterPermeability
2122

2223
if TYPE_CHECKING:
2324
from .common import XmlCommand
@@ -40,10 +41,13 @@
4041
"GetMapSt",
4142
"GetPos",
4243
"GetTrM",
44+
"GetWaterBoxInfo",
45+
"GetWaterPermeability",
4346
"PlaySound",
4447
"PullM",
4548
"PullMP",
4649
"SetCleanSpeed",
50+
"SetWaterPermeability",
4751
]
4852

4953
# fmt: off
@@ -81,6 +85,10 @@
8185
GetPos,
8286

8387
GetCleanSum,
88+
89+
GetWaterPermeability,
90+
GetWaterBoxInfo,
91+
SetWaterPermeability,
8492
]
8593
# fmt: on
8694

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""WaterBox command module."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
from deebot_client.commands.xml.common import (
8+
ExecuteCommand,
9+
XmlCommandWithMessageHandling,
10+
)
11+
from deebot_client.events.water_info import (
12+
WaterAmount,
13+
WaterAmountEvent,
14+
)
15+
from deebot_client.message import HandlingResult
16+
from deebot_client.messages.xml import WaterBoxInfo
17+
from deebot_client.util import get_enum
18+
19+
if TYPE_CHECKING:
20+
from xml.etree.ElementTree import Element
21+
22+
from deebot_client.event_bus import EventBus
23+
24+
25+
class GetWaterPermeability(XmlCommandWithMessageHandling):
26+
"""GetWaterPermeability command."""
27+
28+
NAME = "GetWaterPermeability"
29+
30+
@classmethod
31+
def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
32+
"""Handle xml message and notify the correct event subscribers.
33+
34+
:return: A message response.
35+
"""
36+
if xml.attrib.get("ret") != "ok" or not (value := xml.attrib.get("v")):
37+
return HandlingResult.analyse()
38+
39+
if value.isdecimal() and (value_int := int(value)) >= 0:
40+
event_bus.notify(WaterAmountEvent(WaterAmount(value_int)))
41+
return HandlingResult.success()
42+
43+
return HandlingResult.analyse()
44+
45+
46+
class SetWaterPermeability(ExecuteCommand):
47+
"""SetWaterPermeability command."""
48+
49+
NAME = "SetWaterPermeability"
50+
51+
def __init__(self, amount: WaterAmount | str) -> None:
52+
if isinstance(amount, str):
53+
amount = get_enum(WaterAmount, amount)
54+
super().__init__({"v": str(amount.value)})
55+
56+
57+
class GetWaterBoxInfo(XmlCommandWithMessageHandling, WaterBoxInfo):
58+
"""GetWaterBoxInfo command."""
59+
60+
NAME = "GetWaterBoxInfo"
61+
62+
@classmethod
63+
def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
64+
"""Handle xml message and notify the correct event subscribers.
65+
66+
:return: A message response.
67+
"""
68+
if xml.attrib.get("ret") != "ok":
69+
return HandlingResult.analyse()
70+
71+
return cls._parse_xml(event_bus, xml)

deebot_client/messages/xml/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,24 @@
77
from deebot_client.messages.xml.battery import BatteryInfo
88
from deebot_client.messages.xml.charge_state import ChargeState
99
from deebot_client.messages.xml.pos import Pos
10+
from deebot_client.messages.xml.water_info import WaterBoxInfo
1011

1112
if TYPE_CHECKING:
1213
from collections.abc import Sequence
1314

1415
from deebot_client.message import Message
1516

16-
__all__: Sequence[str] = ["BatteryInfo", "ChargeState", "Pos"]
17+
__all__: Sequence[str] = ["BatteryInfo", "ChargeState", "Pos", "WaterBoxInfo"]
1718
# fmt: off
1819
# ordered by file asc
1920
_MESSAGES: list[type[Message]] = [
2021
BatteryInfo,
2122

2223
ChargeState,
2324

24-
Pos
25+
Pos,
26+
27+
WaterBoxInfo
2528
]
2629
# fmt: on
2730

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Water messages."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
from deebot_client.events.water_info import MopAttachedEvent
8+
from deebot_client.message import HandlingResult
9+
from deebot_client.messages.xml.common import XmlMessage
10+
11+
if TYPE_CHECKING:
12+
from xml.etree.ElementTree import Element
13+
14+
from deebot_client.event_bus import EventBus
15+
16+
17+
class WaterBoxInfo(XmlMessage):
18+
"""WaterBoxInfo message."""
19+
20+
NAME = "WaterBoxInfo"
21+
22+
@classmethod
23+
def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
24+
"""Handle xml message and notify the correct event subscribers.
25+
26+
:return: A message response.
27+
"""
28+
return cls._parse_xml(event_bus, xml)
29+
30+
@classmethod
31+
def _parse_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
32+
"""Handle xml message and notify the correct event subscribers.
33+
34+
:return: A message response.
35+
"""
36+
if (on := xml.attrib.get("on")) is None:
37+
return HandlingResult.analyse()
38+
39+
event_bus.notify(MopAttachedEvent(on != "0"))
40+
return HandlingResult.success()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
5+
import pytest
6+
7+
from deebot_client.command import CommandResult
8+
from deebot_client.commands.xml import GetWaterBoxInfo
9+
from deebot_client.events.water_info import MopAttachedEvent
10+
from deebot_client.message import HandlingState
11+
from tests.commands import assert_command
12+
13+
from . import get_request_xml
14+
15+
if TYPE_CHECKING:
16+
from deebot_client.events.base import Event
17+
18+
19+
@pytest.mark.parametrize(
20+
("state", "expected_event"),
21+
[
22+
(1, MopAttachedEvent(True)),
23+
(0, MopAttachedEvent(False)),
24+
],
25+
ids=["mop_attached", "mop_not_attached"],
26+
)
27+
async def test_get_water_box_info(state: int, expected_event: Event) -> None:
28+
xml_message = get_request_xml(f"<ctl ret='ok' on='{state}' />")
29+
await assert_command(GetWaterBoxInfo(), xml_message, expected_event)
30+
31+
32+
@pytest.mark.parametrize(
33+
"payload",
34+
[
35+
'<ctl ret="error"/>',
36+
'<ctl ret="ok"></ctl>',
37+
],
38+
ids=[
39+
"error",
40+
"no_state",
41+
],
42+
)
43+
async def test_get_water_box_info_error(payload: str) -> None:
44+
xml_message = get_request_xml(payload)
45+
await assert_command(
46+
GetWaterBoxInfo(),
47+
xml_message,
48+
None,
49+
command_result=CommandResult(HandlingState.ANALYSE_LOGGED),
50+
)

0 commit comments

Comments
 (0)