|
13 | 13 |
|
14 | 14 | _LOGGER = logging.getLogger(__name__) |
15 | 15 |
|
16 | | -_START_PARAM_DPS: list[RoborockZeoProtocol] = [ |
| 16 | +_START_PARAM_DPS_WASHER: list[RoborockZeoProtocol] = [ |
17 | 17 | RoborockZeoProtocol.MODE, |
18 | 18 | RoborockZeoProtocol.PROGRAM, |
19 | 19 | RoborockZeoProtocol.TEMP, |
|
24 | 24 | RoborockZeoProtocol.SOFTENER_SET, |
25 | 25 | RoborockZeoProtocol.COUNTDOWN, |
26 | 26 | RoborockZeoProtocol.SOAK, |
| 27 | +] |
| 28 | + |
| 29 | +_START_PARAM_DPS_DRYER: list[RoborockZeoProtocol] = [ |
| 30 | + RoborockZeoProtocol.MODE, |
| 31 | + RoborockZeoProtocol.PROGRAM, |
| 32 | + RoborockZeoProtocol.DRYING_MODE, |
27 | 33 | RoborockZeoProtocol.TOTAL_TIME, |
28 | 34 | RoborockZeoProtocol.DRYING_METHOD, |
29 | 35 | RoborockZeoProtocol.STEAM_VOLUME, |
| 36 | + RoborockZeoProtocol.COUNTDOWN, |
30 | 37 | ] |
31 | 38 |
|
32 | 39 | _FIELD_TO_DP: dict[str, RoborockZeoProtocol] = { |
@@ -102,33 +109,50 @@ async def start_program(self) -> dict[RoborockZeoProtocol, Any]: |
102 | 109 | self._dps_cache[int(dp)] = v |
103 | 110 | return {proto: self._convert_value(proto, dps.get(proto)) for proto in dps} |
104 | 111 |
|
| 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 | + |
105 | 120 | 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 | + """ |
108 | 127 | _LOGGER.debug("Resume command") |
109 | 128 | 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) |
114 | 130 | self._dps_cache[int(RoborockZeoProtocol.START)] = 1 |
115 | 131 | return result |
116 | 132 |
|
| 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 |
117 | 140 |
|
118 | 141 | async def _get_start_params(self) -> ZeoStartParams: |
119 | 142 | """Read programme settings, querying the device on cache miss.""" |
120 | 143 | cache = self._dps_cache |
| 144 | + wanted = _START_PARAM_DPS_DRYER if self._feature_trait.is_dryer else _START_PARAM_DPS_WASHER |
121 | 145 | need_refresh = ( |
122 | 146 | int(RoborockZeoProtocol.MODE) not in cache |
123 | 147 | or int(RoborockZeoProtocol.PROGRAM) not in cache |
124 | 148 | ) |
125 | 149 | if need_refresh: |
126 | 150 | raw = await send_decoded_command( |
127 | 151 | self._channel, |
128 | | - {RoborockZeoProtocol.ID_QUERY: [RoborockZeoProtocol.MODE, RoborockZeoProtocol.PROGRAM]}, |
| 152 | + {RoborockZeoProtocol.ID_QUERY: wanted}, |
129 | 153 | value_encoder=json.dumps, |
130 | 154 | ) |
131 | | - for dp in (RoborockZeoProtocol.MODE, RoborockZeoProtocol.PROGRAM): |
| 155 | + for dp in wanted: |
132 | 156 | if (val := raw.get(dp)) is not None: |
133 | 157 | cache[int(dp)] = val |
134 | 158 | return ZeoStartParams( |
|
0 commit comments