fix(clean): room cleaning via clean/start_clean with a parameterized CleanParam (#25, #37)#49
fix(clean): room cleaning via clean/start_clean with a parameterized CleanParam (#25, #37)#49jgus wants to merge 1 commit into
Conversation
Greptile SummaryThis PR fixes room cleaning on Flow firmware by switching
Confidence Score: 5/5Safe to merge — the root cause fix (wrong MQTT topic + incorrect proto schema) is well-understood, live-validated on a Flow 2, and covered by a thorough new test suite (167 tests, all green). The core change is a clean protocol-level fix: wrong topic → right topic, wrong payload schema → correctly reverse-engineered CleanTask. All new dispatch paths (map_id guard, NOT_READY retry, CONFLICT passthrough, whole-house fallback) have explicit tests. Enum value corrections were validated against a live device. The two observations are both cosmetic or low-impact behavior changes that do not affect cleaning correctness. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant HA as HA vacuum entity
participant Client as NarwalClient
participant Robot as Narwal Robot
HA->>Client: start_rooms(room_ids, work_mode, fan, ...)
alt room_ids is empty
Client->>Robot: clean/plan/start (whole-house)
Robot-->>Client: CommandResponse(SUCCESS)
else room_ids given
Client->>Client: check state.map_data.map_id
alt "map_id == 0"
Client->>Robot: get_map
Robot-->>Client: MapData(map_id, rooms, ...)
end
alt map_id still 0
Client-->>HA: CommandResponse(NOT_APPLICABLE)
else map_id available
Client->>Client: _build_start_clean_payload(room_ids, map_id, CleanParam)
Client->>Robot: clean/start_clean (CleanTask protobuf)
Robot-->>Client: CommandResponse
loop up to 3x while NOT_READY and is_docked
Client->>Client: asyncio.sleep(3s)
Client->>Robot: clean/start_clean (retry)
Robot-->>Client: CommandResponse
end
Client-->>HA: final CommandResponse
end
end
Reviews (3): Last reviewed commit: "fix(clean): room cleaning via clean/star..." | Re-trigger Greptile |
|
Thanks — addressed all three points:
|
…CleanParam (sjmotew#25, sjmotew#37) Room cleans were sent to clean/plan/start, but on Flow firmware that is StartWithPlan{planId, mapId} — it starts a saved plan by id and ignores any room payload, so the robot undocked and wandered instead of cleaning the selection. Switch start_rooms() to clean/start_clean (StartClean → CleanTask). Track the active map id (MapData.map_id, get_map field 2.1), which the CleanTask requires. clean/start_clean only works docked; from STANDBY the robot returns a new code 4 (CommandResult.NOT_READY) — retry briefly while docked. Build the CleanParam from named parameters: start_rooms() takes work_mode/fan/water/mop_strength/passes with defaults at the call site (vacuum-and-mop, standard suction/water/mop, single pass). Names and enums match the app's CleanTask proto: WorkMode (= robot_work_mode_*, whose value is CleanTask.taskType), corrected FanLevel/MopHumidity, added MopStrengthLevel; fan_speed labels use the app's user-visible suction names (quiet/standard/strong/super powerful/ultra powerful). Pre-rename fan_speed values (normal/max) remain accepted for back-compat. Validated live on a Flow 2: room clean returns SUCCESS and the robot cleans the selected rooms (confirmed via clean/current_clean_task/get). Both client copies synced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…water / mop strength / passes) Adds Home Assistant controls for the room-clean parameters, backed by a CleanSettings dataclass on the coordinator (the single source the clean-start path reads): - select entities: work mode (Vacuum / Mop / Vacuum then mop / Vacuum and mop), mopping humidity (Slightly dry / Normal / Slightly wet), mop strength (Normal / High); - number entity: cleaning passes (1-3); - the vacuum's fan_speed is threaded through the same settings. Entity labels use the app's user-visible wording. Values persist across restarts via RestoreEntity (RestoreSelect / RestoreNumber / RestoreEntity) — set once and kept. async_clean_segments threads them into start_rooms; water and fan also apply live while cleaning. Built on sjmotew#49 (parameterized start_rooms / WorkMode). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Room cleaning was broken on Flow firmware — selecting rooms sent the robot off the
dock to wander instead of cleaning the selection. This switches to the correct
command and builds the clean parameters from named, reverse-engineered settings.
Fixes #25, #37.
Root cause
start_rooms()sentclean/plan/start, which on Flow firmware isStartWithPlan{planId, mapId}— it starts a saved plan by id and ignores any roompayload. The robot ran its last plan instead of cleaning the selected rooms.
Fix
clean/start_clean→CleanTask{map_id, [CleanItem{ZoneOption, CleanParam, order}], taskType}. Track the active map id (MapData.map_id,get_mapfield 2.1),which the CleanTask requires.
clean/start_cleanonly works docked; from STANDBY the robot returns a new code 4(
NOT_READY) — retry briefly while docked.Parameterized CleanParam
The CleanParam is built from named parameters with defaults at the call site:
Names and enums match the app's
CleanTaskproto:WorkMode(the app'srobot_work_mode_*selector):VACUUM / MOP / VACUUM_THEN_MOP / VACUUM_AND_MOP; its value is theCleanTask.taskTypethe robot executes.FanLevel/MopHumiditycorrected to the robot's real enum values;MopStrengthLeveladded.fan_speedlabels use the app's user-visible suction names:quiet / standard / strong / super powerful / ultra powerful.Enum class names and CleanParam field names are verbatim from the proto; the integer
values are live-validated on a Flow 2.
Changes
narwal_client/(+ embeddedcustom_components/narwal/narwal_client/copy): rewritestart_rooms/_build_start_clean_payload; addWorkMode+MopStrengthLevel,correct
FanLevel/MopHumidity; addMapData.map_idand track it inget_map.custom_components/narwal/const.py:FAN_SPEED_MAP→ the app's user-visible suction labels.Back-compat:
set_fan_speedstill accepts the pre-rename values (normal→ standard,max→ top); they are not offered in the fan-speed list.TOPIC_CMD_PLAN_START(clean/plan/start)and
TOPIC_CMD_CLEAN_TASK(clean/start_clean, was misleadingly…_LEGACY).tests/test_client_rooms.py: cover the CleanTask builder (taskType/mode dispatch,fan/water/strength encoding, settings forwarding) and
start_roomsdispatch(whole-house fallback, missing map id, NOT_READY retry, CONFLICT passthrough).
Testing
pytest tests/— all green (167).selected rooms (confirmed via
clean/current_clean_task/get).