mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 21:01:21 +00:00
163 lines
9.3 KiB
Markdown
163 lines
9.3 KiB
Markdown
# Единая индикация состояния и активности устройств
|
||
|
||
Статус: **утверждено владельцем и реализовано локально 2026-08-05**.
|
||
|
||
## Цель
|
||
|
||
Заменить четыре пересекающиеся механики — цвет подложки, пользовательскую
|
||
пульсацию, motion/presence-эффекты и движение штор — одной семантической
|
||
системой. Визуал должен отвечать на три разных вопроса:
|
||
|
||
1. Доступно ли устройство.
|
||
2. В каком устойчивом состоянии оно находится.
|
||
3. Что оно делает прямо сейчас или что только что произошло.
|
||
|
||
## Режимы отображения
|
||
|
||
В UI остаются:
|
||
|
||
1. **Значок** — иконка, морфинг и статусная подложка без обычных эффектов
|
||
активности.
|
||
2. **Значок + активность** — то же плюс семантический эффект активности.
|
||
3. **Значение вместо значка** — числовая плашка со статусным цветом; обычная
|
||
активность не рисуется.
|
||
|
||
Опция **«Только пульсация» удаляется**. Legacy `display: ripple` читается как
|
||
`icon_ripple`, а при следующем сохранении конфигурации переписывается в
|
||
`icon_ripple`. Backend временно продолжает принимать старое значение.
|
||
|
||
## Модель визуального состояния
|
||
|
||
Для маркера вычисляется один результат:
|
||
|
||
```ts
|
||
availability: 'available' | 'unavailable'
|
||
status: 'neutral' | 'open' | 'working' | 'alarm'
|
||
activity: 'none' | 'event' | 'presence' | 'transition' | 'running'
|
||
```
|
||
|
||
- `availability` отвечает за приглушение недоступного устройства;
|
||
- `status` управляет подложкой и морфингом;
|
||
- `activity` управляет кольцом или волнами;
|
||
- тревога имеет высший приоритет;
|
||
- недоступность подавляет обычную активность.
|
||
|
||
## Визуальный язык
|
||
|
||
| Смысл | Подложка | Эффект в «Значок + активность» |
|
||
|---|---|---|
|
||
| Доступно, простаивает | нейтральная | нет |
|
||
| Выполняет основную функцию | жёлтая | медленное дыхание |
|
||
| Открыто / разблокировано | оранжевая | только событие/переход, не постоянный эффект |
|
||
| Разовое срабатывание | текущая статусная | три расходящиеся волны, 3,3 с |
|
||
| Присутствие | нейтральная | спокойное статичное кольцо |
|
||
| Механическое движение | текущая статусная | дыхание до конца движения |
|
||
| Недоступно | приглушённая | нет |
|
||
| Тревога (протечка, дым, газ, CO, safety/tamper/problem, сирена, сработавшая охрана) | красная | быстрая красная пульсация при любом display |
|
||
|
||
`prefers-reduced-motion` заменяет анимацию статичным кольцом.
|
||
|
||
## Значение жёлтой подложки
|
||
|
||
Жёлтый означает только **фактическое выполнение основной функции**:
|
||
|
||
- `light/switch/fan/humidifier = on`;
|
||
- climate: `hvac_action = heating/cooling/drying/fan`, но не просто выбранный
|
||
режим `heat/cool/auto`;
|
||
- vacuum: `cleaning` (и работающий механизм при `returning`);
|
||
- бытовая техника: `running/washing/rinsing/spinning/drying/heating/cooking`;
|
||
- маркер с `controls`: работает хотя бы одна управляемая цель.
|
||
|
||
Не являются работой: открытая дверь, разблокированный замок, открытые шторы,
|
||
presence/motion, `enabled`, `home`, `unknown`, `unavailable`, climate `idle`.
|
||
|
||
`media_player` — пассивный медиатранспорт, а не исполнительный механизм:
|
||
`on/idle/playing/paused/standby` остаются нейтральными и не получают running-
|
||
активность, а явный `off` использует то же приглушённое отображение, что
|
||
`unknown/unavailable`. Правило действует на весь домен (телевизоры, ресиверы,
|
||
колонки, саундбары), не на конкретные модели, и не вводит отдельного статуса.
|
||
Если у маркера несколько `media_player`, он бледнеет только когда среди них
|
||
нет доступной и включённой сущности.
|
||
|
||
В glow-режиме у реального источника света жёлтая подложка может быть скрыта:
|
||
его устойчивым индикатором служит световое пятно. Эффект активности остаётся.
|
||
|
||
## Семантика активности
|
||
|
||
### Event, 3,3 секунды
|
||
|
||
- motion: только засвидетельствованный `off -> on`, не весь cooldown;
|
||
- vibration/shock/sound;
|
||
- открытие двери/окна (`off -> on`), но не всё время открытого состояния;
|
||
- button/event;
|
||
- успешный запуск script/scene/automation без устойчивого состояния.
|
||
|
||
Первое состояние после загрузки и восстановление из `unknown/unavailable` не
|
||
создают ложного события. Повторный детект перезапускает окно и анимацию.
|
||
|
||
### Presence
|
||
|
||
`occupancy/presence = on` даёт статичное кольцо до исчезновения присутствия.
|
||
|
||
### Transition
|
||
|
||
- cover: `opening/closing`;
|
||
- lock: `locking/unlocking`;
|
||
- valve: `opening/closing`;
|
||
- vacuum: `returning`.
|
||
|
||
Если промежуточного состояния нет, прямой конечный переход
|
||
`closed <-> open` / `locked <-> unlocked` показывает transition 3,3 секунды.
|
||
|
||
### Running
|
||
|
||
Пока устройство фактически работает, его подложка жёлтая, а в режиме
|
||
«Значок + активность» вокруг неё медленно дышит кольцо.
|
||
|
||
## Источник состояния
|
||
|
||
Приоритет:
|
||
|
||
1. Явный специализированный источник (в будущей расширенной настройке).
|
||
2. Cover, когда tap action явно задан как «Открыть/закрыть».
|
||
3. `controls` — агрегированное состояние всех управляемых целей.
|
||
4. Функциональная сущность устройства / включённый light.
|
||
5. Primary entity.
|
||
|
||
Критические сущности устройства проверяются независимо и не могут быть
|
||
скрыты менее важным primary state.
|
||
|
||
## Приоритет вывода
|
||
|
||
1. alarm;
|
||
2. unavailable;
|
||
3. event;
|
||
4. transition;
|
||
5. presence;
|
||
6. running;
|
||
7. open;
|
||
8. neutral.
|
||
|
||
## Инварианты
|
||
|
||
- Одна функция вычисляет подложку и activity; они не смотрят на разные
|
||
сущности.
|
||
- Обычная активность появляется только в `icon_ripple`.
|
||
- Alarm отображается при любом display и не зависит от пользовательского цвета.
|
||
- Hidden/ghost не получает live-чисел, морфинга, подложки или активности.
|
||
- Static `houseplan-space-card` остаётся статической и не рисует live effects.
|
||
- Пользовательские цвет и размер применяются к обычной активности, но не к
|
||
красной тревоге.
|
||
|
||
## Реализация
|
||
|
||
- Чистая классификация сущностей, агрегация и распознавание переходов:
|
||
`src/device-visual.ts`.
|
||
- Выбор эффективных источников маркера, runtime-окно 3,3 с, миграция legacy
|
||
display и рендер: `src/houseplan-card.ts`.
|
||
- Общий слой колец и reduced-motion варианты: `src/styles.ts`.
|
||
- UI оставляет три режима; backend сохраняет `ripple` только как входное
|
||
legacy-значение до завершения миграционного периода.
|
||
- Unit-спецификация классификатора подготовлена в
|
||
`test/device-visual.test.mjs`; браузерные smokes переведены на новые классы.
|