From 831e694f830ceeb8fb1458be72d2e283a9560034 Mon Sep 17 00:00:00 2001 From: Matysh Date: Fri, 31 Jul 2026 09:05:38 +0300 Subject: [PATCH] docs: the live-vacuum spec, approved scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The base marker never moves — it is the dock. A separate round puck (no badge plate, soft pulse) drives the plan while cleaning and dissolves into the base on docking. All three Tier-A adapters and the trail ship in P1; commands are out entirely. --- docs/VACUUM.md | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 docs/VACUUM.md diff --git a/docs/VACUUM.md b/docs/VACUUM.md new file mode 100644 index 0000000..7a469d3 --- /dev/null +++ b/docs/VACUUM.md @@ -0,0 +1,126 @@ +# Live robot vacuums on the plan — the spec (source of truth) + +Status: approved by the owner 2026-07-31. Scope decisions final: all +three Tier-A adapters in P1, the trail ships in P1, the marker's placed +position IS the dock, and tap-to-clean is out — display only, no +commands (owner: «не нужно вообще»). + +## Principle + +The device marker «Пылесос» NEVER moves: it stands where the user +placed it — that is the base/dock — with its normal badge, states and +tap actions. While the robot cleans, a SECOND visual appears: a round +puck (the vacuum icon in a circle), no badge plate, with a soft +pulse, driving around the plan on live coordinates. Owner's exact +wording: «Иконка движущегося пылесоса должна быть круглой, без +подложки и с легкой пульсацией. Основное устройство "Пылесос" при этом +остается всегда на своем месте (база)». The puck is not clickable UI +chrome duplicating the device — a tap on it opens the same more-info as +the base marker. When the robot docks, the puck drives home and +dissolves into the base marker. + +## Data tiers (auto-detected, zero user input) + +- **Tier A — coordinates + own calibration data.** `vacuum_position + {x,y,angle}` (+ `calibration_points`, rooms, sometimes `path`): + Xiaomi Cloud Map Extractor, dreame-vacuum (Tasshack), Valetudo camera + (sca075). All three ship in P1. +- **Tier B — bare coordinates.** Roomba core (`position {x,y,theta}`), + raw Valetudo MQTT, template sensors. Works after manual calibration. + P3. +- **Tier C — current room only.** `current_room` / `current_segment`. + The room being cleaned gets a soft fill pulse + a 🤖 badge in the + room card; no puck. Segment→room matched by name, manual override in + the dialog. +- **Tier D — nothing.** Today's behaviour; yellow badge on the base + marker while cleaning per the «yellow = working right now» principle. + +Tiers degrade gracefully: coords gone → room highlight; that gone too → +just the base marker. + +## Coordinate binding + +Affine transform (translate+rotate+scale+mirror), 6 numbers, least +squares over ≥3 point pairs. Stored per robot map: +`marker.vacuum.calibration[map_id]` — multi-floor robots get one matrix +per map; an active map without a matrix falls back to Tier C. + +- **Path 1, auto-calibration by rooms (the default):** Tier-A adapters + expose the robot's room list with coordinates; our rooms carry HA + area bindings. Match by name, take centroids of ≥3 matches, solve, + show a live preview («робот сейчас здесь») — one click to confirm. +- **Path 2, manual 3-point wizard (Tier B or when auto fails):** pause + the robot somewhere recognisable → drag the ghost puck to the true + spot → next; three points in different corners, live preview, done. +- Residual over ~40 cm → warn and ask for a fourth point. Mirrored maps + are covered by the affine automatically (negative determinant). + +## Puck behaviour + +Appears when the robot leaves `docked` AND live coords flow; CSS +interpolation ~1.2 s between updates; a data gap over 10 s teleports +without animation (no gliding through walls on sparse cloud updates). +Soft pulse always while visible (respects prefers-reduced-motion: the +pulse freezes, position still animates). A small heading wedge rotates +by `angle` on the puck rim; no angle — no wedge. Size: same --icon-size +system as devices, circle, transparent background, no badge plate. +Stale coords (>60 s while «cleaning»): puck freezes and dims. On +`docked`/`idle`-at-base the puck rides home and fades out. Hidden +markers render neither base nor puck (general hidden rules). Works in +the full card, static card and kiosk; in editors no puck — the base +marker is edited as usual. + +## Trail (ships in P1) + +- Integration `path` when available (Map Extractor) — transform and + draw as-is, includes history from before the card was opened. +- Otherwise self-recorded: client-side ring buffer, ~600 points with + Douglas-Peucker thinning, one SVG polyline. +- Style fixed (translucent accent line), no styling options. Lifecycle: + appears on cleaning start, lives until dock + 10 min, dissolves; + `docked → cleaning` clears the old trail. Ephemeral, never stored. +- Marker option «Показывать след уборки», on by default where data + exists. + +## Setup UX + +A «Живая позиция» section in the device dialog, vacuum markers only: +status line (which source was found / room-only / nothing), one button +(«Настроить автоматически» for Tier A, «Калибровка по трём точкам» for +Tier B), three checkboxes (live position / trail / room highlight, all +on), and for multi-map robots a per-map calibration status list. The +source entity is discovered via the device registry — no YAML, no +entity pickers. + +## Storage & validation + +`marker.vacuum: { live, trail, room_highlight, source, calibration: +{[map_id]: [6 numbers]}, segment_map: {[segment]: room_id} }` — all +optional (old configs stay valid), matrices are 6 finite numbers, +backend-validated. Calibration is server-side state shared by every +screen, like the whole plan. + +## Cases covered explicitly + +Two vacuums (independent markers, calibrations, pucks); one robot on +two floors (maps ↔ spaces, the puck only renders in the space whose map +is active); robot outside the plan (±4 canvas bounds allow it, trail +clipped by viewport); integration restart changes map_id (rebind by +room-list match, else ask to recalibrate); user redraws rooms (the +matrix does not depend on rooms); demo stand gets a scripted synthetic +robot as the showcase. + +## Out of scope + +Commands of any kind (owner decision: display only) — no tap-to-clean, +no zone sending. No-go zones, cleaned-area polygons, cleaning history, +multi-robot collision avoidance — v2 candidates. + +## Phases + +- **P1:** adapter framework + all three Tier-A adapters + + auto-calibration by rooms + manual 3-point wizard + the puck + + heading wedge + trail (both sources). +- **P2:** Tier C room highlight + the demo-stand scripted robot. +- **P3:** Tier B zoo (Roomba, raw Valetudo MQTT), Deebot, multi-map + polish by feedback.