mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-30 08:46:03 +00:00
docs+publish prep: docs/ (architecture, development, changelog, roadmap), CI validate (hacs action + hassfest + build sync check), brand icon, LICENSE
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
name: Validate
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "0 4 * * 1"
|
||||
jobs:
|
||||
hacs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: HACS validation
|
||||
uses: hacs/action@main
|
||||
with:
|
||||
category: integration
|
||||
hassfest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Hassfest validation
|
||||
uses: home-assistant/actions/hassfest@master
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 22 }
|
||||
- run: npm ci && npm run build
|
||||
- name: Card bundle in sync with integration
|
||||
run: cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 JB (justbusiness)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -55,6 +55,13 @@ live_states: true
|
||||
ha-floorplan потребовал бы генератор SVG+конфига и всё равно не дал бы редактирование из UI.
|
||||
Своя карточка (~1 файл) оказалась дешевле и полностью повторяет прототип. Решение: **свой card**.
|
||||
|
||||
## Документация
|
||||
|
||||
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — устройство карточки и интеграции, координаты, WS API
|
||||
- [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) — сборка, деплой, грабли окружения (обязательно к прочтению)
|
||||
- [docs/CHANGELOG.md](docs/CHANGELOG.md) — история версий
|
||||
- [docs/ROADMAP.md](docs/ROADMAP.md) — план до публикации в HACS (универсализация, редактор разметки, виртуальные устройства)
|
||||
|
||||
## Разработка
|
||||
|
||||
```bash
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -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}` |
|
||||
@@ -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-раскладка.
|
||||
@@ -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` (до правки среднего датчика).
|
||||
@@ -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 поддержать обязательно.
|
||||
Reference in New Issue
Block a user