7171
7272_LOGGER = logging .getLogger (__name__ )
7373
74- __all__ = [
74+ __init__ = [
7575 "DyadApi" ,
7676 "ZeoApi" ,
7777 "ZeoFeatureTrait" ,
@@ -119,16 +119,17 @@ def _decode_expansion_type(val: Any, default: int) -> int:
119119 return int (val ) if val is not None else default
120120
121121
122- def to_dp_bool (val : Any ) -> int :
123- """Normalise a boolean-like value to the wire-format integer ``1 `` or ``0 ``.
122+ def to_dp_bool (val : Any ) -> str :
123+ """Normalise a boolean-like value to the wire-format string ``"True" `` or ``"False" ``.
124124
125- Used only in the ``set_value`` encoder path because callers (HA switch
126- entities, external code) may pass Python ``True`` / ``False`` which
127- ``json.dumps`` would serialise as JSON ``true`` / ``false`` — not the
128- integer ``1`` / ``0`` that the device expects. Cache‑reading paths
129- do NOT need this: MQTT push already delivers integers.
125+ The official app serialises booleans as the strings ``"True"`` /
126+ ``"False"`` (its ``DPBoolean`` enum) on SET commands — not as ``1`` / ``0``
127+ or JSON ``true`` / ``false``. Used only in the ``set_value`` encoder
128+ path because callers (HA switch entities, external code) may pass
129+ Python ``True`` / ``False`` which ``json.dumps`` would serialise as
130+ JSON ``true`` / ``false``.
130131 """
131- return 1 if parse_bool (val ) else 0
132+ return "True" if parse_bool (val ) else "False"
132133
133134
134135DYAD_PROTOCOL_ENTRIES : dict [RoborockDyadDataProtocol , Callable ] = {
@@ -687,13 +688,13 @@ async def start(self) -> dict[RoborockZeoProtocol, Any]:
687688 then call ``start()`` to commit and launch.
688689
689690 For pausing / resuming, use :meth:`resume` which sends only
690- ``START = 1 `` without re‑bundling parameters."""
691+ ``START = "True" `` without re‑bundling parameters."""
691692 _LOGGER .debug ("Start command: discovering features and building payload" )
692693 await self ._feature_trait .refresh ()
693694 features = self ._feature_trait .features
694695 p = await self ._get_start_params ()
695696 dps : dict [RoborockZeoProtocol , Any ] = {
696- RoborockZeoProtocol .START : 1 ,
697+ RoborockZeoProtocol .START : "True" ,
697698 RoborockZeoProtocol .MODE : p .mode ,
698699 RoborockZeoProtocol .PROGRAM : p .program ,
699700 }
@@ -722,7 +723,7 @@ async def start(self) -> dict[RoborockZeoProtocol, Any]:
722723 return await send_decoded_command (self ._channel , dps , value_encoder = lambda x : x , qos = MqttQos .AT_LEAST_ONCE )
723724
724725 async def resume (self ) -> dict [RoborockZeoProtocol , Any ]:
725- """Resume a paused cycle — sends only ``START = 1 ``.
726+ """Resume a paused cycle — sends only ``START = "True" ``.
726727
727728 Matches the official app's ``continue()`` / ``start()``
728729 (simple single-DP version). Unlike :meth:`start`, this does
@@ -731,7 +732,7 @@ async def resume(self) -> dict[RoborockZeoProtocol, Any]:
731732 progress. ``continue`` is a Python keyword so the method is
732733 named ``resume``.
733734 """
734- dps : dict [RoborockZeoProtocol , Any ] = {RoborockZeoProtocol .START : 1 }
735+ dps : dict [RoborockZeoProtocol , Any ] = {RoborockZeoProtocol .START : "True" }
735736 return await send_decoded_command (self ._channel , dps , value_encoder = lambda x : x , qos = MqttQos .AT_LEAST_ONCE )
736737
737738 # ── Custom programme (DP 222 bitfield) ──────────────────────────
@@ -951,7 +952,7 @@ async def start_with_preset(self, countdown_minutes: int) -> dict[RoborockZeoPro
951952 features = self ._feature_trait .features
952953 p = await self ._get_start_params ()
953954 dps : dict [RoborockZeoProtocol , Any ] = {
954- RoborockZeoProtocol .START : 1 ,
955+ RoborockZeoProtocol .START : "True" ,
955956 RoborockZeoProtocol .MODE : p .mode ,
956957 RoborockZeoProtocol .PROGRAM : p .program ,
957958 }
0 commit comments