Skip to content

feat(map): retain native Narwal trajectories - #89

Closed
Sean-StarLabs wants to merge 6 commits into
sjmotew:masterfrom
Sean-StarLabs:sean/narwal-native-trails-20260824
Closed

feat(map): retain native Narwal trajectories#89
Sean-StarLabs wants to merge 6 commits into
sjmotew:masterfrom
Sean-StarLabs:sean/narwal-native-trails-20260824

Conversation

@Sean-StarLabs

@Sean-StarLabs Sean-StarLabs commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • decode the rolling native trajectory windows from map/display_map field 2
  • join exact overlapping coordinates into one HA-retained route
  • render only Narwal-native points and keep the sampled-position fallback removed
  • persist the retained route across Home Assistant restarts and terminal pose-only packets
  • clear the prior route whenever a new clean is accepted or confirmed, then build the new route from subsequent native windows

Why

Narwal does not send the complete cleaning route in every display_map packet. A live Flow 2 running v01.09.09.05 capture repeatedly carried a moving 30-point window; a later observed window shared four exact points with its predecessor. Replacing each frame therefore left Home Assistant with only the latest short segment.

The integration joins those robot-recorded windows by exact coordinate overlap. Non-overlapping live windows within one observed session are retained as separate rendered sections, so no connector is invented across missing telemetry. After restart, an active cached prefix is resumed only when the first live window overlaps it; Narwal exposes no cleaning-session identifier, so an unverified prefix is discarded rather than risk joining two different cleans. The integration does not sample robot positions or smooth coordinates. The resulting native route is stored by Home Assistant and retained after the clean finishes until the next clean starts.

A confirmed new-clean transition always clears the old route. The integration does not infer whether a pre-status trajectory packet belongs to the previous or next session; the next native rolling window received after the transition starts the new retained route.

Commit layout

  1. decode and identify native trajectory windows in the client
  2. join, persist, restore, and clear native routes in the coordinator
  3. render only native Narwal trajectories in the camera

Runtime validation

During an active Flow 2 running v01.09.09.05 clean, the persisted route contained 30 points immediately before a Home Assistant restart. After restart it restored that route and grew to 168, then 179, then 183 native points as later robot windows arrived. The robot continued cleaning throughout, and no sampled-position fallback was involved.

Stack

Depends on #87 and #88; #85 and #86 are already merged. This branch is stacked in the fork; until those land, GitHub may show earlier commits in this diff too. The native-trails series is three commits ending at be9009d.

Related

@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch from 65993b1 to ef20ff5 Compare August 27, 2026 15:36
@Sean-StarLabs
Sean-StarLabs marked this pull request as draft August 28, 2026 20:09
@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch 12 times, most recently from feedab7 to 69e2faa Compare August 30, 2026 12:32
@Sean-StarLabs Sean-StarLabs changed the title feat(map): render native Narwal trajectories feat(map): retain native Narwal trajectories Aug 30, 2026
@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch 9 times, most recently from 65c820c to 309fcb4 Compare August 31, 2026 21:03
@sjmotew

sjmotew commented Aug 31, 2026

Copy link
Copy Markdown
Owner

This one now conflicts, and it's my doing — v1.0.6 landed underneath you while the stack was in flight. Here is everything you need so it costs you five minutes rather than an investigation.

The conflict is one file, and it's trivial

tests/test_client.py

That's all of it. We both appended new test classes to the end of the same file, so it's a tail collision with no shared logic — keep both sides. Mine are TestBroadcastDumpLogging and TestDockedRobotIsLeftAlone; yours are your own additions. Nothing in either touches the other's fixtures.

client.py auto-merges, and I checked that it's actually safe

Normally I would not say "it auto-merged" and leave it there — a clean auto-merge is exactly how a landed fix gets silently reverted in this repo, which has bitten us before. So I trial-merged your branch onto master and grepped for every line v1.0.6 added:

