Skip to content

feat!: audit and complete Zeo protocol DP and enum mappings#892

Open
NOisi-x wants to merge 2 commits into
Python-roborock:mainfrom
NOisi-x:pr/zeo-dp-enums
Open

feat!: audit and complete Zeo protocol DP and enum mappings#892
NOisi-x wants to merge 2 commits into
Python-roborock:mainfrom
NOisi-x:pr/zeo-dp-enums

Conversation

@NOisi-x

@NOisi-x NOisi-x commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Complete a full audit of the RoborockZeoProtocol DP enum against the official Roborock Washer app plugin bundle, expanding coverage from 31 to 67 entries and adding all missing enum mappings. Every known Zeo device feature is now represented in the protocol definition.

These findings build upon the excellent reverse engineering work done in ndwzy/roborock_washer_ha.

What was done

A systematic cross-reference was performed between the existing RoborockZeoProtocol enum and the React Native plugin bundle index.ios.bundle extracted from the official Roborock Washer app. Every DP ID, value mapping, and access mode (ro/rw/wo) was verified against the source of truth.

RoborockZeoProtocol — 31 → 67 DP entries

Reorganized into five semantic sections matching the app's internal structure:

Section Count Description
Control actions 3 START, PAUSE, SHUTDOWN
Read-only 17 STATE, ERROR, FEATURE_BITS, DRYER_ERROR, etc.
startWith params 12 MODE, PROGRAM, TEMP, SOAK, DRYING_METHOD, ION_DEODORIZATION, etc.
Independent (immediate) 23 CHILD_LOCK, DETERGENT_TYPE, SILENT_MODE_*, FLUFF_CLEANED, etc.
Meta / RPC / Voice 12 ID_QUERY, RPC_REQUEST, VOICE_VOLUME, VOICE_RECORD, etc.

Newly identified entries (previously undefined):

DIRT_DETECTION_STATUS, DIRT_DETECTION_SWITCH, UV_LIGHT, SOAK, SMART_HOSTING, SMART_HOSTING_TIME, SMART_HOSTING_WAITED_TIME, FEATURE_BITS, CUSTOM_PROGRAM_CLEANING_TIME, SILENT_MODE_ON, SILENT_MODE_START_TIME, SILENT_MODE_END_TIME, DRY_CARE_MODE, SOFTENER_EXPANSION_TYPE, SMILE_LIGHT_STATUS, DETERGENT_EXPANSION_TYPE, FLUFF_CLEANED, IS_NEED_FLUFF_CLEAN, POWER_LIGHT, PANEL_PROGRAM_PARAMS_SET, PANEL_PROGRAM_PARAMS_SET_RESULT, PANEL_TIMING_PROGRAM_PARAMS, SAVE_ADAPTED_CLOUD_PROGRAM, WASH_DRY_LINKED, DRYING_METHOD, STEAM_VOLUME, ION_DEODORIZATION, STEAM_CARE_TIME, DEVICE_BOUND, CLOTH_PUT_IN, CLOTH_READY_TO_DRY_COUNT_DOWN, START_DRYER_ERROR, WIFI_LINKAGE_RESET, SET_SOUND_PACKAGE, VOICE_VOLUME, VOICE_SWITCH, VOICE_RECORD_INFO, VOICE_RECORD, VOICE_RECORD_DELETE

Enum mappings — all missing enums added

Enum Change
ZeoFeatureBits (NEW) 24 bit positions for DP 237 feature discovery
ZeoMode Added treatment = 4
ZeoState Added 8 states: updating, steam_caring, descaling, cloth_ready, waiting_for_drying, pre_heating, pre_heat_complete, in_care
ZeoProgram Expanded from ~8 to 43 programs covering all supported wash/dry cycles
ZeoError Expanded from 1 to 19 specific error codes (E1–E18, Unb)
ZeoDryingMethod (NEW) 3 drying method levels
ZeoSteamVolume (NEW) 5 steam volume levels
ZeoDryAndCare (NEW) Dry-care modes for washer-dryer
ZeoDryerStartError (NEW) 7 dryer-specific startup error states

Data containers — placed per reviewer guidance

Class Purpose Location
ZeoStartParams Parameters bundled with START command zeo_containers.py
ZeoCustomMode Washer custom programme bitfield decoder (DP 222) zeo_containers.py
ZeoDryerCustomMode Dryer custom programme bitfield decoder (DP 222) zeo_containers.py

All three inherit from RoborockBase, following the project convention established by DyadProductInfo and other containers. Placed in roborock/data/zeo/zeo_containers.py to keep the traits module maintainable.

Breaking changes

RoborockZeoProtocol renamed two enum members for consistency with RoborockMessageProtocol:

  • RPC_REQRPC_REQUEST
  • RPC_RESpRPC_RESPONSE

