|
18 | 18 | resolve_cleaning_mode, |
19 | 19 | ) |
20 | 20 | from roborock.devices.traits.common import DpsDataConverter, TraitUpdateListener |
| 21 | +from roborock.exceptions import RoborockUnsupportedFeature |
21 | 22 | from roborock.roborock_message import RoborockDataProtocol |
22 | 23 | from roborock.roborock_typing import RoborockCommand |
23 | 24 |
|
@@ -48,6 +49,7 @@ class StatusTrait(StatusV2, common.V1TraitMixin, TraitUpdateListener): |
48 | 49 | - Fan Speed |
49 | 50 | - Water Mode |
50 | 51 | - Mop Route |
| 52 | + - Clean then mop (``clean_then_mop``, independent of the cleaning mode) |
51 | 53 |
|
52 | 54 | You should use the _options version of the attribute to know which are |
53 | 55 | supported for your device (i.e. fan_speed_options) |
@@ -115,10 +117,18 @@ def mop_route_name(self) -> str | None: |
115 | 117 |
|
116 | 118 | @property |
117 | 119 | def clean_then_mop(self) -> bool | None: |
118 | | - """Whether the current run vacuums each room fully before mopping it. |
| 120 | + """Whether each room is vacuumed fully before it is mopped. |
119 | 121 |
|
120 | | - Reported by the device as ``seq_type``. It describes the run in |
121 | | - progress; it is not a persisted setting and cannot be set directly. |
| 122 | + Reported by the device as ``seq_type`` and persisted on the device: it |
| 123 | + tracks the "vacuum then mop" toggle in the vendor app, also while docked. |
| 124 | +
|
| 125 | + This is a separate axis from ``current_cleaning_mode``. The cleaning |
| 126 | + mode is derived from ``fan_power``, ``water_box_mode`` and ``mop_mode`` |
| 127 | + and describes *what* the robot does in a room (vacuum, mop, both). This |
| 128 | + flag describes the *order* when it does both. Changing one leaves the |
| 129 | + other untouched; set it with ``set_clean_then_mop``. |
| 130 | +
|
| 131 | + ``None`` means the device does not support the feature. |
122 | 132 | """ |
123 | 133 | if self.seq_type is None: |
124 | 134 | return None |
@@ -163,6 +173,27 @@ async def resolve_error(self, error_code: int | None = None) -> None: |
163 | 173 | await self.rpc_channel.send_command(RoborockCommand.RESOLVE_ERROR, params={"error_code": error_code}) |
164 | 174 | await self.refresh() |
165 | 175 |
|
| 176 | + async def set_clean_then_mop(self, enabled: bool) -> None: |
| 177 | + """Set whether each room is vacuumed fully before it is mopped. |
| 178 | +
|
| 179 | + Independent of ``set_cleaning_mode``. The firmware requires the current |
| 180 | + motor-mode values in this request, so they are echoed back unchanged. |
| 181 | + """ |
| 182 | + if not self._device_features_trait.is_clean_then_mop_mode_supported: |
| 183 | + raise RoborockUnsupportedFeature("Clean then mop is not supported") |
| 184 | + seq_type = _SEQ_TYPE_CLEAN_THEN_MOP if enabled else 0 |
| 185 | + params: dict[str, int | None] = { |
| 186 | + "type": seq_type, |
| 187 | + "fan_power": self.fan_power, |
| 188 | + "water_box_mode": self.water_box_mode, |
| 189 | + } |
| 190 | + if self.mop_mode is not None: |
| 191 | + params["mop_mode"] = self.mop_mode |
| 192 | + if enabled and self._device_features_trait.is_ctm_with_repeat_supported: |
| 193 | + params["repeat"] = 1 |
| 194 | + await self.rpc_channel.send_command(RoborockCommand.APP_SET_CLEAN_SEQUENCE_TYPE, params=params) |
| 195 | + self.seq_type = seq_type |
| 196 | + |
166 | 197 | def update_from_dps(self, decoded_dps: dict[RoborockDataProtocol, Any]) -> None: |
167 | 198 | """Update the trait from data protocol push message data. |
168 | 199 |
|
|
0 commit comments