Repository navigation
Conversation
|
Hey! Thanks for this. I think the setter can be used via type: 1 enables clean then mop. mop_type Included when its value is greater than zero and isSupportChangeMop() is true. mop_power Included when its value is nonnegative and isSupportVibrateMop() is true repeat Set to 1 when type == 1 and isCtmWithRepeatSupported() is true. |
allenporter
left a comment
There was a problem hiding this comment.
I see in the comments this is totally separate from CleaningMode -- but just reading the code it's not clear how these work together and how a consumer like home assistant should know the difference here.
Perhaps we can incorporate the setter info discussed by Lash-L and also clarify how these things work together or don't and why its fine.
8d8c9b0 to
ff36835
Compare
|
@Lash-L confirmed against the a288 plugin bundle ( Verified on the Saros 20: @allenporter the |
Lash-L
left a comment
There was a problem hiding this comment.
Looking good! Two small comments
| if enabled and self._device_features_trait.is_ctm_with_repeat_supported: | ||
| params["repeat"] = 1 | ||
| await self.rpc_channel.send_command(RoborockCommand.APP_SET_CLEAN_SEQUENCE_TYPE, params=params) | ||
| self.seq_type = seq_type |
There was a problem hiding this comment.
Can you see if we need self._notify_update() here?
There was a problem hiding this comment.
Yes. Home Assistant's coordinator subscribes to the status trait's update listener, so without it the optimistic value only shows up after the next poll. Added in 15c0db8, with the test asserting a listener fires.
| "fan_power": self.fan_power, | ||
| "water_box_mode": self.water_box_mode, |
There was a problem hiding this comment.
We might need to guard against fan power or water box mode being none here
There was a problem hiding this comment.
Added in 15c0db8: raises RoborockException("Status is not loaded, call refresh() first") when either is None, before anything is sent. params is now dict[str, int]. Test added.
|
@allenporter follow-up on "how these work together", from the a288 plugin bundle:
I put that in the Open question for you both: would you rather |
The device reports seq_type in its get_status payload, but StatusV2 did not model it, so RoborockBase.from_dict discarded it along with every other unmatched key. The vendor app reads the same field off the same payload to derive its "clean then mop" state. Add seq_type to StatusV2 and a clean_then_mop property on StatusTrait that reports whether the current run vacuums each room fully before mopping it. It describes the run in progress rather than a persisted setting, and the device offers no setter, so it is read only here; the value travels outbound as a parameter of the cleaning command instead. Gated for reporting on is_clean_then_mop_mode_supported. Verified against a Roborock Saros 20 (roborock.vacuum.a288).
15c0db8 to
d634f41
Compare
Summary
The device reports
seq_typein itsget_statuspayload, butStatusV2did not model it, soRoborockBase.from_dictdiscarded it along with every other unmatched key.This adds
seq_typetoStatusV2, aclean_then_mopproperty onStatusTraitand aset_clean_then_mopsetter, reporting whether the current configuration vacuums each room fully before mopping it ("clean then mop" / "vacuum then mop").Why it is
get_statusThe vendor Android app derives its own clean-then-mop state from the same field on the same payload. In the cloud-downloaded device plugin for
roborock.vacuum.a288,parseCleanModeStatusdoes:and its caller passes the status object — the same one it parses
charge_status,wash_readyandkctfrom.Verification
Tested against a Roborock Saros 20 (
roborock.vacuum.a288). Rawget_statusexcerpt:{"state": 8, "fan_power": 102, "water_box_mode": 235, "mop_mode": 300, "repeat": 1, "kct": 0, "subdivision_sets": 0, "seq_type": 0, ...}Toggling "vacuum then mop" in the Roborock app, with the robot docked and idle (
state: 8,in_cleaning: 0), flips the field and the new property follows it:seq_typeclean_then_mopFalseTrueSo this is a persisted device setting that tracks the app, not merely a per-run artifact.
uv run pytest(1037 passed) anduv run pre-commit run --all-filesboth pass. One syrupy snapshot updated for the new field.Notes and open questions
Setter.
set_clean_then_mop(enabled)sendsapp_set_clean_sequence_type(as pointed out by Lash-L, and matching the app plugin'ssetCleanThenMopType). The firmware requires the currentfan_power/water_box_mode/mop_modein the request, so the trait echoes its own values back;repeat: 1is added when enabling on devices withis_ctm_with_repeat_supported.mop_type/mop_powerare omitted because the library does not model those fields or theisSupportChangeMop/isSupportVibrateMopfeature bits. Verified on the Saros 20 (idle, undocked):seq_typeset_clean_then_mop(True)set_clean_motor_modewith the same motor valuesset_clean_then_mop(False)Relationship to
CleaningMode. Documented on the property.CleaningModeis derived fromfan_power/water_box_mode/mop_modeand says what the robot does in a room;clean_then_mopis the order when it does both. Writing either one leaves the other unchanged (table above, and toggling in the app earlier). A consumer exposes them as two independent controls, e.g. a select plus a switch.There is also a per-room layer.
get_customize_clean_modereturnsseq_typeandrepeatper segment, e.g.[{"segment": 4, "fan_power": 102, "water_box_mode": 235, "mop_mode": 300, "repeat": 1, "seq_type": 0}]. This PR models only the global value fromget_status; the per-room layer is left alone.Single device. Verified on one Saros 20 only. The field is gated for reporting on
is_clean_then_mop_mode_supported, so devices without the feature are unaffected, but I cannot confirm behaviour on other models.get_statuscarries several other keys this library still drops (distance_off,cleaning_info,extra_time,monitor_status,exit_dock,pet_reminding,sub_error_code,sub_zone). Out of scope here, but happy to follow up if wanted.Motivation
Downstream this lets Home Assistant expose clean-then-mop as real device state rather than guessing. Deliberately not folded into
CleaningMode: the axes are independent — toggling clean-then-mop on the test device leftcurrent_cleaning_modeatvac_and_mop— and with no setter available aCleaningModemember would be readable but not selectable.