Skip to content

feat: add core ZeoApi with ZeoCommandTrait and ZeoFeatureTrait#897

Open
NOisi-x wants to merge 6 commits into
Python-roborock:mainfrom
NOisi-x:pr/zeo-core-api-v2
Open

feat: add core ZeoApi with ZeoCommandTrait and ZeoFeatureTrait#897
NOisi-x wants to merge 6 commits into
Python-roborock:mainfrom
NOisi-x:pr/zeo-core-api-v2

Conversation

@NOisi-x

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

Copy link
Copy Markdown
Contributor

Builds on #895
Closes #833

What this PR does

Finally, this PR gives us the ability to really start a wash programe on Zeo devices.

What you can now do

device.zeo.command.start_program()   # Start washing with current settings
device.zeo.command.pause()           # Pause mid-cycle
device.zeo.command.resume()          # Continue after pause
device.zeo.command.shutdown()        # Power off

The start command reads the device's current mode, program, temperature, rinse, spin, and drying settings via the MQTT cache — no extra network round-trip if the values were already pushed. It bundles everything together and sends it as one MQTT message, the same way the official app does.

How it knows what the device supports

ZeoFeatureTrait does two things at connection time:

  1. Product type detection — looks at the model ID (e.g. roborock.wm.a234) and immediately knows whether it's a dryer or a specific washer series. No device query needed, this info is static per model.

  2. Feature discovery — queries DP 237 once and parses a 24-bit capability mask into readable flags like smart_hosting, ion_deodorization, wash_dry_linkage. These flags control which optional DPs get included in start commands.

RoborockZeoProtocol additions

  • UNKNOWN_246 = 246 — placeholder to prevent "unknown code" errors if a device reports this protocol number
  • UNKNOWN_259 = 259 — same; reserved protocol slot, not found in the plugin bundle

NOisi-X added 4 commits July 20, 2026 11:39
Add MqttQos enum (AT_MOST_ONCE=0, AT_LEAST_ONCE=1, EXACTLY_ONCE=2) and thread a qos parameter through the publish chain (MqttSession -> MqttChannel -> send_decoded_command). All existing callers keep default AT_MOST_ONCE (backward compatible). Also add a unix timestamp field to A01 encode_mqtt_payload, required by Zeo/Dyad devices for command acceptance.
… 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.
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.
…overy

Subscribes to the device DPS MQTT topic after connection. Incoming RPC_RESPONSE messages are decoded and merged into _dps_cache with incremental updates. _discover_features() queries FEATURE_BITS (DP 237) to wake the device and cache capabilities — equivalent to V1's discover_features(). Also fixes TraitUpdateListener init in ZeoApi and a01_properties routing in connect().
@NOisi-x
NOisi-x force-pushed the pr/zeo-core-api-v2 branch 2 times, most recently from 5c3ec4e to 97f4940 Compare July 22, 2026 14:35
ZeoCommandTrait (new: command.py, 165 lines)
- start_program: bundles start params via FIELD_TO_DP, QoS 1
- pause / resume / shutdown: single-DP commands
- Start param sets split by device type (washer 10 DPs, dryer 7 DPs)
- Feature-gated DPs conditionally included from cache
- Dependencies injected: channel, dps_cache, feature_trait, proto_entries

ZeoFeatureTrait (new: device_features.py, 185 lines)
- ZeoFeatures dataclass (24 bool flags): from_feature_bits() via name reflection
- Product type detection: static model ID whitelists (dryer/Hyperion/M1)
- is_dryer / is_hyperion_halia_hera / is_m1_muse_metis — no device query
- refresh(): query DP 237 once, cache in memory

ZeoStartParams (zeo_containers.py): expanded to 13 fields covering washer + dryer
ZEO_PROTOCOL_ENTRIES (__init__.py): expanded to ~69 DP-type mappings
RoborockZeoProtocol: add UNKNOWN_246, UNKNOWN_259 placeholders

Builds on Python-roborock#895 (MQTT push subscription).
@NOisi-x
NOisi-x force-pushed the pr/zeo-core-api-v2 branch from cbb254f to c57f0b7 Compare July 22, 2026 14:38
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.

[Feature/Bug] Zeo Washing Machine (M1S Ultra): Deep Sleep Wakeup Failure & Missing DP Mappings

1 participant