Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0f9bad2
feat: add MQTT QoS support and timestamp to A01 protocol payload
Jul 20, 2026
9077983
feat!: full Zeo protocol definition — 67 DPs, complete enum mappings,…
Jul 20, 2026
2d4a191
refactor(zeo): replace raw integer fields with enum types
Jul 21, 2026
910375b
feat(zeo): add MQTT push subscription with DPS cache and feature disc…
Jul 22, 2026
4432a62
Merge branch 'main' into pr/zeo-push
NOisi-x Jul 22, 2026
d57b81e
Merge branch 'main' into pr/zeo-push
NOisi-x Jul 27, 2026
169a6a9
fix(zeo): narrow exceptions, tighten try/except scope
Jul 28, 2026
2ccb776
Merge branch 'main' into pr/zeo-push
NOisi-x Aug 6, 2026
2c03138
Merge branch 'main' into pr/zeo-push
NOisi-x Aug 12, 2026
d692352
feat(zeo): replace _discover_features with _force_load matching Bundl…
Aug 12, 2026
f3b5144
fix(zeo): add null=0 to multiple Zeo enums, trim verbose docstrings
Aug 12, 2026
0f863db
feat(zeo): implement two-stage force-load and close() cleanup
Aug 13, 2026
7716150
feat(zeo): add A01 wash command/settings/status traits with caller-su…
Aug 15, 2026
6cf8d98
Merge branch 'main' into pr/zeo-core-api-v2
NOisi-x Aug 15, 2026
21d535a
style(zeo): fix pre-commit findings (formatting, unused import, no-re…
Aug 15, 2026
9ea7225
fix(zeo): correct voice DP read/write semantics per bundle
Aug 17, 2026
96a0d5e
style: fix E501 long comment lines in voice DP enums
Aug 17, 2026
0014651
fix(zeo): backfill lazily-built traits from DPS cache on first access
Aug 17, 2026
105417d
fix(zeo): return None from fixed single-DP commands, keep frame retur…
Aug 17, 2026
49901eb
fix(zeo): use query_values return value and tighten sound package inf…
Aug 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 73 additions & 10 deletions roborock/data/zeo/zeo_containers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Data containers for Zeo (washing machine / dryer) devices."""

from dataclasses import dataclass
from dataclasses import dataclass, field

from ..containers import RoborockBase
from .zeo_code_mappings import (
Expand All @@ -17,27 +17,91 @@
)


@dataclass
class ZeoWashRecord(RoborockBase):
"""A single entry in the device's wash-history log (DP 10008)."""

ctrl_type: int = 0
"""Control type of the programme (2 = app, 1 = panel)."""

prog_type: ZeoProgram | None = None

category: ZeoMode | None = None

end_type: int = 0
"""End type (1 = completed, 2 = cancelled/failed)."""

duration: int = 0
"""Programme duration in minutes (0 for entries that never ran)."""

t: int = 0
"""Start timestamp (Unix seconds)."""

end_t: int = 0
"""End timestamp (Unix seconds)."""


@dataclass
class ZeoWashLog(RoborockBase):
"""Wash-history log reported at DP 10008 (JSON string)."""

cnt: int = 0
"""Total number of log entries."""

wash_cnt: int = 0
"""Total wash count."""

dry_cnt: int = 0
"""Total dry count."""

wash_dry_cnt: int = 0
"""Total wash-and-dry count."""

washes: list[ZeoWashRecord] = field(default_factory=list)
"""The individual wash records (oldest → newest)."""


@dataclass
class ZeoStartParams(RoborockBase):
"""Parameters that must be bundled with a START command.
"""All parameters that may be bundled with a START command.

All Zeo devices require ``mode`` and ``program`` to be sent together
with the start signal. The remaining fields are optional and only
included when the device reports a non-None value.
``mode`` and ``program`` are mandatory for every device. Every other
field is optional — when ``None`` it is simply omitted from the MQTT
payload, so the same superset works for washers and dryers alike.
"""

mode: ZeoMode
program: ZeoProgram

# Washer
temperature: ZeoTemperature | None = None
rinse: ZeoRinse | None = None
spin: ZeoSpin | None = None
drying_mode: ZeoDryingMode | None = None

# Dryer
drying_method: ZeoDryingMethod | None = None
steam_volume: ZeoSteamVolume | None = None
# Timed-program running duration in minutes (DP 234).
# This is a fixed parameter of the programme config.
# TODO(program-config): once a programme table exists, this should be
# auto-populated from the programme config instead of passed by the caller.
total_time: int | None = None # depends on programme configs

# Optional across both device families
soak: ZeoSoak | None = None
dry_and_care: ZeoDryAndCare | None = None

# Feature-gated start options (DP 258 / DP 255). In the Bundle these are
# the programme's config ``defaultIonStatus`` and the UI's
# ``wash_dry_linked`` state
ion_deodorization: bool | None = None
wash_dry_linked: bool | None = None


# ── DP 222 (LoadCloudProgram) bitfield decoder ──────────────────────────
# The official app packs all custom-program parameters into a single
# 32-bit integer at DP 222. This mirrors WasherDpsCache.customMode in
# module 725 of the React Native plugin bundle.
# All custom-program parameters are packed into a single
# 32-bit integer at DP 222.


@dataclass
Expand Down Expand Up @@ -101,8 +165,7 @@ class ZeoDryerCustomMode(RoborockBase):
"""Decoded custom programme from DP 222 for a standalone dryer.

Dryers pack a different (shorter) bitfield than washers — only 5
fields after program/mode. Mirrors ``WasherDpsCache.dryerCustomMode``
in module 725 of the plugin bundle.
fields after program/mode.
"""

program: ZeoProgram
Expand Down
Loading
Loading