v1.0.6 change standalone embedded
elif self.state.is_docked:
Docked and quiet for ...
last_resub_time: float | None = None
_renew_topic_subscription
DUMP %s: %r

All present in both copies after the merge, and your diff doesn't touch the keepalive, wake, or resubscribe paths at all. So client.py is genuinely fine — you don't need to review that merge, only the test file.

What landed in v1.0.6 that's worth knowing

Two things in client.py that interact with this stack:

  1. A docked robot no longer gets wake bursts (Docked robot flaps _robot_awake every ~46s, firing ~1,900 wake bursts a day #90). It turned out the robot has a duty cycle — 30 or 45 s of broadcasts, then 60–124 s of silence, resuming on its own — and a 15 s staleness threshold read every gap as sleep. If any of your dock-task or trail work assumed broadcasts arrive continuously while docked, that assumption was never true; it just looked true because we were poking the robot every 46 seconds.
  2. Subscription renewal now stands on its own rather than riding on the wake burst, and last_resub_time starts at None instead of 0.0. time.monotonic() is system uptime on Linux, so the old comparison silently deferred the first subscription on a host up under 8 minutes.

Point 1 is the one I'd double-check against #89 specifically: your native-trail retention depends on display_map broadcasts, and the cadence of those while docked is now the robot's own rather than one we were manufacturing. Mid-clean is unaffected — the robot broadcasts continuously then, and nothing about the cleaning path changed.

Rebase or merge, your call

git merge origin/master is fine here; you don't need a rebase for a one-file tail conflict, and I'd rather you didn't redo 19 commits over it.

Once it's green again this rejoins the queue behind #85#86#87#88.

Where the stack stands from my side

Everything except this conflict is now waiting on one thing: these are all still marked draft, so I can't merge any of them. Un-draft #85 and I'll land it immediately, then #86, and so on up the stack. Nothing is blocked on review any more.

@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch 3 times, most recently from 51c1df6 to 590207b Compare August 31, 2026 21:44
@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch 13 times, most recently from 108f2cb to a5f5e3e Compare September 1, 2026 13:44
@Sean-StarLabs
Sean-StarLabs marked this pull request as ready for review September 1, 2026 14:14
@Sean-StarLabs
Sean-StarLabs force-pushed the sean/narwal-native-trails-20260824 branch 7 times, most recently from bec75cb to 745a0a0 Compare September 4, 2026 21:59
Make vacuum start honor selected rooms and their profiles while preserving native whole-floor behavior when no rooms are selected.
Make supported_features reflect the commands that are currently valid for the robot and dock state. Cleaning progress, current room, active rooms, charge-to-resume, and task summary now live on the vacuum entity so standard HA cards can use the vacuum contract instead of separate progress/current-room sensors.

Keep robot controls available during compatible dock drying, block starts and unsafe stops during incompatible dock work, and avoid treating off-dock robot telemetry as dock activity. Remove legacy standalone task/status sensor registry entries after their values move onto the vacuum entity or current metric sensors.

Correct suction ordering for five-tier models so Ultra maps below Super while four-tier models keep exposing their top supported level as Super. Compatibility aliases remain accepted for existing automations.
Decode Narwal's rolling display-map coordinate streams without synthesizing robot-position samples. Preserve each window's raw float streams and deterministic signature so higher layers can join exact overlaps.
Join overlapping Narwal trajectory windows, persist the retained route in Home Assistant storage, and clear it only when a new clean is accepted or confirmed. A confirmed new-clean transition always drops the prior route before later native windows are accepted.
Render the route reported by Narwal's display-map stream and remove the sampled-position fallback. Keep coordinate transforms and render caching tied to native trajectory signatures.
@sjmotew

sjmotew commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Merged into master as d56e318 (stack: #87 4a05395#88 84a200d#89 d56e318#91 566491d). GitHub marked this closed rather than merged because the whole stack landed in one push; the commits are on master and ship in v1.0.8 today. Closes #75 — the trail now persists across restarts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cleaning trail does not persist for the whole session (lost when navigating away; app keeps it)

2 participants