Skip to content

Commit 8d33ed9

Browse files
author
NOisi-X
committed
feat(zeo): add pause(), resume(), shutdown() and split start param DPs by device type
Add pause() (DP 201), shutdown() (DP 202), and update resume() to align with the official app's WasherDpsManager module 727. Split _START_PARAM_DPS into _START_PARAM_DPS_WASHER (10 DPs) and _START_PARAM_DPS_DRYER (7 DPs) so fallback queries only request DPs the device actually supports, avoiding send_decoded_command timeouts on partial responses.
1 parent 4eccebf commit 8d33ed9

1 file changed

Lines changed: 33 additions & 9 deletions

File tree

roborock/devices/traits/a01/command.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
_LOGGER = logging.getLogger(__name__)
1515

16-
_START_PARAM_DPS: list[RoborockZeoProtocol] = [
16+
_START_PARAM_DPS_WASHER: list[RoborockZeoProtocol] = [
1717
RoborockZeoProtocol.MODE,
1818
RoborockZeoProtocol.PROGRAM,
1919
RoborockZeoProtocol.TEMP,
@@ -24,9 +24,16 @@
2424
RoborockZeoProtocol.SOFTENER_SET,
2525
RoborockZeoProtocol.COUNTDOWN,
2626
RoborockZeoProtocol.SOAK,
27+
]
28+
29+
_START_PARAM_DPS_DRYER: list[RoborockZeoProtocol] = [
30+
RoborockZeoProtocol.MODE,
31+
RoborockZeoProtocol.PROGRAM,
32+
RoborockZeoProtocol.DRYING_MODE,
2733
RoborockZeoProtocol.TOTAL_TIME,
2834
RoborockZeoProtocol.DRYING_METHOD,
2935
RoborockZeoProtocol.STEAM_VOLUME,
36+
RoborockZeoProtocol.COUNTDOWN,
3037
]
3138

3239
_FIELD_TO_DP: dict[str, RoborockZeoProtocol] = {
@@ -102,33 +109,50 @@ async def start_program(self) -> dict[RoborockZeoProtocol, Any]:
102109
self._dps_cache[int(dp)] = v
103110
return {proto: self._convert_value(proto, dps.get(proto)) for proto in dps}
104111

112+
async def pause(self) -> dict[RoborockZeoProtocol, Any]:
113+
"""Pause the current programme (DP 201 = "True")."""
114+
_LOGGER.debug("Pause command")
115+
dps = {RoborockZeoProtocol.PAUSE: "True"}
116+
result = await send_decoded_command(self._channel, dps)
117+
self._dps_cache[int(RoborockZeoProtocol.PAUSE)] = 1
118+
return result
119+
105120
async def resume(self) -> dict[RoborockZeoProtocol, Any]:
106-
"""Resume a paused programme or start without rebundling).
107-
Only works while the device is powered on."""
121+
"""Resume / continue a paused programme (DP 200 = "True").
122+
123+
The device remembers its programme — only START is sent, no
124+
parameters are re‑bundled. Matches the official app's
125+
``continue()`` which calls ``publishDp({Start, True})``.
126+
"""
108127
_LOGGER.debug("Resume command")
109128
dps = {RoborockZeoProtocol.START: "True"}
110-
result = await send_decoded_command(
111-
self._channel,
112-
dps,
113-
)
129+
result = await send_decoded_command(self._channel, dps)
114130
self._dps_cache[int(RoborockZeoProtocol.START)] = 1
115131
return result
116132

133+
async def shutdown(self) -> dict[RoborockZeoProtocol, Any]:
134+
"""Shut down the device (DP 202 = "True")."""
135+
_LOGGER.debug("Shutdown command")
136+
dps = {RoborockZeoProtocol.SHUTDOWN: "True"}
137+
result = await send_decoded_command(self._channel, dps)
138+
self._dps_cache[int(RoborockZeoProtocol.SHUTDOWN)] = 1
139+
return result
117140

118141
async def _get_start_params(self) -> ZeoStartParams:
119142
"""Read programme settings, querying the device on cache miss."""
120143
cache = self._dps_cache
144+
wanted = _START_PARAM_DPS_DRYER if self._feature_trait.is_dryer else _START_PARAM_DPS_WASHER
121145
need_refresh = (
122146
int(RoborockZeoProtocol.MODE) not in cache
123147
or int(RoborockZeoProtocol.PROGRAM) not in cache
124148
)
125149
if need_refresh:
126150
raw = await send_decoded_command(
127151
self._channel,
128-
{RoborockZeoProtocol.ID_QUERY: [RoborockZeoProtocol.MODE, RoborockZeoProtocol.PROGRAM]},
152+
{RoborockZeoProtocol.ID_QUERY: wanted},
129153
value_encoder=json.dumps,
130154
)
131-
for dp in (RoborockZeoProtocol.MODE, RoborockZeoProtocol.PROGRAM):
155+
for dp in wanted:
132156
if (val := raw.get(dp)) is not None:
133157
cache[int(dp)] = val
134158
return ZeoStartParams(

0 commit comments

Comments
 (0)