Skip to content

feat(dyad): add F25 Ultra setting and self-clean commands - #1021

Draft
infy1995 wants to merge 2 commits into
Python-roborock:mainfrom
infy1995:feat/dyad-set-drying-mode
Draft

infy1995 wants to merge 2 commits into
Python-roborock:mainfrom
infy1995:feat/dyad-set-drying-mode

Conversation

@infy1995

@infy1995 infy1995 commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1019, based on the review comment suggesting a typed set_drying_mode. While adding it I checked the other F25 Ultra (roborock.wdv.a194) settings for the same kind of protocol quirk, and added commands only where plain set_value is not enough.

New DyadApi commands

Method Data points sent Why a method is needed
set_drying_mode(mode) 225 The mode is written to DP 225 and read from DP 272
set_self_clean_intensity(intensity) 203, 223, 239 The setting spans three data points; smart differs from standard only in DP 239
set_suction(suction) 206, 208 The app pairs each suction level with a brush speed, and the device does not change it by itself
set_sponge_suction(suction) 244, 245 Same pairing for sponge mode
start_self_clean() 200, 203 The start command carries the current DP 203, so it is read from the device first
stop_self_clean() 200 Same write as stop_drying(), named for what the caller is doing

The setters are F25 Ultra only, and their docstrings say so. On older Dyad models DP 225 is the silent drying duration in minutes. set_drying_mode and set_self_clean_intensity reject unknown. The suction setters accept only l2, l3 and l4, the levels seen on this device, and raise ValueError for others.

Settings on a single data point stay with set_value. Writing WATER_LEVEL (207) through set_value was checked on the device and changes nothing else.

Verification on a real device

Values were read back from the device after each call, with the vacuum docked. Original settings were restored afterwards.

Data points reported after changes in the app:

{"203":1,"223":1,"239":1}   # smart
{"203":1,"223":1,"239":0}   # standard
{"203":2,"223":2,"239":0}   # deep

{"206":2,"208":1}           # eco
{"206":3,"208":2}           # standard
{"206":4,"208":2}           # turbo

Sponge mode uses the same pairs on 244 and 245.

Self-clean started from the app:

{"200":1,"203":1}           # DP 203 set to 1
{"200":1,"203":2}           # DP 203 set to 2 (deep)

Results through the library:

  • set_drying_mode: fast and silent both switched, and the app followed.
  • set_self_clean_intensity: deep, standard and smart were all read back correctly, the status stayed charging, and the app followed.
  • Writing only DP 206 or 244 at eco left the brush speed at l2. This is why the suction setters send both data points. With the new methods all three levels were read back with the expected brush speed, in both modes.
  • start_self_clean reached status 4 (mop_washing). After 8 s stop_self_clean returned to status 3 (charging), and the settings did not change.

Not verified

  • start_self_clean() was run on the device at smart only (DP 203 = 1). The deep case is covered by a unit test and by the app traffic above.
  • The suction levels were confirmed by reading the values back while docked, not by measuring brush speed or suction during cleaning.
  • Older Dyad models were not tested. These commands are documented as F25 Ultra only.

Tests

  • Full pytest under WSL2 (Ubuntu, Python 3.14) with dependency versions from uv.lock: 2237 passed, 53 xfailed
  • pre-commit on the changed files: clean

Add typed DyadApi commands for F25 Ultra settings that span several data
points or need a value from the device:

- set_drying_mode writes DP 225, while the mode is read from DP 272
- set_self_clean_intensity writes DPs 203, 223 and 239 together
- set_suction and set_sponge_suction send the brush speed the app pairs
  with each level, because the device does not change it by itself
- start_self_clean sends the current DP 203 with the start command, as
  the app does
- stop_self_clean stops a running cycle
@infy1995
infy1995 marked this pull request as draft November 8, 2026 23:02

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant