feat(r2449a): X40 Ultra Complete compat + decode CLEANING_MODE bitfield#9
Open
carvalho2707 wants to merge 1 commit into
Open
feat(r2449a): X40 Ultra Complete compat + decode CLEANING_MODE bitfield#9carvalho2707 wants to merge 1 commit into
carvalho2707 wants to merge 1 commit into
Conversation
Verified node-dreame end-to-end against a Dreame X40 Ultra Complete (`dreame.vacuum.r2449a`, firmware FU174072, EU region) on 2026-05-21. Auth, transport, MQTT, OSS map fetch, and the catalogue subset used by my dashboard integration all work unchanged on the X40. The X40 capture also closes the open "siid 4 piid 23 — not decoded" question in README.md: low 2 bits are the `CleaningMode` enum, the constant `0x1400` mask is always-on capability bits. The r2532a `5120 ↔ 5122` transitions decode cleanly as `Sweeping ↔ SweepAndMop`. Added - `dreame.vacuum.r2449a` MODEL_CAPABILITIES entry (mirrors r2532a) - `DOCK_PROP.CLEAN_GENIUS_SUB_MODE` at siid 28 piid 5 - `CleanGenius` enum (Off=0, Normal=1, Deep=2 — 3-state, not bool) - `CleanGeniusSubMode` enum (VacAndMop=2, MopAfterVac=3) Changed - `VACUUM_PROP.CLEANING_MODE` bitfield decoded - `VACUUM_PROP.MOP_PADS_STATE` JSDoc rewritten — verified canonical write path for the clean-mode enum on r2449a (writing to `CLEANING_MODE` directly and dropping the `0x1400` capability bits silently bricks the next clean) - `CleaningMode` enum promoted ASSUMED → VERIFIED - `FEATURE_CONFIG_KEYS.CleanRoute` promoted ~ → ✓ (values 1-4) - `FEATURE_CONFIG_KEYS.SmartHost` promoted ~ → ✓ (3-state, 0-2) - README "Tested model" badge lists both r2532a and r2449a Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verified
node-dreameend-to-end against a Dreame X40 Ultra Complete (dreame.vacuum.r2449a, firmwareFU174072, EU region) on 2026-05-21. Auth, transport, MQTT, OSS map fetch, and the catalogue subset I use from a Next.js dashboard all work unchanged on the X40 — confirming the README's model-agnostic claim about the auth/transport layer.The capture also closes the open
siid 4 piid 23 — not decodedquestion flagged in README.md andVACUUM_PROP.CLEANING_MODE's JSDoc:value & 0x3→CleaningModeenum (Sweeping/Mopping/SweepAndMop/MopAfterSweep)value & 0x1400→ always-on capability bits (constant across every observation on both r2532a and r2449a)The r2532a
5120 ↔ 5122transitions decode cleanly asSweeping ↔ SweepAndMop— the user (or app) toggling Vac-only vs Vac + Mop, which co-fires with the dock's mop-install/remove sequence. The earlier "bit 1 = mop pads physically attached" reading is bit-pattern-compatible but the better mental model is "low 2 bits = clean-mode enum"; the mop-attachment correlation falls out of which modes need pads.Verified the same field is mirrored cleanly on
MOP_PADS_STATE(siid 2 piid 6) as plain0..3. Writing directly toCLEANING_MODEand dropping the0x1400capability bits silently bricks the next clean on r2449a — the device 200-OKs the write but refuses subsequentstart()until the bits are restored.MOP_PADS_STATEavoids that trap, which is why this PR documents it as the canonical write path.Two more X40 findings landed alongside:
FEATURE_CONFIG_KEYS.SmartHostis 3-state, not boolean — values0=Off, 1=Normal, 2=Deep(addedCleanGeniusenum).siid 28 piid 5isCleanGenius's sub-mode selector —2=Vac+Mop, 3=MopAfterVac(addedDOCK_PROP.CLEAN_GENIUS_SUB_MODE+CleanGeniusSubModeenum). Not in Tasshack's enum.Both
FEATURE_CONFIG_KEYS.CleanRouteandSmartHostare promoted from~to✓per CONTRIBUTING.md's tag conventions.What changed
src/spec/vacuum-props.tsCLEANING_MODEbitfield; rewriteMOP_PADS_STATEJSDoc to reflect r2449a observation that it mirrors the low 2 bits ofCLEANING_MODE(and that the r2532a0 ↔ 2mop-install correlation is consistent with that).src/spec/feature-config.tsCleanRouteandSmartHostfrom~to✓with verified value enums.src/spec/dock-props.tsCLEAN_GENIUS_SUB_MODEatsiid 28 piid 5.src/spec/enums.tsCleaningModefromASSUMEDtoVERIFIED; addCleanGeniusandCleanGeniusSubModeenums.src/capabilities.tsdreame.vacuum.r2449aentry (mirrors r2532a — both are flagship Ultra-class Dock-Series-3 robots).src/vacuum.tsrefreshFromCloudJSDoc confirming thegetProperties80001-spin behaviour also holds on r2449a.README.mdCleaningModeline in "Known specifically-NOT-verified pieces" updated from "not decoded" to "decoded; see JSDoc".FEATURE_CONFIG_KEYScount bumped 11 → 13.CHANGELOG.md[Unreleased]entry under Added / Changed.How it was verified
properties_changedandevent_occuredpushes against an X40 Ultra Complete over a multi-minute window (full session: full-house clean → in-progress → mop install → dock → drying), tagged against the publishednode-dreameMIoT spec.FEATURE_CONFIG_KEYSvalue was confirmed by toggling the corresponding setting in the Dreamehome app and observing the JSON payload echo.CLEANING_MODE↔MOP_PADS_STATElockstep was confirmed by both writingMOP_PADS_STATE = Nfor eachN ∈ {0,1,2,3}and observingCLEANING_MODEsettle at(0x1400 | N), AND by writingCLEANING_MODE = Ndirectly (dropping0x1400) and observing the nextstart()refusal — once0x1400was restored the next clean succeeded.341 passed, 13 skipped); typecheck and lint clean; build emits the expected dist.Test plan
npm run typecheck— cleannpm run lint— cleannpm test— 341 passed (no new tests; the catalogue/JSDoc changes are documentation-typed)npm run build— emits ESM + CJS + DTSNotes for the maintainer
VERIFIED <model> <YYYY-MM-DD>,UPPER_SNAKE_CASEfor spec constants,as constat every level, no firmware-version branches).MOP_PADS_STATEas the property name despite the JSDoc rewrite — a rename is a public API break and the legacy name is fine as long as the doc explains what the field actually is. Happy to rename if you prefer, e.g. toCLEAN_MODE_MIRROR.r2449acapabilities mirrorr2532a. I'm confident every dock-side flag holds (X40 Ultra Complete ships with the same Dock-Series-3 station), and every boolean is true on the X40, but I haven't individually verified every supported enum value via setter writes. If you'd rather take the entry withverified: false, I can flip that.TASK_STATUS = 18(steady-state post-clean) doesn't appear in theTaskStatusenum; I did NOT add it because I'm not sure of its label (the X40 Ultra log shows18as the resting "ready for next task" value). Happy to follow up with a separate PR after a longer capture if useful.🤖 Generated with Claude Code