Skip to content

feat(dyad): limit commands to what the app offers and fix data point mappings - #1021

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

infy1995 wants to merge 5 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 compared the Dyad data points with the Roborock app plugin (com.roborock.wetdryvac, plugin version 2674), so this also fixes mappings that were wrong and limits the new commands to the models the app enables them for.

New DyadApi commands

Method Data points sent Models
set_clean_mode(mode) 205 All known models, limited to the modes the app offers for each
set_water_level(level) 207 Models where the app offers these levels
set_drying_mode(mode) 225 Morph and YaoGuang series (F25 family)
set_self_clean_intensity(intensity) 203, 223, and 239 where smart exists All known models; smart only on models that have it
set_suction(suction) 206, 208 Models where the app pairs suction with a brush speed
set_sponge_suction(suction) 244, 245 Same as above
start_self_clean() 200, 203 All models
pause_self_clean() 200 All models except Dagger and Saber Plus
resume_self_clean() 200 Same as above

stop_drying() is renamed to stop(), because the device has one stop command for drying and self-clean. The method was added in #1019.

DyadApi.supports(DyadFeatureBits) reads the feature bits from DP 235.

DyadApi now receives the product model, as ZeoApi already does. The new dyad_feature module holds the app's model table (78 models). A command used on a model the app does not enable it for, or on an unknown model, raises RoborockUnsupportedFeature and sends nothing. set_drying_mode needs this because DP 225 is a duration in minutes on models without drying modes.

These methods accept only the values the app offers. set_value stays a raw write, and its docstring now says that it checks nothing.

Mapping fixes

These change values reported by the library:

  • POWERWHEEL_DIRECTION (249): 3 is left and 4 is right. 5 to 8 are the diagonals. 5 and 6 were wrongly named left and right.
  • FLAT_STATUS (248) is now standing, flat or error instead of a bool, which reported the error state as lying flat.
  • DyadError has unknown. An unknown code used to fall back to none, so a real error looked like no error. Added 20010.
  • Added status 15 (combination) and self-clean water temperatures low and mid.

Added the data points 251, 256, 273 to 276 and 10008. The names of statuses 4 and 14 do not match the app, but I kept them for compatibility and added comments.

Verification

On a real F25 Ultra (roborock.wdv.a194), reading values back after each call with the vacuum docked and restoring the settings afterwards:

  • set_drying_mode: fast and silent both switched, and the app followed.
  • set_self_clean_intensity: deep, standard and smart read back correctly, and the app followed.
  • Writing only DP 206 or 244 left the brush speed unchanged. With the new methods all three levels read back with the expected brush speed, in both modes.
  • start_self_clean reached status 4. The stop command (200: 0) returned to status 3 and the settings did not change.
  • set_clean_mode: auto, steam, hot water and sponge read back correctly, and max and power saving were rejected without being sent.
  • pause_self_clean reached status 13, resume_self_clean returned to status 4, and the settings did not change.

The model sets in dyad_feature were compared programmatically with the capability checks in the app plugin for all 78 models.

Not verified

  • Only the F25 Ultra was tested on a device. Every other model follows the app plugin and has not been run.
  • The values in the drying list shared by Morph and YaoGuang could not be read from the plugin. 5 and 22 come from the F25 Ultra. Other models using that list are expected to accept them.
  • The mapping fixes come from the app plugin. Driving the vacuum through DP 249 was deliberately not tested.
  • start_self_clean() was run on the device at smart only.
  • The meaning of DP 243 on the F25 Ultra is unconfirmed, since the app reads it only on Dagger and Saber Plus.

Existing test changed

test_start_connect_failure failed on CI on Python 3.11 for this PR. It waited for is_connected and then expected the ready callback at once, but the callback only runs after the device has finished starting, so the test could check between the two. It now waits for the callback, with a limit of 1 s instead of 0.1 s, and still checks that the device is connected and that the callback ran exactly once.

With a 50 ms pause added between the subscribe and the end of connect, the old test failed 5 of 5 runs and the new one passed 5 of 5. With the full suite pinned to one busy CPU, the old test failed 1 of 4 runs with the same assertion as CI, and the new one passed 6 of 6. I could not establish why CI hit this on this PR and not on others.

Tests

  • Full pytest under WSL2 (Ubuntu) with the CI flags and dependency versions from uv.lock, merged with main: 2376 passed, 52 xfailed on Python 3.11 and 3.14
  • 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
Add the app's Dyad model table and accept only the models and values
the app offers. Add set_clean_mode, set_water_level, pause_self_clean,
resume_self_clean and feature bit support. Replace stop_drying and
stop_self_clean with a single stop.

Fix the remote control directions, the flat status states and unknown
error codes being reported as no error.
@infy1995 infy1995 changed the title feat(dyad): add F25 Ultra setting and self-clean commands feat(dyad): limit commands to what the app offers and fix data point mappings Nov 9, 2026
@infy1995
infy1995 marked this pull request as ready for review November 9, 2026 17:15

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