@@ -242,6 +242,14 @@ priority decision. `resolveVacSource()` is sticky for saved sources and limits
|
||||
automatic selection to compatible entities on the same HA device; the card
|
||||
adds registry status through the shared `resolveHaBindingStatus()` authority.
|
||||
|
||||
`smoothVacPath()` is the shared pure presentation step for current and previous
|
||||
runs. It consumes calibrated flat plan coordinates and returns typed
|
||||
`move|line|quadratic` commands with a caller-supplied physical radius; the card
|
||||
then applies flat/isometric scene projection and SVG serialization. Each corner
|
||||
uses a quadratic inside the adjacent-segment convex hull, bounded by half of
|
||||
both segment lengths, so the 17.5 cm product limit, exact endpoints and literal
|
||||
subpath gaps are structural rather than renderer-specific accidents.
|
||||
|
||||
Room auto-calibration uses the same shoelace `areaCentroid()` for plan polygons
|
||||
and robot outlines. Residuals are converted through resolved grid pitch and
|
||||
cell centimetres; matrices above the 40 cm threshold remain proposals until an
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Robot-vacuum trails now follow the same recorded points with softly rounded
|
||||
corners instead of a visibly segmented polyline. Current and previous runs
|
||||
use the same bounded curve, preserve telemetry gaps and never deviate by more
|
||||
than 17.5 cm from the recorded route
|
||||
([#209](https://github.com/Matysh/houseplan-card/issues/209)).
|
||||
|
||||
- A robot vacuum that reports its live position no longer freezes the card
|
||||
on a freshly opened page: the map-id lookup ran inside the render cycle
|
||||
and required editor code that a cold tab has not loaded yet, so the very
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
## Не выпущено
|
||||
|
||||
- След пылесоса теперь повторяет те же записанные точки с мягко скруглёнными
|
||||
поворотами вместо заметной ломаной. Текущая и предыдущая уборки используют
|
||||
одну ограниченную кривую, сохраняют разрывы телеметрии и не отклоняются от
|
||||
записанного маршрута более чем на 17,5 см
|
||||
([#209](https://github.com/Matysh/houseplan-card/issues/209)).
|
||||
|
||||
- Робот-пылесос с живой позицией больше не замораживает карточку на только
|
||||
что открытой странице: определение id карты выполнялось внутри цикла
|
||||
отрисовки и требовало код редактора, который холодная вкладка ещё не
|
||||
|
||||
@@ -33,7 +33,7 @@ metadata). Only an explicit owner-approved emergency hotfix may skip this gate.
|
||||
| Furniture | #159 replaces the flat ~30-item picker with a two-level category/variant palette and 56 top-view symbols. The reviewed 77-SVG MIT source pack is vendored under `assets/furniture/houseplan-0.3.0`; plan art stays in the initial View graph, front-view category art stays in the lazy editor graph, and existing saved geometry is unchanged. |
|
||||
| Tests | Four layers: Node unit (`npm test`: frontend pure modules + tooling policy), pure backend (`pytest tests_backend`, runs anywhere), HA-harness backend (same folder, CI only — needs py3.13 + pytest-homeassistant-custom-component), and browser smokes (`demo/smoke_*.mjs`, headless chromium). **Counts are not written down here** — they went stale within two releases while the version line beside them was kept current, which reads as less coverage than exists (review R5-2). Run `npm run inventory` for the current numbers, or read them off the last CI run |
|
||||
| Input support | Owner's rule since 2026-08-08: View and kiosk are fully supported and release-blocking on touch. All three editors are desktop-first; touch editing is best effort and may be awkward, reduced or absent when parity is expensive. `docs/TOUCH-SUPPORT.md` defines the non-negotiable safety floor and documentation/test rules |
|
||||
| Vacuums | Live puck, server-side trails and fit calibration are shipped. The local v1.61 Stage 1 contract in docs/VACUUM.md adds explicit Dreame/XCME/Valetudo coverage, registry-less source selection, capability diagnostics, path-gap preservation and source-health warnings; #205's issue branch resumes one ended same-map run through an inclusive 30-minute station/pause grace. Roomba remains Stage 2 |
|
||||
| Vacuums | Live puck, server-side trails and fit calibration are shipped. The local v1.61 Stage 1 contract in docs/VACUUM.md adds explicit Dreame/XCME/Valetudo coverage, registry-less source selection, capability diagnostics, path-gap preservation and source-health warnings; #205 resumes one ended same-map run through an inclusive 30-minute station/pause grace. #209 renders current and previous trails through the same bounded 17.5 cm rounded-corner curve without changing stored points or gaps. Roomba remains Stage 2 |
|
||||
| Demo stand | **https://demo.houseplan.tech** — public, login `demo`/`demo`, resets to a pristine synthetic home every hour. **https://dev.houseplan.tech** — closed (basic auth), auto-deploys the `dev` branch every 10 min. Host: `ssh -i ~/.ssh/hp_stand hp@135.106.166.146`; layout, seeds and gotchas in the memory note `houseplan-demo-stand`. Since 2026-07-31 the stand covers most of the manual checklist: a scripted robot vacuum (`demo/stand/demo_robot` — Tasshack-shaped map sensor, serpentine run, pre-solved calibration, seeded server trail), Zigbee-style LQI template sensors, hand/auto-triggered leak+smoke alarms, an hvac_action climate marker and working script/scene/automation targets for tap-run. The stand-specific how-to-check guide is **docs/TESTING-DEMO.md** |
|
||||
| Community | **Telegram chat: https://t.me/ha_houseplan** (created 2026-07-27) — the primary user-facing support channel; GitHub issues stay for bugs/features. Link it from any new release notes and posts |
|
||||
| Product scope | `docs/SCOPE.md` is the feature guard rail; `docs/TOUCH-SUPPORT.md` is the input-support contract — check both before accepting interaction work |
|
||||
|
||||
@@ -37,6 +37,26 @@
|
||||
мутантам с браузерным гвардом; компиляция тестов в worktree стартует с
|
||||
тёплого `test-build/` основного дерева.
|
||||
|
||||
## Vacuum trail smoothing (#209)
|
||||
|
||||
- [ ] Pure `smoothVacPath` tests prove exact endpoints, separate subpaths,
|
||||
degenerate/reversal fallbacks, the 17.5 cm sampled deviation bound and
|
||||
the 64-subpath/4000-point `≤2N` command budget
|
||||
[unit: `test/vacuum.test.mjs`].
|
||||
- [ ] The production bundle renders current and previous runs through paired
|
||||
case/core `<path>` elements with quadratic commands, unchanged source
|
||||
authority/modes, live-target trim and puck tip
|
||||
[auto: `demo/smoke_vacuum.mjs`].
|
||||
- [ ] Flat and dormant-Iso projections retain the same curved live layer on
|
||||
touch and across HA updates [auto: `demo/smoke_isometric_live_touch.mjs`].
|
||||
- [ ] `vacuum-trail-smoothing-dark` contains two current subpaths plus a stored
|
||||
previous run; its semantic guard requires two `M` sections, quadratic
|
||||
commands and byte-identical case/core geometry before PNG comparison.
|
||||
The baseline is accepted only from reviewed Linux CI
|
||||
[golden: `demo/golden/matrix.mjs`].
|
||||
- [ ] Replacing the quadratic corner with a straight vertex makes the focused
|
||||
unit guard red [mutation: `vacuum-trail-smoothing-disabled`].
|
||||
|
||||
## Stable wall-segment identity (#282)
|
||||
|
||||
- [ ] Wall junction limits (#329): drawing refuses an apex under 15°, a seventh
|
||||
|
||||
@@ -1414,6 +1414,9 @@ Map Extractor, dreame-vacuum (Tasshack) и Valetudo-подобные камер
|
||||
- Позиция старше 60 секунд визуально считается устаревшей.
|
||||
- Разрывы integration path сохраняются отдельными участками и не соединяются
|
||||
ложной линией. Хранятся максимум 64 рисуемых участка и 4000 точек.
|
||||
- Текущий и предыдущий следы автоматически показываются плавными кривыми. Они
|
||||
сохраняют исходные концы и разрывы маршрута и отклоняются от записанной
|
||||
ломаной не более чем на 17,5 см независимо от масштаба и вида плана.
|
||||
- Для текущего пути приоритет таков: путь интеграции → серверный текущий run →
|
||||
локальный буфер. Пустой или одноточечный участок приоритет не перехватывает.
|
||||
- Остановка, пауза или визит на базу сразу скрывают текущий след в режиме
|
||||
|
||||
@@ -106,6 +106,13 @@ two points are discarded before limits are applied. The newest 64 drawable
|
||||
subpaths are kept, with at most 4000 total points; both endpoints of every kept
|
||||
subpath survive deterministic proportional thinning.
|
||||
|
||||
Current and previous trails use the same bounded rounded-corner curve. The
|
||||
curve preserves every subpath endpoint and never leaves the recorded polyline
|
||||
by more than 17.5 cm in physical plan coordinates. Smoothing happens after
|
||||
vacuum calibration and before flat/isometric projection, so zoom, viewport,
|
||||
DPR and projection do not change that limit. The live target is still trimmed
|
||||
before rendering, and smoothing never bridges an integration data gap.
|
||||
|
||||
| Display mode | While moving | After movement stops |
|
||||
|---|---|---|
|
||||
| `never` | Hidden | Hidden |
|
||||
|
||||
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 327 KiB After Width: | Height: | Size: 277 KiB |
|
Before Width: | Height: | Size: 289 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 290 KiB After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 116 KiB |
@@ -2,8 +2,8 @@
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"chromium": "151.0.7922.34",
|
||||
"oxipng": null,
|
||||
"sourceFingerprint": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"oxipng": "oxipng 10.2.0",
|
||||
"sourceFingerprint": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"captureScriptSha256": "fe76c8e2e27501e9a377d7aa15dd6cba6a018d55c07deb602dbee097f0a0a5ba",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -15,8 +15,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "36223106c073f07d8cc3ecf8eaab37192ebb2687daba65c5c21047d0b7890de0"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "f8c9541c9d7fde462d0efba63dff70944dc03df76ce988eecaf2b269e2863a96"
|
||||
},
|
||||
"view-touch": {
|
||||
"file": "02-view-touch.png",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "a4aa3af48578ee41594a9b1a6e98b4d39f3324a949a9fd9e63d5854576d5db85"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "21c6fe7d79ff5c878ade8e98a64cc90dfd7bcc66338c864fb5a0bd411471313d"
|
||||
},
|
||||
"space-create": {
|
||||
"file": "03-space-create.png",
|
||||
@@ -37,8 +37,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "0dc024726327f60f4a9ceaf3044381691f81f1090af81d1812e870f22d9343ba"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "f6d190f0b2ac9125cea68aea2ebbcdf9a7081ae2a3565ff253fb1ed0c4a56483"
|
||||
},
|
||||
"room-contour-close": {
|
||||
"file": "04-room-contour-close.png",
|
||||
@@ -48,8 +48,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "44cfaa95bd51e2cd628400e28db0ad8b2f0cd904385845bd402494f3f5c0d93c"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "ca8bb143d0d6679ff09f8e9c1f5ad68b2ca7cfd96a4740a4a650c251f55dfba5"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
"file": "05-plan-context-tray.png",
|
||||
@@ -59,8 +59,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "e0662429b423fb74151b583dcc2c8635b001b637d03bbf7a6b16aec46399c3f8"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "06b67c5108f9ee29a226cc2920484ccffe0c79840aec09721072b25b91ef8f03"
|
||||
},
|
||||
"device-editor": {
|
||||
"file": "06-device-editor.png",
|
||||
@@ -70,8 +70,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "d0ffd31ce80bfde21ab75da356a5fc1af38246f2b301030880320620c228d89d"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "9e435a6fe89564b9215b82a61fb7eae998266dd05483524ffa84160c35630e0c"
|
||||
},
|
||||
"device-display-preview": {
|
||||
"file": "06-device-display-preview.png",
|
||||
@@ -81,8 +81,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "2cdabae1f89c3286e4fac0ce30f757ee1690b707ab8a5488748b7cd420626160"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "cc5abe1b3364bf9812bea6ea5cfa84f35120ff9639ed3c4c92958cb646a8caf7"
|
||||
},
|
||||
"background-editor": {
|
||||
"file": "07-background-editor.png",
|
||||
@@ -92,8 +92,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "30147bb00a90eea7136b4cee30995f6e6a9217b5132f3e8d3ad7471413b1af8a"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "7e308a2b105fa6a9f788449ca30b8183375a32f0d0f8726f4a131e4f35527f57"
|
||||
},
|
||||
"room-card": {
|
||||
"file": "08-room-card.png",
|
||||
@@ -103,8 +103,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "029a3e69ec647a8a370d99e6bb7f9225833c526739076022f6b52ba54bff30ea"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "f1bc10b478f7afc68e70cb4c37148f680b0bbd41d50a7d63a21067fc952ff134"
|
||||
},
|
||||
"device-info": {
|
||||
"file": "09-device-info.png",
|
||||
@@ -114,8 +114,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "0896c482848c70ed7071b4e2396294fd83072352403a859447b53fc3c10cc6ae",
|
||||
"imageSha256": "dd492f53150b7149085daada5cce9eeae9bde9e7ea1d86679a54b3041f72f517"
|
||||
"sourceSha256": "4b183589451e9a238ceeab91d847fcc1806215e85ee64f2c27b4b1cb167f6181",
|
||||
"imageSha256": "2634cd7ead5720ce46ea4d6fa8f31006b740c520a73ddc97afe9a6d9d3b49778"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||