From 1b1a749eb6bbe6a76a002d18a3aa8d7e3019756e Mon Sep 17 00:00:00 2001 From: NOisi-X Date: Mon, 20 Jul 2026 13:17:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat!:=20full=20Zeo=20protocol=20definition?= =?UTF-8?q?=20=E2=80=94=2067=20DPs,=20complete=20enum=20mappings,=20all=20?= =?UTF-8?q?56=20devices=20covered?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- roborock/data/zeo/zeo_code_mappings.py | 356 ++++++++++++++++++------- roborock/data/zeo/zeo_containers.py | 139 ++++++++++ roborock/roborock_message.py | 113 +++++--- 3 files changed, 489 insertions(+), 119 deletions(-) diff --git a/roborock/data/zeo/zeo_code_mappings.py b/roborock/data/zeo/zeo_code_mappings.py index 4e5c79d16..76b8d7b8f 100644 --- a/roborock/data/zeo/zeo_code_mappings.py +++ b/roborock/data/zeo/zeo_code_mappings.py @@ -1,142 +1,320 @@ +"""Zeo (washing machine) device enums. + +Member-level comments show the manufacturer's official identifiers +extracted from the React Native app plugin bundle. + +For enums that map between protocol-level positions and physical units +(e.g. spin speed, temperature), the comment format is +``# L, `` where ``L`` is the protocol position +and ```` is the user-facing display value +(RPM, degrees Celsius, minutes, etc.). + +Enums commented out at the bottom of this file are App-internal lookup +tables and UI state machines — they are not DP protocol enums and are +never sent to the device. +""" + from ..code_mappings import RoborockEnum +class ZeoFeatureBits(RoborockEnum): + """Bit positions in DP 237 (FEATURE_BITS). + + Extracted from the official Roborock Washer app plugin bundle + (index.ios.bundle, module 726). Each member's integer value + is the exact bit offset the device reports at DP 237. + """ + + smart_hosting = 0 + silent_mode = 1 + new_custom_program = 2 + dry_care = 3 + set_uvc_in_appointment = 4 + detect_door_status = 5 + expand_softener = 6 + set_params_in_working = 7 + thirty_min_soak = 8 + smile_light = 9 + set_uvc_in_pause = 10 + concentrated_detergent = 11 + wool_detergent = 12 + voice_assistant = 13 + adapted_custom_program = 14 + voice_assistant_record = 15 + fluff_clean_notification = 16 + power_button_indicator_light = 17 + dirt_detection = 18 + deep_self_clean = 19 + save_panel_program_params = 20 + steam_care = 21 + wash_dry_linkage = 22 + ion_deodorization = 23 + + class ZeoMode(RoborockEnum): - null = 0 + null = 0 # (not found in app bundle) wash = 1 wash_and_dry = 2 dry = 3 + treatment = 4 class ZeoState(RoborockEnum): standby = 1 - weighing = 2 + weighing = 2 # Checking soaking = 3 washing = 4 rinsing = 5 - spinning = 6 + spinning = 6 # Dewatering drying = 7 cooling = 8 - under_delay_start = 9 - done = 10 - aftercare = 12 - waiting_for_aftercare = 13 + under_delay_start = 9 # Appointment + done = 10 # Complete + updating = 11 + aftercare = 12 # SmartHosting + waiting_for_aftercare = 13 # SmartHostingWaiting + steam_caring = 14 + descaling = 15 + cloth_ready = 16 + waiting_for_drying = 17 + pre_heating = 18 + pre_heat_complete = 19 + in_care = 20 class ZeoProgram(RoborockEnum): - null = 0 - standard = 1 + null = 0 # (not found in app bundle) + standard = 1 # Mixed quick = 2 - sanitize = 3 + sanitize = 3 # Sterilization wool = 4 - air_refresh = 5 - custom = 6 - bedding = 7 + air_refresh = 5 # Air + custom = 6 # CloudProgram + bedding = 7 # HomeTextile down = 8 silk = 9 - rinse_and_spin = 10 - spin = 11 - down_clean = 12 - baby_care = 13 - anti_allergen = 14 - sportswear = 15 + rinse_and_spin = 10 # RinseAndDehydrate + spin = 11 # Dehydrate + down_clean = 12 # SelfClean + baby_care = 13 # Baby + anti_allergen = 14 # MitesRemoval + sportswear = 15 # Sports night = 16 - new_clothes = 17 - shirts = 18 - synthetics = 19 + new_clothes = 17 # New + shirts = 18 # Shirt + synthetics = 19 # ChemicalFiber underwear = 20 - gentle = 21 - intensive = 22 - cotton_linen = 23 + gentle = 21 # Soft + intensive = 22 # Strong + cotton_linen = 23 # CottonOrLinen season = 24 - warming = 25 + warming = 25 # Warm bra = 26 - panties = 27 - boiling_wash = 28 + panties = 27 # Underpants + boiling_wash = 28 # Boiling + soaking = 29 socks = 30 - towels = 31 - anti_mite = 32 - exo_40_60 = 33 - twenty_c = 34 - t_shirts = 35 - stain_removal = 36 + towels = 31 # Towel + anti_mite = 32 # MitesRemoval2 + exo_40_60 = 33 # Eco + twenty_c = 34 # TwentyDegrees + t_shirts = 35 # TShirt + stain_removal = 36 # Dirt + small_things = 37 + mixing = 39 + bath_towel = 40 + jeans = 41 + outdoors = 42 + timed_drying = 43 + outdoor_jackets = 44 + yoga = 45 + quilt_drying = 46 + flax = 47 + suit = 48 + sport_shoes = 49 + rack_drying = 50 + summer_quilt = 51 + wind_breaker = 52 + steam_care = 53 + descaling = 54 + deep_self_clean = 55 + pet_care = 56 + small_things_drying = 57 class ZeoSoak(RoborockEnum): - normal = 0 - low = 1 - medium = 2 - high = 3 - max = 4 + normal = 0 # L0, 0min + low = 1 # L1, 5min + medium = 2 # L2, 10min + high = 3 # L3, 15min + max = 4 # L4, 20min + very_max = 5 # L5, 30min class ZeoTemperature(RoborockEnum): - normal = 1 - low = 2 - medium = 3 - high = 4 - max = 5 - twenty_c = 6 - ninety_c = 7 + normal = 1 # L1, 0 C + low = 2 # L2, 30 C + medium = 3 # L3, 40 C + high = 4 # L4, 60 C + max = 5 # L5, 90 C + twenty_c = 6 # L6, 20 C + ninety_c = 7 # L7, 95 C class ZeoRinse(RoborockEnum): - none = 0 - min = 1 - low = 2 - mid = 3 - high = 4 - max = 5 + none = 0 # L0, None + min = 1 # L1, Min + low = 2 # L2, Low + mid = 3 # L3, Mid + high = 4 # L4, High + max = 5 # L5, Max class ZeoSpin(RoborockEnum): - null = 0 - none = 1 - very_low = 2 - low = 3 - mid = 4 - high = 5 - very_high = 6 - max = 7 + null = 0 # (not found in app bundle) + none = 1 # L1, 0 RPM + very_low = 2 # L2, 400 RPM + low = 3 # L3, 600 RPM + mid = 4 # L4, 800 RPM + high = 5 # L5, 1000 RPM + very_high = 6 # L6, 1200 RPM + max = 7 # L7, 1400 RPM class ZeoDryingMode(RoborockEnum): none = 0 - quick = 1 - iron = 2 - store = 3 + quick = 1 # Quick, Mid + iron = 2 # Iron, Low + store = 3 # Store, High class ZeoDetergentType(RoborockEnum): - empty = 0 - low = 1 - medium = 2 - high = 3 + empty = 0 # T0 + low = 1 # T1 + medium = 2 # T2 + high = 3 # T3 class ZeoSoftenerType(RoborockEnum): - empty = 0 - low = 1 - medium = 2 - high = 3 + empty = 0 # T0 + low = 1 # T1 + medium = 2 # T2 + high = 3 # T3 + + +class ZeoDetergentExpansionType(RoborockEnum): + concentrated_detergent = 1 + detergent = 2 + + +class ZeoSoftenerExpansionType(RoborockEnum): + softener = 1 + softener_expansion = 2 + wool_detergent = 3 + + +class ZeoDirtDetectionStatus(RoborockEnum): + idle = 0 + detecting = 1 + detection_completed = 2 class ZeoError(RoborockEnum): - none = 0 - refill_error = 1 - drain_error = 2 - door_lock_error = 3 - water_level_error = 4 - inverter_error = 5 - heating_error = 6 - temperature_error = 7 - communication_error = 10 - drying_error = 11 - drying_error_e_12 = 12 - drying_error_e_13 = 13 - drying_error_e_14 = 14 - drying_error_e_15 = 15 - drying_error_e_16 = 16 - drying_error_water_flow = 17 # Check for normal water flow - drying_error_restart = 18 # Restart the washer and try again - spin_error = 19 # re-arrange clothes + none = 0 # No error + refill_error = 1 # Refill error (E1). Check if the water tap is turned on. + drain_error = 2 # Drain error (E2). Check the drain hose. + door_lock_error = 3 # Door lock error (E3). Close the door properly. + water_level_error = 4 # Drum water level error (E4). + inverter_error = 5 # DD motor variable-frequency drive error (E5). + heating_error = 6 # Water heater error (E6). + temperature_error = 7 # Drum water temperature error (E7). + communication_error = 10 # Communication error (E10). + drying_error = 11 # Temperature error (E11). + drying_error_e_12 = 12 # Temperature error (E12). + drying_error_e_13 = 13 # Temperature error (E13). + drying_error_e_14 = 14 # Temperature error (E14). + drying_error_e_15 = 15 # Drying air heater error (E15). + drying_error_e_16 = 16 # Fan RPM error (E16). + drying_error_water_flow = 17 # Drying temperature protection (E17). + drying_error_restart = 18 # Fan RPM error (E18). + spin_error = 19 # Balance error (Unb). + + +class ZeoDryingMethod(RoborockEnum): + l1 = 1 # L1, Saving + l2 = 2 # L2, Standard + l3 = 3 # L3, SuperFast + + +class ZeoSteamVolume(RoborockEnum): + none = 0 # L0, None + low = 1 # L1, Min + medium = 2 # L2, Low + high = 3 # L3, Mid + max = 4 # L4, High + + +class ZeoDryAndCare(RoborockEnum): + soft = 1 + normal = 2 + + +class ZeoDryerStartError(RoborockEnum): + dryer_running = 1 # Washer-Dryer Pairing cannot start: Dryer is running. + dryer_error = 2 # Washer-Dryer Pairing cannot start: Dryer has an error. + dryer_done = 3 # Dryer drying is complete, please remove the clothes first. + dryer_waiting_hosting = 4 # Dryer is waiting for smart hosting. + dryer_smart_hosting = 5 # Dryer is in smart hosting mode. + dryer_countdown = 6 # Dryer is in preset countdown. + dryer_network_fail = 7 # Please check the dryer network connection. + + +# The following are App-internal lookup tables extracted from the bundle. +# They are NOT DP protocol enums — the device never receives these values. +# They control how the official app adjusts recommended dosages or UI visibility. +# +# class Cleanser(RoborockEnum): +# detergent = 0 +# additions = 1 +# +# class Detergents(RoborockEnum): +# concentrated = 1 +# regular = 2 +# baby = 3 +# +# class Additions(RoborockEnum): +# softener = 1 +# disinfectant = 2 +# fragrance = 3 +# +# The following are App UI state enums — internal state machines used by the +# official app for page rendering and progress display. +# +# class HomePageStatus(RoborockEnum): +# updating = 0 +# loading = 1 +# load_failed = 2 +# idle = 3 +# working = 4 +# smart_hosting = 5 +# preset = 6 +# descaling = 7 +# cloth_ready = 8 +# wait_to_dry = 9 +# +# class Progress(RoborockEnum): +# soak = 0 +# wash = 1 +# rinse = 2 +# spin = 3 +# dry = 4 +# steam_care = 5 +# +# class ProgressStatus(RoborockEnum): +# done = 0 +# doing = 1 +# will_do = 2 +# +# class SmartHostStatus(RoborockEnum): +# smart_host_waiting = 0 +# smart_hosting = 1 diff --git a/roborock/data/zeo/zeo_containers.py b/roborock/data/zeo/zeo_containers.py index e69de29bb..00d8017ce 100644 --- a/roborock/data/zeo/zeo_containers.py +++ b/roborock/data/zeo/zeo_containers.py @@ -0,0 +1,139 @@ +"""Data containers for Zeo (washing machine / dryer) devices.""" + +from dataclasses import dataclass + +from ..containers import RoborockBase + + +@dataclass +class ZeoStartParams(RoborockBase): + """Parameters that must 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: int + """Wash mode (e.g. wash, wash-and-dry, dry, treatment).""" + + program: int + """Wash program (e.g. standard, quick, wool).""" + + temp: int | None = None + """Water temperature (always ``None`` for dryers).""" + + rinse_times: int | None = None + """Number of rinse cycles (always ``None`` for dryers).""" + + spin_level: int | None = None + """Spin speed in RPM (always ``None`` for dryers).""" + + drying_mode: int | None = None + """Drying mode (e.g. quick, iron, store).""" + + +# ── 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. + + +@dataclass +class ZeoCustomMode(RoborockBase): + """Decoded custom programme parameters from DP 222 (LoadCloudProgram). + + Null / absent fields are represented as ``0`` which matches the + official app's behaviour (the right-shifted-and-masked value is + always non-negative). + """ + + program: int + """Wash program (bits 0-7).""" + + mode: int + """Wash mode (bits 8-9).""" + + temperature: int + """Temperature (bits 10-12).""" + + rinse: int + """Rinse cycle (bits 13-15).""" + + spin: int + """Spin speed (bits 16-18).""" + + dry: int + """Drying mode (bits 19-21).""" + + soak: int + """Soak (bits 22-24).""" + + dry_care_mode: int + """Dry-care mode (bits 25-27).""" + + steam_volume: int + """Steam volume (bits 28-30).""" + + total_time_min: int = 0 + """Total programme time in minutes (from DP 239).""" + + @classmethod + def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoCustomMode": + """Decode a raw 32-bit custom-programme value.""" + return cls( + program=(raw & 0xFF), + mode=(raw >> 8) & 0x3, + temperature=(raw >> 10) & 0x7, + rinse=(raw >> 13) & 0x7, + spin=(raw >> 16) & 0x7, + dry=(raw >> 19) & 0x7, + soak=(raw >> 22) & 0x7, + dry_care_mode=(raw >> 25) & 0x7, + steam_volume=(raw >> 28) & 0x7, + total_time_min=total_time_min or 0, + ) + + +@dataclass +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. + """ + + program: int + """Drying program (bits 0-7).""" + + mode: int + """Drying mode (bits 8-10).""" + + dry: int + """Drying level (bits 11-13).""" + + dry_method: int + """Drying method (bits 14-16).""" + + steam_volume: int + """Steam volume (bits 17-19).""" + + total_time_min: int = 0 + """Total programme time in minutes (from DP 239).""" + + @classmethod + def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoDryerCustomMode": + """Decode a raw 32-bit dryer custom-programme value.""" + return cls( + program=(raw & 0xFF), + # Dryer mode spans bits 8-10 (0x700, 3 bits) because the + # temperature field is absent from the dryer bitfield and + # bit 10 is re-allocated to mode. Washer uses 2 bits + # (0x300, bits 8-9) to make room for temperature at 10-12. + mode=(raw >> 8) & 0x7, + dry=(raw >> 11) & 0x7, + dry_method=(raw >> 14) & 0x7, + steam_volume=(raw >> 17) & 0x7, + total_time_min=total_time_min or 0, + ) diff --git a/roborock/roborock_message.py b/roborock/roborock_message.py index b78ce5bab..82b14ee57 100644 --- a/roborock/roborock_message.py +++ b/roborock/roborock_message.py @@ -125,45 +125,98 @@ class RoborockDyadDataProtocol(RoborockEnum): class RoborockZeoProtocol(RoborockEnum): - START = 200 # rw + """Zeo device Data Point protocol IDs (200-266) and meta/RPC commands (10000+). + + Comment tags: + ro — read-only + rw — read-write + wo — write-only + [startWith] — must be bundled with START via start() + [independent] — immediate effect, works via set_value() + """ + + # ── DP 200-266 ───────────────────────────────────────────────────── + START = 200 # rw [action → start()] PAUSE = 201 # rw SHUTDOWN = 202 # rw STATE = 203 # ro - MODE = 204 # rw - PROGRAM = 205 # rw - CHILD_LOCK = 206 # rw - TEMP = 207 # rw - RINSE_TIMES = 208 # rw - SPIN_LEVEL = 209 # rw - DRYING_MODE = 210 # rw - DETERGENT_SET = 211 # rw - SOFTENER_SET = 212 # rw - DETERGENT_TYPE = 213 # rw - SOFTENER_TYPE = 214 # rw - COUNTDOWN = 217 # rw + MODE = 204 # rw [startWith] + PROGRAM = 205 # rw [startWith] + CHILD_LOCK = 206 # rw [independent] + TEMP = 207 # rw [startWith] + RINSE_TIMES = 208 # rw [startWith] + SPIN_LEVEL = 209 # rw [startWith] + DRYING_MODE = 210 # rw [startWith] + DETERGENT_SET = 211 # rw [independent] + SOFTENER_SET = 212 # rw [independent] + DETERGENT_TYPE = 213 # rw [independent] + SOFTENER_TYPE = 214 # rw [independent] + DIRT_DETECTION_SWITCH = 215 # rw [independent] + DIRT_DETECTION_STATUS = 216 # ro + COUNTDOWN = 217 # rw [independent] also used in start_with_preset() WASHING_LEFT = 218 # ro DOORLOCK_STATE = 219 # ro ERROR = 220 # ro - CUSTOM_PARAM_SAVE = 221 # rw - CUSTOM_PARAM_GET = 222 # ro - SOUND_SET = 223 # rw + CUSTOM_PARAM_SAVE = 221 # rw [independent] see save_cloud_program() + CUSTOM_PARAM_GET = 222 # rw [independent] read via get_custom_mode(), write via load_cloud_program() + SOUND_SET = 223 # rw [independent] TIMES_AFTER_CLEAN = 224 # ro - DEFAULT_SETTING = 225 # rw + DEFAULT_SETTING = 225 # rw [independent] DETERGENT_EMPTY = 226 # ro SOFTENER_EMPTY = 227 # ro - LIGHT_SETTING = 229 # rw - DETERGENT_VOLUME = 230 # rw - SOFTENER_VOLUME = 231 # rw - APP_AUTHORIZATION = 232 # rw - ID_QUERY = 10000 - F_C = 10001 - SND_STATE = 10004 - PRODUCT_INFO = 10005 - PRIVACY_INFO = 10006 - OTA_NFO = 10007 - WASHING_LOG = 10008 - RPC_REQ = 10101 - RPC_RESp = 10102 + UV_LIGHT = 228 # rw [independent] + LIGHT_SETTING = 229 # rw [independent] server schema only, not found in bundle + DETERGENT_VOLUME = 230 # rw [independent] server schema only, not found in bundle + SOFTENER_VOLUME = 231 # rw [independent] server schema only, not found in bundle + APP_AUTHORIZATION = 232 # ro + SOAK = 233 # rw [startWith] + TOTAL_TIME = 234 # ro used in dryer startWith payload + SMART_HOSTING = 235 # rw [independent] + SMART_HOSTING_TIME = 236 # ro + FEATURE_BITS = 237 # ro decoded by ZeoFeatureBits + SMART_HOSTING_WAITED_TIME = 238 # ro + CUSTOM_PROGRAM_CLEANING_TIME = 239 # ro + SILENT_MODE_ON = 240 # rw [independent] use set_silent_mode() for bundled set + SILENT_MODE_START_TIME = 241 # rw [independent] minute-of-day + SILENT_MODE_END_TIME = 242 # rw [independent] minute-of-day + DRY_CARE_MODE = 244 # rw [startWith] + SOFTENER_EXPANSION_TYPE = 245 # rw [independent] + SMILE_LIGHT_STATUS = 247 # rw [independent] + DETERGENT_EXPANSION_TYPE = 248 # rw [independent] + FLUFF_CLEANED = 249 # rw [independent] + IS_NEED_FLUFF_CLEAN = 250 # ro + POWER_LIGHT = 251 # rw [independent] + PANEL_PROGRAM_PARAMS_SET = 252 # rw [independent] + PANEL_PROGRAM_PARAMS_SET_RESULT = 253 # ro + SAVE_ADAPTED_CLOUD_PROGRAM = 254 # rw [independent] + WASH_DRY_LINKED = 255 # rw [startWith / feature-gated] + DRYING_METHOD = 256 # rw [startWith] + STEAM_VOLUME = 257 # rw [startWith] + ION_DEODORIZATION = 258 # rw [startWith / feature-gated] + PANEL_TIMING_PROGRAM_PARAMS = 260 # ro + STEAM_CARE_TIME = 261 # ro + DEVICE_BOUND = 262 # ro + CLOTH_PUT_IN = 263 # ro + CLOTH_READY_TO_DRY_COUNT_DOWN = 264 # ro + START_DRYER_ERROR = 265 # ro + WIFI_LINKAGE_RESET = 266 # rw [independent] + + # ── Meta / RPC / Voice (10000+) ──────────────────────────────────── + ID_QUERY = 10000 # -- multi-DP query request (not a device DP) + F_C = 10001 # ro query via checkFCCState() + SET_SOUND_PACKAGE = 10003 # wo setSoundPackage(JSON) + SND_STATE = 10004 # ro query via updateSoundPackageInfo() + PRODUCT_INFO = 10005 # ro query via loadGeneralInfo() (10s timeout) + PRIVACY_INFO = 10006 # wo syncPrivacyToDevice(agreed) + OTA_NFO = 10007 # ro forceLoad only + WASHING_LOG = 10008 # ro forceLoad only, JSON + VOICE_VOLUME = 10009 # wo [independent] setVoiceVolume(int) → JSON + RPC_REQUEST = 10101 # wo rpcRequest(method) → JSON + RPC_RESPONSE = 10102 # -- MQTT push protocol 102, not a device DP + VOICE_SWITCH = 10301 # wo [independent] setVoiceSwitchStatus(bool) → JSON + VOICE_RECORD_INFO = 10302 # ro cache-derived, auto JSON decoded + VOICE_RECORD = 10303 # ro query via getVoiceControlRecord(), JSON + VOICE_RECORD_DELETE = 10304 # wo [independent] deleteVoiceControlRecord(id) → JSON class RoborockB01Protocol(RoborockEnum): From faf8f32d11bb7216ec73a77bc18a8372cb696c3a Mon Sep 17 00:00:00 2001 From: NOisi-X Date: Tue, 21 Jul 2026 16:38:44 +0800 Subject: [PATCH 2/2] refactor(zeo): replace raw integer fields with enum types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- roborock/data/zeo/zeo_containers.py | 91 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/roborock/data/zeo/zeo_containers.py b/roborock/data/zeo/zeo_containers.py index 00d8017ce..5711cc1f9 100644 --- a/roborock/data/zeo/zeo_containers.py +++ b/roborock/data/zeo/zeo_containers.py @@ -3,6 +3,18 @@ from dataclasses import dataclass from ..containers import RoborockBase +from .zeo_code_mappings import ( + ZeoDryAndCare, + ZeoDryingMethod, + ZeoDryingMode, + ZeoMode, + ZeoProgram, + ZeoRinse, + ZeoSoak, + ZeoSpin, + ZeoSteamVolume, + ZeoTemperature, +) @dataclass @@ -14,23 +26,12 @@ class ZeoStartParams(RoborockBase): included when the device reports a non-None value. """ - mode: int - """Wash mode (e.g. wash, wash-and-dry, dry, treatment).""" - - program: int - """Wash program (e.g. standard, quick, wool).""" - - temp: int | None = None - """Water temperature (always ``None`` for dryers).""" - - rinse_times: int | None = None - """Number of rinse cycles (always ``None`` for dryers).""" - - spin_level: int | None = None - """Spin speed in RPM (always ``None`` for dryers).""" - - drying_mode: int | None = None - """Drying mode (e.g. quick, iron, store).""" + mode: ZeoMode + program: ZeoProgram + temperature: ZeoTemperature | None = None + rinse: ZeoRinse | None = None + spin: ZeoSpin | None = None + drying_mode: ZeoDryingMode | None = None # ── DP 222 (LoadCloudProgram) bitfield decoder ────────────────────────── @@ -48,31 +49,31 @@ class ZeoCustomMode(RoborockBase): always non-negative). """ - program: int + program: ZeoProgram """Wash program (bits 0-7).""" - mode: int + mode: ZeoMode """Wash mode (bits 8-9).""" - temperature: int + temperature: ZeoTemperature """Temperature (bits 10-12).""" - rinse: int + rinse: ZeoRinse """Rinse cycle (bits 13-15).""" - spin: int + spin: ZeoSpin """Spin speed (bits 16-18).""" - dry: int + drying_mode: ZeoDryingMode """Drying mode (bits 19-21).""" - soak: int + soak: ZeoSoak """Soak (bits 22-24).""" - dry_care_mode: int + dry_and_care: ZeoDryAndCare """Dry-care mode (bits 25-27).""" - steam_volume: int + steam_volume: ZeoSteamVolume """Steam volume (bits 28-30).""" total_time_min: int = 0 @@ -82,15 +83,15 @@ class ZeoCustomMode(RoborockBase): def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoCustomMode": """Decode a raw 32-bit custom-programme value.""" return cls( - program=(raw & 0xFF), - mode=(raw >> 8) & 0x3, - temperature=(raw >> 10) & 0x7, - rinse=(raw >> 13) & 0x7, - spin=(raw >> 16) & 0x7, - dry=(raw >> 19) & 0x7, - soak=(raw >> 22) & 0x7, - dry_care_mode=(raw >> 25) & 0x7, - steam_volume=(raw >> 28) & 0x7, + program=ZeoProgram(raw & 0xFF), + mode=ZeoMode((raw >> 8) & 0x3), + temperature=ZeoTemperature((raw >> 10) & 0x7), + rinse=ZeoRinse((raw >> 13) & 0x7), + spin=ZeoSpin((raw >> 16) & 0x7), + drying_mode=ZeoDryingMode((raw >> 19) & 0x7), + soak=ZeoSoak((raw >> 22) & 0x7), + dry_and_care=ZeoDryAndCare((raw >> 25) & 0x7), + steam_volume=ZeoSteamVolume((raw >> 28) & 0x7), total_time_min=total_time_min or 0, ) @@ -104,19 +105,19 @@ class ZeoDryerCustomMode(RoborockBase): in module 725 of the plugin bundle. """ - program: int + program: ZeoProgram """Drying program (bits 0-7).""" - mode: int + mode: ZeoMode """Drying mode (bits 8-10).""" - dry: int + drying_mode: ZeoDryingMode """Drying level (bits 11-13).""" - dry_method: int + drying_method: ZeoDryingMethod """Drying method (bits 14-16).""" - steam_volume: int + steam_volume: ZeoSteamVolume """Steam volume (bits 17-19).""" total_time_min: int = 0 @@ -126,14 +127,14 @@ class ZeoDryerCustomMode(RoborockBase): def from_raw(cls, raw: int, total_time_min: int | None = None) -> "ZeoDryerCustomMode": """Decode a raw 32-bit dryer custom-programme value.""" return cls( - program=(raw & 0xFF), + program=ZeoProgram(raw & 0xFF), # Dryer mode spans bits 8-10 (0x700, 3 bits) because the # temperature field is absent from the dryer bitfield and # bit 10 is re-allocated to mode. Washer uses 2 bits # (0x300, bits 8-9) to make room for temperature at 10-12. - mode=(raw >> 8) & 0x7, - dry=(raw >> 11) & 0x7, - dry_method=(raw >> 14) & 0x7, - steam_volume=(raw >> 17) & 0x7, + mode=ZeoMode((raw >> 8) & 0x7), + drying_mode=ZeoDryingMode((raw >> 11) & 0x7), + drying_method=ZeoDryingMethod((raw >> 14) & 0x7), + steam_volume=ZeoSteamVolume((raw >> 17) & 0x7), total_time_min=total_time_min or 0, )