From ed59c71fb5ca540ec1593d855774cb909157c9a4 Mon Sep 17 00:00:00 2001 From: Sascha <37313763+mrbungle64@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:58:04 +0100 Subject: [PATCH] Add 'Mop-Only' commands and event (#388) Co-authored-by: Robert Resch --- deebot_client/capabilities.py | 2 ++ deebot_client/commands/json/__init__.py | 6 ++++++ deebot_client/commands/json/common.py | 15 ++++++++++++--- deebot_client/commands/json/sweep_mode.py | 22 ++++++++++++++++++++++ deebot_client/events/__init__.py | 6 ++++++ deebot_client/hardware/deebot/2o4lnm.py | 5 +++++ tests/commands/json/__init__.py | 3 ++- tests/commands/json/test_sweep_mode.py | 22 ++++++++++++++++++++++ 8 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 deebot_client/commands/json/sweep_mode.py create mode 100644 tests/commands/json/test_sweep_mode.py diff --git a/deebot_client/capabilities.py b/deebot_client/capabilities.py index 3d7f37cf..676a2cb5 100644 --- a/deebot_client/capabilities.py +++ b/deebot_client/capabilities.py @@ -32,6 +32,7 @@ RoomsEvent, StateEvent, StatsEvent, + SweepModeEvent, TotalStatsEvent, TrueDetectEvent, VoiceAssistantStateEvent, @@ -177,6 +178,7 @@ class CapabilitySettings: efficiency_mode: ( CapabilitySetTypes[EfficiencyModeEvent, EfficiencyMode] | None ) = None + sweep_mode: CapabilitySetEnable[SweepModeEvent] | None = None true_detect: CapabilitySetEnable[TrueDetectEvent] | None = None voice_assistant: CapabilitySetEnable[VoiceAssistantStateEvent] | None = None volume: CapabilitySet[VolumeEvent, int] diff --git a/deebot_client/commands/json/__init__.py b/deebot_client/commands/json/__init__.py index 26e8df1a..5944d2a4 100644 --- a/deebot_client/commands/json/__init__.py +++ b/deebot_client/commands/json/__init__.py @@ -33,6 +33,7 @@ from .pos import GetPos from .relocation import SetRelocationState from .stats import GetStats, GetTotalStats +from .sweep_mode import GetSweepMode, SetSweepMode from .true_detect import GetTrueDetect, SetTrueDetect from .voice_assistant_state import GetVoiceAssistantState, SetVoiceAssistantState from .volume import GetVolume, SetVolume @@ -80,6 +81,8 @@ "GetPos", "SetRelocationState", "GetStats", + "GetSweepMode", + "SetSweepMode", "GetTotalStats", "GetTrueDetect", "SetTrueDetect", @@ -152,6 +155,9 @@ SetRelocationState, + GetSweepMode, + SetSweepMode, + GetStats, GetTotalStats, diff --git a/deebot_client/commands/json/common.py b/deebot_client/commands/json/common.py index a2b64464..e0d9f176 100644 --- a/deebot_client/commands/json/common.py +++ b/deebot_client/commands/json/common.py @@ -98,6 +98,8 @@ def handle_set_args( class GetEnableCommand(JsonGetCommand, ABC): """Abstract get enable command.""" + _field_name: str = "enable" + @property # type: ignore[misc] @classmethod @abstractmethod @@ -112,15 +114,22 @@ def _handle_body_data_dict( :return: A message response """ - event: EnableEvent = cls.event_type(bool(data["enable"])) # type: ignore[call-arg, assignment] + event: EnableEvent = cls.event_type(bool(data[cls._field_name])) # type: ignore[call-arg, assignment] event_bus.notify(event) return HandlingResult.success() +_ENABLE = "enable" + + class SetEnableCommand(JsonSetCommand, ABC): """Abstract set enable command.""" - _mqtt_params = MappingProxyType({"enable": InitParam(bool)}) + _field_name = _ENABLE + + def __init_subclass__(cls, **kwargs: Any) -> None: + cls._mqtt_params = MappingProxyType({cls._field_name: InitParam(bool, _ENABLE)}) + super().__init_subclass__(**kwargs) def __init__(self, enable: bool) -> None: # noqa: FBT001 - super().__init__({"enable": 1 if enable else 0}) + super().__init__({self._field_name: 1 if enable else 0}) diff --git a/deebot_client/commands/json/sweep_mode.py b/deebot_client/commands/json/sweep_mode.py new file mode 100644 index 00000000..5a164a93 --- /dev/null +++ b/deebot_client/commands/json/sweep_mode.py @@ -0,0 +1,22 @@ +"""SweepMode command module for "Mop-Only" option.""" +from __future__ import annotations + +from deebot_client.events import SweepModeEvent + +from .common import GetEnableCommand, SetEnableCommand + + +class GetSweepMode(GetEnableCommand): + """GetSweepMode command.""" + + name = "getSweepMode" + event_type = SweepModeEvent + _field_name = "type" + + +class SetSweepMode(SetEnableCommand): + """SetSweepMode command.""" + + name = "setSweepMode" + get_command = GetSweepMode + _field_name = "type" diff --git a/deebot_client/events/__init__.py b/deebot_client/events/__init__.py index 095efbcf..2ccfca44 100644 --- a/deebot_client/events/__init__.py +++ b/deebot_client/events/__init__.py @@ -51,6 +51,7 @@ "Position", "PositionType", "PositionsEvent", + "SweepModeEvent", "WaterAmount", "WaterInfoEvent", "WorkMode", @@ -238,3 +239,8 @@ class TrueDetectEvent(EnableEvent): @dataclass(frozen=True) class VoiceAssistantStateEvent(EnableEvent): """VoiceAssistantState event.""" + + +@dataclass(frozen=True) +class SweepModeEvent(EnableEvent): + """SweepMode event ("Mop-Only" option).""" diff --git a/deebot_client/hardware/deebot/2o4lnm.py b/deebot_client/hardware/deebot/2o4lnm.py index f3c0ea83..6e41a6b0 100644 --- a/deebot_client/hardware/deebot/2o4lnm.py +++ b/deebot_client/hardware/deebot/2o4lnm.py @@ -49,6 +49,7 @@ from deebot_client.commands.json.pos import GetPos from deebot_client.commands.json.relocation import SetRelocationState from deebot_client.commands.json.stats import GetStats, GetTotalStats +from deebot_client.commands.json.sweep_mode import GetSweepMode, SetSweepMode from deebot_client.commands.json.true_detect import GetTrueDetect, SetTrueDetect from deebot_client.commands.json.voice_assistant_state import ( GetVoiceAssistantState, @@ -83,6 +84,7 @@ RoomsEvent, StateEvent, StatsEvent, + SweepModeEvent, TotalStatsEvent, TrueDetectEvent, VoiceAssistantStateEvent, @@ -176,6 +178,9 @@ [GetCarpetAutoFanBoost()], SetCarpetAutoFanBoost, ), + sweep_mode=CapabilitySetEnable( + SweepModeEvent, [GetSweepMode()], SetSweepMode + ), true_detect=CapabilitySetEnable( TrueDetectEvent, [GetTrueDetect()], SetTrueDetect ), diff --git a/tests/commands/json/__init__.py b/tests/commands/json/__init__.py index 0aa696bf..17f128a5 100644 --- a/tests/commands/json/__init__.py +++ b/tests/commands/json/__init__.py @@ -85,6 +85,7 @@ async def assert_set_enable_command( expected_get_command_event: type[EnableEvent], *, enabled: bool, + field_name: str = "enable", ) -> None: - args = {"enable": 1 if enabled else 0} + args = {field_name: 1 if enabled else 0} await assert_set_command(command, args, expected_get_command_event(enabled)) diff --git a/tests/commands/json/test_sweep_mode.py b/tests/commands/json/test_sweep_mode.py new file mode 100644 index 00000000..834182af --- /dev/null +++ b/tests/commands/json/test_sweep_mode.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +import pytest + +from deebot_client.commands.json import GetSweepMode, SetSweepMode +from deebot_client.events import SweepModeEvent +from tests.helpers import get_request_json, get_success_body + +from . import assert_command, assert_set_enable_command + + +@pytest.mark.parametrize("value", [False, True]) +async def test_GetSweepMode(*, value: bool) -> None: + json = get_request_json(get_success_body({"type": 1 if value else 0})) + await assert_command(GetSweepMode(), json, SweepModeEvent(value)) + + +@pytest.mark.parametrize("value", [False, True]) +async def test_SetSweepMode(*, value: bool) -> None: + await assert_set_enable_command( + SetSweepMode(value), SweepModeEvent, enabled=value, field_name="type" + )