Repository navigation
fix: preserve water-slide codes in cleaning-mode commands and status - #961
xiaoyaner0201 wants to merge 3 commits into
Conversation
|
Hi thanks for the fix! Can we take it a step further? Right now, this will still fail for say 223. Can we resolve the value via the range? When the user selects a value - we can set it to an exact value. But if the user changes it in the app to one of the inbetween slider values, we could still display the closest category. e.g. Add a small feature-gated range resolver Preserve the raw value 223. Resolve its range (221–223) to "slight". |
|
Additional affected model: Qrevo Edge 2 Flow ( An exact-source offline reproduction confirms ordinary slide water codes 225/235/248/250 cannot be classified through the original enum path. The feature-aware mapping approach used here also resolves those read cases in our isolated tests. We have not installed this PR or tested its write path on this robot, so this is not a full hardware validation of #961. There is a separate issue on this device: it reports the valid custom triplet 106/204/302, with custom and smart feature flags enabled, but The independent archive-order issue is #976. Thanks for preserving existing UI strings and addressing both read and write mappings; these separate reports are not a claim that this PR fixes those additional cases. |
Share the existing app range resolver between water-flow names and cleaning-mode classification. Preserve raw telemetry and the legacy fallback for non-slide codes, including custom and smart modes. Cover every slider position across vacuum and mop fan settings, with capability gating and raw-value preservation checks.
|
@Lash-L thanks for pushing on this, and sorry for the slow turnaround. Done in 7e59415. Since your comment, #975 landed the app's range table (
The tests cover every position from 221 to 250 across three fan settings. Without the change, 69 of them fail on in-between positions. Full suite: 1582 passed on Python 3.11 and 3.14 after merging current One heads-up: #983 also edits |
Summary
Refs #931 and #930. Thanks to @liborplisek for identifying the enum-alias root cause, @BlackRockCity for the command/status captures, and @frenck for the app range table in #975.
Bring the combined cleaning-mode paths into line with the feature-aware water-mode handling on water-slide devices:
vac_and_mopandmopemit235instead of the aliased member's legacy202.water_mode_namealready uses since fix: map water slide positions to the app's flow ranges #975. A position set from the app between two named steps (e.g.223,248) now yieldsvac_and_mop/mopinstead ofNone. The rawwater_box_modevalue is preserved, and the resolver is gated onis_water_slide_mode_supported.PURE_WATER_FLOW_MIDDLE.codeon both sides (they were passing with the same incorrect202); expected wire values now use explicit protocol integers. Add publicStatusTraitread/write regressions covering every slider position, vacuum/mop selection, optional mop-route fields, legacy codes, enum inputs, capability gating and unknown/incomplete status.How the range resolution works
get_water_slide_mode_name()and cleaning-mode classification now share one pure helper,_resolve_water_slide_mode(code), built on the existing_WATER_SLIDE_RANGES. There is no second copy of the range boundaries, andget_water_slide_mode_name()returns exactly what it returned before for every input (checked for every integer inrange(-10, 400)).On water-slide devices, an integer water code is classified like this:
200→ off →vacuum221–250→ the app range for that position →vac_and_mop, ormopwith the mop-only fan setting201/202/203→vac_and_mop,204→custom,209→smart_mode, and220/251/unknown →NoneDevices without
is_water_slide_mode_supportedare unchanged: an in-between code such as223still classifies asNonethere. Commands still send the exact representative code for the selected mode (235for vac_and_mop/mop,200for vacuum). The range resolver is read-only.Compatibility and scope
Public enum values, option lists,
WATER_SLIDE_MODE_MAPPING,_WATER_SLIDE_RANGESand user-facing option strings are unchanged, so consumers usingmode.valueneed no migration. This fixes the combined-mode command and classification paths, not the standalone enum-alias representation:WaterModes.PURE_WATER_FLOW_MIDDLE.codeand genericWaterModes.from_code_optional(235)are still affected. A broader unique-value/display-name migration remains separate, so this PR references rather than closes #931.Out of scope: water-slide
custom/smart_modeoption exposure (#977), other protocol families, Home Assistant automation policies, and login fixes.Overlap with open PR #983: both PRs edit
get_water_slide_mode_name(). #983 adds aSMART_WATERearly return, and this PR moves that function's body into_resolve_water_slide_mode(). Whichever lands second needs a one-line textual resolution: returnWaterModes.SMART_WATERfrom the helper instead of.value. Happy to rebase onto #983 if it merges first.Reproduction and hardware evidence
On a G30S Ultra with Home Assistant 2026.9.1 and python-roborock 7.2.3, a real status payload contained
fan_power=102, water_box_mode=235, mop_mode=303. Individual settings decoded as balanced/medium/deep_plus, but the combined mode wasNone(HAunknown). An automation waiting for confirmedvac_and_mopstopped before sending its start command.After applying the same feature-mapping read/write fix locally, the combined mode reported
vac_and_mop, the outgoing combined-mode payload used235, and the automation passed its setting check and started real cleaning. Direct device readback showed cleaning active with no error and the expected motor settings; the cleaning counters increased. The in-between slider path is covered by unit tests on currentmainand was not separately re-run on hardware.Validation
Head merged with
mainat6a0aab0543d6812c3eafa92571605444ab74cdb3(ordinary merge, no rebase or force-push).None == <CleaningMode...>for the 23 positions between the seven representative codes, across three fan settings, with no collection errors. Reverting only the classification line reproduces the same 69 failures.uv run pytest tests/devices/traits/v1/test_status.py -q— 190 passed.uv run pytest -q: 1582 passed, 53 xfailed, 11 deselected on Python 3.11 and on Python 3.14. On the samemaincommit without this PR: 1462 passed, 53 xfailed.uv run pre-commit run --all-files: passed (Ruff, Ruff format, Mypy, Codespell).uv build: source distribution and wheel built.No device/account credentials, raw diagnostic dumps, or deployment scripts are included.
中文说明
概要
关联 #931 和 #930。感谢 @liborplisek 找出枚举别名的根因,感谢 @BlackRockCity 提供命令和状态抓包,也感谢 @frenck 在 #975 里整理的 App 水量区间表。
让带水量滑块的设备在"组合清扫模式"上的读写,和已有的按设备能力处理水量模式的逻辑保持一致:
vac_and_mop(扫拖)和mop(纯拖)发235,不再发别名成员遗留的202。water_mode_name自 fix: map water slide positions to the app's flow ranges #975 起已经在用的同一张 App 区间表来识别。用户在 App 里把滑块停在两个命名档位之间(例如223、248)时,清扫模式现在识别为vac_and_mop/mop,不再是None。设备上报的原始water_box_mode值保持不变,区间解析只在is_water_slide_mode_supported为真时启用。PURE_WATER_FLOW_MIDDLE.code比较的问题(两边都是同一个错误的202,所以一直能过),期望的协议值改成明确写出的整数。新增经公开StatusTrait读写的回归测试,覆盖全部滑块位置、扫/拖选择、可选的拖地路线字段、旧码、枚举输入、能力开关,以及未知或不完整的状态。区间解析怎么工作
get_water_slide_mode_name()和清扫模式识别现在共用一个纯函数_resolve_water_slide_mode(code),它基于现有的_WATER_SLIDE_RANGES,没有再复制一份区间边界。get_water_slide_mode_name()对任何输入的返回值都和改动前完全一致(已对range(-10, 400)内每个整数逐一核对)。滑块设备上报整数水量码时,识别规则是:
200→ 关水 →vacuum(纯扫)221–250→ 该位置所在的 App 区间 →vac_and_mop;风机为纯拖档时为mop201/202/203→vac_and_mop,204→custom,209→smart_mode,220/251/未知值 →None不支持
is_water_slide_mode_supported的设备行为不变,例如223在这类设备上仍识别为None。下发命令仍然发所选模式的标准代表值(扫拖/纯拖发235,纯扫发200),区间解析只用于读取。兼容性与范围
公开的枚举值、选项列表、
WATER_SLIDE_MODE_MAPPING、_WATER_SLIDE_RANGES和面向用户的选项字符串都没有改,使用mode.value的下游无需迁移。本 PR 修的是组合模式的命令和识别路径,不是枚举别名本身的表示问题:WaterModes.PURE_WATER_FLOW_MIDDLE.code和通用的WaterModes.from_code_optional(235)仍受影响。更大范围的"唯一值/显示名"迁移另行处理,所以本 PR 只引用、不关闭 #931。不在本 PR 范围内:滑块设备上
custom/smart_mode选项的暴露(#977)、其他协议族、Home Assistant 自动化策略、登录相关修复。与进行中的 PR #983 的重叠: 两个 PR 都改了
get_water_slide_mode_name()。#983 加了一个SMART_WATER提前返回,本 PR 把这个函数的主体移进了_resolve_water_slide_mode()。后合并的一方需要做一行文本冲突解决:在 helper 里返回WaterModes.SMART_WATER,而不是.value。如果 #983 先合并,我们可以基于它更新本分支。复现与实机证据
在 G30S Ultra 上(Home Assistant 2026.9.1、python-roborock 7.2.3),真实状态里是
fan_power=102, water_box_mode=235, mop_mode=303。单项设置分别解析为 balanced/medium/deep_plus,但组合模式是None(HA 显示unknown)。一个等待确认vac_and_mop的自动化因此在发送启动命令前就停下了。在本地应用同样的读写修复后,组合模式显示
vac_and_mop,下发的组合模式命令用的是235,自动化通过了设置检查并真正开始清扫。直接读设备确认清扫进行中、无报错、电机设置符合预期,清扫计数也增加了。滑块中间位置这条路径在当前main上由单元测试覆盖,没有另外在实机上重跑。验证
分支已与
main的6a0aab0543d6812c3eafa92571605444ab74cdb3普通合并(没有 rebase,也没有 force-push)。None == <CleaningMode...>,没有收集错误。只回退识别那一行,会复现同样的 69 个失败。uv run pytest tests/devices/traits/v1/test_status.py -q,190 个全部通过。uv run pytest -q:Python 3.11 和 Python 3.14 上都是 1582 通过、53 个预期失败(xfail)、11 个按默认标记取消选择。同一个main提交不带本 PR:1462 通过、53 个 xfail。uv run pre-commit run --all-files:通过(Ruff、Ruff format、Mypy、Codespell)。uv build:源码包和 wheel 构建成功。不包含任何设备或账号凭据、原始诊断数据或部署脚本。