feat: add MQTT push subscription and real-time state tracking for Zeo devices#895
Open
NOisi-x wants to merge 5 commits into
Open
feat: add MQTT push subscription and real-time state tracking for Zeo devices#895NOisi-x wants to merge 5 commits into
NOisi-x wants to merge 5 commits into
Conversation
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.
NOisi-x
force-pushed
the
pr/zeo-push
branch
7 times, most recently
from
July 22, 2026 04:26
698b11b to
44465af
Compare
added 2 commits
July 22, 2026 18:45
… 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.
NOisi-x
force-pushed
the
pr/zeo-push
branch
4 times, most recently
from
July 22, 2026 13:28
8d33ed9 to
2764f2e
Compare
…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
pushed a commit
to NOisi-x/python-roborock
that referenced
this pull request
Jul 22, 2026
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
pushed a commit
to NOisi-x/python-roborock
that referenced
this pull request
Jul 22, 2026
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
pushed a commit
to NOisi-x/python-roborock
that referenced
this pull request
Jul 22, 2026
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
pushed a commit
to NOisi-x/python-roborock
that referenced
this pull request
Jul 22, 2026
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).
Lash-L
requested changes
Jul 25, 2026
| @@ -1,142 +1,320 @@ | |||
| """Zeo (washing machine) device enums. | |||
|
|
|||
| Member-level comments show the manufacturer's official identifiers | |||
Collaborator
There was a problem hiding this comment.
This line isn't needed. A lot of what I said on the other or stands here imo
| class ZeoFeatureBits(RoborockEnum): | ||
| """Bit positions in DP 237 (FEATURE_BITS). | ||
|
|
||
| Extracted from the official Roborock Washer app plugin bundle |
Collaborator
|
Will review more when we merge the other pr as this seems to have some of the same work in it |
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
Builds on #892. Add MQTT push subscription and real-time state tracking for Zeo devices.
What's new in this PR
1. MQTT Push Subscription
ZeoApi.start()subscribes to the device's DPS MQTT topic after connection. All device state changes — both physical (button presses, dial rotations) and remote (App commands) — are received as real-time push messages.2. DPS Cache with Incremental Updates
Incoming push messages are decoded from RPC protocol 102, parsed as
{dps: {dp_id: value, ...}}, and merged into_dps_cache. Only changed DPs are pushed — the device sends incremental updates, not full state each time.3. Feature Discovery (
_discover_features)Mirrors V1's
discover_features()pattern: after subscribing, queries FEATURE_BITS (DP 237) to wake the device and cache supported capabilities. Exposessupports(ZeoFeatureBits)for runtime feature checks.4. Bug Fixes Found During Testing
ZeoApi.__init__: missingTraitUpdateListener.__init__()call caused_update_callbacksAttributeErrordevice.py connect():self.a01_properties(doesn't exist) →self.zeo5. DP 243 Placeholder
Observed on a114, increments with each push. Not found in the plugin bundle. Added as
UNKNOWN_243with a comment.Testing
Tested on two Zeo devices (a234, a114) using a multi-device MQTT monitor:
_discover_features()wake