9.3 KiB
Единая индикация состояния и активности устройств
Статус: утверждено владельцем и реализовано локально 2026-08-05.
Цель
Заменить четыре пересекающиеся механики — цвет подложки, пользовательскую пульсацию, motion/presence-эффекты и движение штор — одной семантической системой. Визуал должен отвечать на три разных вопроса:
- Доступно ли устройство.
- В каком устойчивом состоянии оно находится.
- Что оно делает прямо сейчас или что только что произошло.
Режимы отображения
В UI остаются:
- Значок — иконка, морфинг и статусная подложка без обычных эффектов активности.
- Значок + активность — то же плюс семантический эффект активности.
- Значение вместо значка — числовая плашка со статусным цветом; обычная активность не рисуется.
Опция «Только пульсация» удаляется. Legacy display: ripple читается как
icon_ripple, а при следующем сохранении конфигурации переписывается в
icon_ripple. Backend временно продолжает принимать старое значение.
Модель визуального состояния
Для маркера вычисляется один результат:
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
Пока устройство фактически работает, его подложка жёлтая, а в режиме «Значок + активность» вокруг неё медленно дышит кольцо.
Источник состояния
Приоритет:
- Явный специализированный источник (в будущей расширенной настройке).
- Cover, когда tap action явно задан как «Открыть/закрыть».
controls— агрегированное состояние всех управляемых целей.- Функциональная сущность устройства / включённый light.
- Primary entity.
Критические сущности устройства проверяются независимо и не могут быть скрыты менее важным primary state.
Приоритет вывода
- alarm;
- unavailable;
- event;
- transition;
- presence;
- running;
- open;
- 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 переведены на новые классы.