A grep of the current main branch confirms zero references to the old names — no code or test is affected.

Device coverage

🧺 Washers — 52 models

Series Models
H1 a63 H1, a114 H1C, a102 H1 (Global), a90 H1Lite, a91 H1Lite (Global), a237 H1 Lite (Rev2), a242 H1C (Global), a115 H1C, a126-128 H1 (JP/TW/KR - deprecated)
M1 a92 M1, a93 M1 (Global), a133 M1Lite, a277 M1Lite (Rev3), a162 M1Lite (Global), a233 M1Lite Plus, a276 M1Lite Plus (Rev2), a234 M1 Plus, a218 M1 (Rev2), a129-131 M1 (TW/JP/KR - deprecated)
Hyperion a141 Hyperion, a149 HyperionPro, a207 Hyperion Plus, a230 Hyperion (Global)
Muse / Metis a142 Muse, a215 Muse (Global), a154 Metis, a214 Metis (Global)
Hera a227 Hera, a261 (DE), a273 (NO), a268 (KR), a269 (TW)
Pandora a239 Pandora, a262 (DE), a272 (NO), a270 (KR), a271 (TW)
Halia a240 Halia, a241 Halia Lite
Poseidon a180 Pro, a181, a201 Pro+, a255 (Global)
Other a105 Couple, a191 Crius, a192 Coeus, a211 Mitty, a213 Medusa

👕 Dryers — 4 models

Model Name Region
a188 Apollo Pro+ CN
a265 Apollo Pro+ Global (US/EU)
a204 Apollo Pro CN
a258 Apollo Pro Global (US/EU)

Reviewer notes

Addresses the following feedback from #871:

  • [allenporter] Performed a full audit of every DP enum member name against the official app plugin bundle. Where the existing name and the bundle-discovered name differ, the old name is preserved and the bundle name is noted in a comment alongside the UI display label, giving the maintainer full context to decide whether to rename later. No existing names are removed or renumbered.
  • [Lash-L] Inherit data containers from RoborockBase
  • [Lash-L] Place data containers in zeo_containers.py instead of the traits file

Part of: #871

@NOisi-x
NOisi-x force-pushed the pr/zeo-dp-enums branch 2 times, most recently from 13614b7 to 7763c0e Compare July 20, 2026 16:11
… all 56 devices covered

Expand RoborockZeoProtocol from 31 to 67 DP entries, ordered by numeric ID. Add all missing enum classes (ZeoFeatureBits, ZeoDryingMethod, ZeoSteamVolume, ZeoDryAndCare, ZeoDryerStartError) and extend existing enums to cover every state/value found in the official app plugin bundle. Add ZeoStartParams, ZeoCustomMode, and ZeoDryerCustomMode data containers inheriting from RoborockBase, placed in zeo_containers.py per reviewer guidance.
Comment thread roborock/data/zeo/zeo_containers.py Outdated
included when the device reports a non-None value.
"""

mode: int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this ZeoMode? If you can also change here and below that would be great

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes yse

Comment thread roborock/data/zeo/zeo_containers.py Outdated
mode: int
"""Wash mode (e.g. wash, wash-and-dry, dry, treatment)."""

program: int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this ZeoProgram?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes yse

Comment thread roborock/data/zeo/zeo_containers.py Outdated
spin_level: int | None = None
"""Spin speed in RPM (always ``None`` for dryers)."""

drying_mode: int | None = None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be ZeoDryingMode

@NOisi-x NOisi-x Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All done — hope I didn't misunderstand what you meant.

Update ZeoStartParams, ZeoCustomMode, and ZeoDryerCustomMode to use typed enum fields (ZeoMode, ZeoProgram, ZeoTemperature, etc.) instead of raw int, aligning with the V1 container pattern in v1_containers.py. Rename shorthand fields (rinse_times→rinse, spin_level→spin) for consistency across all three classes. Unify drying-mode field naming.
@@ -1,142 +1,320 @@
"""Zeo (washing machine) device enums.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of these comments can be removed or shortened as they are more of a response from the agent than a comment on the code, does that make sense?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referencing the bundle isn't needed because the files will change a lot. I.e. no need to say module 706

class ZeoProgram(RoborockEnum):
null = 0
standard = 1
null = 0 # (not found in app bundle)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to say not found in bundle here

dryer_network_fail = 7 # Please check the dryer network connection.


# The following are App-internal lookup tables extracted from the bundle.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this commented out code

"""Dry-care mode (bits 25-27)."""

steam_volume: ZeoSteamVolume
"""Steam volume (bits 28-30)."""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are good

"""Total programme time in minutes (from DP 239)."""

@classmethod
def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoCustomMode":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the typing.Self here if possible, not a big fan of forward references

"""Total programme time in minutes (from DP 239)."""

@classmethod
def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoDryerCustomMode":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

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.

3 participants