Skip to content

Commit 6192e02

Browse files
committed
Add more XML commands and messages
1 parent 7f4b426 commit 6192e02

6 files changed

Lines changed: 151 additions & 9 deletions

File tree

deebot_client/commands/xml/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,22 @@
4444
# fmt: off
4545
# ordered by file asc
4646
_COMMANDS: list[type[XmlCommand]] = [
47+
Charge,
4748
Clean,
4849
CleanArea,
49-
GetError,
5050
GetBatteryInfo,
51+
GetChargeState,
5152
GetCleanLogs,
5253
GetCleanSpeed,
5354
GetCleanState,
55+
GetCleanSum,
56+
GetError,
5457
GetLifeSpan,
58+
GetPos,
5559
GetWaterBoxInfo,
5660
GetWaterPermeability,
57-
SetCleanSpeed,
5861
PlaySound,
62+
SetCleanSpeed,
5963
]
6064
# fmt: on
6165

deebot_client/commands/xml/clean_logs.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
from deebot_client.command import CommandResult
88
from deebot_client.events import (
9-
CleanJobStatus,
109
CleanLogEntry,
1110
CleanLogEvent,
1211
)
1312
from deebot_client.logging_filter import get_logger
1413
from deebot_client.message import HandlingResult
14+
from deebot_client.util import get_enum
1515

1616
from .common import XmlCommandWithMessageHandling
17+
from .enum import XmlStopReason
1718

1819
if TYPE_CHECKING:
1920
from xml.etree.ElementTree import Element
@@ -46,14 +47,24 @@ def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
4647
if len(resp_logs) >= 0:
4748
logs: list[CleanLogEntry] = []
4849
for log in resp_logs:
50+
xml_stop_reason_attrib = str(log.attrib["f"])
51+
stop_reason = XmlStopReason.FINISHED
52+
try:
53+
stop_reason = get_enum(XmlStopReason, xml_stop_reason_attrib)
54+
except Exception as e:
55+
_LOGGER.error(
56+
"Could not decode stop reason: %s",
57+
xml_stop_reason_attrib,
58+
exc_info=e,
59+
)
4960
try:
5061
logs.append(
5162
CleanLogEntry(
5263
timestamp=int(log.attrib["s"]),
5364
image_url="", # Missing
5465
type=log.attrib["t"],
5566
area=int(log.attrib["a"]),
56-
stop_reason=CleanJobStatus.FINISHED, # To be extracted
67+
stop_reason=stop_reason.to_clean_job_status(), # To be extracted
5768
duration=int(log.attrib["l"]),
5869
)
5970
)

