docs+publish prep: docs/ (architecture, development, changelog, roadmap), CI validate (hacs action + hassfest + build sync check), brand icon, LICENSE

This commit is contained in:
JB
2026-07-04 10:30:40 +03:00
parent 40540e8673
commit 1d576164f4
8 changed files with 311 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
# Архитектура House Plan
Обновлено: 2026-07-04 (v1.2.2). Репозиторий = HACS-интеграция (категория **Integration**),
которая содержит и бэкенд (`custom_components/houseplan`), и Lovelace-карточку (`src/``dist/`).
## Состав
```
houseplan-card/
├─ src/ # исходники карточки (TypeScript + Lit 3)
│ ├─ houseplan-card.ts # карточка: рендер, состояния, drag, tooltip, sticky-шапка
│ ├─ editor.ts # GUI-редактор конфига (ha-form + селекторы)
│ ├─ rules.ts # правила иконок (iconFor), курирование, группы, приоритет доменов
│ └─ data/
│ ├─ house.ts # геометрия: ROOMS (комнаты→area), FLOOR_VB (viewBox), названия
│ └─ backgrounds.ts # ВЕКТОРНЫЕ планы (SVG base64) + FLOOR_BG_RECT (позиционирование)
├─ dist/houseplan-card.js # сборка (rollup+terser), ~290 КБ, планы внутри
├─ custom_components/houseplan/ # интеграция HA
│ ├─ __init__.py # setup: Store, WS-команды, раздача JS (add_extra_js_url)
│ ├─ websocket_api.py # houseplan/layout/get|set|update
│ ├─ config_flow.py # одна запись; опция admin_only (правка только админам)
│ ├─ const.py # DOMAIN, STORAGE_KEY, VERSION, FRONTEND_URL
│ └─ frontend/houseplan-card.js # копия dist, раздаётся как /houseplan_files/houseplan-card.js
├─ assets/ # исходники планов: f1_plan.svg, f2_plan.svg (РЕМПЛАННЕР), *_bg.png (старые растровые)
├─ hacs.json # манифест HACS
└─ docs/ # эта документация
```
## Ключевые решения
1. **Один репозиторий — интеграция + карточка.** Интеграция сама раздаёт JS
(`hass.http.async_register_static_paths` + `frontend.add_extra_js_url`), пользователю не
нужно прописывать ресурс Lovelace. Паттерн как у browser_mod/xiaomi_vacuum_map.
2. **Раскладка иконок — на сервере.** `helpers.storage.Store(1, "houseplan.layout")`
`.storage/houseplan.layout`. Карточка читает/пишет через `hass.callWS`
(`houseplan/layout/get|set|update`). Fallback — localStorage (если интеграции нет).
3. **Без токена.** Всё из объекта `hass` фронтенда: `hass.states` (реактивно),
`hass.devices/entities/areas` (реестры). Никаких прямых WS-подключений.
4. **Реактивность.** Каждое изменение состояния в HA приводит к set hass → re-render.
Температуры/LQI/вкл-выкл live по определению (проверено подменой state).
## Координатная система
- Базовое пространство: **1489×1053** («пиксели» старого PNG-рендера, 1 ед. = 1 px).
Все комнаты, позиции иконок и viewBox этажей — в нём. НЕ менять без миграции раскладки.
- Векторные планы вставляются `<image href=svg>` в прямоугольник `FLOOR_BG_RECT`:
- f1: scale **0.647**, offset **(490, 27)** → rect [490, 27, 774.2, 949.3]
- f2: scale **0.896**, offset **(351, 21)** → rect [351, 21, 1048.4, 961.4]
- вычислено растровой корреляцией (cv2.matchTemplate по бинаризованным картам темноты)
рендера SVG с эталонным PNG; точность ~1 px. Скрипты воспроизводимы (docs/DEVELOPMENT.md).
- Комнаты (`ROOMS`) сняппены к внутренним граням стен (полуавто: поиск ближайшей «тёмной линии»
по профилю + ручная доводка по overlay-рендерам).
## Модель данных карточки (runtime)
`DevItem`: id (device_id), name, model, area, floor, icon, entities[], primary (сущность для
more-info по приоритету доменов), temp, members[] (группа ламп), link/linkPrimary (Z2M-группа).
Построение из реестров (`_buildDevices`), правила 1-в-1 из прототипа:
- показываются только устройства с area из списка комнат;
- скрываются: entry_type=service, интеграции из EXCLUDED_DOMAINS, model=Group, сцены, мосты,
под-устройства myheat, дубли по «имя|area»;
- **устройство с сущностью `lock.*` всегда получает `mdi:lock`** (TTLock-замки в реестре
называются «Дом»/«Терраса»/«Кладовка» — по имени не распознать);
- лампы (mdi:lightbulb) ≥2 в комнате схлопываются в группу `mdi:lightbulb-group`
(клик → меню: вся группа + отдельные).
## Живые данные
- Температура: сущность с device_class=temperature / °C / `_temperature$` → метка справа.
- LQI (zigbee): среднее по `*_linkquality`-сущностям → метка под иконкой; цвет
`lqiColor()`: ≤40 красный → ≥180 зелёный (hsl-градиент). Среднее по комнате — в тултипе комнаты.
- Классы состояния иконки: on (жёлтый), open (оранжевый: cover/valve/lock/binary_sensor
проблемных классов), unavail (прозрачность).
## Размеры
`icon_size` в конфиге = **% ширины видимой области плана** (дефолт 2.5). Реализация:
`.stage { container-type: inline-size }` + размеры в `cqw`. Легаси px-значения (>8) игнорируются.
## Sticky-шапка
`.head { position: sticky; top: var(--header-height, 56px) }`; ОБЯЗАТЕЛЬНО
`ha-card { overflow: visible }``overflow: hidden` ломает sticky.
## WS API интеграции
| Команда | Параметры | Ответ |
|---|---|---|
| `houseplan/layout/get` | — | `{layout: {device_id: {x,y}}}` |
| `houseplan/layout/set` | `layout` | `{ok}` (admin_only опционально) |
| `houseplan/layout/update` | `device_id`, `pos` | `{ok}` |
+30
View File
@@ -0,0 +1,30 @@
# Changelog
## v1.2.2 — 2026-07-04
- Тулбар карточки (вкладки этажей) закрепляется при скролле под шапкой HA
(`position: sticky; top: var(--header-height)`; ha-card overflow: visible).
- Инцидент: промежуточная сборка на нестабильном mount дала битый бандл, роняющий рендер
дашбордов; правило «собирать только в /tmp + md5-контроль» закреплено в DEVELOPMENT.md.
## v1.2.1 — 2026-07-04
- Иконки не увеличиваются при наведении/перетаскивании (убран transform: scale).
## v1.2.0 — 2026-07-03
- Границы комнат сняппены к стенам векторного плана.
- Zigbee LQI: значение под иконкой, среднее по комнате в тултипе, градиент красный→зелёный,
опция show_signal.
- `mdi:lock` для любых устройств с сущностью lock.* (TTLock).
- Выключатель прихожей: исправлена зона устройства в реестре HA (был в detskaia_elina).
## v1.1.0 — 2026-07-03
- Векторные подложки (SVG РЕМПЛАННЕР), автосовмещение масштаба/сдвига растровой корреляцией.
- Размер иконок в % ширины плана (container queries, дефолт 2.5%).
## v1.0.1 — 2026-07-03
- fix: вложенные SVG-фрагменты через lit svg`` (подложка/комнаты не рендерились).
- fix: версия из const вместо блокирующего чтения manifest.json в event loop.
## v1.0.0 — 2026-07-03
- Первый релиз: Lovelace-карточка (TS+Lit, без токена, от hass) + интеграция houseplan
(WS-хранилище раскладки, раздача JS). Перенос модели прототипа: курирование, группы ламп,
iconFor, температура, more-info, навигация в зоны, drag-раскладка.
+58
View File
@@ -0,0 +1,58 @@
# Разработка и деплой
## Окружение (cowork-сессии)
- Эталон кода — **git-репозиторий** (в сессии живёт в `/tmp/hpc`, восстанавливается из
`houseplan-card.git.bundle`: `git clone houseplan-card.git.bundle hpc`).
- Папка пользователя `houseplan/houseplan-card/` — зеркало репо (rsync после каждого коммита)
+ актуальный `houseplan-card.git.bundle`.
### ⚠️ Грабли файловой синхронизации (критично)
1. Сетевой mount иногда отдаёт файлы **обрезанными/перемешанными** — правки через Edit-tool
с Windows-стороны ненадёжны. Правило: **править python-патчами по чистой копии в /tmp,
писать через bash**, assert на count(old)==1.
2. **Сборку rollup вести ТОЛЬКО в /tmp/hpc** (`npm ci` уже сделан). Сборка на mount однажды
дала синтаксически валидный, но битый бандл («wi is not defined»), который валил рендер
ВСЕХ дашбордов HA (карточка грузится как extra_module на каждой странице!).
3. `.git` на mount не создаётся («Operation not permitted» на dot-каталогах) — поэтому bundle.
## Сборка
```bash
cd /tmp/hpc && npm ci # один раз
npx rollup -c # → dist/houseplan-card.js
node --check dist/houseplan-card.js
cp dist/houseplan-card.js custom_components/houseplan/frontend/
```
## Деплой на дачу (ha.jbstudio.pro)
- SSH: порт **323**, root, ключ `ha_jb` (пользователь загружает в чат; в песочнице /tmp/ha_jb, chmod 600).
- JS: `scp -P 323 -i /tmp/ha_jb dist/houseplan-card.js root@ha.jbstudio.pro:/config/custom_components/houseplan/frontend/`
- Интеграция целиком: tar c custom_components/houseplan (--exclude __pycache__) → tar x на сервере.
- **Проверка обязательна**: `md5sum` локально == на сервере == `curl http://homeassistant:8123/houseplan_files/houseplan-card.js | md5sum`
(внутри SSH-аддона `localhost` — НЕ HA, использовать хост `homeassistant`).
- Изменения Python требуют рестарта HA (`ha core restart`, держит соединение до конца, HTTP
поднимается через 1–3 мин). Изменения JS — только обновление страницы (static path отдаётся
с no-cache).
- После деплоя JS — проверить в браузере (Ctrl+F5) и console (не должно быть ошибок из
houseplan-card.js; битый бандл роняет все дашборды).
## Релиз
Тег `vX.Y.Z` + GitHub Release → workflow `.github/workflows/release.yml` собирает и прикладывает
`houseplan-card.js`. Версию бампать синхронно: `src/houseplan-card.ts` (CARD_VERSION),
`package.json`, `custom_components/houseplan/manifest.json`, `custom_components/houseplan/const.py`.
## Воспроизводимые скрипты (данные)
- Извлечение геометрии/подложек из прототипа и генерация `src/data/*` — см. историю коммитов
и docs/ARCHITECTURE.md (трансформации SVG→базовое пространство: f1 0.647/(490,27), f2 0.896/(351,21)).
- Подгонка комнат: рендер плана с прямоугольниками поверх (cv2) → снап к стенам → ручная доводка.
## Прод-объекты в HA (дача)
- Дашборд `plan-doma`, панельный вид, карточка `custom:houseplan-card` (icon_size 2.5).
- Интеграция houseplan: entry загружен, `.storage/houseplan.layout` — раскладка (сервер).
- Старый прототип `/config/www/houseplan/` (iframe) сохранён как запасной, не трогать.
- Бэкапы configuration.yaml: `.bak-avgtemp` (до правки среднего датчика).
+73
View File
@@ -0,0 +1,73 @@
# Роадмап: от «карты дачи» к публикуемой универсальной интеграции
Цель: опубликовать в HACS (сначала custom repository, затем PR в default) универсальную
интеграцию «интерактивный план дома»: свои планы на пространство, ручная разметка комнат,
полуавтоматическое размещение устройств, скрытие/переименование/смена иконок, виртуальные
устройства. Никакого хардкода конкретного дома в коде.
## Принципы (зафиксировано)
- Пишем полноценный компонент по паттернам HA dev docs, не захардкоженную фичу.
- Все данные конкретного дома — это **конфигурация инстанса** (server-side Store),
а не код/бандл. Текущие данные дачи станут первым мигрированным инстансом.
- Документировать всё сразу в docs/ (контекст сессий теряется).
- Версионирование хранилищ (Store minor_version + async_migrate) с первого дня.
## Фаза 0 — Гигиена публикации (быстро, без новых фич)
- [x] hacs.json, manifest с обязательными ключами, структура custom_components/*
- [x] CI: hacs/action + hassfest (workflow validate.yml) — добавлено, проверить на GitHub
- [x] brand/icon.png
- [ ] Публичный GitHub-репозиторий: description, topics, issues on; первый Release v1.2.x
- [ ] README EN (основной) + README.ru.md; скриншоты/GIF (обязательны для витрины HACS)
- [ ] Заменить codeowners/documentation/issue_tracker на реальные URL после создания репо
## Фаза 1 — Конфиг на сервере (декаплинг от дачи) ← ФУНДАМЕНТ
Новое хранилище `houseplan.config` (Store v1):
```json
{ "spaces": [ { "id": "f1", "title": "1 этаж", "plan": {"media_id": "...", "type": "svg"},
"view_box": [x,y,w,h], "rooms": [{"id","name","area_id","x","y","w","h"}] } ],
"device_overrides": { "<device_id>": {"hidden":bool,"icon":str,"name":str} },
"virtual_devices": [ {"id","space","name","icon","x","y","note"?, "entity_id"?} ],
"settings": {"exclude_integrations": [...], "group_lights": bool, ...} }
```
- WS API v2: `houseplan/config/get|set`, `houseplan/plan/upload` (файл плана →
`<config>/houseplan/` через process-executor, отдача через static path), layout как сейчас.
- Карточка: при наличии server-config использует его; бандл-данные дачи становятся
**fallback-примером** и затем выпиливаются (миграционный скрипт зальёт их в Store).
- Единицы координат: нормированные (0..1 от плана) для новых конфигов — независимость от
разрешения исходника; миграция дачи пересчитает 1489×1053 → нормированные.
## Фаза 2 — Редактор разметки в карточке
- Режим «Настройка» (отдельно от drag-раскладки): рисование/ресайз прямоугольников комнат
поверх плана, привязка к area (селектор ha-area-picker), редактирование viewBox (кадр).
- Позже: полигональные комнаты (SVG path), повороты планов.
- Загрузка плана из UI (file upload → WS) + выбор существующего media.
## Фаза 3 — Управление устройствами
- Панель устройств в режиме настройки: список неразмещённых (с фильтрами), drag из панели
на план; авто-раскладка «сеткой по комнате» кнопкой.
- Оверрайды per-device: скрыть, своя иконка (ha-icon-picker), своё имя. Хранение в config.
- Настраиваемое курирование: исключения интеграций/доменов в options flow вместо хардкода.
## Фаза 4 — Виртуальные устройства
- CRUD виртуальных маркеров (имя, иконка, координаты, заметка; опционально ссылка на
entity/URL): септик, кран, счётчик без датчика и т.п. Рендер как обычные иконки,
клик → карточка с заметкой или more-info привязанной сущности.
## Фаза 5 — Полировка UX/фич
- Клик-действия по настройке: toggle для света/розеток, long-press → more-info.
- Тюнинг live-индикации (цвета по теме, badge-и), light-тема.
- Тултипы на тач-устройствах (long-press), доступность (клавиатура, aria).
- Опция LQI: порог «плохого» сигнала, скрытие меток на не-zigbee инстансах.
## Фаза 6 — Качество и публикация
- Тесты: pytest (config_flow, websocket_api, миграции Store) + hassfest/hacs action в CI;
фронт: vitest на rules/geometry-утилиты.
- Типизация: strict TS-интерфейсы hass (custom-card-helpers или свои), mypy для python.
- Переводы integration+card: en + ru (translations/, локализация строк карточки).
- Quality scale bronze → silver чек-лист; PR в hacs/default; опционально PR в
home-assistant/brands (пока хватает brand/ в репо).
## Открытые вопросы
- Имя для публикации: «House Plan Card»? домен `houseplan` не занят в HACS default — проверить.
- Лицензия MIT (в package.json уже MIT) — добавить LICENSE файл.
- Формат планов: SVG предпочтителен (вектор, вес), PNG поддержать обязательно.