v1.60.1-beta.1: harden editing and device state

This commit is contained in:
Matysh
2026-08-07 14:19:02 +03:00
parent 6db9eb0a66
commit fe5f5b6a24
31 changed files with 1312 additions and 373 deletions
+5 -1
View File
@@ -465,7 +465,11 @@ hash falls back to the default.
passive readings as the final fallback. `_visualSamples` consumes the full
result; `primaryEntity` only selects its first member where a single action
target is required. Integration option switches can no longer make an
otherwise healthy device working or unavailable merely by list order.
otherwise healthy device working or unavailable merely by list order. For
`climate`, an explicit `hvac_action` is authoritative; only integrations that
omit it fall back to a current non-off state advertised by `hvac_modes` (or a
standard HA HVAC mode), so `idle` never becomes yellow while mode-only
entities still report actual operation.
- **Resolved light sources** (UX-12): `resolvedLightSources(hass, devices,
room?)` is the only light-membership resolver. Per marker the precedence is
`controls[]` -> the primary controllable entity when `is_light` is set ->
+30
View File
@@ -1,5 +1,35 @@
# Changelog
## v1.60.1-beta.1 — 2026-08-07
- Climate markers whose integrations omit `hvac_action` now fall back to the
current non-off HA mode advertised in `hvac_modes`, so enabled air
conditioners regain their yellow working plate. A present action remains
authoritative, therefore `hvac_action: idle` stays neutral.
- Room settings now opens at the medium dialog width. Long radio labels and
source names wrap or ellipsize within the content area, eliminating the
horizontal scrollbar while retaining responsive mobile sizing.
- Erase now treats a text label as one atomic decor object across its full
bounding box. Clicking between glyphs or on its selection glow can no longer
remove only the apparent outline; an empty-canvas miss is a true no-op.
- Space tabs, View/editor changes and switches between editors now use one
short, subtle transition. Editor controls expand and collapse smoothly, and
reduced-motion preferences still disable all navigation motion.
- While drawing a room outline, Ctrl/Cmd+click now closes the last point back
to the first without adding another vertex. Closure requires at least two
existing edges and refuses degenerate or self-intersecting contours.
- Editor Undo/Redo shortcuts now use layout-independent keyboard codes, so
Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z and Ctrl/Cmd+Y work with non-Latin layouts too.
Focused text and number fields retain their native browser history.
- Closed the v1.60.0 follow-up audit: reconnecting during resume settle can no
longer strand the plan veil; legacy self-controlled switches retain their
light-source intent and migrate to `is_light`; colour/opacity pickers use the
browser top layer and flip/clamp inside small dialogs; Optimize repairs
out-of-range `cell_cm` while preserving unknown/duplicate control targets;
entity-bound legacy relays discard only their exact self-control and keep
explicitly added sibling light targets; wall SVG fallbacks now use valid
literal colours.
## v1.60.0 — 2026-08-07
- **Audit hardening.** Deleting one virtual marker no longer removes its
+32
View File
@@ -6,6 +6,38 @@
> **Правило проекта:** оба файла пополняются в одном коммите с самим
> изменением — как и остальная документация (см. docs/STATUS.md).
## v1.60.1-beta.1 — 2026-08-07
- Climate-маркеры интеграций без `hvac_action` теперь используют текущий
включённый режим из `hvac_modes`, поэтому работающий кондиционер снова имеет
жёлтую подложку. Если action присутствует, он остаётся приоритетным:
`hvac_action: idle` по-прежнему нейтрален.
- Настройки комнаты теперь открываются в диалоге средней ширины. Длинные
подписи вариантов и имена источников переносятся или сокращаются внутри
окна, поэтому горизонтального скролла больше нет, в том числе на мобильных.
- «Стереть» теперь воспринимает текстовую надпись как единый объект по всей её
рамке. Клик между буквами или по подсветке выделения больше не может визуально
удалить только «обводку»; промах по пустому холсту ничего не меняет.
- Переключение пространств, вход и выход из редакторов, а также переходы между
редакторами получили единую короткую плавную анимацию. Панель инструментов
раскрывается и закрывается без скачка; при `prefers-reduced-motion` анимации
по-прежнему отключены.
- При рисовании контура комнаты `Ctrl`/`Cmd` + клик теперь замыкает последнюю
точку на первую, не добавляя новую вершину. Нужны минимум две уже нарисованные
грани; вырожденный или самопересекающийся контур не замыкается.
- «Отменить»/«Повторить» в редакторах теперь используют независимые от раскладки
коды клавиш: `Ctrl`/`Cmd` + `Z`, `Ctrl`/`Cmd` + `Shift+Z` и `Ctrl`/`Cmd` + `Y`
работают и при русской раскладке. В полях ввода сохраняется нативная история.
- Закрыты замечания повторного аудита v1.60.0: переподключение во время resume
больше не оставляет план под вечным veil; старые self-controls выключателей
сохраняют роль источника света и мигрируют в `is_light`; выбор цвета и
прозрачности вынесен в верхний слой браузера с переворотом/ограничением внутри
мобильных диалогов; оптимизация исправляет `cell_cm` вне диапазона, но не
удаляет неизвестные или повторяющиеся controls; у entity-привязки старого
реле удаляется только её точный self-control, а явно добавленные соседние
источники света сохраняются; SVG-fallback стен стал валидным буквальным
цветом.
## v1.60.0 — 2026-08-07
- **Исправления по аудиту.** Удаление одного виртуального маркера больше не
+1 -1
View File
@@ -33,7 +33,7 @@ device state or Home Assistant actions.
| Oval | Drag its bounding box; `Shift` makes a circle | `R` for a circle, `Rx × Ry` for an oval | bounding size, angle, contour and optional fill |
| Text | Click to open the text form | the saved label is selected immediately | content, HA variables, colour/opacity, physical size and angle |
| Furniture | Pick a symbol, then click its centre | wall magnet unless `Shift` is held | size, angle and contour style; the common frame preserves ratio unless `Shift` is held |
| Erase | Click a decor object | confirmation dialog, then removal | Undo restores it |
| Erase | Click a decor object; text uses its whole logical bounding box, including spaces between glyphs | confirmation dialog, then atomic removal of the whole object | A miss changes nothing; Undo restores a removed object |
The editor always opens on **Select**. If the space has an image, the Plan
backdrop tool appears next to Select but is never armed implicitly.
+8
View File
@@ -147,6 +147,14 @@ cancelled or one-hour-timed-out Validate withholds the asset. Bump the version
everywhere in sync: `src/houseplan-card.ts` (CARD_VERSION), `package.json`,
`custom_components/houseplan/manifest.json`, `custom_components/houseplan/const.py`.
Local release gates are deliberately different. A pre-release runs
`npm run build` plus only the unit tests and browser smokes selected for the
changed surfaces; record the exact selection in the release handoff. A stable
release runs the complete local frontend, backend and smoke gates before its
tag is created. The exact-SHA Validate required by `release.yml` remains in
force for both and can run a broader matrix automatically; the local policy
does not weaken the publication guard.
## Reproducible scripts (data)
- Extracting the geometry/backgrounds from the prototype and generating `src/data/*` — see the commit
+18 -4
View File
@@ -110,19 +110,33 @@ source precedence is (`_visualSamples` / `_actEntity`):
1. the device's **cover**, when the marker's tap action is explicitly
«Открыть/закрыть» (`tap_action: 'cover'` — `coverEntityOf`, the same helper
and the same entity the tap drives). It wins over EVERYTHING below;
2. the marker's **resolved light sources** (`resolvedLightSources`): bound
`controls` first (other targets only: an `entity:*` marker's bound entity and
a `device:*` marker's child entities are excluded), otherwise its primary controllable entity when
`is_light` is set, otherwise automatic `light.*` only when `light` is the
2. the marker's **resolved light sources** (`resolvedLightSources`): external
`controls` plus its own primary controllable entity when `is_light` is set
(an `entity:*` marker's bound entity and a `device:*` marker's child entities
are excluded from the external list), otherwise automatic `light.*` only when `light` is the
device's resolved functional role. An auxiliary LED/display light on a
media player or appliance does not turn the whole marker into a lamp. This exact set also feeds
Glow, Light fill, room light stats and group toggle;
For compatibility, a pre-v1.60 marker that lists its own `switch.*` in
`controls` is interpreted as `is_light`. Marker Save converts either binding;
Optimize Plans can convert the losslessly identifiable `entity:switch.*` case
(a `device:*` marker needs the HA registry and is therefore left to Save).
External controls remain additive, so migration does not change Glow, Light
fill or room statistics.
3. otherwise the device's **resolved state role**
(`resolvedDeviceStateEntities`): functional device domains first, then
semantic binary signals, then switches, then passive readings together.
`primaryEntity` is only the first entity of this same set for actions which
require one target; it no longer defines marker availability by itself.
For `climate.*`, a real `hvac_action`/equivalent action remains authoritative:
`idle` stays neutral even while the selected mode is `heat`. If the integration
does not expose an action at all, the current non-off state is matched against
HA's `hvac_modes` (plus the standard modes) and used as the enabled/working
fallback. This keeps mode-only air conditioners visible without overriding a
more precise idle signal when one exists.
Rule 1 was added 2026-08-04 on the owner's report: his Aqara «Roller shade
driver E1» curtains ship the `cover.*` hidden by the integration and a visible
`switch.*_reverse_direction`, so `primaryEntity` picked the service switch —
+8 -6
View File
@@ -15,11 +15,11 @@
| Item | State |
|---|---|
| Version | **v1.60.0** everywhere (manifest, const.py, package.json, CARD_VERSION) — stable release of the unified Background editor, true device deletion and the complete beta audit hardening. Stable publication fast-forwards `main` to the exact tested `dev` commit and uses `prerelease=false` |
| Version | **v1.60.1-beta.1** everywhere (manifest, const.py, package.json, CARD_VERSION) — pre-release with the v1.60.0 follow-up audit fixes, smoother editor navigation, safer room/decor editing, responsive room settings and the climate mode fallback. The tag points at `dev`; `main` remains on v1.60.0 |
| Workflow | Owner's rule since 2026-08-05: ordinary fixes/features are made **locally, without tests and without commits**. A requested pre-release gets the full tests/build/smokes, one tested `dev` commit/tag and a GitHub Release with `prerelease=true`; `main` stays untouched. A requested stable release gets the same full gate, then `main` is fast-forwarded to the exact tested `dev` SHA and the GitHub Release uses `prerelease=false`. Nothing is copied to the home instance by hand |
| Workflow | Owner's rule since 2026-08-07: ordinary fixes/features are made **locally, without tests and without commits**. A requested pre-release gets a production build plus the smallest targeted unit/smoke set covering the changed surfaces, one tested `dev` commit/tag and a GitHub Release with `prerelease=true`; `main` stays untouched. The complete local frontend/backend/smoke gate runs only before a stable release, after which `main` is fast-forwarded to the exact tested `dev` SHA and the GitHub Release uses `prerelease=false`. Nothing is copied to the home instance by hand |
| GitHub | https://github.com/Matysh/houseplan-card — `main` carries stable releases; pre-release tags may point directly at `dev`. Work lands on `dev` and is merged into `main` for a stable release, so `dev` is normally equal to or ahead of `main`, never behind. Push via SSH key `ha_jb` (remote git@github.com:…); API releases via the fine-grained PAT in `~/.git-credentials` (Contents R/W, issued 2026-07-23) |
| CI | v1.60.0 uses the full local release gate; exact counts are recorded by `npm run inventory` and the test logs rather than copied here. Native Windows cannot start the current HA pytest plugin (`fcntl` is Unix-only), so the exact-SHA Ubuntu Validate remains mandatory: `release.yml` withholds the asset until every matching run finishes green; GitHub Validate and the release asset are verified after the tag is pushed |
| CI | v1.60.1-beta.1 uses the targeted local pre-release gate; exact commands belong in the release handoff rather than this snapshot. The exact-SHA Ubuntu Validate remains mandatory and may run the broader CI matrix automatically: `release.yml` withholds the asset until every matching run finishes green. Stable releases additionally require the complete local frontend/backend/smoke gate before tagging |
| HACS | Custom repository works. **Inclusion PR: hacs/default#9004** — open, valid, labeled, mergeable clean, never drafted. Queue: 1212 open, 835 older than ours. Merge rate COLLAPSED: 75 in July but almost all in the first decade, 0 in the last week (checked 2026-07-29) — maintainers process in rare bursts; ETA unknowable, months at best. Nothing actionable on our side |
| Home instance | ha.jbstudio.pro (SSH port **22222**, key `ha_jb`; HA config root is `/mnt/data/supervisor/homeassistant` — `/config` does NOT exist in this SSH environment), last direct copy was **v1.57.0**; from v1.58.0 on it updates itself through HACS by tag (no scp) |
| Localization | UI en/ru (src/i18n/*.json), everything user-visible localized incl. kiosk popover |
@@ -72,9 +72,11 @@
the binding to Add. Deleted devices are absent from every plan aggregate and
linked presentation; layout/files/trails are cleaned and stale layout writes
are rejected.
- **Yellow = working right now** (v1.51.0): climate by hvac_action, service
switches can no longer become primary, glow pool and icon share one
condition. Editor gestures on touch (pinch/pan) landed the same release.
- **Yellow = working right now** (v1.51.0): climate uses `hvac_action` when
available and falls back to a current advertised non-off HVAC mode only when
the integration omits the action; service switches can no longer become
primary, and glow pool and icon share one condition. Editor gestures on touch
(pinch/pan) landed the same release.
- **Unified device status/activity** (v1.59.0-beta.10, 2026-08-05): three display
modes (Icon / Icon + activity / Value), one semantic resolver for yellow
actual work, orange open/unlocked, unavailable and always-red alarms;
+4 -2
View File
@@ -1,8 +1,10 @@
# Manual testing checklist
> **Policy:** this checklist is updated **in the same commit** as any functional
> change (like CHANGELOG.md). Every release: run at least the smoke column on the
> synthetic demo (`demo/`), and the full list before major releases. Items marked
> change (like CHANGELOG.md). For a pre-release, build the production bundle and
> run the smallest unit/smoke subset that covers its changed surfaces. Run the
> complete local frontend, backend and smoke gates only before a stable release.
> The exact-SHA GitHub Validate remains mandatory for publication. Items marked
> `[manual]` are covered by unit tests or the headless smokes in `demo/` — they still
> deserve an occasional eyeball. File every failure as a GitHub issue before fixing.
+9 -6
View File
@@ -230,7 +230,9 @@ title: План дома
2. Выберите **Контур комнаты**.
3. При необходимости укажите толщину новых стен справа от кнопки. `0`/пусто создаёт тонкую осевую границу.
4. Поставьте минимум три точки по сетке.
5. Замкните контур кликом по первой точке.
5. Замкните контур кликом по первой точке или `Ctrl` + кликом в любом месте.
Быстрое замыкание доступно после двух нарисованных граней и не сработает,
если замыкающая стена создаёт самопересечение.
6. В диалоге задайте название и выберите свободную HA-зону либо сохраните без зоны.
Во время рисования показываются длина сегмента и угол. Углы, кратные 45°, выделяются. Новая комната не может частично перекрывать другую, но полностью вложенная «островная» комната поддерживается.
@@ -464,7 +466,7 @@ House Plan читает реестры устройств, сущностей и
| Вид | Что означает | Примеры |
|---|---|---|
| Красная авария | Критическое событие; показывается даже при выключенных живых состояниях | Дым, газ, CO, протечка, tamper/problem/safety, сирена `on`, охранная панель `triggered` |
| Жёлтая подложка | Устройство сейчас выполняет работу | Свет/реле/вентилятор/увлажнитель `on`; climate реально heating/cooling; vacuum cleaning/returning; script on; техника washing/drying/etc. |
| Жёлтая подложка | Устройство сейчас выполняет работу | Свет/реле/вентилятор/увлажнитель `on`; climate реально heating/cooling либо включён по HVAC-режиму, если action недоступен; vacuum cleaning/returning; script on; техника washing/drying/etc. |
| Оранжевая подложка | Физически открыто/разблокировано | Датчик двери/окна/гаража `on`, замок unlocked/open, клапан open/opening/closing |
| Бледный маркер | Данные недоступны либо медиаплеер выключен | Все рабочие сущности маркера `unknown`, `unavailable` или отсутствуют; `media_player.* = off` |
| Нейтральный | Нет аварии, работы и открытого состояния | Выключено, закрыто, idle/standby/docked и т. п. |
@@ -480,7 +482,7 @@ House Plan читает реестры устройств, сущностей и
| Событие | Около 3.3 секунды | Motion/vibration/sound при срабатывании; открытие контакта; button/event при изменении; ручной запуск сценария из карточки |
| Присутствие | Пока состояние активно | Binary sensor с классом occupancy/presence |
| Переход | Пока идёт движение; при мгновенном переходе около 3.3 секунды | Cover opening/closing, lock locking/unlocking, valve opening/closing, moving sensor, vacuum returning |
| Работа | Пока устройство работает | Свет, switch, fan, humidifier, climate action, vacuum cleaning, script и известные рабочие состояния техники |
| Работа | Пока устройство работает | Свет, switch, fan, humidifier, climate action (либо включённый HVAC-режим при отсутствии action), vacuum cleaning, script и известные рабочие состояния техники |
Цвет и размер кольца можно изменить для конкретного маркера. Если цвет не задан, RGB-свет может передать кольцу свой текущий цвет.
@@ -518,7 +520,7 @@ House Plan читает реестры устройств, сущностей и
| `cover.*` garage/door/gate | Нейтральный | Переход во время движения | Закрыто/открыто | Только карточка; Open/close намеренно не предлагается |
| `lock.*` | Оранжевый при unlocked/open | Переход при locking/unlocking | Замкнут/открыт | Карточка; Toggle запрещён |
| `valve.*` | Оранжевый при open/opening/closing | Переход при opening/closing | Обычно нет | Карточка; Toggle можно выбрать явно |
| `climate.*` | Жёлтый только при реальном heating/cooling/working и т. п. | Работа по `hvac_action`/аналогичному атрибуту | Нет | Внутренняя карточка |
| `climate.*` | Жёлтый при реальном heating/cooling/working; если интеграция не отдаёт action — пока включён HVAC-режим | Работа по `hvac_action`/аналогичному атрибуту, иначе по режиму из `hvac_modes` | Нет | Внутренняя карточка |
| `media_player.*` | Нейтральный при любом включённом/транспортном состоянии; приглушённый при `off`, как при `unknown`/`unavailable` | Нет: `playing`, вспомогательная подсветка и служебные переключатели не считаются работой | Нет | Внутренняя карточка |
| `vacuum.*` | Жёлтый при cleaning и returning | Работа при cleaning, переход при returning | Нет | Внутренняя карточка; движущийся puck открывает HA more-info |
| `script.*` | Жёлтый, пока `on` | Работа, пока выполняется | Нет | Внутренняя карточка или явный Run |
@@ -536,7 +538,7 @@ House Plan читает реестры устройств, сущностей и
| Световые источники | Включённые лампы и отмеченные реле | Дом затемняется, вокруг источников рисуются световые пятна | Остаётся базовая темнота |
| Нет | — | Прозрачная комната/только граница | — |
| Zigbee signal | Средний LQI устройств HA-зоны | Градиент от красного (≤40) до зелёного (≥180) | Без заливки |
| Свет | Единый набор видимых источников комнаты: `controls` → «Это источник света» → `light.*` | Цвет «включено», «всё выключено» или «нет источников» | Цвет «нет источников», если его прозрачность >0 |
| Свет | Единый набор видимых источников комнаты: внешние `controls` + собственный источник по флагу «Это источник света»; автоматические `light.*` — fallback | Цвет «включено», «всё выключено» или «нет источников» | Цвет «нет источников», если его прозрачность >0 |
| Температура | Источник комнаты или среднее датчиков | Холодно ниже минимума, комфорт между границами, жарко выше максимума | Без заливки |
Новая вручную созданная область по умолчанию предлагает «Световые источники». Старые планы без сохранённого режима остаются без заливки.
@@ -774,7 +776,8 @@ icon_size: 2.5
| Операция | Что меняется |
|---|---|
| Миграции модели | Старые, однозначно преобразуемые поля переводятся в текущий формат |
| Миграции модели | Старые, однозначно преобразуемые поля переводятся в текущий формат; для `entity:switch.*` собственный switch в старом `controls` становится флагом «Это источник света» (для `device:*` это делает сохранение настроек устройства, где доступен реестр HA) |
| Масштаб сетки | Некорректный старый `cell_cm` приводится к допустимому диапазону 0,1–1000 см |
| Комнаты | Вершины округляются к сетке |
| Декор и мебель | Положение и размеры округляются к сетке |
| Устройства и подписи комнат | Позиции округляются к сетке |