15 KiB
Матрица настроек света устройства
Актуально для локальной реализации issues #84
и #88. Каноническая модель
геометрии и распространения света остаётся в LIGHT.md.
Обозначения
- A — режим «Авто» нашёл у устройства собственный пространственный источник.
- S — у устройства есть собственная управляемая
light.*/switch.*, способная дать состояние и принять service call. - Источник — устройство участвует в Glow, заливке «Свет», карточке и статистике комнаты.
- Live — доступен режим цвета «Из источника».
- Ручн. — доступны ручной цвет и ручная яркость.
- R — доступен локальный радиус Glow.
Авто → фикс.— сохранённый режим не переписывается, но в UI и runtime пассивный источник получает безопасный fallback: общий цвет, яркость 100%.
Комбинация A=да, S=нет приведена для полноты контракта и мутационных тестов, но
недостижима штатным resolver: автоматически найденный источник всегда имеет реальную
light.*. Остальные 27 строк достижимы.
Полная матрица role × A × S × режим Glow
| # | Роль | A | S | Сохранённый режим | Источник | Пассивный | Live | Ручн. | R | Эффективный режим |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Авто | нет | нет | Из источника | нет | нет | нет | нет | нет | Из источника, disabled |
| 2 | Авто | нет | нет | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled |
| 3 | Авто | нет | нет | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled |
| 4 | Авто | нет | да | Из источника | нет | нет | нет | нет | нет | Из источника, disabled |
| 5 | Авто | нет | да | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled |
| 6 | Авто | нет | да | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled |
| 7 | Авто | да | нет | Из источника | да | да | нет | да | да | Авто → фикс. (теоретическая) |
| 8 | Авто | да | нет | Задать цвет | да | да | нет | да | да | Задать цвет (теоретическая) |
| 9 | Авто | да | нет | Цвет + яркость | да | да | нет | да | да | Цвет + яркость (теоретическая) |
| 10 | Авто | да | да | Из источника | да | нет | да | да | да | Из источника |
| 11 | Авто | да | да | Задать цвет | да | нет | да | да | да | Задать цвет |
| 12 | Авто | да | да | Цвет + яркость | да | нет | да | да | да | Цвет + яркость |
| 13 | Всегда | нет | нет | Из источника | да | да | нет | да | да | Авто → фикс. |
| 14 | Всегда | нет | нет | Задать цвет | да | да | нет | да | да | Задать цвет |
| 15 | Всегда | нет | нет | Цвет + яркость | да | да | нет | да | да | Цвет + яркость |
| 16 | Всегда | нет | да | Из источника | да | нет | да | да | да | Из источника |
| 17 | Всегда | нет | да | Задать цвет | да | нет | да | да | да | Задать цвет |
| 18 | Всегда | нет | да | Цвет + яркость | да | нет | да | да | да | Цвет + яркость |
| 19 | Всегда | да | нет | Из источника | да | да | нет | да | да | Авто → фикс. (теоретическая) |
| 20 | Всегда | да | нет | Задать цвет | да | да | нет | да | да | Задать цвет (теоретическая) |
| 21 | Всегда | да | нет | Цвет + яркость | да | да | нет | да | да | Цвет + яркость (теоретическая) |
| 22 | Всегда | да | да | Из источника | да | нет | да | да | да | Из источника |
| 23 | Всегда | да | да | Задать цвет | да | нет | да | да | да | Задать цвет |
| 24 | Всегда | да | да | Цвет + яркость | да | нет | да | да | да | Цвет + яркость |
| 25 | Никогда | нет | нет | Из источника | нет | нет | нет | нет | нет | Из источника, disabled |
| 26 | Никогда | нет | нет | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled |
| 27 | Никогда | нет | нет | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled |
| 28 | Никогда | нет | да | Из источника | нет | нет | нет | нет | нет | Из источника, disabled |
| 29 | Никогда | нет | да | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled |
| 30 | Никогда | нет | да | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled |
| 31 | Никогда | да | нет | Из источника | нет | нет | нет | нет | нет | Из источника, disabled (теоретическая) |
| 32 | Никогда | да | нет | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled (теоретическая) |
| 33 | Никогда | да | нет | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled (теоретическая) |
| 34 | Никогда | да | да | Из источника | нет | нет | нет | нет | нет | Из источника, disabled |
| 35 | Никогда | да | да | Задать цвет | нет | нет | нет | нет | нет | Задать цвет, disabled |
| 36 | Никогда | да | да | Цвет + яркость | нет | нет | нет | нет | нет | Цвет + яркость, disabled |
Ручной цвет при stateful-источнике оставляет живую яркость. Режим «Цвет + яркость» фиксирует оба значения. Для пассивного источника живой яркости нет, поэтому «Задать цвет» означает яркость 100%, а «Цвет + яркость» использует сохранённое значение.
Ведущая сущность (#88)
| Роль | Управляемых собственных сущностей | Сохранённый light_entity |
UI и runtime |
|---|---|---|---|
| Авто / Никогда | любое число | любое значение | Селектор скрыт; поле сохраняется без изменения, но на текущую роль не влияет |
| Всегда | 0 | отсутствует | Пассивный источник, селектор скрыт |
| Всегда | 1 | отсутствует | Единственная сущность выбирается автоматически, селектор скрыт |
| Всегда | 2+ | отсутствует | Селектор показан; fallback binding → primary → первая управляемая |
| Всегда | 1+ | валидное значение | Выбранная сущность даёт state и service target |
| Всегда | любое число | сущность исчезла | Предупреждение; временный fallback, сохранённая ссылка не стирается |
Выбор не зависит от текущего on/off/unavailable: capability берётся из binding и
реестра HA, а live state обрабатывается отдельно.
Связи «Управляет другими источниками света» (#84)
Цель в controls |
Состояние цели | Service call контроллера | Glow и статистика |
|---|---|---|---|
light.* / switch.* |
Фактическое состояние entity; группа — any(on) |
Только реальные entity IDs | Реальный отдельный marker владеет позицией; иначе цель участвует без отдельного пятна у контроллера |
marker:<id> stateful |
Состояние ведущей сущности цели | Ведущая сущность цели, с дедупликацией | Позиция, комната, цвет и радиус принадлежат marker-цели |
marker:<id> passive, один controller |
Его реальные targets, иначе собственная ведущая entity | Сам marker:* никогда не отправляется в HA |
Пассивная лампа следует controller и светит в своей позиции |
| Passive, несколько controllers | OR всех активных driver entities | По каждому действию — только его реальные targets | Один источник и один голос комнаты, без дублей |
Exact virtual + «Всегда» + Toggle, есть links |
OR всех активных driver entities; ручной bit временно не участвует | Клик controller — его группа; клик лампы — deduplicated union всех её drivers | HA state едино управляет Glow, заливкой, статистикой и обоими marker |
Exact virtual + «Всегда» + Toggle, links отсутствуют |
Operational Store #107; отсутствие записи = on |
Клик лампы меняет только operational state, без HA service | Ручное состояние общее для full/static и сохраняется после restart |
| Passive без сохранённых links, не exact-режим #107 | Всегда on |
Нет собственного вызова | Постоянный Glow и 1 из 1 |
| Links есть, но все drivers скрыты/disabled/удалены | off / dormant |
Нет вызова по битой цели | Ссылка сохраняется, пятна нет |
Прямая entity + marker: на тот же stateful source |
Одно effective состояние | Один service target | Один источник и один голос |
| Target переведён из «Всегда» в «Авто без источника»/«Никогда» | Dormant | Нет marker-service | Link сохраняется и оживает при возврате «Всегда» |
| Target скрыт или disabled в HA | Dormant | Нет marker-service | Не рисуется и не влияет на комнату |
| Target удалён с плана | Ссылка удаляется атомарно | Нет | Устройство снова можно добавить заново |
| Broken legacy ref | Игнорируется с диагностикой | Нет | Open → Save не уничтожает ссылку |
| Self-link / новый цикл | Запрещено | — | UI не предлагает, backend отклоняет запись/import |
Связи разрешены между комнатами и пространствами одного плана. При экспорте одного
пространства внутренние marker:-ссылки ремапятся вместе с marker ID, а внешние
отбрасываются с предупреждением в preview.
Независимые переключатели отображения
| Настройка | Влияние на световую модель |
|---|---|
| «Значок + состояние» | Подложка устройства показывает его resolved working state; Glow определяется матрицей выше |
| «Значок + состояние и активность» | Дополнительно показывает короткую или постоянную пульсацию; источник света не меняется |
| «Значение + состояние» | Меняет только содержимое маркера; источник света не меняется |
| «Всегда статичный значок» | Блокирует динамику самого значка/подложки, но не отменяет отдельно настроенные Glow, заливку «Свет» и статистику комнаты |
| Glow выключен у пространства | Пятна не рисуются, но источник, состояние комнаты и заливка «Свет» продолжают вычисляться |
| Маркер скрыт / HA-disabled | Маркер и его собственный источник не участвуют в плане независимо от остальных настроек |
Проверяемый контракт
- Все 36 строк первой таблицы проверяются pure unit-тестом.
- Выбор ведущей сущности, stale fallback, passive OR, dormant links, alias-dedupe,
lifecycle и запрет передачи
marker:*в HA покрыты отдельными unit-тестами. - Контекстный селектор, passive-гейтинг и plan-source picker покрыты browser smoke.
- Backend отдельно проверяет новые ссылки, циклы и перенос между пространствами.