diff --git a/deebot_client/commands/xml/__init__.py b/deebot_client/commands/xml/__init__.py
index 03be99968..20166cc89 100644
--- a/deebot_client/commands/xml/__init__.py
+++ b/deebot_client/commands/xml/__init__.py
@@ -10,6 +10,7 @@
from .error import GetError
from .fan_speed import GetFanSpeed
from .life_span import GetLifeSpan
+from .play_sound import PlaySound
from .pos import GetPos
from .stats import GetCleanSum
@@ -23,6 +24,7 @@
"GetFanSpeed",
"GetLifeSpan",
"GetPos",
+ "PlaySound",
]
# fmt: off
@@ -30,6 +32,7 @@
_COMMANDS: list[type[XmlCommand]] = [
GetError,
GetLifeSpan,
+ PlaySound,
]
# fmt: on
diff --git a/deebot_client/commands/xml/common.py b/deebot_client/commands/xml/common.py
index bc04d3d9c..ac026df71 100644
--- a/deebot_client/commands/xml/common.py
+++ b/deebot_client/commands/xml/common.py
@@ -8,10 +8,10 @@
from defusedxml import ElementTree # type: ignore[import-untyped]
-from deebot_client.command import Command, CommandWithMessageHandling
+from deebot_client.command import Command, CommandWithMessageHandling, SetCommand
from deebot_client.const import DataType
from deebot_client.logging_filter import get_logger
-from deebot_client.message import HandlingResult, MessageStr
+from deebot_client.message import HandlingResult, HandlingState, MessageStr
if TYPE_CHECKING:
from deebot_client.event_bus import EventBus
@@ -60,3 +60,29 @@ def _handle_str(cls, event_bus: EventBus, message: str) -> HandlingResult:
"""
xml = ElementTree.fromstring(message)
return cls._handle_xml(event_bus, xml)
+
+
+class ExecuteCommand(XmlCommandWithMessageHandling, ABC):
+ """Command, which is executing something (ex. Charge)."""
+
+ @classmethod
+ def _handle_xml(cls, _: EventBus, xml: Element) -> HandlingResult:
+ """Handle message->xml and notify the correct event subscribers.
+
+ :return: A message response
+ """
+ # Success event looks like
+ if xml.attrib.get("ret") == "ok":
+ return HandlingResult.success()
+
+ _LOGGER.warning(
+ 'Command "%s" was not successful. XML response: %s', cls.NAME, xml
+ )
+ return HandlingResult(HandlingState.FAILED)
+
+
+class XmlSetCommand(ExecuteCommand, SetCommand, ABC):
+ """Xml base set command.
+
+ Command needs to be linked to the "get" command, for handling (updating) the sensors.
+ """
diff --git a/deebot_client/commands/xml/play_sound.py b/deebot_client/commands/xml/play_sound.py
new file mode 100644
index 000000000..31eaf6be9
--- /dev/null
+++ b/deebot_client/commands/xml/play_sound.py
@@ -0,0 +1,14 @@
+"""Play sound commands."""
+
+from __future__ import annotations
+
+from .common import ExecuteCommand
+
+
+class PlaySound(ExecuteCommand):
+ """Play sound command."""
+
+ NAME = "PlaySound"
+
+ def __init__(self) -> None:
+ super().__init__({"sid": "30"})
diff --git a/tests/commands/xml/test_play_sound.py b/tests/commands/xml/test_play_sound.py
new file mode 100644
index 000000000..f3b158da4
--- /dev/null
+++ b/tests/commands/xml/test_play_sound.py
@@ -0,0 +1,24 @@
+from __future__ import annotations
+
+import pytest
+
+from deebot_client.command import CommandResult
+from deebot_client.commands.xml import PlaySound
+from deebot_client.message import HandlingState
+from tests.commands import assert_command
+
+from . import get_request_xml
+
+
+@pytest.mark.parametrize(
+ ("xml_response", "command_result"),
+ [
+ ("", HandlingState.SUCCESS),
+ ("", HandlingState.FAILED),
+ ],
+)
+async def test_play_sound(xml_response: str, command_result: HandlingState) -> None:
+ json = get_request_xml(xml_response)
+ await assert_command(
+ PlaySound(), json, None, command_result=CommandResult(command_result)
+ )