deebot_client/commands/xml/enum.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Enums used only by XML messages."""
2+
3+
from __future__ import annotations
4+
5+
from enum import StrEnum
6+
7+
from deebot_client.events import CleanJobStatus
8+
9+
10+
class XmlStopReason(StrEnum):
11+
"""Reasons why cleaning has been stopped."""
12+
13+
FINISHED = "s"
14+
BATTERY_LOW = "r"
15+
STOPPED_BY_APP = "a"
16+
STOPPED_BY_REMOTE_CONTROL = "i"
17+
STOPPED_BY_BUTTON = "b"
18+
STOPPED_BY_WARNING = "w"
19+
STOPPED_BY_NO_DISTURB = "f"
20+
STOPPED_BY_CLEARMAP = "m"
21+
STOPPED_BY_NO_PATH = "n"
22+
STOPPED_BY_NOT_IN_MAP = "u"
23+
STOPPED_BY_VIRTUAL_WALL = "v"
24+
25+
def to_clean_job_status(self) -> CleanJobStatus:
26+
"""Convert this value to a CleanJobStatus for compatibility proposes."""
27+
if self == XmlStopReason.FINISHED:
28+
return CleanJobStatus.FINISHED
29+
if self in (
30+
XmlStopReason.STOPPED_BY_APP,
31+
XmlStopReason.STOPPED_BY_REMOTE_CONTROL,
32+
XmlStopReason.STOPPED_BY_BUTTON,
33+
):
34+
return CleanJobStatus.MANUALLY_STOPPED
35+
return CleanJobStatus.FINISHED_WITH_WARNINGS

deebot_client/messages/xml/__init__.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66

77
from deebot_client.messages.xml.battery import BatteryInfo
88
from deebot_client.messages.xml.charge import ChargeState
9-
from deebot_client.messages.xml.clean import CleanReport, CleanSt
9+
from deebot_client.messages.xml.clean import (
10+
CleanedPos,
11+
CleanReport,
12+
CleanReportServer,
13+
CleanSt,
14+
)
1015
from deebot_client.messages.xml.map import MapP
1116
from deebot_client.messages.xml.pos import Pos
17+
from deebot_client.messages.xml.sleep import SleepStatus
1218
from deebot_client.messages.xml.water_info import WaterBoxInfo
1319

1420
if TYPE_CHECKING:
@@ -18,9 +24,12 @@
1824
"BatteryInfo",
1925
"ChargeState",
2026
"CleanReport",
27+
"CleanReportServer",
2128
"CleanSt",
29+
"CleanedPos",
2230
"MapP",
2331
"Pos",
32+
"SleepStatus",
2433
"WaterBoxInfo",
2534
]
2635
# fmt: off
@@ -29,10 +38,13 @@
2938
BatteryInfo,
3039
ChargeState,
3140
CleanReport,
32-
WaterBoxInfo,
33-
Pos,
41+
CleanReportServer,
42+
CleanSt,
43+
CleanedPos,
3444
MapP,
35-
CleanSt
45+
Pos,
46+
SleepStatus,
47+
WaterBoxInfo,
3648
]
3749
# fmt: on
3850

deebot_client/messages/xml/clean.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44

55
from typing import TYPE_CHECKING
66

7-
from deebot_client.events import FanSpeedEvent, FanSpeedLevel, StateEvent
7+
from deebot_client.events import (
8+
FanSpeedEvent,
9+
FanSpeedLevel,
10+
Position,
11+
PositionsEvent,
12+
StateEvent,
13+
)
814
from deebot_client.logging_filter import get_logger
915
from deebot_client.message import HandlingResult
1016
from deebot_client.messages.xml.common import XmlMessage
1117
from deebot_client.models import CleanAction, State
18+
from deebot_client.rs.map import PositionType
1219

1320
if TYPE_CHECKING:
1421
from xml.etree.ElementTree import Element
@@ -43,6 +50,8 @@ class CleanReport(XmlMessage):
4350
def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
4451
"""Handle xml message and notify the correct event subscribers.
4552
53+
b"<ctl ts='1744467249311' td='CleanReport'><clean type='auto' speed='standard' st='s' rsn='a' a='' l='' sts=''/></ctl>"
54+
4655
:return: A message response
4756
"""
4857
if (clean := xml.find("clean")) is None:
@@ -64,3 +73,45 @@ def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
6473
_LOGGER.debug("Ignored CleanState %s", clean_action)
6574

6675
return HandlingResult.success()
76+
77+
78+
class CleanReportServer(XmlMessage):
79+
"""CleanReportServer message."""
80+
81+
NAME = "CleanReportServer"
82+
83+
@classmethod
84+
def _handle_xml(cls, _event_bus: EventBus, _xml: Element) -> HandlingResult:
85+
"""Handle xml message and notify the correct event subscribers.
86+
87+
b"<ctl ts='1744467262312' td='CleanReportServer' act='s' type='auto' cs='1134230540'/>"
88+
b"<ctl ts='1744467393682' td='CleanReportServer' act='h' type='auto' sts='1744467262' cs='1134230540' area='1' last='76' mapCount='6'/>"
89+
90+
:return: A message response
91+
"""
92+
return HandlingResult.analyse()
93+
94+
95+
class CleanedPos(XmlMessage):
96+
"""CleanedPos message."""
97+
98+
NAME = "CleanedPos"
99+
100+
@classmethod
101+
def _handle_xml(cls, event_bus: EventBus, xml: Element) -> HandlingResult:
102+
"""Handle xml message and notify the correct event subscribers.
103+
104+
b"<ctl ts='1744467393682' td='CleanedPos' t='p' p='-2450,-996' a='-88' csid='1134230540'/>"
105+
106+
:return: A message response
107+
"""
108+
if p := xml.attrib.get("p"):
109+
p_x, p_y = p.split(",", 2)
110+
p_a = xml.attrib.get("a", 0)
111+
position = Position(
112+
type=PositionType.DEEBOT, x=int(p_x), y=int(p_y), a=int(p_a)
113+
)
114+
event_bus.notify(PositionsEvent(positions=[position]))
115+
return HandlingResult.success()
116+
117+
return HandlingResult.analyse()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Sleep messages."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
from deebot_client.message import HandlingResult
8+
from deebot_client.messages.xml.common import XmlMessage
9+
10+
if TYPE_CHECKING:
11+
from xml.etree.ElementTree import Element
12+
13+
from deebot_client.event_bus import EventBus
14+
15+
16+
class SleepStatus(XmlMessage):
17+
"""SleepStatus message."""
18+
19+
NAME = "SleepStatus"
20+
21+
@classmethod
22+
def _handle_xml(cls, _event_bus: EventBus, _xml: Element) -> HandlingResult:
23+
"""Handle xml message and notify the correct event subscribers.
24+
25+
b"<ctl ts='1744467249545' td='SleepStatus' st='0'/>"
26+
27+
:return: A message response
28+
"""
29+
return HandlingResult.analyse()

0 commit comments

Comments
 (0)