mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
2384 lines
240 KiB
Markdown
Executable File
2384 lines
240 KiB
Markdown
Executable File
# История изменений
|
||
|
||
> Русская версия [docs/CHANGELOG.md](CHANGELOG.md). Переведены записи начиная
|
||
> с v1.42.0 (2026-07-26); более ранние доступны только в английском файле.
|
||
>
|
||
> **Правило проекта:** оба файла пополняются в одном коммите с самим
|
||
> изменением — как и остальная документация (см. docs/STATUS.md).
|
||
|
||
## v1.61.0-beta.2 — 2026-08-10
|
||
|
||
- Свечение источников света стало независимым слоем и может одновременно
|
||
работать с заливкой по температуре, Zigbee-сигналу, состоянию света или без
|
||
заливки. Старые планы с режимом Glow сохраняют прежний результат и без потерь
|
||
мигрируют при обычном сохранении или «Оптимизации планов».
|
||
- Пересекающиеся световые пятна теперь складываются как свет: пересечение
|
||
становится ярче и смешивает цвета. Карточка проверяет реальную поддержку SVG
|
||
в браузере и безопасно возвращается к обычному наложению, если её нет.
|
||
- После закрытия карточки устройства, открытой долгим нажатием мыши, план больше
|
||
не прилипает к курсору и диалог не открывается повторно из старого жеста.
|
||
|
||
## v1.61.0-beta.1 — 2026-08-09
|
||
|
||
- Сохраняемые цвета плана теперь используют единый строгий формат `#RRGGBB` на
|
||
границах API и рендера. Некорректные старые или импортированные значения
|
||
безопасно заменяются штатным цветом и не могут добавить CSS declarations;
|
||
динамические RGB-цвета ламп Home Assistant продолжают работать через
|
||
отдельную числовую генерацию.
|
||
- Покрытие интеграций пылесосов стало явным и диагностируемым. Единый
|
||
закрепляемый и независимый от порядка resolver автоматически находит
|
||
источник в устройстве и позволяет лениво выбрать registry-less камеру карты,
|
||
различает удаление, деактивацию, недоступность и ограниченные права и не
|
||
выводит на план старую телеметрию деактивированного источника.
|
||
- Многосегментный путь Xiaomi Cloud Map Extractor сохраняет настоящие разрывы;
|
||
арбитраж пути, лимиты точек и ID карты детерминированы во фронтенде и
|
||
бэкенде. Автокалибровка использует площадные центроиды с обеих сторон и
|
||
сохраняет bbox-only диалекты через последний fallback на центр bbox, а
|
||
физическая ошибка более 40 см требует явного применения или ручной подгонки
|
||
до изменения настроек.
|
||
- Серверный recorder выдаёт одно дедуплицированное предупреждение на инцидент
|
||
удаления/деактивации источника и фиксирует восстановление. Документация
|
||
содержит честную матрицу Dreame/XCME/Valetudo; Roomba остаётся этапом 2.
|
||
|
||
## v1.60.3 — 2026-08-09
|
||
|
||
- Панели редакторов больше не меняют рабочую область: действия выделения,
|
||
временные настройки инструментов и палитра мебели открываются в единой
|
||
доступной суб-панели поверх плана, а кнопка закрытия остаётся на месте.
|
||
Широкая, средняя и узкая компоновки покрыты детерминированными golden-сценариями.
|
||
- При возврате на вкладку план больше не мигает и кратковременно не сбрасывает
|
||
масштаб или дневное состояние. Жест двумя пальцами не активирует лежащий под
|
||
ним marker, а подгонка карты пылесоса изолирует собственную область жестов.
|
||
- Символ, вырез и заливка проёма в толстой стене используют единую привязку к
|
||
стене. Отдельные и T-образные стены не перехватывают сторону, перекрывающиеся
|
||
проёмы не усиливают непрозрачность, а между атомарными участками тоннеля
|
||
больше не появляются тонкие SVG-полосы.
|
||
- Предпросмотры мебели остаются внутри своих кнопок, крестик закрытия редактора
|
||
отцентрирован, а закрытие невыбранной палитры не оставляет блокировку клика.
|
||
- Технические улучшения включают детерминированное golden-покрытие,
|
||
performance-gate на одном runner и перенос активного backlog в GitHub Issues
|
||
+ Project v2.
|
||
- Мелкие исправления и улучшения.
|
||
|
||
## v1.60.3-beta.2 — 2026-08-09
|
||
|
||
- Панели редакторов сохраняют стабильную высоту при выделении объектов и смене
|
||
контекста инструмента. «Свойства», «Удалить», параметры рисования, подсказки
|
||
операции и палитра мебели используют одну полупрозрачную суб-панель поверх
|
||
рабочей области: план больше не сжимается и не масштабируется заново, а
|
||
кнопка закрытия закреплена на месте. Та же доступная поверхность подготовлена
|
||
для будущих явно спроектированных групп инструментов; существующие кнопки
|
||
автоматически не объединяются.
|
||
- Жест двумя пальцами больше не активирует интерактивный объект плана, даже если
|
||
начался над ним, а при подгонке карты пылесоса масштаб плана под оверлеем не
|
||
меняется. Палитра мебели и будущие группы инструментов надёжно закрываются по
|
||
нажатию вне карточки и не поглощают следующий посторонний клик.
|
||
- Мелкие исправления и улучшения: снова учитывается системное сокращение
|
||
анимаций, устаревшие действия суб-панели сразу отклоняются после локальных
|
||
правок, а регрессионные проверки UI и производительности стали строже.
|
||
|
||
## v1.60.3-beta.1 — 2026-08-08
|
||
|
||
- При быстром возврате на вкладку больше не выполняется принудительный
|
||
однокадровый сброс дневного фона и hover, из-за которого мог мигать весь план.
|
||
После долгого сна защитная стабилизация и актуализация солнца сохраняются.
|
||
- Проёмы в толстых стенах теперь используют единую кэшируемую привязку стены
|
||
для символа, выреза и тоннеля с цветом комнаты. Отдельно стоящая параллельная
|
||
стена и перпендикулярное плечо T-стыка больше не перехватывают сторону
|
||
тоннеля, а перекрывающиеся проёмы не усиливают непрозрачность заливки. Старый
|
||
проём, сохранённый с углом или смещением, которые фактически уже не совпадают
|
||
со стеной, больше не вырезает и не сдвигает её; для восстановления достаточно
|
||
повторно привязать проём к стене в редакторе плана.
|
||
- Расширено покрытие режима «Всегда статичный значок»: проверяются подавление
|
||
RGB, размер и поворот, приоритет lifecycle, переключение режимов, паритет
|
||
плана/предпросмотра/статической карточки и отсутствие live-слоя пылесоса.
|
||
- Подготовлен maintenance-фундамент: локальный реестр и аудит compatibility-
|
||
полей, проходящий backend-схему performance-baseline большого дома с защитой
|
||
от старого bundle и ложных замеров памяти, детерминированная golden-image
|
||
инфраструктура capture/review и первый render-only вынос из корневой
|
||
карточки. Сохранённые данные, SVG-контракт и пользовательское взаимодействие
|
||
не меняются.
|
||
|
||
## v1.60.2 — 2026-08-08
|
||
|
||
- Тоннели дверей, окон и ворот в толстых стенах теперь продолжают фактическую
|
||
заливку комнаты вместо белой полосы подложки. Во внешней стене цвет комнаты
|
||
занимает всю глубину проёма, а в общей стене разные заливки ровно делятся по
|
||
её оси. Поведение Glow, солнечных лучей и символов проёмов не изменилось.
|
||
- В настройках отображения устройства появился режим **«Всегда статичный
|
||
значок»**. Он сохраняет обычный тёмный значок при работе, открытии, тревоге,
|
||
недоступности, RGB-цвете и любых значениях, скрывает дополнительные бейджи и
|
||
живой puck/след пылесоса. Hover, действия, controls и отдельное влияние
|
||
устройства на освещение комнаты не меняются. Прежний режим **«Значок»**
|
||
переименован в **«Значок + динамическая подложка»**.
|
||
- Выключатель больше не становится физической точкой Glow только из-за списка
|
||
управляемых источников: `controls` по-прежнему задаёт групповое управление,
|
||
состояние освещения и статистику комнаты, но световое пятно рисуется у
|
||
маркера самой лампы. Собственный `switch.*` в старом `controls` также больше
|
||
не включает скрытое legacy-поведение — для реле-светильника нужен явный флаг
|
||
«Это устройство — источник света».
|
||
|
||
## v1.60.2-beta.3 — 2026-08-08
|
||
|
||
- Сохранённые устройства, деактивированные в Home Assistant, теперь полностью
|
||
исключаются из плана и всех расчётов до повторной активации, а в редакторе
|
||
устройств остаются подписанными служебными ghost-маркерами. Сверка реестров
|
||
восстанавливается даже при недоступной подписке на обновления; статусы и
|
||
объяснения предпросмотра и статической карточки синхронизированы. Также вошли
|
||
небольшие исправления accessibility и навигации.
|
||
- В список проёмов добавлены «Ворота». Датчик, замок, вырез стены и
|
||
пропуск Glow работают как у двери, но по умолчанию ширина равна
|
||
300 см, а две половинные створки открываются наружу только на 10° без
|
||
огромной дуги на плане.
|
||
- Солнце в окнах больше не зависит от погодной сущности: облачность, дождь и
|
||
снег не ослабляют и не скрывают геометрически корректные лучи. Устаревший
|
||
выбор погоды удалён из настроек, сохранённые старые значения безопасно игнорируются.
|
||
- В настройках устройства появился живой предпросмотр: он показывает
|
||
фактическое текущее состояние, используемые сущности, интеграцию-провайдера,
|
||
объяснение результата и безопасный локальный пример эффекта активности.
|
||
Полный план, предпросмотр и read-only карточка пространства теперь используют
|
||
общий resolver отображения и единый renderer значка.
|
||
- Уже сохранённый режим «Значение вместо иконки» теперь показывает не только
|
||
числа, но и локализованные текстовые состояния. Длинное корректное значение
|
||
сокращается многоточием без расширения зоны marker, а полный текст остаётся
|
||
доступен в подсказке и accessibility-описании.
|
||
- При нескольких равноправных источниках режим «Значение вместо иконки» больше
|
||
не берёт случайно первую сущность registry: отображается иконка, а
|
||
предпросмотр объясняет неоднозначность.
|
||
- Для готовой линии в редакторе подложки теперь можно выбрать сплошной или
|
||
пунктирный стиль в свойствах, открываемых двойным кликом. Старые и новые линии
|
||
по умолчанию остаются сплошными; пунктир удобно выбирается и в промежутках.
|
||
- В редакторе плана отдельные кнопки «Виртуальная стена» и «Физическая стена»
|
||
заменены одним контекстным инструментом «Граница». Две точки на сплошной
|
||
общей стене открывают виртуальный участок, а один клик по пунктиру целиком
|
||
восстанавливает его физическое тело; будущая толщина видна в предпросмотре.
|
||
Экранные зоны попадания не меняются от масштаба, неоднозначные стыки и
|
||
независимая кладка блокируют опасное редактирование, а незавершённая первая
|
||
точка отменяется через Esc, Undo/Redo, навигацию, reconnect или multi-touch.
|
||
- Общий `hp-dialog` теперь переносит длинные локализованные заголовки и имена
|
||
устройств целиком вместо обрезания по ширине. Числовые поля угла во всех
|
||
редакторах показывают не более трёх знаков после запятой, не округляя
|
||
сохранённую геометрию.
|
||
|
||
## v1.60.2-beta.2 — 2026-08-08
|
||
|
||
- Составные устройства, представленные только набором switch-сущностей, теперь
|
||
используют один репрезентативный источник состояния вместо трактовки каждого
|
||
служебного переключателя как работы всего устройства. Отдельная сущность
|
||
Power определяется по общим метаданным Home Assistant: включённое устройство
|
||
остаётся нейтральным, а выключенное или недоступное отображается приглушённым.
|
||
Одиночные реле по-прежнему подсвечиваются жёлтым при работе.
|
||
- Информационная карточка устройства переведена на широкий адаптивный диалог;
|
||
кнопки «Редактировать», «Открыть в HA» и «Закрыть» корректно располагаются и
|
||
переносятся на узких экранах.
|
||
- В диалоге «Новая комната» оставлен единый сценарий сохранения: выбор
|
||
«— без зоны —» и введённое имя активируют обычную кнопку «Сохранить», комната
|
||
записывается с `area: null`. Дублирующая кнопка «Без зоны» удалена.
|
||
- Инструмент «Стереть» в редакторе подложки получил невидимую экранную область
|
||
попадания 16 px для тонких линий и контуров. Внешний вид объектов не меняется,
|
||
а удобная ширина сохраняется при любом масштабе.
|
||
|
||
## v1.60.2-beta.1 — 2026-08-07
|
||
|
||
- Финальные правки по ревью сделали инвалидацию геометрических кэшей
|
||
независимой от пути загрузки конфига и ограничили кэши LRU-вытеснением.
|
||
Pan/pinch снова работает над незавершёнными контурами, частично числовой
|
||
ввод отклоняется, оптимизатор не материализует отсутствующий угол колонны,
|
||
а ручка поворота получила полноценную область 24 px. Для булевой геометрии
|
||
добавлен безопасный последовательный fallback; объединение контуров и
|
||
анимация высоты панелей теперь проверяются browser smoke-сценариями.
|
||
|
||
- В редакторе плана появились сохраняемые незавершённые контуры комнат,
|
||
независимые перегородки и квадратные/круглые колонны. Они всегда привязаны к
|
||
сетке, вычитаются из чистой площади, блокируют Glow и солнечные лучи и входят
|
||
в общий Undo/Redo геометрии. В режиме «Выбрать» доступны перенос, свойства и
|
||
ручка поворота квадратной колонны; сохранённые контуры можно продолжать и
|
||
соединять конец с концом. Лимиты клиента и сервера совпадают, а неверная
|
||
толщина теперь отклоняется с подсказкой вместо молчаливого обрезания.
|
||
- По итогам аудита добавлены кэши чистого пола и световой геометрии, полная
|
||
блокировка источника внутри стены, непротекающая тень длинных перегородок,
|
||
строгая серверная проверка колонн, отмена активных жестов при серверном echo
|
||
и браузерный smoke-сценарий новых физических объектов.
|
||
- При рисовании контура комнаты `Shift` теперь фиксирует новый отрезок по
|
||
ближайшему направлению, кратному 45°. Предпросмотр и итоговая вершина
|
||
совпадают, а точка остаётся строго на сетке.
|
||
- Панель редактора плана стала компактнее: инструменты теперь называются
|
||
«Объединить», «Виртуальная стена», «Физическая стена» и «Толщина». У кнопок
|
||
«Отменить» и «Повторить» оставлены только иконки, при этом локализованные
|
||
подсказки и доступные имена сохранены.
|
||
- В редакторе подложки физические, толстые и пунктирные виртуальные стены
|
||
теперь приглушаются до тех же 35%, что и остальные слои вне декора.
|
||
- Переключение редакторов внутри одного пространства теперь заметно и плавно
|
||
проявляет новую панель, одновременно интерполируя её измеренную высоту.
|
||
Разное количество строк и состав инструментов больше не дёргают план, а
|
||
быстрое повторное переключение продолжается с текущей промежуточной высоты.
|
||
- Усилена надёжность по итогам аудита: Undo/Redo однозначно работают на
|
||
QWERTZ/AZERTY и нелатинских раскладках, SVG-текст получил цельную область
|
||
попадания с резервным режимом для Gecko/WebKit, а скрытая панель редактора и
|
||
анимации полностью сбрасываются при смене жизненного цикла. Высота области
|
||
плана теперь следует точному измерению шапки.
|
||
- Открытие и сохранение маркера больше не теряет порядок, повторы и временно
|
||
неизвестные внешние controls. Climate распознаёт `preheating`/`defrosting` и
|
||
игнорирует служебные псевдо-action перед проверкой режима; «Оптимизировать
|
||
планы» исправляет нулевой, пустой и отрицательный масштаб сетки на 5 см.
|
||
|
||
## v1.60.1-beta.1 — 2026-08-07
|
||
|
||
- Climate-маркеры интеграций без `hvac_action` теперь используют текущий
|
||
включённый режим из `hvac_modes`, поэтому работающий кондиционер снова имеет
|
||
жёлтую подложку. Если action присутствует, он остаётся приоритетным:
|
||
`hvac_action: idle` по-прежнему нейтрален.
|
||
- Настройки комнаты теперь открываются в диалоге средней ширины. Длинные
|
||
подписи вариантов и имена источников переносятся или сокращаются внутри
|
||
окна, поэтому горизонтального скролла больше нет, в том числе на мобильных.
|
||
- «Стереть» теперь воспринимает текстовую надпись как единый объект по всей её
|
||
рамке. Клик между буквами или по подсветке выделения больше не может визуально
|
||
удалить только «обводку»; промах по пустому холсту ничего не меняет.
|
||
- Переключение пространств, вход и выход из редакторов, а также переходы между
|
||
редакторами получили единую короткую плавную анимацию. Панель инструментов
|
||
раскрывается и закрывается без скачка; при `prefers-reduced-motion` анимации
|
||
по-прежнему отключены.
|
||
- При рисовании контура комнаты `Ctrl`/`Cmd` + клик теперь замыкает последнюю
|
||
точку на первую, не добавляя новую вершину. Нужны минимум две уже нарисованные
|
||
грани; вырожденный или самопересекающийся контур не замыкается.
|
||
- «Отменить»/«Повторить» в редакторах теперь используют независимые от раскладки
|
||
коды клавиш: `Ctrl`/`Cmd` + `Z`, `Ctrl`/`Cmd` + `Shift+Z` и `Ctrl`/`Cmd` + `Y`
|
||
работают и при русской раскладке. В полях ввода сохраняется нативная история.
|
||
- Закрыты замечания повторного аудита v1.60.0: переподключение во время resume
|
||
больше не оставляет план под вечным veil; старые self-controls выключателей
|
||
сохраняют роль источника света и мигрируют в `is_light`; выбор цвета и
|
||
прозрачности вынесен в верхний слой браузера с переворотом/ограничением внутри
|
||
мобильных диалогов; оптимизация исправляет `cell_cm` вне диапазона, но не
|
||
удаляет неизвестные или повторяющиеся controls; у entity-привязки старого
|
||
реле удаляется только её точный self-control, а явно добавленные соседние
|
||
источники света сохраняются; SVG-fallback стен стал валидным буквальным
|
||
цветом.
|
||
|
||
## v1.60.0 — 2026-08-07
|
||
|
||
- **Исправления по аудиту.** Удаление одного виртуального маркера больше не
|
||
удаляет соседние; реальные id вида `v_*` можно перемещать; tombstone скрыт
|
||
даже для старых клиентов и действует на привязку, а не вырезает entity из
|
||
живого родительского HA-устройства. Временно неактивные controls больше не
|
||
стираются при обычном сохранении. Удаление trail стало транзакционным.
|
||
Оптимизация ограничивает мигрируемые физические размеры, валидирует
|
||
`cell_cm`, не выбрасывает некорректный legacy transform и честно отделяет
|
||
bump версии модели от миграции. Нулевые фигуры отбрасываются, список мебели
|
||
выбирает сохранённый символ, resize повернутого объекта сохраняет опорный
|
||
угол, а смена режима отменяет незавершённый transform.
|
||
Английские имена устройств со словом `thermometer` теперь распознаются как
|
||
датчики температуры, а не попадают под более общее правило счётчиков.
|
||
- Автоиконка обновляется сразу после смены привязки и может быть явно
|
||
закреплена; границы толщины в imperial-режиме показываются в дюймах;
|
||
геометрия магнита кешируется; Undo и Redo одинаково работают с живым жестом.
|
||
- Маркер больше не может записать собственную entity или сущность привязанного
|
||
устройства в список других управляемых источников света. Старая самоссылка сразу
|
||
игнорируется; сохранение маркера удаляет её, а оптимизация планов также чистит
|
||
прямую самоссылку `entity:*`;
|
||
считать само реле источником света можно только явным флагом. Включённая
|
||
вытяжка/вентилятор по-прежнему получает жёлтую подложку работающего устройства,
|
||
но не участвует в Glow, заливке «Свет» и статистике освещения комнаты.
|
||
|
||
- **Редактор подложки получил единую систему стилей и трансформаций.** Любой
|
||
объект декора можно выбрать, переместить, пропорционально масштабировать
|
||
(`Shift` — разные оси), повернуть и точно изменить числами; у линии есть
|
||
ручки концов. Контур/текст и заливка имеют независимые цвет и прозрачность,
|
||
толщина и размер текста хранятся физически в см/дюймах, прямоугольник показывает площадь, а
|
||
овал — радиусы. Магнит использует только декор и контуры комнат. Декор и
|
||
картинка сохраняют обе стороны на сетке даже при пропорциональном размере и
|
||
используют общий именованный Undo/Redo на 50 шагов. У картинки
|
||
отдельный инструмент, непрозрачность 0.5 под остальными инструментами,
|
||
независимые оси и поворот; вне редактора она полностью непрозрачна. Старые
|
||
стили/трансформации не меняются визуально и мигрируют только явной
|
||
оптимизацией планов.
|
||
|
||
- **Устройства теперь можно действительно удалить с плана, а не только
|
||
скрыть.** Кнопка «Удалить» находится рядом со «Скрыть»/«Показать» и требует
|
||
подтверждения. Удалённая HA-привязка не рисуется, не показывается среди
|
||
скрытых и не участвует в LQI, климате, источниках комнаты, свете/Glow,
|
||
статистике, controls, проёмах и живом тексте, но снова доступна через
|
||
«Добавить». Повторное добавление заменяет служебную запись и начинает с новой
|
||
позиции. Виртуальный маркер удаляется полностью; layout, вложения, runtime
|
||
активности и следы пылесоса очищаются, а поздний drag из старой вкладки не
|
||
способен воскресить позицию.
|
||
|
||
- **Нижняя панель диалога устройства снова занимает всю ширину.** Общий
|
||
`hp-dialog` теперь передаёт footer как полноширинный элемент, а не как
|
||
сжимаемую по содержимому flex-строку. Разделитель больше не начинается с
|
||
середины окна, «Скрыть» остаётся слева, «Отмена» и «Сохранить» — справа.
|
||
|
||
- **У автоматической иконки больше не пропадает подпись в редакторе.** Если у
|
||
маркера нет явной замены иконки, селектор HA получает вычисленную автоиконку
|
||
как отображаемое значение и показывает и сам значок, и его имя `mdi:*`.
|
||
Сохранённое переопределение при этом остаётся пустым, пока пользователь сам
|
||
не выберет иконку.
|
||
|
||
- **Питание медиаплеера больше не считается работой.** Маркеры
|
||
`media_player` остаются нейтральными в состояниях `on`, `idle`, `playing`,
|
||
`paused` и других состояниях транспорта; явный `off` использует то же
|
||
приглушённое отображение, что `unknown` / `unavailable`. Это правило домена
|
||
для телевизоров, ресиверов, колонок и саундбаров, а не исключение для
|
||
конкретной модели. Составной медиамаркер бледнеет, только когда среди его
|
||
сущностей нет доступной и включённой.
|
||
|
||
- **Возврат к давно свёрнутому Просмотру больше не дёргает план.** В обычном
|
||
Просмотре (не киоск) нулевые и промежуточные размеры `ResizeObserver` больше
|
||
не перезаписывают сохранённый viewport. После действительно долгого сна
|
||
вкладки план открывается, когда размер сцены уже измерен и успокоился, а
|
||
масштаб и центр применяются одним кадром. Критические параметры заливки и
|
||
контура толстых стен теперь также заданы прямо на SVG-путях: при тёплом
|
||
пересоздании Lovelace браузер не успевает показать стандартную чёрную
|
||
заливку до восстановления стилей компонента. Редакторы, киоск и быстрые
|
||
переключения вкладок работают по-прежнему без задержки.
|
||
|
||
- **Действия карточки устройства не выходят за границы узкого диалога.**
|
||
Кнопки «Редактировать», «Открыть в HA» и «Закрыть» теперь переносятся только
|
||
целиком, если в малом диалоге HA не хватает одной строки; на телефоне также
|
||
уменьшены боковые отступы. Первая кнопка больше не уезжает за левый край.
|
||
|
||
## v1.59.2 — 2026-08-07
|
||
|
||
- **A11Y-02: единая доступная оболочка диалогов.** Все модальные окна House Plan
|
||
переведены на `hp-dialog`: внутри Home Assistant используются штатная
|
||
модальная поверхность и focus trap `ha-dialog`, а автономный demo-режим
|
||
получает fallback на нативном `<dialog>`. У каждого окна теперь есть
|
||
объявляемый скринридеру заголовок, предсказуемый начальный фокус, закрытие по
|
||
`Esc`, удержание Tab-фокуса внутри и возврат фокуса на открывший элемент,
|
||
включая вложенные окна и переход из одного диалога в другой.
|
||
|
||
## v1.59.1 — 2026-08-06
|
||
|
||
Технический релиз сводит состояние устройств и все световые представления к
|
||
общим семантическим resolver-функциям, смягчает Glow и устраняет последний
|
||
артефакт Т-стыка после объединения стен.
|
||
|
||
- **Системный resolver состояния устройства вместо «первой сущности».** У HA
|
||
нет единого состояния Device: House Plan теперь сначала исключает
|
||
`config`/`diagnostic`, затем выбирает функциональную роль устройства,
|
||
семантические binary-сигналы и лишь при их отсутствии обычные switches.
|
||
Пассивные датчики агрегируются, поэтому одна недоступная сущность не делает
|
||
недоступным весь маркер. Это одним правилом исправляет X50 с недоступным
|
||
Customized Cleaning, presence с включённым Anti interference, TRV со
|
||
служебными switches и аналогичные интеграции. Настоящая сущность cover также
|
||
сильнее настройки reverse-direction, но смешанное устройство lamp+cover
|
||
остаётся лампой до явного выбора действия шторы.
|
||
- **UX-12: один набор источников света.** Glow, заливка «Свет», строка света
|
||
карточки комнаты, индикация маркера и групповое управление теперь используют
|
||
`resolvedLightSources(room)`. Приоритет един: `controls` → флаг «Это источник
|
||
света» → автоматические `light.*`; скрытые маркеры исключаются, сущности не
|
||
дублируются, а ручной `room_id` точнее HA-зоны. Поэтому отмеченное реле и
|
||
управляемая группа одинаково трактуются во всех световых режимах.
|
||
- **Более мягкий glow источников.** Весь слой свечения теперь отображается с
|
||
непрозрачностью `0.7`; затемнение комнат и жёлтая подложка работающего
|
||
устройства не изменились.
|
||
- **Чистые Т-стыки реальных и виртуальных стен после объединения отрезков.**
|
||
Один максимальный реальный отрезок может проходить через более короткие
|
||
коллинеарные стороны нескольких комнат. Теперь точные концы восстанавливают
|
||
толщину на каждой полностью покрытой стороне, даже если midpoint длинной
|
||
записи находится за пределами комнаты. Поэтому hover остаётся на внутренней
|
||
грани, а у виртуального продолжения не появляется ложный торец реальной стены.
|
||
|
||
## v1.59.0 — 2026-08-06
|
||
|
||
Стабильная 1.59 превращает House Plan в существенно более полный редактор
|
||
планов, сохраняя цельное живое представление Home Assistant. В неё входят все
|
||
изменения beta/RC ниже; линейку завершают hover по границе чистого пола и
|
||
устойчивое объединение тел стен.
|
||
|
||
- **Реальные стены, виртуальные границы и проёмы работают как одна система.** В
|
||
комнате можно смешивать толщины, одна стена может состоять из реальных и
|
||
виртуальных участков, а соседние одинаковые фрагменты снова объединяются.
|
||
Resize сохраняет точные концы интервалов; частичные открытия, виртуальные
|
||
Т-стыки, дверные тоннели в толстых стенах и солнечные лучи из внутренних
|
||
углов окон обрабатываются согласованно.
|
||
- **Правки плана однозначны и обратимы.** «Контур комнаты», Split, «Закрыть
|
||
границу», «Объединить комнаты», «Удалить комнату», Resize, толщина стен и
|
||
операции с проёмами имеют по одному результату и используют общий
|
||
именованный Undo/Redo на 50 команд. Delete удаляет только выбранный объект.
|
||
- **Единый обязательный инвариант сетки.** Комнаты, проёмы, маркеры, декор,
|
||
мебель и подложка всегда попадают в сетку либо квантуются вдоль своей стены.
|
||
«Оптимизировать планы» показывает preview и применяет все актуальные
|
||
миграции без потерь, исправляет старые/off-grid данные, уплотняет фрагменты
|
||
стен и оставляет безопасную одношаговую отмену.
|
||
- **Редакторы получили рабочие пользовательские сценарии.** Свойства объектов
|
||
подложки открываются двойным кликом; мебель имеет реальные размеры и магнит
|
||
к стенам; живые надписи принимают произвольный текст вперемешку с вручную
|
||
введёнными или вставленными из picker токенами Home Assistant; управление
|
||
видимостью слоёв и объектов стало явным.
|
||
- **Индикация устройств говорит на одном семантическом языке.** Жёлтый означает
|
||
фактическую работу, оранжевый — открыто/разблокировано, тревога имеет высший
|
||
приоритет, недоступное устройство приглушается, движение является коротким
|
||
событием, а присутствие длится весь детект. Подложка маркера, пульсация и
|
||
заливка «Свет по источникам» согласованы для штор, климата, вентиляторов,
|
||
реле, медиаплееров и других работающих устройств.
|
||
- **Комната объясняет себя в Просмотре.** Glow и toast не перехватывают
|
||
указатель; hover и тултип работают сквозь световое пятно, тултип показывает
|
||
чистую площадь, а диалог устройства содержит явное действие
|
||
«Скрыть»/«Показать». Акцент hover теперь идёт по тем же внутренним граням,
|
||
что используются для площади; у вложенной комнаты выбирается грань,
|
||
обращённая к родительскому полу, а двери, окна и виртуальные участки остаются
|
||
разрывами.
|
||
- **Финальная коррекция тел стен.** Тела формируются как объединение собственного
|
||
кольца `внешний − внутренний` каждой комнаты. Чистый пол родительской комнаты
|
||
больше не может вырезать половину вложенной стены толщиной 15 см либо оставить
|
||
белую щель на сложном перекрёстке.
|
||
- **Документация заново собрана по продукту.** Полное русское руководство,
|
||
таблицы поведения настроек/устройств и план улучшений описывают выпущенный
|
||
код; устаревшие аудиты и разовые debug-материалы перенесены в `legacy/`.
|
||
|
||
## v1.59.0-rc.2 — 2026-08-06
|
||
|
||
Второй release candidate делает редактирование плана предсказуемым и
|
||
обратимым, вводит единый инвариант сетки и завершает обновление документации.
|
||
|
||
- **Один инструмент — один результат.** Закрытие виртуальной границы,
|
||
объединение комнат и удаление комнаты теперь являются тремя отдельными
|
||
действиями редактора плана. Delete удаляет только явно выбранную комнату, а
|
||
инструмент открытия больше не закрывает существующий пунктирный участок.
|
||
Рисование переименовано в «Контур комнаты»: оно создаёт замкнутую комнату, а
|
||
не свободную стену.
|
||
- **Единая именованная история геометрии.** Создание, Split, Merge, Resize,
|
||
удаление комнаты, толщина стен, виртуальные границы и добавление,
|
||
редактирование, перемещение или удаление дверей/окон используют общий стек
|
||
Undo/Redo на 50 команд. Кнопки панели и Ctrl+Z, Ctrl+Shift+Z/Ctrl+Y работают
|
||
с теми же именованными шагами; новая ветка очищает Redo. Эхо собственных
|
||
серверных записей карточки сохраняет историю, а действительно новая внешняя
|
||
ревизия безопасно её сбрасывает.
|
||
- **Сетка обязательна.** Shift больше не позволяет поставить комнаты, маркеры,
|
||
подписи, декор, мебель, подложку или проёмы между позициями сетки. Свободные
|
||
точки попадают в узлы, а привязанные к стене объекты проецируются и
|
||
квантуются вдоль неё. Shift остался только у явно угловых контролов.
|
||
«Оптимизировать планы» исправляет старые и импортированные off-grid данные.
|
||
- **Понятнее обратная связь.** Glow больше не перехватывает указатель, поэтому
|
||
hover комнаты и тултип работают сквозь световое пятно. Контур hover в режиме
|
||
просмотра охватывает весь физический периметр, включая общие толстые стены.
|
||
В диалоге существующего устройства появилось явное нижнее левое действие
|
||
«Скрыть»/«Показать». Из редактора статической карточки удалено неработавшее
|
||
поле `aspect_ratio`. Toast-уведомления не перехватывают указатель и больше не
|
||
могут перекрыть рабочую ручку инструмента под собой.
|
||
- **Документация и порядок в репозитории.** Новое полное русское руководство и
|
||
продуктовый аудит/план улучшений описывают фактическое поведение, матрицы
|
||
настроек и устройств. Устаревшие аудиты, отклонённые дизайн-заметки и разовые
|
||
debug-скрипты перенесены в `legacy/`; активная документация и автоматические
|
||
сценарии приведены к новым контрактам сетки, Undo и раздельных действий.
|
||
|
||
## v1.59.0-rc.1 — 2026-08-06
|
||
|
||
Первый release candidate линейки 1.59: безопасная оптимизация всех планов,
|
||
понятнее редактирование объектов и обратная связь по комнатам, а также правки
|
||
по результатам аудита beta.10.
|
||
|
||
- **Оптимизация всех планов с безопасной отменой.** Бывшее действие
|
||
«Выровнять по сетке» заменено на «Оптимизировать планы». В одном preview
|
||
выполняются все актуальные без потерь миграции модели, привязка геометрии к
|
||
сетке и стенам, материализация старых открытых границ, объединение соседних
|
||
виртуальных частей и одинаковых по толщине реальных фрагментов. Config и
|
||
layout записываются через устойчивое намерение для двух хранилищ; одна отмена
|
||
доступна до следующей правки плана. Калибровка подложки, сохранённые виды,
|
||
непривязанные позиции и пользовательские файлы не изменяются. Прерванная
|
||
оптимизация или отмена завершается при следующем запуске интеграции.
|
||
- **Свойства объекта подложки по двойному клику.** В режиме «Выбрать» редактора
|
||
подложки двойной клик по любому объекту открывает его свойства: для надписи
|
||
остаётся форма текста, а для линии, прямоугольника, овала и мебели появляется
|
||
компактный диалог цвета и толщины линии (для замкнутых фигур — ещё и заливка).
|
||
Черновик нового диалога переживает тёплый ре-маунт карточки.
|
||
- **Комната обозначает себя в Просмотре.** При наведении подсвечивается именно
|
||
текущая комната, в том числе без настроенной заливки или HA area. В тултипе
|
||
также показывается форматированная чистая площадь пола; при толстых стенах
|
||
используется тот же внутренний контур, что в подписях и измерениях Resize.
|
||
- **Жёлтая подложка работающего устройства остаётся универсальной.** Устройство
|
||
в семантическом состоянии «включено / работает» остаётся жёлтым и при заливке
|
||
комнаты «Свет по источникам». Световое пятно дополняет состояние маркера, а
|
||
не заменяет его.
|
||
- **Исправления по аудиту beta.10.** Первое настоящее событие устройства после
|
||
загрузки больше не поглощается перестроением реестра, а смена фактического
|
||
источника маркера сразу сбрасывает короткий эффект старого источника. При
|
||
редактировании старой живой надписи явная единица или непредставимый inline-
|
||
грамматикой атрибут сохраняются без потерь; старый выбор `attr: state`
|
||
превращается в токен состояния, а не в несуществующий атрибут. Фрагменты
|
||
толщины стен теперь хранят точные нормализованные концы (старые midpoint-ключи
|
||
продолжают читаться), переживают Resize и после закрытия виртуальных частей объединяются
|
||
в максимальные сплошные отрезки одинаковой толщины. Пунктир виртуальных стен
|
||
виден во всех редакторах даже при скрытых границах. Release CI теперь явно
|
||
сообщает о проблеме порядка prerelease в GitHub/HACS, а не молча публикует
|
||
beta, которую HACS не может обнаружить.
|
||
|
||
## v1.59.0-beta.10 — 2026-08-05
|
||
|
||
Десятый pre-release линейки 1.59: единая система состояния устройств и набор
|
||
точечных улучшений стен, света через дверные проёмы и надписей подложки.
|
||
|
||
- **Единый язык состояния устройств.** Подложка и эффекты маркера теперь
|
||
вычисляются одним семантическим resolver: жёлтый означает фактическую работу,
|
||
оранжевый — открыто/разблокировано, недоступное устройство приглушается, а
|
||
тревога всегда остаётся красной. В списке отображения остались «Значок»,
|
||
«Значок + активность» и «Значение вместо иконки»; удалённый режим «Только
|
||
пульсация» при следующем сохранении переходит в «Значок + активность».
|
||
Активность различает короткое событие, постоянное присутствие, механическое
|
||
движение и фактическую работу, не создавая ложного события при загрузке или
|
||
восстановлении связи. Короткие эффекты также сбрасываются при смене
|
||
фактического источника маркера, а реальное открытие/закрытие шторы имеет
|
||
приоритет над временной реакцией на нажатие.
|
||
- **Более понятная панель рисования стен.** Бывшая кнопка «Добавить» в
|
||
редакторе плана теперь называется «Стены», а поле толщины новых стен стоит
|
||
сразу справа от неё, а не после остальных инструментов панели.
|
||
- **В режиме просмотра виртуальные стены находятся под телом толстой стены.**
|
||
Их сохранённая геометрия по-прежнему доходит до физической осевой линии, но в
|
||
View штриховка скрывает концы пунктира внутри примыкающих толстых стен. Во
|
||
всех трёх редакторах сохранённый пунктир и живой preview остаются поверх тела
|
||
стены, чтобы весь отрезок был виден во время правки.
|
||
- **Свет из двери учитывает откосы толстой стены.** Теперь свет проходит через
|
||
дверной проём только по свободной ширине его физического тоннеля. Ближний и
|
||
дальний внутренние срезы совместно ограничивают пучок, поэтому оба стеновых
|
||
откоса корректно отсекают лучи смещённого источника; для стены без толщины
|
||
сохраняется прежний сектор проёма.
|
||
- **Inline-переменные HA в тексте подложки.** Одна надпись теперь может
|
||
сочетать обычный текст и несколько ссылок `{entity}` / `{entity:attribute}`.
|
||
Выбор состояния или атрибута вставляет токен в позицию курсора textarea.
|
||
Отдельное поле единицы, подсказка про один слот и предпросмотр удалены;
|
||
старые связанные надписи продолжают читаться и при редактировании переходят
|
||
на inline-токены.
|
||
- **Канонические фрагменты стен.** Соседние или перекрывающиеся виртуальные
|
||
отрезки на одной границе одной пары комнат теперь объединяются в один
|
||
`open_span`; части Split, принадлежащие разным парам комнат, остаются
|
||
раздельными. Если после удаления последних виртуальных участков исходная
|
||
стена снова целиком реальная и имеет одну толщину, её атомарные ключи
|
||
схлопываются обратно в один ключ цельной стены.
|
||
|
||
## v1.59.0-beta.9 — 2026-08-05
|
||
|
||
Девятый pre-release линейки 1.59: целостный resize смешанных
|
||
виртуальных/толстых стен и чистые, видимые виртуальные Т-стыки.
|
||
|
||
- **Resize сохраняет смешанную виртуальную/толстую стену.** Во время перетаскивания
|
||
`open_spans` и целые/атомарные ключи толщины теперь двигаются вместе с polygon
|
||
комнат; commit больше не удаляет толщину реальных остатков, а Undo
|
||
восстанавливает всю транзакцию целиком.
|
||
- **Чистые Т-стыки с виртуальной стеной.** Реальные плечи, принадлежащие разным
|
||
контурам комнат, получают недостающий митровый угол у конца `open_span` вместо
|
||
ступеньки. Пунктир и двухкликовое preview виртуальной стены рисуются поверх
|
||
реального тела стены и видны до самой осевой линии стыка.
|
||
|
||
## v1.59.0-beta.8 — 2026-08-05
|
||
|
||
Восьмой pre-release линейки 1.59: правки после аудита beta.7, fail-closed
|
||
контур выпуска, паритет рендера стен в полной и статической карточках
|
||
и солнечные лучи из внутренних углов толстых оконных проёмов.
|
||
|
||
- **Солнечные лучи начинаются из внутренних углов окна.** При заданной
|
||
толщине стены полное основание луча теперь лежит на внутренней грани
|
||
проёма, поэтому оба чётких боковых ребра выходят точно из двух
|
||
внутренних углов даже при косом солнце. Внутренний контур пола по-прежнему
|
||
не даёт свету проходить через тело стены.
|
||
- **Правки по аудиту beta.7.** Split поперёк одного `open_span` теперь сохраняет
|
||
все валидные отрезки для разных пар комнат и строит `open_to` для обеих новых
|
||
комнат, не превращая половину прохода обратно в сплошную стену
|
||
(`AUD-159B7-01`).
|
||
- **Безопасный выпуск.** `release.yml` разворачивает опубликованный tag в точный
|
||
commit и ждёт зелёного завершения всех Validate этого SHA; отсутствие,
|
||
ошибка, отмена или timeout не дают приложить asset (`AUD-159B7-02`).
|
||
Для той же fail-closed политики добавлены автоматические negative tests.
|
||
- **Паритет тестов и рендера.** Smoke общих настроек учитывает группу Walls,
|
||
inventory считает методы классов и trail-тесты backend, а статическая
|
||
карточка применяет тот же порог 3 px для отключения штриховки тонкой стены,
|
||
что и полная (`AUD-159B7-03`, `AUD-159B7-04`).
|
||
|
||
## v1.59.0-beta.7 — 2026-08-05
|
||
|
||
Седьмой pre-release линейки 1.59: правки по аудиту частичных стен и lifecycle,
|
||
плюс цвет заливки **под** штриховкой.
|
||
|
||
- **Заливка + штриховка.** Общая настройка `fill_colors.wall_fill` (по умолчанию
|
||
непрозрачный белый) рисуется под диагональной штриховкой; штриховка остаётся.
|
||
На экране тоньше ~3px — только заливка, чтобы штриховка не превращалась в шум.
|
||
- **Атомарные интервалы стен (AUD-159B6-01).** Толщина и открытые отрезки идут
|
||
по концам shared / open-span, а не по целой грани polygon — частичная общая
|
||
стена больше не «протекает» толщиной на внешний остаток, а открытый отрезок
|
||
не у midpoint грани снимает толщину только со своего куска.
|
||
- **Транзакция open_spans (AUD-159B6-02).** `open_spans` в snapshot/Undo
|
||
ресайза; Split / Merge / Delete пересчитывают spans и `open_to` одним шагом,
|
||
без воскрешения legacy mid-mutation.
|
||
- **Схема backend `open_spans` (AUD-159B6-03)** с cap / finite points / dedupe;
|
||
frontend fail-soft отбрасывает битые записи.
|
||
- **Warm owner vs pending nav (AUD-159B6-04):** принятие warm viewport сбрасывает
|
||
глобальный pending mode из LS.
|
||
- **Smoke / inventory (AUD-159B6-06):** двухкликовые фикстуры, island по id,
|
||
inventory считает `test` и `it`.
|
||
|
||
## v1.59.0-beta.6 — 2026-08-05
|
||
|
||
Шестой pre-release линейки 1.59: частичные открытые отрезки стен и «Удалить» по стенам.
|
||
|
||
- **Частичные открытые (виртуальные) отрезки стен** (`space.open_spans`): два
|
||
клика в «Открытая граница» (якорь → второй конец на общей стене, не дальше
|
||
ближайших углов); курсор-крестик; проёмы на виртуальном удаляются и не
|
||
ставятся; толщина сбрасывается при открытии и восстанавливается с соседнего
|
||
глухого / 15 см при закрытии. Старый `open_to` на чтении = вся shared boundary.
|
||
- **«Удалить» по стенам**: виртуальная → обычная; общая глухая → confirm merge
|
||
(вся shared); внешняя или клик внутрь → confirm удалить комнату.
|
||
|
||
## v1.59.0-beta.5 — 2026-08-05
|
||
|
||
Пятый pre-release линейки 1.59: переработка толщины стен (бесшовные кольца ±½, чистый пол/заливка/солнце), рисование с толщиной, новое пространство открывает редактор плана, hygiene по аудиту beta.4.
|
||
|
||
- **Рисование с толщиной стен.** В панели Draw редактора плана — поле толщины
|
||
(по умолчанию 15 см / дюймы HA). Новые комнаты получают её при сохранении;
|
||
общие стены сохраняют значение соседа; пустое поле — без толщины. Живой
|
||
превью толстых стен во время черчения.
|
||
|
||
- **Новое пространство открывает редактор плана.** После сохранения только что
|
||
созданного пространства включается Plan с инструментом «рисовать», чтобы
|
||
пустой этаж не оставался в View без содержимого (как при онбординге первого
|
||
пространства).
|
||
|
||
- **Переработка толщины стен (docs/WALL-THICKNESS.md).** Стены растут ±½ от
|
||
осевой (наружные и общие); тела — кольца outset−inset, объединённые в одну
|
||
штриховку (бесшовные L/T); заливка/glow/солнце клипятся по внутреннему
|
||
контуру; м² — чистый пол; лучи сужаются в туннеле проёма. Resize/undo/scale
|
||
сохраняют и пере-ключают `walls`; проёмы привязываются по углу; режим
|
||
редактора восстанавливается после `can_write`. Штриховка совпадает с цветом
|
||
контура.
|
||
|
||
## v1.59.0-beta.4 — 2026-08-05
|
||
|
||
Четвёртый пре-релиз ветки 1.59: толщина стен в редакторе плана и фикс — в
|
||
редакторах под сеткой остаётся белый лист даже с загруженной подложкой.
|
||
|
||
- **Толщина стен в редакторе плана (docs/WALL-THICKNESS.md).** У стены одна
|
||
толщина (`space.walls: [{ key, cm }]`), ввод в см или дюймах по системе HA.
|
||
Общие стены растут пополам в каждую комнату; наружные — внутрь; открытая
|
||
граница толщины не принимает. Штриховка следует `show_borders` (в редакторе
|
||
плана всегда видна); проёмы вырезают slab на всю глубину, дуга двери — от
|
||
внутренней грани. Площадь, glow и солнце остаются на полигоне. Static
|
||
space-card рисует те же тела. Юнит + smoke: `test/wall-thickness.test.mjs`,
|
||
`demo/smoke_wall_thickness.mjs`.
|
||
|
||
- **В редакторах под сеткой остаётся белый лист и с подложкой.** С загруженной
|
||
картинкой плана редакторы плана / устройств / декора брали цвет карточки
|
||
темы вместо белого листа рукописного плана. Теперь лист белый; Просмотр без
|
||
изменений (тема под картинкой, белый без неё).
|
||
|
||
## v1.59.0-beta.3 — 2026-08-05
|
||
|
||
Третий пре-релиз ветки 1.59: план можно обставить символами вида
|
||
сверху в реальном размере, скрыть декоративный слой или проёмы в режиме
|
||
просмотра, не теряя их, нацелить card-mod на стабильные `data-*`, а
|
||
значения сущностей форматировать так же, как родная карточка «Подробнее»
|
||
в HA. С этим же — полировка редакторов (ручки-бусины, редактор подложки
|
||
открывается на своём инструменте, виртуальные стены следуют опции границ)
|
||
и правки по аудиту (политика записи, дифференциация в README, жёстче
|
||
валидация). Толщина стен утверждена только как спецификация
|
||
(docs/WALL-THICKNESS.md); в коде её ещё нет.
|
||
|
||
- **Два новых переключателя в настройках пространства: «Скрыть декоративный
|
||
слой» и «Скрыть проёмы».** Оба только прячут. Фигуры, надписи, мебель и
|
||
проёмы остаются в конфиге, и каждый слой видно в том редакторе, которому он
|
||
принадлежит: декор — в редакторе подложки, проёмы — в редакторе плана.
|
||
Слой, которого не видно, — это слой, который нельзя отредактировать. Смысл
|
||
проёма не меняется вообще: свет по-прежнему проходит, солнце светит в окно,
|
||
датчик открытия срабатывает — исчезает только символ. По умолчанию оба
|
||
выключены и в этом состоянии ничего не хранят, так что все существующие
|
||
планы читаются без изменений.
|
||
|
||
- **Если пространство не рисует границы комнат — оно больше не рисует и
|
||
виртуальные стены.** При выключенной опции «Всегда отображать границы
|
||
комнат» пунктиры открытых границ оставались сами по себе, и на плане не было
|
||
стен, кроме нескольких висящих в воздухе пунктирных кусков. Теперь они
|
||
подчиняются той же опции. В редакторе плана пунктиры остаются — инструменту
|
||
«Открытая граница» надо показывать то, что он правит.
|
||
|
||
- **Редактор подложки открывается на том инструменте, в честь которого
|
||
назван.** Если в пространстве есть картинка, инструмент «Картинка-подложка»
|
||
включён сразу при входе, и картинка тянется мышью с первого движения, а не
|
||
после того, как инструмент найден. Рамка вокруг картинки рисовалась при
|
||
входе и раньше — то есть обещала, что картинку можно двигать; теперь
|
||
обещание выполняется. «Выбрать» никуда не делся, он в одном клике и
|
||
по-прежнему оставляет тело картинки одностопальцевому панорамированию.
|
||
|
||
- **Ручки по углам снова бусины, а не блины.** Все угловые ручки карточки —
|
||
рамка картинки-подложки, рамка масштаба комнаты и подгонка карты робота —
|
||
рисуются кружком **вчетверо** меньше прежнего, а область нажатия у них
|
||
прежняя, как уже сделано у текстового блока. Ручка размером с комнату
|
||
закрывает собой то, что ею настраивают.
|
||
|
||
- **План можно обставить мебелью (docs/FURNITURE.md).** В редакторе подложки
|
||
появился седьмой инструмент — **«Мебель»**: палитра из ~30 символов вида
|
||
СВЕРХУ, сгруппированных по-человечески (мебель / техника / сантехника /
|
||
прочее — лестница, камин, ковёр), и ставятся они в **реальном размере**.
|
||
Выбрали диван, поправили 2,2 × 0,9 м в двух полях, если ваш диван другой,
|
||
кликнули по плану — и он занимает ровно 2,2 м *вашего* плана, потому что
|
||
размер идёт через `cell_cm` пространства, как и любая другая длина в этой
|
||
карточке. Пока предмет ставится или тащится, ближайшая стена в пределах
|
||
~30 см забирает его себе: спинка ложится вплотную к стене, предмет
|
||
доворачивается по ней — «поставить кровать к той стене» это один клик.
|
||
Shift магнит отключает, как отключает здесь любое прилипание. Поставленный
|
||
предмет сразу выделен в инструменте «Выбрать» и носит рамку текстового
|
||
блока: угловые ручки теперь меняют **ширину и глубину НЕзависимо** (кровать
|
||
не становится глубже оттого, что стала шире), во время растягивания видны
|
||
живые плашки с обоими размерами в метрах или футах, а ручка сверху
|
||
поворачивает предмет шагом 5°. Символы **нарисованы нами, прямо в коде**:
|
||
иконочный набор рисует диван спереди в квадрате 24 × 24, и растянуть такую
|
||
картинку на прямоугольник 2,2 × 0,9 м — это получить иконку, лежащую на
|
||
полу, а не план. Заодно это закрывает лицензионный вопрос начисто: ничего
|
||
чужого в бандл не попало. У каждого предмета есть `data-kind="furniture"` и
|
||
`data-symbol`, так что card-mod красит всю сантехнику одним правилом. Вид
|
||
фигуры новый, миграции нет: план, написанный до этого, читается
|
||
байт-в-байт.
|
||
|
||
- **У плана появились стабильные «крючки» для card-mod
|
||
(docs/STYLING-HOOKS.md).** У каждого объекта, который рисует план, теперь
|
||
одна и та же опознавательная тройка: `data-hp` говорит, что это
|
||
(`device`, `room`, `room-label`, `opening`, `decor`, `space-tab`), `data-id`
|
||
— его идентификатор в вашем конфиге, а где уместно — `data-entity`,
|
||
`data-area` и `data-kind` (дверь/окно, линия/прямоугольник/овал/текст). И
|
||
это всё: мы не заводим поле для CSS, не делаем редактор тем и не
|
||
поддерживаем пользовательские стили — мы просто перестаём мешать тому, кто
|
||
уже поставил card-mod, и кому не хватало только чего-то устойчивого, за что
|
||
зацепиться. Эти имена теперь контракт: переименовать хоть одно — ломающее
|
||
изменение. Всё, чего в таблице НЕТ — оснастка редакторов, загрузочные
|
||
классы, обёртки слоёв, разметка диалогов — контрактом явно не является. В
|
||
документе таблица, три разобранных примера, ограничения shadow DOM
|
||
(стилизовать хост `ha-icon` можно, его внутренности — нет) и прямая
|
||
оговорка, что card-mod не наш и поддерживать его мы не будем.
|
||
|
||
- **Значения форматирует Home Assistant, а не мы.** Везде, где карточка
|
||
печатает состояние одной сущности — бейдж маркера в режиме «значение вместо
|
||
значка», живая надпись в декоре, инфо-карточка устройства — теперь зовётся
|
||
`hass.formatEntityState` (и `hass.formatEntityAttributeValue` для атрибута),
|
||
ровно то же, что делает родная карточка «Подробнее» в HA. Значит, работает
|
||
настроенная у датчика точность отображения (`display_precision`), разделитель
|
||
дробной части — ваш, а `on` наконец читается как «Включено», а не как `on`.
|
||
Единица попадает в строку ровно один раз: форматтер обычно приписывает её
|
||
сам, а где не приписал — приписываем мы; своя единица на надписи декора
|
||
ЗАМЕНЯЕТ единицу сущности, а не громоздится следом. Старый Home Assistant
|
||
без этих методов ведёт себя в точности как раньше. Маленькие плашки °/%
|
||
рядом со значком намеренно оставлены нашими: это производное показание
|
||
(среднее по датчикам зоны, `current_temperature` климата), а не состояние
|
||
сущности, и весь план читается как один прибор именно потому, что они
|
||
одинаковые.
|
||
|
||
- **Ручки текстового блока стали в четыре раза меньше** (просьба владельца).
|
||
Кружки по углам и ручка поворота над выделенной надписью теперь размером с
|
||
бусину, а не с кнопку, — рамка перестала закрывать те самые слова, которые
|
||
обрамляет. Область, за которую можно взяться, не изменилась: невидимый
|
||
пальцевый круг по-прежнему держит жест на прежних 1,8 % видимого вида —
|
||
ровно то же разделение, что у ручек ресайза стен.
|
||
|
||
- **Толщина стен — утверждённая спецификация (docs/WALL-THICKNESS.md).** Пока
|
||
не реализована; в документе модель (толщина у стены, а не у ребра комнаты),
|
||
ключи сегментов, пережившие ресайз, штриховка без влияния на площадь и
|
||
отрисовка проёмов в толстой стене.
|
||
|
||
Правки по аудиту (`legacy/docs/audit-v1.58.0/AUDIT-RECOMMENDATIONS.md`, 2026-08-05):
|
||
|
||
- **Политика записи выровнена (P0-4).** `admin_only` по умолчанию **включён**
|
||
для новых установок и при отсутствии ключа; `houseplan/config/get` отдаёт
|
||
`can_write` из `may_write`, а редакторы карточки следуют этому флагу.
|
||
Отсутствующий `hass.user` больше не открывает редакторы «на удачу».
|
||
- **Дифференциация в README (P0-3).** Таблица сравнения ставит House Plan
|
||
против YAML/SVG и против GUI-рисовалок (напр. easy-floorplan): общий
|
||
`.storage`-план и комнаты по зонам, а не CAD мебели.
|
||
- **Жёстче валидация (P3-4).** `binding` маркера — только `device:…` /
|
||
`entity:…` / `virtual`; `ripple_color` — `#rrggbb`; размеры decor
|
||
строго положительные; `id` пространства по `SPACE_ID_RE`.
|
||
- **Гигиена (P3-5).** В `quality_scale.yaml` верный файл теста config-flow;
|
||
card-level `tap_action` помечен как deprecated/ignored.
|
||
|
||
## v1.59.0-beta.2 — 2026-08-04
|
||
|
||
Второй пре-релиз ветки 1.59, и он про надписи на плане. Надпись в декоре
|
||
умеет показывать живое значение сущности — подпись становится показанием,
|
||
не превращаясь в язык шаблонов. Сам текстовый блок лишился выбора из трёх
|
||
размеров шрифта: он масштабируется углами и поворачивается ручкой, как
|
||
любой другой объект плана, и в нём может быть несколько строк. Под этим
|
||
закрыты три находки аудита beta.1 — две одинаковые карточки больше не
|
||
делят одну тёплую памятку, быстрый двойной ре-маунт не съедает черновик,
|
||
а просроченный диалог не держит в памяти файл плана.
|
||
|
||
- **Надпись на плане может показывать живое значение (docs/LIVE-TEXT.md).**
|
||
У текстовой фигуры появились три необязательных поля — `entity`, `attr`,
|
||
`unit`, — а её `text` стал шаблоном, в котором `{}` — место значения:
|
||
`Бак {}` читается как *Бак 68 %*. Без плейсхолдера значение добавляется в
|
||
конец; без сущности надпись остаётся ровно той статичной надписью, какой
|
||
была. Единица берётся из сущности, если не задать свою; мёртвая,
|
||
неизвестная или отсутствующая сущность показывает прочерк, а не исчезает
|
||
молча. Ничего не округляется и не переформатируется — значение такое,
|
||
каким его отдаёт Home Assistant: округление живёт в `display_precision`
|
||
сенсора, и дублировать его здесь означало бы две правды. Это не язык
|
||
шаблонов: одно значение, одно место, нечего написать неправильно.
|
||
|
||
- **В форме надписи появились пикер сущности, пикер атрибута и живой
|
||
предпросмотр.** Список атрибутов — собственные атрибуты выбранной
|
||
сущности, в поле единицы подсказкой стоит единица сущности, а
|
||
предпросмотр рисуется той же подстановкой, что и сам план.
|
||
|
||
- **Размер текстового блока задаётся углами, поворот — ручкой.** Выбор из
|
||
трёх размеров шрифта убран: выделите надпись и тяните угол, чтобы менять
|
||
размер, или крутите ручку над блоком — шаг 5°, Shift для любого угла
|
||
(механика та же, что у рамки картинки-подложки). Надписи, сделанные со
|
||
старыми «Мелкий/Средний/Крупный», возвращаются ровно в своём прежнем
|
||
размере, а первая же протяжка заменяет эту настройку тем масштабом,
|
||
который она означала.
|
||
|
||
- **В надписи может быть несколько строк.** Поле текста стало
|
||
многострочным: ваши переводы строк сохраняются и рисуются как переводы
|
||
строк, по центру, а блок растёт вокруг своей точки. Автопереносов нет —
|
||
надпись, которая перекомпоновывается при каждом изменении состояния, это
|
||
надпись, которая прыгает по плану.
|
||
|
||
- **Инструмент «текст» открывает ту надпись, по которой вы нажали.**
|
||
Рисующие инструменты владеют холстом (начало новой линии должно вставать
|
||
ровно на конец старой), и это остаётся в силе — с одним исключением:
|
||
нажатие на существующую надпись инструментом «текст» открывает ЕЁ форму,
|
||
а не создаёт вторую поверх. По пустому месту и по нетекстовой фигуре
|
||
по-прежнему создаётся новая надпись.
|
||
|
||
- **Две одинаковые карточки на одной странице больше не делят тёплую
|
||
памятку (AUD-159B1-01).** Ключом памятки были размер окна и конфиг
|
||
карточки — он не различает два РАЗМЕЩЕНИЯ одного и того же конфига:
|
||
последним писателем оказывался сосед, и карточка, пересозданная на
|
||
своём месте, просыпалась с чужим этажом, чужим режимом и чужим зумом,
|
||
а черновик её настоящего предшественника съедался проверкой режима.
|
||
Теперь памятка хранит запись на каждое РАЗМЕЩЕНИЕ: в ключ вошёл
|
||
`location.pathname` (вид дашборда), а внутри ключа запись занимается
|
||
по DOM-слоту — родительский элемент и позиция в нём, — и запись живого
|
||
соседа не усыновляется никогда. Если два размещения действительно
|
||
неразличимы, усыновляется только осевшая высота шапки (она у них
|
||
одинаковая), но не вьюпорт и не диалог.
|
||
|
||
- **Быстрый двойной ре-маунт больше не уничтожает черновик
|
||
(AUD-159B1-02).** `disconnectedCallback()` сбрасывал флаг «я ещё должен
|
||
предшественнику диалог» ДО снимка, поэтому промежуточный экземпляр в
|
||
цепочке A→B→C писал `dlg: null` поверх черновика, который сам ещё не
|
||
успел восстановить, и третьему не доставалось ничего. Снимок теперь
|
||
делается, пока флаг ещё поднят: несохранённый диалог просто едет по
|
||
цепочке, пока кто-нибудь не проживёт достаточно долго, чтобы его
|
||
открыть.
|
||
|
||
- **Просроченный диалог больше не держит свой payload (AUD-159B1-03).**
|
||
10-секундный TTL был правилом, которое проверяли только в момент
|
||
воскрешения; сама запись продолжала держать диалог — а у диалога
|
||
пространства это целый файл плана в base64 — до перезагрузки страницы.
|
||
Отсоединение теперь заводит защищённую очистку, которая освобождает
|
||
payload ровно тогда, когда он перестаёт быть воскрешаемым (и убирает
|
||
устаревший слот, чтобы следующее усыновление снова было однозначным).
|
||
|
||
## v1.59.0-beta.1 — 2026-08-04
|
||
|
||
Минорный пре-релиз: карточка переживает пересоздание в Lovelace
|
||
бит-в-бит — панорамирование, зум и даже открытый диалог возвращаются
|
||
вместе с ней, — у солнечных лучей появляется тонкая кромка, за счёт
|
||
которой их видно на белой бумаге, «+» для добавления пространства
|
||
уходит из редактора Плана в ряд вкладок, а список уже загруженных на
|
||
сервер планов перестаёт схлопываться в полоску.
|
||
|
||
- **Карточка больше не дёргается — и не теряет открытый диалог — при
|
||
возврате на вкладку (docs/WARM-REMOUNT.md).** Lovelace пересоздаёт
|
||
элемент карточки при переподключении websocket; v1.58.0 убрала мигание
|
||
прелоадера, но новому экземпляру всё ещё приходилось угадывать, на что
|
||
смотрел умерший. Измерено: ПАН не переживал экземпляр вообще (вид,
|
||
отъеханный в угол, возвращался в центр: x=50 → x=250 при зуме 2.2), а
|
||
зум РЕДАКТОРА намеренно не сохраняется, тогда как РЕЖИМ редактора —
|
||
сохраняется; поэтому ре-маунт внутри редактора возвращался на 1.0
|
||
вместо 3.0. Тёплая памятка теперь несёт весь вьюпорт (пространство,
|
||
режим, зум, сам прямоугольник `_view`, снимок вида для выхода из
|
||
редактора, кадр «показать дальние», выбранный инструмент и выделение,
|
||
локальный переключатель «показать скрытые») — восстанавливается тот же
|
||
ПРЯМОУГОЛЬНИК, а не то же число зума: бит-в-бит, проверено покадрово.
|
||
|
||
- **Открытый диалог переживает пересоздание вместе с черновиком.**
|
||
Памятка — состояние модуля, её никто не сериализует, поэтому живой
|
||
объект-черновик (в том числе наполовину заполненный диалог устройства с
|
||
уже загруженными PDF) переезжает бесплатно. Правило: **воскрешаем
|
||
черновик, не воскрешаем решение** — подтверждения «Выровнять всё по
|
||
сетке» и объединения комнат намеренно НЕ восстанавливаются (модалка, всё
|
||
содержимое которой «нажмите OK, и я перепишу ваш план», не должна
|
||
встречать вернувшегося пользователя), как и подтверждение действия по
|
||
тапу (оно держит замыкание на мёртвый экземпляр), мастер импорта этажей
|
||
(он открывается сам) и любой диалог с записью в полёте. Воскрешение
|
||
требует того же пространства и того же режима, происходит не более
|
||
одного раза (снимок съедается) и только если прошлый экземпляр умер не
|
||
раньше чем 10 с назад. Осознанно закрытый диалог — Esc, «Отмена» или
|
||
«Сохранить» — записывает в памятку `null` на ближайшей же отрисовке,
|
||
поэтому вернуться уже не может (smoke_warm_dialogs).
|
||
|
||
- **У солнечных лучей появилась кромка (docs/SUN.md, «The rim»).** На
|
||
белом плане клин света был почти не виден, и прозрачностью это не
|
||
лечится: рисовать свет — значит добавлять яркость, а у белой бумаги её
|
||
больше нет. Теперь у каждого клина по двум БОКОВЫМ рёбрам — тем, что
|
||
уходят вглубь комнаты от концов окна, — идёт тонкая чёрная линия в
|
||
1 px. Она гаснет ровно вместе с заливкой: та же ось градиента, та же
|
||
кривая, тот же порог 85 % (второй градиент собран на стопах первого),
|
||
остаётся ровно в один экранный пиксель при любом зуме
|
||
(`non-scaling-stroke`), обрезается комнатой так же, как сам клин, и
|
||
живёт в том же слое — поэтому порог 3°, двухсекундная анимация,
|
||
облачность, ночь и редакторы управляют ею сами, без единой строки
|
||
отдельной логики. Максимальная непрозрачность 0.42 — подобрана и на
|
||
белом листе, и на тёмном холсте glow. Модель «тень вместо света» из
|
||
legacy/docs/SUN-CONTRAST.md отклонена в пользу этой кромки; тот файл теперь
|
||
фиксирует решение и хранит анализ, из которого оно выросло.
|
||
|
||
- **«+» для добавления пространства — не инструмент редактора.** Кнопка
|
||
рядом с названиями этажей существовала только внутри редактора Плана,
|
||
поэтому добавить второй этаж означало сначала открыть редактор, который
|
||
тебе не нужен. Добавление пространства — это навигация, а не разметка:
|
||
теперь «+» стоит в ряду вкладок во ВСЕХ режимах — в Просмотре и во всех
|
||
трёх редакторах, ровно там же, где уже живёт шестерёнка пространства, и
|
||
по тому же правилу (только администратор). Киоск — витрина: там кнопка
|
||
не отрисовывается вовсе (шапка у него `display:none`, а скрытый, но
|
||
присутствующий узел всё ещё кликабелен из скрипта). Ряд вкладок
|
||
по-прежнему переносится на 390 px (smoke_gear_tabs меряет переполнение).
|
||
|
||
- **«Уже загруженные» снова показывают планы.** В обоих диалогах
|
||
пространства (создание и настройки) список планов, сохранённых на
|
||
сервере, схлопывался в тонкую скруглённую полоску: строки
|
||
отрисовывались, а сам контейнер имел высоту 14 px. Прокручиваемый
|
||
блок — это flex-элемент с автоматическим минимальным размером ноль, а
|
||
тело диалога — flex-колонка с потолком 66 vh, так что сжать до нуля
|
||
можно было именно список. Теперь он не сжимается и держит собственный
|
||
минимум: одновременно видно до пяти миниатюр, остальные прокручиваются.
|
||
Состояния «пусто» и «загрузка» больше не режут собственный текст
|
||
(smoke_plan_picker меряет высоты — старый смок считал только узлы DOM
|
||
и проходил).
|
||
|
||
## v1.58.0 — 2026-08-04
|
||
|
||
Минорный релиз: картинка-подложка становится объектом, который можно
|
||
двигать и масштабировать, непрозрачный лист плана переопределён как
|
||
контуры комнат, рисующие инструменты декора перестают перехватывать
|
||
клик по чужой фигуре, а «Выровнять всё по сетке» честно говорит, что
|
||
собирается сделать.
|
||
|
||
### Картинку-подложку можно двигать и масштабировать (docs/BACKDROP.md)
|
||
|
||
- **Картинка плана больше не прибита гвоздями.** В редакторе подложки
|
||
у неё появляется рамка трансформации: тянешь за тело — двигается,
|
||
тянешь за угол — меняет размер равномерно (пропорции сохраняются,
|
||
противоположный угол стоит на месте). Пока тянешь, плашка пишет
|
||
реальный размер картинки в метрах (или футах) — через `cell_cm`
|
||
пространства. Положение и размер ложатся на сетку, Shift снимает
|
||
привязку. Больше ничего не двигается: комнаты, двери, устройства и
|
||
декор остаются на месте; поворота нет.
|
||
- Три новых необязательных поля пространства: `plan_x`, `plan_y`,
|
||
`plan_scale`. Их отсутствие — ровно прежнее поведение, поэтому
|
||
**старые планы рисуются один в один и ничего не мигрируется**.
|
||
Кнопка «Вернуть картинку» в панели их удаляет.
|
||
- **Непрозрачный лист-бумага теперь всегда строится по контурам
|
||
комнат.** Раньше при картинке бумагой был её прямоугольник; теперь
|
||
картинка рисуется НА бумаге — над ней и под стенами. Цвет сцены
|
||
(`bg_color`, небо `daynight`) поэтому доходит до наружных стен и на
|
||
плане с картинкой. Осознанное следствие: у прозрачной картинки без
|
||
нарисованных комнат сквозь неё виден фон сцены.
|
||
- «Вписать всё» учитывает сдвинутую и отмасштабированную картинку —
|
||
потерять её за экраном больше нельзя.
|
||
|
||
### Рисующие инструменты больше не хватают фигуру под курсором
|
||
|
||
- **Рисующий инструмент владеет холстом.** Когда в редакторе декора
|
||
выбрана Линия, Прямоугольник, Овал или Текст, клик по существующей
|
||
фигуре начинает НОВУЮ фигуру, а не выделяет старую — поэтому линию
|
||
можно начать ровно на конце другой линии, а прямоугольник нарисовать
|
||
поверх залитого. Двойной клик по тексту под рисующим инструментом
|
||
тоже больше не открывает его на правку. Та же инертность работает в
|
||
инструменте «Картинка-подложка»: лежащая поверх плана фигура декора
|
||
не должна мешать тащить саму картинку.
|
||
- «Выбрать» и «Стереть» не изменились: там фигуры по-прежнему
|
||
кликабельны — выделять и удалять положено именно ими.
|
||
|
||
### «Выровнять всё по сетке» держит обещание (AUD-158B1-01)
|
||
|
||
У действия нет отмены, поэтому диалог подтверждения — единственная
|
||
защита, а он занижал масштаб происходящего.
|
||
|
||
- **Максимальный сдвиг измеряется по той геометрии, которая
|
||
записывается**, а не по промежуточной. У прямоугольника мерились
|
||
только исходный угол и дальний — поэтому доводка до минимального
|
||
размера, которая потом раздвигает слишком узкую коробку, в замер не
|
||
попадала, а два угла, где ошибка по X одной стороны складывается с
|
||
ошибкой по Y другой, не смотрели вовсе. Обычная коробка могла
|
||
сдвинуться в √2 раза дальше обещанного, а коробка тоньше шага сетки —
|
||
намного дальше.
|
||
- **Каждое пространство переводится через свой `cell_cm`.** Диалог брал
|
||
один нормализованный максимум и умножал его на размер клетки ПЕРВОГО
|
||
пространства: на плане, где первый этаж нарисован по 5 см на клетку, а
|
||
мансарда по 100 см, обещали 2,5 см вершине, которая уезжала на 50 см.
|
||
Отчёт теперь несёт максимум в сантиметрах и пространство, которому он
|
||
принадлежит, а диалог называет это пространство, если их больше
|
||
одного.
|
||
- Последняя десятая сантиметра округляется **вверх**: обещание не может
|
||
оказаться меньше сделанного.
|
||
|
||
### Проём, у которого неверен только угол, теперь можно исправить (AUD-158B1-02)
|
||
|
||
- Окно, стоящее ровно на своей стене, но с неправильным `angle`,
|
||
возвращалось с `changed: false` — диалог писал «двигать нечего» и не
|
||
показывал кнопку, хотя возвращённый план отличался от поданного.
|
||
Такие проёмы нельзя было выровнять никогда. Угол теперь входит в
|
||
разницу; диалог считает такие проёмы отдельно, а смещение меряется по
|
||
КОНЦАМ проёма, так что поворот на месте в отчёте тоже не бесплатен.
|
||
Разворот проёма на 180° по-прежнему считается исправлением, но ничего
|
||
не смещает.
|
||
|
||
## v1.57.0 — 2026-08-04
|
||
|
||
Минорный релиз: холст становится бесконечным — больше нет «размера
|
||
плана» и края, за который нельзя выйти, — плюс тап-действие для штор и
|
||
жалюзи, полировка солнца, живые линейки при размещении проёмов и
|
||
тёплый ре-маунт без миганий.
|
||
|
||
### Бесконечный холст (docs/CANVAS.md)
|
||
|
||
Понятие «размер сетки» или «размер плана» упразднено. Холст условно
|
||
бесконечен — допустима любая координата, а предел `±5000` оставлен
|
||
только как страховка от мусора (около 60 км плана в масштабе самой
|
||
карточки).
|
||
|
||
- **Если ваш план «уехал» за границу — теперь он просто работает.**
|
||
Некоторые планы выросли за пределы старого квадрата, и устройства
|
||
снаружи было не поставить; единственным выходом было перерисовать
|
||
всё заново. Этого ограничения больше нет: рисуйте, двигайте и
|
||
ставьте устройства где угодно, перерисовывать ничего не нужно. Сам
|
||
сохранённый план не тронут — координаты значат ровно то же, что и
|
||
раньше, никакой миграции.
|
||
- **Существующие планы открываются в точности как прежде.** Проверено
|
||
на реальном конфиге с тремя этажами: стартовые рамки совпадают с
|
||
v1.56.0 бит-в-бит.
|
||
- **Стартовый вид строится по тому, что реально нарисовано.**
|
||
`view_box` стал необязательной подсказкой только для самого первого
|
||
кадра; дальше вид всегда считается по фактическому содержимому, с
|
||
отбраковкой выбросов — одна случайная комната больше не сжимает
|
||
весь план.
|
||
- **Панорамирование при любом зуме и во всех редакторах.** Раньше
|
||
план можно было тащить только выше 100%; теперь — на любом
|
||
масштабе и в любом режиме правки, с запасом в один экран вокруг
|
||
содержимого.
|
||
- **Зум-аут до 3× содержимого** — видно и весь план, и воздух вокруг
|
||
него.
|
||
- **Кнопка «Вписать всё»** — одно нажатие возвращает кадр по всему
|
||
содержимому.
|
||
- **Стрелка «дом там»** появляется, когда вы уехали от плана, и
|
||
показывает дорогу обратно.
|
||
- **Адаптивная сетка.** Шаг сетки выбирается по зуму
|
||
(1 / 2 / 5 / 10 … 1000) вместо фиксированной клетки, а точки
|
||
остаются приглушённой подсказкой и не спорят с планом.
|
||
|
||
### Шторы и жалюзи
|
||
|
||
- **Новое тап-действие «Открыть/закрыть» для штор.** Закрытая —
|
||
откроется, открытая — закроется, а штора в движении остановится.
|
||
Предлагается только для незащищённых классов: гаражные ворота,
|
||
двери и калитки намеренно остаются на информационном диалоге.
|
||
- **Состояние видно по самому значку**: он морфится между открытой и
|
||
закрытой формой (таблица классов штор плюс алиасы по базовой
|
||
иконке) и мягко пульсирует кольцом, пока штора едет.
|
||
- **У шторы никогда нет цветной подложки.** Заливки по состоянию за
|
||
маркером cover не будет.
|
||
- **Cover ищется среди всех сущностей маркера**, а не только среди
|
||
основной — частый случай для устройств Aqara и zigbee2mqtt, — а
|
||
явно выбранное «Открыть/закрыть» всегда имеет приоритет индикации.
|
||
|
||
### Полировка солнца
|
||
|
||
- **Лучи ярче и короче.** Непрозрачность поднята до 0.30, длина
|
||
уменьшена на 30%, боковые грани снова чёткие.
|
||
- **Свет затухает только вдоль луча** и гарантированно доходит до
|
||
нуля раньше конца клина — клин теперь обрезается по расстоянию
|
||
вдоль луча, и «светлый бортик», вылезавший на низком косом солнце,
|
||
исчез.
|
||
- **Жёсткий порог в 3°.** Лучи появляются и исчезают на трёх градусах
|
||
высоты солнца с двухсекундной анимацией, а не вкатываются плавно.
|
||
- **Фон «день/ночь» догоняет солнце** при возврате на вкладку: разрыв
|
||
больше 3° перекрашивается мгновенно, обычный ход по-прежнему дышит
|
||
плавно.
|
||
|
||
### Прочее
|
||
|
||
- **Живые линейки и магнит центра теперь и при РАЗМЕЩЕНИИ проёма**, а
|
||
не только при перетаскивании; расстояния считаются по ребру своей
|
||
комнаты.
|
||
- **Тёплый ре-маунт.** Когда Lovelace пересоздаёт карточку при
|
||
реконнекте, прелоадер больше не показывается и план не мигает, а
|
||
обрыв WebSocket никогда не очищает уже показанный план.
|
||
- **Цвет границ и названий комнат по умолчанию — тёмно-серый
|
||
`#55606c`** вместо синего акцента. Если цвет выбран явно, ничего не
|
||
меняется.
|
||
- **Блок «О карточке» в конце общих настроек** — версия, ссылки на
|
||
GitHub и Telegram.
|
||
- **Шаг угла значка — 5°.**
|
||
- Находки аудитов: кэш солнечных лучей переживает локальные правки,
|
||
скрытые устройства не растягивают кадр, кадр редактора не протекает
|
||
в режим просмотра, комната-выброс не раздувает размер иконок, а
|
||
киоск-пан остаётся паном и не перелистывает этаж.
|
||
|
||
## v1.56.0 — 2026-08-03
|
||
|
||
Минорный релиз: на план приходит солнце — компас, фон «день/ночь» и
|
||
настоящий свет из окон — плюс температура с климатических устройств,
|
||
дизайн-токены в UI, живые линейки при перетаскивании проёмов и фикс
|
||
кэша солнечных лучей.
|
||
|
||
- **Солнце на плане дома** (docs/SUN.md). Скажите плану, где север —
|
||
круговой компас в общих настройках с переопределением в каждом
|
||
пространстве — и карточка начинает жить по `sun.sun` самого
|
||
Home Assistant:
|
||
- *Фон «день/ночь»* (`bg_mode: daynight`): сцена за планом следует
|
||
за высотой солнца — белый ясный день, тёплое золото золотого
|
||
часа, остывающие сумерки, глубокая ночь. Сам план ночью
|
||
приглушается лишь на ~10%, комнаты остаются читаемыми.
|
||
- *Свет из окон* (`sun_rays`): каждое окно на внешней стене пускает
|
||
в свою комнату мягкий клин света — обрезанный контуром комнаты,
|
||
теплее у горизонта, длинный на рассвете и закате, короткий в
|
||
полдень и гаснущий ночью.
|
||
- *Облачность — по желанию* (`weather_entity`): укажите
|
||
weather-сущность, и пасмурное небо приглушит клинья, а дождь или
|
||
снег погасит совсем. Мёртвый датчик солнце не выключает.
|
||
- План теперь лежит на *непрозрачном листе бумаги*, повторяющем
|
||
контуры комнат: фон сцены — `bg_color` или небо «дня/ночи» —
|
||
виден только вокруг стен и не просвечивает сквозь комнаты; в
|
||
режиме «день/ночь» у листа мягкая тень.
|
||
- Пока компас не задан, фича полностью молчит; без `sun.sun`
|
||
диалог настроек объясняет, почему.
|
||
- **Температура с климатических устройств.** Новый чекбокс в диалоге
|
||
устройства выводит `current_temperature` кондиционера или
|
||
термостата на плашку у значка и учитывает её в средней температуре
|
||
комнаты.
|
||
- **Модернизация UI.** Токен-проход по `styles.ts` — 209 «зашитых»
|
||
значений сведены в шкалы отступов/радиусов/шрифтов/теней — и
|
||
родные `ha-switch` / `ha-slider` в диалогах с жёстким фолбэком на
|
||
старые инпуты там, где компоненты HA недоступны.
|
||
- **Живые линейки проёмов.** При перетаскивании двери или окна теперь
|
||
видны живые расстояния до обоих концов стены — по ребру своей
|
||
комнаты; пунктирная направляющая и мягкий магнит центрируют проём
|
||
на стене (Shift отключает магнит).
|
||
- **Фикс DEV-B701-01** — кэш солнечных лучей теперь сбрасывается и
|
||
локальными правками геометрии: клин больше не «застревает», если
|
||
подвинуть стену до подтверждения сервера.
|
||
|
||
## v1.55.3 — 2026-08-02
|
||
|
||
Патч-релиз: два исправления вуали первого открытия из v1.55.2,
|
||
найденные adversarial-аудитом жизненного цикла (AUD-1552-01/02).
|
||
|
||
- **Пересборка дашборда во время первого открытия больше не оставляет
|
||
план скрытым навсегда** (AUD-1552-01). Отключение карточки при
|
||
поднятой вуали (Lovelace пересоздаёт DOM, переключение вью
|
||
перемонтирует карточку) убивало таймеры стабилизации, но сохраняло их
|
||
id — и вуаль уже никогда не снималась. Теперь жизненный цикл вуали
|
||
перезапускается при каждом повторном подключении — с новым отсчётом и
|
||
безусловным жёстким таймаутом; затухание тоже переживает размонтирование
|
||
посреди fade.
|
||
- **Вуаль больше не открывается рано, прямо перед поздней панелью**
|
||
(AUD-1552-02). Два одинаковых замера высоты на 200/400 мс открывали
|
||
план уже на ~400 мс, и хром Home Assistant, пришедший на 450+ мс,
|
||
прыгал на видимом плане — ровно то, от чего вуаль должна защищать.
|
||
Теперь вуаль держится полное защитное окно с trailing quiescence
|
||
(изменения высоты у края окна продлевают ожидание), а короткое время
|
||
после открытия поздний сдвиг применяется плавно (transition высоты),
|
||
а не скачком. Намеренные изменения высоты (вход в редактор)
|
||
по-прежнему применяются мгновенно.
|
||
|
||
## v1.55.2 — 2026-08-02
|
||
|
||
Патч-релиз: спокойное первое открытие — без вспышки зума и прыжков
|
||
макета, пока Home Assistant догружается, — плюс новая настройка цвета
|
||
фона и две полировки редактора.
|
||
|
||
- **План больше не мигает видом по умолчанию перед сохранённым зумом**
|
||
(HP-1551). Сохранённый зум применялся на такт позже первого рендера:
|
||
карточка на кадр рисовала стандартную подгонку и лишь потом прыгала к
|
||
вашей позиции. Теперь он применяется синхронно, до первой отрисовки —
|
||
план появляется ровно там, где вы его оставили.
|
||
- **Вуаль первого открытия прячет план, пока макет не устаканится**
|
||
(HP-1552). Пока Home Assistant догружает свои панели, высота сцены
|
||
может меняться несколько раз, и план заметно прыгал вместе с ней.
|
||
Теперь карточка ждёт под тёмной вуалью с пульсирующим контуром домика,
|
||
пока высота не перестанет меняться, и показывает план уже на месте.
|
||
В режиме киоска вуаль не показывается вовсе.
|
||
- **Новая настройка: цвет фона вокруг плана** (HP-1554). Области вокруг
|
||
плана теперь можно задать любой цвет — в общих настройках для всей
|
||
карточки или отдельно для каждого пространства. Бэкенд проверяет
|
||
значение как hex-цвет #rrggbb.
|
||
- **Круглые концы и стыки линий в редакторе подложки** (HP-1553). Штрихи
|
||
обрывались и стыковались квадратными срезами; теперь концы линий и
|
||
углы скруглены — обведённые стены и контуры выглядят аккуратно.
|
||
- **Ручки стен в инструменте Resize теперь выглядят по делу.** Они вдвое
|
||
меньше прежних, несут значок «стенка со стрелочками», повёрнутый вдоль
|
||
своей стены, и показывают курсор grab — при этом зона клика осталась
|
||
прежней, большой.
|
||
|
||
## v1.55.1 — 2026-08-01
|
||
|
||
Патч-релиз: четыре находки аудита v1.55.0, все — в новом инструменте
|
||
ресайза комнат (HP-1550-01..04).
|
||
|
||
- **Отложенное сохранение больше не утаскивает живое перетаскивание на
|
||
сервер** (HP-1550-01). Превью ресайза писалось прямо в общий объект
|
||
конфигурации, и отложенная запись, оставшаяся в очереди от прошлой
|
||
правки, могла сфотографировать его посреди перетаскивания — ресайз,
|
||
который вы затем отменили по Esc, тихо оставался на сервере и
|
||
возвращался после перезагрузки. Теперь живая геометрия живёт в
|
||
отдельном слое, который видит только отрисовка; в конфигурацию она
|
||
попадает ровно один раз — при отпускании ручки.
|
||
- **Прерванное перетаскивание отменяется, а не сохраняется**
|
||
(HP-1550-03). Когда систему прерывает сам поток ввода — переключение
|
||
приложения, ладонь на планшете — инструмент считал это отпусканием и
|
||
сохранял недоделанную геометрию. Теперь такие прерывания идут тем же
|
||
путём, что и Esc: исходная геометрия возвращается, без шага отмены и
|
||
без записи.
|
||
- **Дверь посреди стены больше не мешает менять её размер**
|
||
(HP-1550-04). Невидимая зона клика двери ложилась поверх ручки стены,
|
||
и такую стену нельзя было схватить ни у одной из комнат. В
|
||
инструменте ресайза ручки теперь главные в hit-тесте (проёмы там всё
|
||
равно не редактируются — они просто едут вместе со стеной), а во всех
|
||
остальных инструментах редактора проёмы кликаются как раньше.
|
||
- **Минимум ~30 см теперь держится для комнаты любой формы**
|
||
(HP-1550-02). Старая проверка мерила только параллельные
|
||
противоположные стены: треугольную комнату можно было сплющить в
|
||
щепку, а повёрнутая комната при масштабировании незаметно уводила
|
||
свою реальную короткую сторону ниже порога. Обе меры теперь не
|
||
зависят от ориентации: перетаскивание стены упирается в любое
|
||
препятствие на её пути (вершину треугольника, косую стену), а рамка
|
||
масштабирования использует истинную минимальную ширину комнаты.
|
||
Комнаты, уже более тонкие, по-прежнему можно улучшать, но не ухудшать.
|
||
|
||
## v1.55.0 — 2026-08-01
|
||
|
||
Минорный релиз: комнаты больше не высечены в камне — новый инструмент
|
||
«Размер» в редакторе плана меняет их габариты перетаскиванием стен;
|
||
плюс обе находки аудита v1.54.3 (HP-1543-01/02).
|
||
|
||
- **Ресайз комнат — новый инструмент «Размер» в редакторе плана**
|
||
(спека: docs/RESIZE.md). У каждой стены появляется ручка в середине;
|
||
тяните её — и стена едет целиком, оставаясь параллельной себе, с
|
||
привязкой к сетке. Работает и для полигонов (включая Г-образные), и
|
||
для старых прямоугольников.
|
||
- **Общие стены всегда двигаются вместе.** Если перетаскиваемая стена
|
||
совпадает с границей соседа, сосед следует за ней: ваша комната
|
||
растёт — соседняя сжимается, щели и наложения не появляются по
|
||
построению. На Т-стыках следует только совпадающий отрезок, при
|
||
необходимости в контур соседа вставляются новые вершины.
|
||
- **Живые цифры во время перетаскивания.** Перетаскиваемая стена и две
|
||
смежные показывают длины в реальных метрах/футах, а площадь комнаты
|
||
в м² обновляется в центре комнаты вживую — для общей стены — площади
|
||
обеих комнат.
|
||
- **Стена упирается там, где должна.** Комната не может стать тоньше
|
||
~30 см (ни своя, ни соседская), контур не пересекает сам себя,
|
||
растущая стена останавливается о чужие комнаты и острова, а двери и
|
||
окна — якоря: проём едет вместе со стеной, и стена с проёмами не
|
||
может стать для них слишком короткой.
|
||
- **Рамка масштабирования всей комнаты.** Клик по комнате в
|
||
инструменте выбирает её: перетаскивание уголка пунктирной рамки
|
||
пропорционально масштабирует контур — с теми же упорами.
|
||
- **Esc и Ctrl+Z.** Esc отменяет текущее перетаскивание и возвращает
|
||
исходную геометрию; одно отпускание ручки — один шаг отмены, Ctrl+Z
|
||
откатывает до 30 шагов, пока инструмент активен.
|
||
- **Исправлено: детекция наложения комнат пропускала равновысокие
|
||
прямоугольники, надвинутые друг на друга.** Найдено при постройке
|
||
упоров ресайза; slide-over теперь считается наложением везде, где
|
||
используется эта проверка, включая инструмент рисования.
|
||
- **Исправлено (HP-1543-01): редакторский зум оставался на экране
|
||
после смены этажа внутри редактора.** Выход из редактора на другом
|
||
этаже, чем тот, где начинали, пропускал восстановление вьюпорта и
|
||
оставлял рабочий зум редактора в режиме просмотра. Теперь такой
|
||
выход откатывается к сохранённому view-зуму текущего этажа.
|
||
- **Исправлено (HP-1543-02): датчик движения, сработавший повторно
|
||
посреди вспышки, оставался невидимым.** Быстрое off→on до конца
|
||
текущей вспышки не перезапускало CSS-анимацию — второе срабатывание
|
||
ничего не проигрывало. Теперь каждый зафиксированный trip получает
|
||
новую идентичность анимации, и вспышка стартует заново; при
|
||
prefers-reduced-motion остаётся статичное кольцо, как и раньше.
|
||
|
||
## v1.54.3 — 2026-08-01
|
||
|
||
Патч-релиз: три раунда качества жизни — спутники значка теперь слушаются
|
||
пер-девайсного множителя размера, редакторский зум перестал протекать в
|
||
режим просмотра, а датчики движения получили собственный визуальный язык.
|
||
|
||
- **Пер-девайсный множитель размера теперь масштабирует и спутники
|
||
значка.** Репорт владельца со скриншотом: у уменьшенного устройства
|
||
бейдж значения, плашки температуры и влажности, подпись LQI, точка
|
||
«new» и кольцо тревоги оставались полноразмерными и нависали над
|
||
крошечным значком. Теперь все спутники следуют за множителем вместе со
|
||
значком.
|
||
- **Редакторский зум — рабочий инструмент, а не сохранённая настройка.**
|
||
Приблизить до 500%, чтобы точно поставить маркер, и закрыть редактор
|
||
раньше означало оказаться в режиме просмотра на тех же 500%. Выход из
|
||
любого редактора теперь восстанавливает тот вид, который был в режиме
|
||
просмотра до начала правок.
|
||
- **Исправлено: редакторский зум всё ещё «воскресал» при переключении
|
||
этажей.** Редакторский вьюпорт гонялся с пер-этажным хранилищем вида и
|
||
побеждал: переключите этаж во время правок — и 500% записывались как
|
||
сохранённый вид этого этажа и встречали вас в следующий раз (шаги
|
||
воспроизведения — от владельца). Теперь редакторский зум в хранилище
|
||
не пишется никогда.
|
||
- **Сработавшие датчики движения и присутствия сигнализируют жёлтым
|
||
кольцом.** Правило прежнее — «подложка = включено»: движение — разовая
|
||
вспышка, три удара в момент обнаружения, без пульсации на хвосте
|
||
cool-down; occupancy/presence держат статичное кольцо, пока
|
||
докладывают о присутствии.
|
||
- Только для стенда: `services.yaml` для стендового `demo_guard`, чтобы
|
||
hassfest оставался зелёным; в саму интеграцию это не попадает.
|
||
|
||
## v1.54.2 — 2026-07-31
|
||
|
||
Патч-релиз: единственная оставшаяся находка повторного аудита v1.54.1
|
||
(HP-1541-01), закреплена регрессиями с обеих сторон контракта.
|
||
|
||
- **Исправлено: пылесос с собственным `selected_map: 0` делил калибровку и
|
||
след между двумя id карты.** Контракт map id из v1.54.1 («побеждает
|
||
первое существующее значение, и ноль — значение») был применён к
|
||
source-сущности, но не к фолбэку карточки на `selected_map` самого
|
||
пылесоса: фронтенд по-прежнему судил по «истинности» и превращал `0` в
|
||
`default`, тогда как серверный рекордер писал уборку под `0`. Калибровка
|
||
сохранялась под ключом, которого рекордер не использовал, а записанный
|
||
след после перезагрузки не отображался. Теперь фолбэк живёт по тому же
|
||
правилу «не-null» с обеих сторон (`vacMapIdWithFallback` в карточке,
|
||
`resolve_map_id` на сервере), с кросс-регрессиями для `selected_map` =
|
||
`0`, `"0"` и `""`.
|
||
|
||
## v1.54.1 — 2026-07-31
|
||
|
||
Патч-релиз: всё, что нашёл adversarial-аудит v1.54.0 (HP-1540-01..06),
|
||
каждый фикс закреплён регрессией, падающей на старом коде.
|
||
|
||
- **Исправлено: первая калибровка только что обнаруженного пылесоса молча
|
||
ничего не делала.** Пока диалог устройства ни разу не сохранён, у робота
|
||
нет маркера в конфиге — а раздел «Живая позиция» уже полностью
|
||
интерактивен: каждый обработчик тихо выходил, но автокалибровка всё равно
|
||
объявляла успех. Теперь любая правка пылесоса сама создаёт маркер, а тост
|
||
успеха появляется только после того, как матрица действительно легла в
|
||
конфиг.
|
||
- **Исправлено: робот с первой картой `map_index: 0` терял серверный
|
||
след.** Бэкенд выбирал id карты по «истинности» и выбрасывал ноль, так
|
||
что записанная уборка хранилась под ключом, который карточка не искала.
|
||
Теперь обе стороны живут по одному явному правилу: побеждает первое
|
||
существующее значение, и ноль — значение.
|
||
- **Исправлено: один робот на двух этажах писал историю только для
|
||
последнего этажа.** Рекордер держал по одному маркеру на источник, и
|
||
второе размещение молча вытесняло первое. Теперь каждый маркер источника
|
||
получает свою копию уборки.
|
||
- **Исправлено: автокалибровка не видела планы из прямоугольных комнат.**
|
||
Сопоставление принимало только полигоны, а потом сваливало вину на имена
|
||
комнат. Старые прямоугольники считаются, как и во всей остальной
|
||
карточке.
|
||
- **Исправлено: пересекающиеся обновления рекордера текли подписками.**
|
||
Два одновременных сохранения конфига могли подписаться оба и бросить один
|
||
callback до перезапуска; обновления теперь сериализованы, а teardown
|
||
выигрывает у любого ещё летящего обновления.
|
||
- Тосты «нет комнат» / «имена не совпали» и docs/VACUUM.md больше не
|
||
отправляют к несуществующей калибровке по трём точкам — они ведут к
|
||
«Подогнать вручную», которая существует.
|
||
|
||
## v1.54.0 — 2026-07-31
|
||
|
||
### Роботы-пылесосы вживую
|
||
|
||
План теперь показывает робота за работой. Маркер устройства остаётся там,
|
||
куда вы его поставили — это база, — а по плану в реальном времени едет
|
||
круглая шайба, «выливая» путь из-под себя. Только отображение: карточка
|
||
ничего роботу не командует.
|
||
|
||
- **Калибровка без арифметики.** «Настроить автоматически» сопоставляет
|
||
комнаты робота с вашими по именам и решает привязку в один клик. Если
|
||
имена не совпали, панель подгонки кладёт комнаты робота на план
|
||
пунктирным призраком: перетащите на место, растяните за уголки, поворот
|
||
на 90° и зеркало — двумя кнопками. Зеркало включено по умолчанию: у всех
|
||
измеренных нами роботов ось Y перевёрнута относительно экрана. Своя
|
||
калибровка на каждую карту робота, поэтому два этажа не мешают друг другу.
|
||
- **Путь пишется на сервере.** Интеграция следит за роботом сама, поэтому
|
||
след записывается даже без открытой карточки, переживает перезагрузку
|
||
страницы, и все экраны видят одну и ту же линию. Хранятся текущая уборка
|
||
и одна предыдущая — сразу видно, где робот уже прошёл, а где ещё нет.
|
||
- **«Показывать путь робота»**: никогда / во время уборки (по умолчанию) /
|
||
всегда. Прошлая уборка бледной линией рисуется только в последнем режиме.
|
||
- След никогда не обгоняет иконку: отрисованные отрезки отстают на точку, а
|
||
растущий кончик каждый кадр приклеен к центру едущей шайбы. Рисуется
|
||
тёмным ореолом со светлой сердцевиной — читается на любой заливке комнат.
|
||
При смене вида (зум, этаж, возврат на вкладку) шайба телепортируется, а
|
||
не едет через весь план.
|
||
- Поддержаны Xiaomi Cloud Map Extractor, dreame-vacuum (Tasshack) и
|
||
Valetudo. Проверено на живом Dreame X50 Master.
|
||
|
||
### Кроме того
|
||
|
||
- **«Свет по источникам» — режим по умолчанию для новых пространств** и
|
||
первый в списке. Существующие планы не трогаем: пространство, где режим
|
||
не выбирали, выглядит как раньше.
|
||
- **Исправлено: поиск «что запускать» не показывал результатов.** Список —
|
||
прокручиваемый блок, и как flex-элемент он схлопывался в полоску 1px:
|
||
совпадения были, но отрисовывались в ничто.
|
||
|
||
## v1.53.1 — 2026-07-30
|
||
|
||
- **Фикс: поиск «что запускать» не показывал результатов.** Результаты были —
|
||
список это прокручиваемый блок, и как flex-элемент внутри тела диалога он
|
||
схлопывался в полоску 1px: 26 подходящих автоматизаций отрисовывались в
|
||
ничто. Найдено владельцем через минуты после v1.53.0. Теперь список держит
|
||
высоту; смок измеряет эту высоту, а не просто считает строки в DOM —
|
||
именно поэтому он и пропустил сломанную сборку.
|
||
|
||
## v1.53.0 — 2026-07-30
|
||
|
||
**Нажатие может запускать вашу автоматизацию** (ТЗ владельца)
|
||
|
||
- **Новое действие по нажатию: «Запустить автоматизацию/скрипт/сцену».** Мы
|
||
не можем знать каждое экзотическое устройство, но вы знаете, что должен
|
||
делать тап по нему: выберите любую автоматизацию, скрипт или сцену из
|
||
списка с поиском — тап её запустит (`automation.trigger`,
|
||
`script.turn_on` или `scene.turn_on` по типу цели, с тостом «Запущено»).
|
||
Скрипт — идиоматичное «действие» HA, поэтому предлагаются все три
|
||
запускаемых типа: не нужны автоматизации-пустышки без триггера.
|
||
Сохранение без цели блокируется; удалённая позже цель подсвечивается в
|
||
диалоге и безопасно отвечает тостом при тапе.
|
||
- **Чекбокс «Спрашивать подтверждение»** — защита от случайных нажатий для
|
||
любого действия, меняющего состояние: и toggle, и запуск, включая
|
||
настенные выключатели с привязанными целями. Диалог собственный (Esc,
|
||
клик мимо или «Отмена» — ничего не происходит), поэтому работает и на
|
||
настенном планшете.
|
||
- **Шторы переключаются нативно:** cover и valve добавлены в домены
|
||
card-wide toggle — с одним осознанным исключением: гаражные ворота, двери
|
||
и калитки (классы garage/door/gate) остаются ВНЕ дефолтного переключения —
|
||
случайный тап не должен открыть гараж. Явный per-device toggle остаётся
|
||
осознанным выбором владельца, а замки и охранные панели, как и всегда,
|
||
с плана неприкосновенны.
|
||
|
||
## v1.52.2 — 2026-07-29
|
||
|
||
**По ревью v1.52.1** (рантайм не менялся — качество теста и формулировок)
|
||
|
||
- Проверка регресса в редакторе плана целится ИМЕННО в лампу (HP-1521-01):
|
||
старый ассерт принимал любой жёлтый значок, и горящая розетка из той же
|
||
фикстуры прошла бы его даже без фикса лампы. Проверено мутацией: откат
|
||
гейта v1.52.1 валит смок.
|
||
- Последняя формулировка «жёлтый в любом режиме» — пункт чек-листа и
|
||
комментарий в _stateClass — приведена к фактическому контракту: состояние
|
||
источника считается условием glow-пула, а жёлтая подложка показывается
|
||
только там, где пятно не рисуется (HP-1521-02).
|
||
|
||
## v1.52.1 — 2026-07-29
|
||
|
||
**По ревью v1.52.0**
|
||
|
||
- **У горящей лампы всегда ровно один индикатор (HP-1520-01).** В редакторе
|
||
плана glow-слой скрыт, но подавление жёлтого там всё равно действовало —
|
||
горящая лампа не показывала ни пятна, ни подложки. Гейт подавления теперь
|
||
равен фактической видимости слоя: где пятно не рисуется, жёлтая подложка
|
||
возвращается.
|
||
- **Статичная карточка уважает размер и поворот маркера (HP-1513-01).** Один
|
||
и тот же маркер рендерился на read-only карточке базовым и неповёрнутым.
|
||
Теперь она зеркалит --dev-scale и угол полной карточки — только геометрия,
|
||
по-прежнему схема.
|
||
- Документация догнала цветовой контракт v1.52.0 (HP-1520-02): ожидания
|
||
RGB-окраски в TESTING/UX-MODES и устаревший комментарий в коде.
|
||
|
||
## v1.52.0 — 2026-07-29
|
||
|
||
**Один вид источников света, чем бы их ни переключали** (правило владельца)
|
||
|
||
- **Цвет лампы живёт только в её свечении.** RGB-окраска иконки, рамки и
|
||
тени убрана: в зависимости от того, пришли ли с состоянием данные о
|
||
цвете, одна и та же лампа попадала то в ветку «цветная иконка на тёмной
|
||
подложке», то в «жёлтая подложка» — выключение одной лампы тапом и
|
||
остальных выключателем выглядело по-разному. Ветки больше нет.
|
||
- **В режиме glow индикатор — само пятно света.** Подложка источника всегда
|
||
стандартная, горит он или нет — всё говорит свет вокруг. Розетка,
|
||
вентилятор или чайник остаются жёлтыми и в glow: они не светят, правило —
|
||
только для источников.
|
||
- **В остальных режимах горящий источник — просто жёлтый**, как греющая
|
||
термоголовка; RGB и обычные лампы одинаково.
|
||
- Морфинг иконки (контур «лампа с лучами») остаётся во всех режимах, а цвет
|
||
пульсации по-прежнему берёт фолбэком цвет свечения лампы.
|
||
|
||
## v1.51.3 — 2026-07-29
|
||
|
||
- **Множитель «размер значка» масштабирует и сам глиф, а не только
|
||
подложку.** Изменение размера устройства растило подложку, пульсацию и
|
||
бейджи значений, но иконка внутри оставалась дефолтной — большая пустая
|
||
рамка вокруг маленького глифа (репорт пользователя). Теперь глиф считается
|
||
от того же поустройственного размера, что и всё остальное, и держит
|
||
пропорцию при любом множителе и зуме.
|
||
|
||
## v1.51.2 — 2026-07-29
|
||
|
||
**По ревью v1.51.1**
|
||
|
||
- **Авто-сетка одинакова на обеих карточках (HP-1511-01).** Полная карточка
|
||
резервирует клетки сетки за скрытыми устройствами (их призраки держат
|
||
место в редакторе); статичная уплотняла сетку по одним видимым — свежее
|
||
устройство без сохранённой позиции вставало на разных местах двух
|
||
карточек. Теперь статичная передаёт сетке полный список и по-прежнему
|
||
рисует только видимых.
|
||
- **Ripple-призрак сохраняет базовую иконку (HP-1511-02).** Скрытый маркер с
|
||
отображением «пульсация» рендерился безликим неподвижным пульсом — в
|
||
редакторе его нельзя было узнать. Призрак теперь полностью снимает
|
||
«одежду» отображения: базовая иконка и имя, каким бы ни был режим.
|
||
|
||
## v1.51.1 — 2026-07-29
|
||
|
||
**По ревью v1.51.0**
|
||
|
||
- **Статичная карточка снова учитывает скрытые устройства в LQI комнаты
|
||
(HP-1510-01).** Её фильтр видимости незаметно стал фильтром агрегации: одна
|
||
и та же комната показывала разное Zigbee-здоровье на двух карточках. Теперь
|
||
агрегация и отрисовка используют разные списки — скрытые устройства
|
||
считаются в сигнале на обеих карточках, не рисуются ни на одной и
|
||
по-прежнему не дают света.
|
||
- **Призрак не показывает живых чисел (HP-1510-02).** Скрытое устройство в
|
||
«Показать скрытые» подавляло цвета состояний, но по-прежнему рисовало
|
||
значение, температуру, влажность, бейдж LQI и морф иконки. Всё это убрано:
|
||
у призрака только базовая иконка и имя — достаточно, чтобы узнать
|
||
устройство и открыть диалог.
|
||
|
||
## v1.51.0 — 2026-07-29
|
||
|
||
**Скрытие — теперь явная галка** (docs/FILTERING.md)
|
||
|
||
- **В диалоге каждого устройства — включая виртуальные — есть галка «Скрыть
|
||
устройство с плана».** Старый фильтр «на лету» остался только сеятелем
|
||
этих галок: при первом открытии редактором конфиг один раз
|
||
материализуется — нефизические устройства (мосты, сцены, служебные
|
||
интеграции, лампы, свёрнутые в световую группу) получают галку, и дальше
|
||
она принадлежит вам. Снятая галка — навсегда: сеятель не возвращается к
|
||
устройству, о котором вы уже решили. Новые нефизические прячутся молча;
|
||
физические — с красной точкой, как раньше.
|
||
- **«Показать все» стала «Показать скрытые»** — локальный инструмент
|
||
редактора устройств (на настенных планшетах ничего не мигает): скрытые
|
||
рисуются полупрозрачными СИНИМИ пунктирными призраками — не спутать с
|
||
серым недоступным — и совсем без живой индикации: призрак — это
|
||
конфигурация, а не статус. Клик — и галку можно снять. «Удалить с плана»
|
||
у привязанных устройств убрана (галка — единственный путь); «Удалить» у
|
||
виртуального по-прежнему удаляет.
|
||
- Скрытые устройства учитываются в Zigbee-сигнале комнаты, но не дают ни
|
||
пятна света, ни заливки — не видно устройства, не видно и света. Климат
|
||
комнат без изменений. Старые конфиги ведут себя по-старому, пока их не
|
||
материализует клиент с правом записи.
|
||
|
||
**Жёлтый значит «работает прямо сейчас»**
|
||
|
||
- Один принцип для светящегося значка: лампа светит, розетка подаёт,
|
||
вентилятор крутится, медиа играет, пылесос убирает — или термоголовка
|
||
РЕАЛЬНО греет (hvac_action), а не просто включена на зиму. Раньше
|
||
термоголовка могла светиться жёлтым из-за включённой защиты от накипи, а
|
||
реально греющая оставалась тёмной: выбор главной сущности пропускал
|
||
служебный свитч производителя вперёд видимого climate. Исправлено —
|
||
служебная сущность больше никогда не побеждает видимую основную функцию
|
||
(это чинит и tap-переключение, и морфинг иконок у таких устройств).
|
||
- Пятно света и цвет значка задают один и тот же вопрос: горящая лампа
|
||
желтит значок в любом режиме заливки ровно тем условием, что зажигает её
|
||
пятно. README (en+ru) описывает язык цветов.
|
||
|
||
**Редакторы на телефоне**
|
||
|
||
- Пинч-зум и панорамирование жестами работают во всех редакторах: рисование
|
||
кликовое, так что они совместимы — палец с движением панорамирует, два
|
||
пальца зумируют, отпускание после жеста не ставит точку, чистый тап —
|
||
ставит.
|
||
|
||
**Кнопка настроек комнаты**
|
||
|
||
- Отвязана от (передвигаемого) названия: стоит в ВИЗУАЛЬНОМ центре комнаты —
|
||
центр наибольшей вписанной окружности с тяготением к центроиду площади,
|
||
поэтому вытянутая комната центрирует её по обеим осям, а Г-образная
|
||
держит в середине широкой части и не утаскивает в узкую.
|
||
- Вдвое меньше прежней, размер от иконки устройства (70% бокса) и зумится
|
||
ВМЕСТЕ с планом, а не держит постоянный экранный размер.
|
||
- Мелкие подписи под названием комнаты (температура, влажность, сигнал,
|
||
свет) теперь видны и в редакторе плана, а название рендерится ровно в том
|
||
же месте в просмотре и в редакторе.
|
||
|
||
## v1.50.4 — 2026-07-29
|
||
|
||
**По ревью v1.50.3**
|
||
|
||
- **Обе карточки строят модель одним кодом (HP-1503-01).** Полная карточка
|
||
носила рукописную копию общего построителя модели, и копия не получила
|
||
фолбэки для legacy-store из v1.50.3 — один и тот же битый store в
|
||
статической карточке рендерился починенным, а в основной — пустым
|
||
`viewBox="0 0 0 0"`. Дубликат удалён: полная карточка вызывает общий
|
||
построитель и лишь подменяет сырой url плана, который нужен её подписи.
|
||
Новый смок прогоняет точный вектор аудита через обе модели и оба
|
||
DOM-дерева и проверяет паритет.
|
||
|
||
## v1.50.3 — 2026-07-29
|
||
|
||
**По ревью v1.50.2**
|
||
|
||
- **Размер — не координата (HP-1502-01).** Граница ±4 из v1.50.2 мерила все
|
||
четыре элемента view_box и w/h комнат одинаково, поэтому `[0, 0, 0, 0]` и
|
||
отрицательные размеры всё ещё проходили — а нулевая ось сериализуется в
|
||
`viewBox="0 0 0 0"`: пустой план у всех клиентов, и `aspect-ratio: 0 / 0` у
|
||
статичной карточки сверху. У размеров теперь свой validator: строго
|
||
положительные, пол — одна тысячная холста; координаты по-прежнему могут
|
||
быть отрицательными — начало кропа законно выходит за край. А поскольку в
|
||
сторе битый viewport может уже лежать, обе карточки падают на полный холст
|
||
вместо пустого экрана, и legacy-прямоугольник с отрицательным размером
|
||
читается как тот же прямоугольник, нарисованный из другого угла.
|
||
|
||
**Также в этом релизе**
|
||
|
||
- Кнопка настроек комнаты переехала в самый низ карточки комнаты, а имя
|
||
комнаты отображается ровно в одном и том же месте в просмотре и в
|
||
редакторе плана — кнопка и метрики больше не участвуют в центрировании.
|
||
|
||
## v1.50.2 — 2026-07-29
|
||
|
||
**По ревью v1.50.1**
|
||
|
||
- **Величины геометрии ограничены на обоих слоях (HP-1501-01).** v1.50.1
|
||
ограничила позиции устройств, но прямоугольники комнат, вершины полигонов,
|
||
view_box и координаты проёмов всё ещё принимали любое конечное число — одна
|
||
проходящая схему вершина 1e100 растягивала кадр так, что план становился
|
||
точкой у всех клиентов, и сервер хранил это как вполне корректную
|
||
конфигурацию. Теперь схема конфига ограничивает геометрию ±4 (углы ±360°),
|
||
а рамка содержимого применяет к вершинам комнат тот же конверт холста, что
|
||
уже применяла к позициям устройств — конфиг, где абсурдная координата уже
|
||
лежит с прежних времён, всё равно рендерится: точка рисуется, где стоит,
|
||
просто кадром больше не командует. Вершина чуть за краём холста работает
|
||
как раньше.
|
||
- **Пустой repair больше не съедает бэкап (HP-1501-02).** Опечатка в space_id
|
||
«успешно» отвечала moved: 0 — и её пустой результат заменял бэкап глубиной
|
||
один, уничтожая единственный путь назад ровно тогда, когда он нужнее всего:
|
||
сразу после починки не того пространства. Теперь «нечего чинить» — ошибка
|
||
(`nothing_to_repair`): ничего не пишется, ревизия не растёт, предыдущий
|
||
repair по-прежнему отменяем.
|
||
|
||
## v1.50.1 — 2026-07-29
|
||
|
||
**По ревью v1.50.0**
|
||
|
||
- **Карточка ниже другого контента дашборда снова получает сцену
|
||
(HP-1500-02).** Замер высоты в v1.50.0 брал абсолютную координату документа:
|
||
высокая карточка перед этой записывалась в «шапку», и сцена схлопывалась в
|
||
ноль. Теперь меряется только собственная обвязка плюс ограниченная поправка
|
||
на то, что дашборд держит сверху; перемер — по resize окна, слушатель
|
||
снимается при демонтаже.
|
||
- **Рамка содержимого больше не бывает вырожденной или абсурдной
|
||
(HP-1500-03).** Одинокий значок в пустом пространстве давал viewBox нулевой
|
||
площади — пустую сцену; одна сохранённая координата вида 1e100 (любое
|
||
конечное число проходило проверку) растягивала рамку так, что план
|
||
становился точкой — у всех зрителей пространства. Почти нулевая ось теперь
|
||
раскрывается до минимального кадра вокруг значка, точки далеко за холстом
|
||
рамкой не командуют (рисуются, где стоят), а сервер отклоняет координаты вне
|
||
±4 — щедрый запас для значка, утащенного за край, но не для абсурда. Узкая
|
||
комната сохраняет тесный кадр, датчик калитки чуть за краём по-прежнему
|
||
учитывается.
|
||
- **Путь восстановления для установок, застрявших в окне миграции v1.48
|
||
(HP-1500-01).** Если старая миграция упала между двумя записями, значки
|
||
пространства остаются в старых координатах, и по данным это недоказуемо — а
|
||
повторное преобразование правильных координат их испортит, поэтому ничего
|
||
автоматического тут быть не может. Явный ответ —
|
||
`houseplan/geometry/repair {space_id, aspect}`: `dry_run` показывает точные
|
||
перемещения, прежние позиции уезжают той же записью хранилища как резервная
|
||
копия глубиной один, `undo` их возвращает, и обычные перетаскивания эту
|
||
копию больше не затирают. Протокол `geom_pending` из v1.50.0 уже защищает
|
||
все будущие миграции; это — для тех, кому он опоздал.
|
||
|
||
## v1.50.0 — 2026-07-28
|
||
|
||
**Задачи владельца**
|
||
|
||
- **Масштаб по умолчанию считает устройства содержимым.** Им можно стоять вне
|
||
комнат — датчик калитки у забора, камера на столбе — и стартовый вид теперь
|
||
включает их, даже в пространстве совсем без комнат.
|
||
- **Вход в редактор больше не сдвигает план.** Высота сцены считалась как
|
||
«экран минус 118px шапки», а шапка редактора выше: сцена уезжала вниз на
|
||
разницу, низ пропадал за краём. Карточка измеряет, где сцена начинается на
|
||
самом деле, и отдаёт ей остаток экрана.
|
||
- **Масштаб теперь и отдаляется.** До 0.4×; в отдалении план висит по центру,
|
||
а не прилипает к углу.
|
||
|
||
**По ревью v1.49.0**
|
||
|
||
- **Миграция на квадратный холст переживает сбой между двумя записями
|
||
(HP-1490-01).** Конфиг и позиции живут в разных хранилищах, пишутся по
|
||
очереди, и первая запись удаляла именно те поля, которые нужны второй — сбой
|
||
между ними навсегда оставлял значки в старых координатах. Теперь намерение
|
||
миграции сохраняется до того, как что-либо меняется, и снимается той же
|
||
записью, что сохраняет позиции: какая половина не успела — ту следующий
|
||
запуск и доделает, ровно один раз.
|
||
- **Параллельные загрузки не проскакивают квоту вместе (HP-1490-02).** N
|
||
загрузок мерили хранилище до того, как любая из них записала файл, и все
|
||
проходили предел, под который помещалась одна. Замер и запись — один
|
||
атомарный шаг под отдельным замком; отдельным — чтобы медленный обход папки
|
||
не тормозил сохранения конфига.
|
||
- **Редакторы снова видят весь холст (HP-1490-03).** Рамка содержимого
|
||
ограничивала и панорамирование, и координаты указателя, так что после первой
|
||
комнаты рисовать вторую было негде. Режимы редактирования меряют от полного
|
||
квадрата; просмотр остаётся по содержимому, а смена режима пересчитывает
|
||
вид, вместо того чтобы тащить его прижатым не к той основе.
|
||
- **Сохранение ждёт пропорции выбранного плана (HP-1490-04).** Save до ответа
|
||
картинки записывал пропорции ПРЕДЫДУЩЕГО файла, и новый план навсегда
|
||
оставался в чужой форме. Выбор плана сразу стирает старое значение, Save
|
||
дожидается ограниченного по времени чтения; не дождался — записывается
|
||
«неизвестно»: честный квадрат лучше унаследованной формы.
|
||
- Гигиена релиза из §5: package-lock.json догнал версию пакета, задвоенный
|
||
комментарий в space-geometry.ts убран.
|
||
|
||
## v1.49.0 — 2026-07-28
|
||
|
||
**Холст стал квадратным** (см. v1.48.0, выпущена вместе с этой).
|
||
|
||
- **Масштаб открывается по нарисованному, а не по всему холсту.** Пространство
|
||
без подложки теперь вписывается по границам своих комнат с полями 5%: маленький
|
||
план на большом холсте заполняет экран, а не сидит посередине точкой. С
|
||
подложкой ничего не меняется — картинка и есть план, и обрезать её по комнатам
|
||
значило бы спрятать то, что ещё не обведено.
|
||
- **Переключение пространств свайпом и в киоске стало с анимацией.** План
|
||
уезжает туда, куда пошёл палец, следующий приходит с другой стороны.
|
||
Уважает системную настройку «уменьшить движение».
|
||
- Кнопка настроек комнаты подписана «Настройки комнаты», а не просто «Комната»,
|
||
и слегка светлеет под курсором.
|
||
- Слово «курирование» заменено на «фильтрацию» — в интерфейсе, документации и
|
||
коде.
|
||
|
||
**По ревью v1.47.0**
|
||
|
||
- **Только что выбранный план больше нельзя удалить из того же диалога
|
||
(HP-1470-02).** Он ещё не сохранён, поэтому сервер справедливо считал его
|
||
свободным — а сохранение потом записывало ссылку, за которой нет файла.
|
||
Кнопка заблокирована, и, поскольку два клиента могут сделать это в любом
|
||
порядке, сервер сверяет с диском каждую внутреннюю ссылку, которую
|
||
конфигурация добавляет, и отказывает, если файла нет. Ссылку, уже записанную
|
||
в конфигурации, он пропускает: файл может исчезнуть и мимо Home Assistant, а
|
||
отказ заблокировал бы ровно ту правку, которая его отцепляет. Чужие ссылки не
|
||
трогаются.
|
||
- **Загрузки ограничены (HP-1470-01).** По возрасту не удаляется ничего — это
|
||
дважды стоило настоящих планов, — поэтому предел стоит там, где решение и так
|
||
принимается: загрузка отклоняется, если хранилище перевалит за 256 МБ или 200
|
||
планов (1 ГБ и 1000 для вложений) либо если на диске останется меньше 512 МБ.
|
||
Список планов отдаётся по 60 самых свежих, миниатюры грузятся лениво.
|
||
- **Выбор сохранённого плана читает его настоящие пропорции (HP-1470-03).**
|
||
Карточка ничего не ждала и, если подпись для защищённой ссылки ещё не пришла,
|
||
записывала пропорции «по умолчанию» — квадратный план получался растянутым.
|
||
Теперь она дожидается подписи, привязывает результат к тому диалогу, который
|
||
спрашивал, а превью в диалоге подписывается, как и всё остальное.
|
||
|
||
## v1.48.0 — 2026-07-28 (холст всегда квадратный)
|
||
- **У пространства больше нет собственных пропорций.** Область рисования —
|
||
квадрат, а картинка плана сохраняет свою форму и вписывается в него по
|
||
центру: у широкого плана появляются поля сверху и снизу, у вытянутого — по
|
||
бокам. Выбирать нечего, поэтому настройка ориентации холста для пространств
|
||
без картинки убрана.
|
||
- **Существующие планы переносятся один раз, при обновлении.** В самом рисунке
|
||
ничего не меняется: коробка дополняется до квадрата, и все координаты
|
||
пересчитываются относительно неё — комнаты, двери и окна, декор, позиции
|
||
значков и сохранённая область просмотра. Углы, пропорции комнат и взаимное
|
||
расположение сохраняются точно. Для вытянутых планов заодно пересчитывается
|
||
масштаб в сантиметрах на клетку: сетка привязана к ширине, и без этого стены
|
||
молча стали бы короче.
|
||
|
||
## v1.47.0 — 2026-07-28 (выбор из уже загруженных планов)
|
||
- **Диалог пространства показывает планы, сохранённые на сервере.** Отцепление
|
||
плана оставляет картинку на диске — так с v1.46.4, но вернуть её можно было
|
||
только найдя исходный файл у себя и загрузив заново. «Уже загруженные»
|
||
показывают, что есть: миниатюра, размер файла и то, какое пространство его
|
||
использует. Клик прикрепляет, пропорции читаются из самой картинки — так же,
|
||
как при загрузке.
|
||
- **Там же план и удаляется.** Файл плана никогда не удаляется автоматически —
|
||
ни за отцепление, ни за возраст, — и это разумная политика ровно до тех пор,
|
||
пока видно, что именно хранится, и есть способ убрать это осознанно. Кнопка
|
||
корзины делает это и отказывает, пока план используется пространством: ответ
|
||
на вопрос «можно ли удалить» даёт сохранённая конфигурация, а не браузер.
|
||
- Документация догнала код: несколько комментариев всё ещё описывали удаление по
|
||
возрасту, убранное в v1.46.6.
|
||
|
||
## v1.46.6 — 2026-07-28 (обещание про отцепление, теперь выполненное)
|
||
- **Переключение пространства в «нарисовать» больше не удаляет его картинку.**
|
||
v1.46.4 и v1.46.5 утверждали, что не удаляет, и плановая уборка действительно
|
||
отцеплённые планы не трогала — но само сохранение удаляло файл в тот момент,
|
||
когда снималась ссылка, ещё до всех этих проверок. Причина: файл, покинувший
|
||
конфигурацию, считался «заменённым», а по одной этой разнице замену плана,
|
||
отцепление и удаление пространства различить невозможно. Удалением, о котором
|
||
просили, является только первое. Теперь переход классифицируется по
|
||
пространству-владельцу, и та же разница применяется к вложениям: убрали файл у
|
||
существующего устройства — он удаляется, удалили устройство — его инструкции
|
||
остаются.
|
||
- **План удалённого пространства сохраняется**, а не тридцать дней, как обещала
|
||
v1.46.5: тридцать дней по возрасту файла всё равно бессмысленны — обычно он
|
||
загружен месяцы назад.
|
||
- **По возрасту больше не удаляется ничего**, кроме промежуточной папки диалога.
|
||
Правило, которое вычищало «отвергнутые загрузки», оказалось в гонке с
|
||
повторной попыткой: уборка удаляла файл неудавшегося сохранения ровно тогда,
|
||
когда следующая попытка коммитила ссылку на него. Правило, способное удалить
|
||
файл, на который кто-то вот-вот сошлётся, не стоит освобождаемого места.
|
||
Файлы уходят по действию, в остальных случаях остаются.
|
||
|
||
## v1.46.5 — 2026-07-28 (ревизия всех автоматических удалений)
|
||
- **Отцеплённый план не удаляется никогда, ни в каком возрасте.** В v1.46.4 ему
|
||
давался месяц; теперь это навсегда, и причина записана там, где её увидит
|
||
следующая правка. Правило, оно же в docs/SCOPE.md: компонент вправе удалить
|
||
файл только тогда, когда об этом говорит действие пользователя — замена
|
||
плана, удаление вложения, удаление устройства. «На это больше никто не
|
||
ссылается» таким действием не является. Ошибки несимметричны: занятое зря
|
||
место видно, стоит копейки и обратимо; удалённый файл — ничего из этого.
|
||
- **`houseplan/files/cleanup` больше не сносит папку по слову клиента.** После
|
||
перепривязки устройства файлы копируются под новый id, а старая папка
|
||
удалялась — через `rmtree`, по тому id, который прислала карточка. Два плохих
|
||
исхода: при частичном копировании часть ссылок продолжает указывать внутрь
|
||
этой папки (миграция намеренно их не переписывает — то есть это были живые
|
||
ссылки на удаляемые файлы), а неверный или устаревший id от любого клиента
|
||
уничтожил бы инструкции существующего устройства. Теперь сервер сам сверяется
|
||
с сохранённой конфигурацией, под её блокировкой, и удаляет только то, на что
|
||
никто не ссылается.
|
||
- **План удалённого пространства ждёт тридцать дней вместо часа.** Удаление
|
||
пространства осознанно, но час — короткое окно, чтобы заметить промах.
|
||
|
||
## v1.46.4 — 2026-07-28 (потеря данных: отцеплённые планы убирались как мусор)
|
||
- **Отцеплённый план больше не удаляется через час.** Переключение пространства
|
||
в режим «нарисовать» снимает ссылку и, как редактор всегда и говорил,
|
||
оставляет картинку на диске, чтобы её можно было вернуть. Уборка, добавленная
|
||
в v1.46.0, этой разницы не делала: считала «на файл сейчас никто не
|
||
ссылается» синонимом «файл брошен» и применяла часовое правило. На установке
|
||
автора плановый проход в итоге удалил два плана этажей, отцеплённых
|
||
несколькими неделями раньше, — восстановить их было нечем. Если вы отцепляли
|
||
план после v1.46.0 и инстанс перезапускался или проработал сутки — загляните в
|
||
`config/houseplan/plans/` и напишите в Telegram-чат, если файла нет.
|
||
Правило теперь такое: **коммит по-прежнему удаляет ровно то, что заменил**, —
|
||
это он знает наверняка. Дальше вопрос в том, означает ли «непривязан»
|
||
«брошен», и ответ зависит от случая. У пространства, у которого плана нет
|
||
вовсе, его отцепили — и, возможно, вернут: его файлы не удаляются никогда. У
|
||
пространства, у которого план есть, лишние файлы могут быть только его же
|
||
отвергнутыми загрузками — они по-прежнему уходят через час. Вложения вне
|
||
промежуточной папки диалога ждут месяц; сама промежуточная папка, где по
|
||
построению лежит только загрузка из несохранённого диалога, сохраняет часовое
|
||
правило.
|
||
|
||
## v1.46.3 — 2026-07-28 (перепроверка v1.46.2: HP-1462-01)
|
||
- **Уборка при старте действительно убирает.** Она искала свои же runtime-данные
|
||
по домену, а во время запуска Home Assistant ещё не считает интеграцию
|
||
загруженной — поэтому поиск возвращал пустоту, и проход тихо вырождался в
|
||
удаление незавершённых передач, оставляя настоящую работу таймеру через
|
||
24 часа. При перезапусках чаще, чем раз в сутки, она не выполнялась вообще.
|
||
Теперь используется объект, который у неё и так был на руках.
|
||
- **Тест, который должен был это доказать, проходил по неверной причине.** Он
|
||
создавал лишние файлы *до* сохранения конфигурации, а сохранение тоже
|
||
собирает мусор — так что к моменту перезапуска убирать было уже нечего.
|
||
Переписан: файлы создаются после сохранения; добавлен второй тест, который
|
||
дёргает плановый таймер отдельно, и третий, который запускает перезапуск и
|
||
сохранение одновременно и проверяет, что принятая конфигурация никогда не
|
||
ссылается на удалённый уборкой файл.
|
||
|
||
## v1.46.2 — 2026-07-28 (перепроверка v1.46.1: HP-1461-01, -02)
|
||
- **Файл, который в итоге никому не понадобился, убирается, даже если больше
|
||
ничего не сохраняют (HP-1461-01).** Сборка привязана к записи конфигурации —
|
||
это верно для того, что запись вытесняет, но оставляет зазор: отмените диалог
|
||
после того, как файл уже загрузился, потеряйте связь сразу после, или
|
||
вызовите API загрузки напрямую — и на файл никто не ссылается, а будущей
|
||
записи, которая бы это заметила, нет. Добавленное в v1.46.1 ежедневное
|
||
подметание убирало только незавершённые передачи, поэтому обещание «отменённое
|
||
вложение исчезнет через час» не выполнялось там, где никто ничего не правит.
|
||
Теперь подметание сверяется с сохранённой конфигурацией — под той же
|
||
блокировкой, что и запись, — и собирает устаревшие непривязанные вложения и
|
||
планы тоже.
|
||
- **Перетаскивание больше не отменяется чужим перемещением (HP-1461-02).** Когда
|
||
в v1.46.1 полная карточка научилась следить за позициями, она защищала те,
|
||
что вы подвинули, но ещё не отправили, — вот только читала этот список *после*
|
||
сброса отложенной записи, а сброс его первым делом опустошает. При настоящем
|
||
перетаскивании, когда запись уже запланирована, список оказывался пустым, и
|
||
старая серверная позиция закрашивала ваше движение. Теперь снимок снимается до
|
||
сброса, и вдобавок удерживаются позиции, отправленные, но ещё не
|
||
подтверждённые: пока сервер не подтвердил позицию, авторитет по ней — та
|
||
карточка, которая её подвинула.
|
||
- Два теста доросли до своих же описаний: тест загрузки теперь действительно
|
||
отменяет задачу запроса, а не только проходит по путям ошибок, а смоук
|
||
синхронизации позиций планирует настоящую отложенную запись и задерживает её —
|
||
именно этот порядок и терял перетаскивание.
|
||
|
||
## v1.46.1 — 2026-07-28 (перепроверка v1.46.0: HP-1460-01 … -03)
|
||
- **Две загрузки с одинаковым именем больше не сталкиваются (HP-1460-01).**
|
||
v1.46.0 перестала затирать вложения, но выбор свободного имени и его занятие
|
||
были двумя шагами: две загрузки, попавшие между ними, сходились на одном
|
||
имени, обе рапортовали успех, и одни байты заменяли другие. Теперь имя
|
||
занимается атомарно в момент выбора — двадцать одновременных загрузок
|
||
`manual.pdf` дают двадцать файлов. Тот же механизм используется при переносе
|
||
файлов на перепривязке, где был ровно такой же зазор.
|
||
Заодно там же: имя предельной длины теряло расширение, а суффикс коллизии
|
||
выталкивал его за предел, и вложение сохранялось под именем, которое сервер
|
||
обратно не отдаёт — вечный 404 на файл, который интерфейс считал
|
||
прикреплённым.
|
||
- **Прерванная загрузка больше не оставляет временный файл навсегда
|
||
(HP-1460-02).** Уборка стояла в `except Exception`, мимо которого отменённый
|
||
запрос проходит насквозь, а сборщик заглядывает только в папки маркеров —
|
||
поэтому оборванная передача оставляла `.upload-*`, и убрать его было некому.
|
||
Теперь убирает любой путь выхода, запрос с двумя файлами отклоняется сразу, а
|
||
брошенные временные подметаются при старте и раз в сутки. Запись идёт
|
||
порциями по мегабайту, а не отдельной задачей на каждые 64 КБ.
|
||
- **Две полные карточки рядом держат одинаковые позиции (HP-1460-03).** v1.46.0
|
||
научила следить за перемещениями статическую карточку и оставила позади
|
||
полную, поэтому перетаскивание иконки в одном окне не двигало её в другом до
|
||
перезагрузки. Теперь следит — и не мешает собственному перетаскиванию: чужая
|
||
ревизия, пришедшая в его разгар, сливается, а не накатывается сверху, и
|
||
карточка не перечитывает то, что записала сама.
|
||
|
||
## v1.46.0 — 2026-07-28 (полный внешний аудит v1.45.4: HP-1454-01 … -10)
|
||
|
||
**Безопасность**
|
||
|
||
- **Загруженный SVG-план больше не является живым документом origin вашего
|
||
Home Assistant (HP-1454-01, high — блокер релиза).** Внутри карточки план
|
||
подключён через `<image>`, где скрипты не выполняются; но тот же URL,
|
||
открытый напрямую, становился документом верхнего уровня в origin самого HA,
|
||
и `<script>` в нём мог читать `localStorage` сессии и обращаться к API. Для
|
||
загрузки нужно право записи, а оно по умолчанию есть у каждого
|
||
аутентифицированного пользователя, и подписанную ссылку несложно передать
|
||
администратору. Ответы с SVG теперь несут заголовок Content-Security-Policy
|
||
`sandbox`, который помещает документ в opaque origin. Только SVG — CSP на PDF
|
||
способен сломать встроенный просмотрщик браузера, а растровая картинка ничего
|
||
выполнить не может. Для существующих планов ничего не меняется: карточка
|
||
рисует их ровно как раньше.
|
||
|
||
**Целостность данных**
|
||
|
||
- **Инструкция, приложенная к устройству, больше не затирает предыдущую
|
||
(HP-1454-02).** Загрузка писала прямо в `<маркер>/<имя файла>`, вне
|
||
транзакции конфигурации: отмена диалога или отвергнутое сохранение оставляли
|
||
сохранённую ссылку указывающей на новые байты. А все новые иконки грузили в
|
||
одну общую папку, поэтому две с файлом `manual.pdf` начинали ссылаться на
|
||
один физический файл. Теперь загрузка занимает свободное имя и никогда не
|
||
перезаписывает, новая иконка получает собственную промежуточную папку, файлы
|
||
из которой переезжают к настоящей иконке при принятом сохранении, а загрузка,
|
||
которую никто не сохранил, убирается через час. Имя, на которое уходит
|
||
коллизия, сменилось с `manual (2).pdf` на `manual-2.pdf`: старое санитайзилось
|
||
на обратном пути, поэтому переименованное вложение записывалось и больше не
|
||
отдавалось (нашёл новый тест; до этого релиза так же ломались коллизии при
|
||
перепривязке).
|
||
- **Две быстрые правки больше не теряют вторую (HP-1454-03).** Debounce
|
||
разносил старты сохранения, а не сами сохранения. Если одно длилось дольше
|
||
полусекунды — занятый сервер, медленная связь, — следующая правка уходила с
|
||
той же ревизией, сервер принимал первую и отклонял вторую, а обработчик
|
||
конфликта перечитывал серверную копию поверх локальной. Правка исчезала, и
|
||
сообщение винило «другое окно», которого не было. Записи сериализованы: по
|
||
одной за раз, каждая с ревизией, которую вернула предыдущая.
|
||
|
||
**Корректность и пределы**
|
||
|
||
- **Открытые границы снова следуют за геометрией (HP-1454-04).** Их кэш
|
||
ключевался только по id комнат и связям, поэтому смена пропорций
|
||
пространства или перетаскивание вершины оставляли открытые границы — и свет,
|
||
который через них проходит, — в старых координатах до перезагрузки. Ключом
|
||
стала сама отрисованная модель, из которой они и вычисляются.
|
||
- **Конфигурацию больше нельзя сделать сколь угодно тяжёлой (HP-1454-05).**
|
||
Внешние коллекции были ограничены, вложенные — нет. Полигон на 150 000 точек
|
||
или список из 100 000 идентификаторов проходили валидацию, а потом каждый
|
||
рендер по ним ходил. Появились пределы на вершины полигона, связи открытых
|
||
границ, управляемые сущности, вложения, длину текста и ссылок, плюс общий
|
||
предел размера сериализованной конфигурации. Устаревшее поле `segments`
|
||
отбрасывает сервер, а не надежда на современный клиент.
|
||
- **Большие файлы передаются потоком, а не через память (HP-1454-06).**
|
||
Инструкция на 50 МБ целиком читалась в память на приёме и ещё раз на отдаче;
|
||
пара параллельных скачиваний — заметная нагрузка на слабый хост Home
|
||
Assistant. Загрузка пишется во временный файл потоком, отдача идёт с диска.
|
||
|
||
**Согласованность**
|
||
|
||
- **Статическая карточка пространства учитывает настройки заливки комнаты
|
||
(HP-1454-07).** Она строит модель другой функцией, и настройки комнаты в неё
|
||
не переносились — комната, которой вы выключили заливку, всё равно
|
||
закрашивалась.
|
||
- **Перемещение иконки сразу видно на статической карточке (HP-1454-08).**
|
||
Layout — отдельное состояние без ревизии и без события: перетаскивание на
|
||
полной карточке оставляло соседнюю статическую со старой позицией до
|
||
изменения конфигурации или перезагрузки страницы. Теперь записи layout хранят
|
||
ревизию, возвращают её и сообщают о себе — заодно оптимистическая блокировка
|
||
на полной записи layout начала что-то значить, ведь точечная запись раньше
|
||
сбрасывала счётчик.
|
||
- **Предупреждение о пропавшем плане исчезает вместе с пространством
|
||
(HP-1454-09).** Уборка смотрела только на существующие пространства, поэтому
|
||
удаление или переименование оставляло предупреждение в «Ремонте» навсегда.
|
||
- Сборка: `serialize-javascript` поднят выше двух advisory (HP-1454-10). В
|
||
рантайме недостижим, production-зависимости и так были чисты, но это одна
|
||
строка.
|
||
|
||
## v1.45.4 — 2026-07-28 (ревью v1.45.3: R5-1, R5-2)
|
||
- **Частично успешный ответ на подпись больше не пропускает выдержку (R5-1).**
|
||
Бэкенд подписывает каждый путь независимо: тот, что подписать не удалось,
|
||
логируется, пропускается, и вызов всё равно завершается успешно с остальными
|
||
ссылками. Карточка считала любой успешный вызов «весь батч готов», сбрасывала
|
||
выдержку для всех путей в нём и записывала только вернувшиеся ссылки — и путь,
|
||
который бэкенд стабильно пропускал, запрашивался заново на каждом рендере, то
|
||
есть ровно то усиление, ради которого выдержка и вводилась в v1.45.2. Теперь
|
||
путь считается подписанным, только если в ответе действительно есть ссылка на
|
||
него; остальные уходят в выдержку по отдельности, ключи, которых не просили,
|
||
игнорируются, а перерисовка запускается лишь при появлении хотя бы одной новой
|
||
подписи.
|
||
- **Снимок состояния больше не противоречит репозиторию (R5-2).** Там всё ещё
|
||
было написано, что в `main` лежат релизы только до v1.40.1, и приводились
|
||
счётчики тестов на несколько релизов назад — при том что строка версии рядом
|
||
исправно обновлялась. Читающий его человек или агент получал неверную
|
||
модель веток и заниженное представление о покрытии. Роли веток описаны точно,
|
||
а счётчики убраны: `npm run inventory` печатает их из дерева, и устаревать
|
||
больше нечему.
|
||
|
||
## v1.45.3 — 2026-07-27
|
||
- **«Значение вместо иконки» невозможно было сохранить (issue #3).** Опция
|
||
появилась в редакторе устройств ещё в v1.26.0, но серверная схема всё это
|
||
время принимала только `badge`, `ripple` и `icon_ripple`. При её выборе
|
||
сохранение падало с
|
||
`not a valid value for dictionary value @ data['config']['markers'][n]['display']`,
|
||
а поскольку один отвергнутый маркер валит всю запись конфигурации, план не
|
||
сохранялся вообще, пока настройку не отменишь. Спасибо @RemyRoux за отчёт и
|
||
точный текст ошибки.
|
||
- **Списки опций теперь в одном месте и сверяются между языками.**
|
||
`DISPLAY_MODES`, `TAP_ACTIONS`, `SPACE_FILL_MODES` и `ROOM_FILL_MODES`
|
||
экспортируются из карточки, и backend-тест читает их, проверяя, что схема
|
||
принимает каждое значение, которое пользователь реально может выбрать.
|
||
Теперь добавить опцию в редактор и забыть про схему — значит уронить тесты, а
|
||
не узнать об этом из чужого сообщения об ошибке.
|
||
|
||
## v1.45.2 — 2026-07-27 (закалка по ревью v1.45.1: R4-1, R4-2)
|
||
- **Сбой уборки больше не превращает принятое сохранение в ошибку (R4-1).**
|
||
Сборка вытесненных файлов плана идёт уже после того, как конфигурация
|
||
сохранена, но ошибка при обходе каталога — он может исчезнуть или стать
|
||
недоступным между проверкой и обходом — вылетала наружу из `config/set`.
|
||
Клиент видел неудачу для ревизии, которую сервер закоммитил, а его повтор
|
||
возвращался с конфликтом. Теперь сборщик сообщает «ничего не убрано» вместо
|
||
исключения, а `config/set` пишет в лог и продолжает: событие уходит, новая
|
||
ревизия возвращается.
|
||
- **Один запрос подписи на ссылку вместо одного на рендер (R4-2).** Множество
|
||
ожидающих очищалось в момент отправки батча, а не по возвращении, поэтому
|
||
пока запрос `content/sign` был в полёте, каждая перерисовка ставила ещё
|
||
один — шесть вызовов там, где нужен один, и куда хуже на медленном (а не
|
||
просто занятом) сокете. Состояния «в очереди» и «в полёте» теперь разделены,
|
||
после ошибки включается выдержка (2 с с удвоением до 60 с) вместо повтора на
|
||
следующем кадре, а запрос, который так и не завершился, перестаёт блокировать
|
||
повторы через 15 с. Поздний ответ, пришедший после размонтирования карточки,
|
||
больше не вызывает перерисовку.
|
||
- Тесты: восемь юнит-тестов подписывателя с ручным разрешением promise (четыре
|
||
падают на v1.45.1), backend-тест на то, что сломанный сборщик оставляет
|
||
сохранение успешным с рабочей ревизией, и проверка исчезнувшего каталога в
|
||
тестах чистого сборщика.
|
||
|
||
## v1.45.1 — 2026-07-27 (повторное ревью v1.45.0: R3-1, R3-2)
|
||
- **Уборка старых файлов плана перенесена внутрь транзакции конфига (R3-1,
|
||
high).** v1.45.0 сделала загрузку безопасной, но отдала удаление клиенту:
|
||
после успешного сохранения карточка просила бэкенд убрать всё, кроме только
|
||
что закоммиченного файла. Два открытых редактора невозможно упорядочить —
|
||
задержавшийся запрос одного клиента удалял план, который только что сохранил
|
||
другой, и принятая конфигурация оставалась со ссылкой в пустоту, то есть
|
||
ровно с тем ущербом, ради которого вводился copy-on-write. Команда
|
||
`houseplan/plan/cleanup` убрана. Теперь `config/set` убирает сам, под своей
|
||
блокировкой, сравнивая конфигурацию, которую заменил, с той, которую принял:
|
||
файл, на который ссылалась старая ревизия и не ссылается новая, удаляется, а
|
||
любая другая непривязанная загрузка не трогается, пока ей не исполнится час —
|
||
свежая может принадлежать ещё не завершённой чужой транзакции.
|
||
- **Статическая карточка пространства снова показывает подложку (R3-2).** Она
|
||
подписывала URL и выбрасывала результат — `getCardSize()` правил временную
|
||
модель, а `render()` строил свою заново из конфига, — поэтому `<image>`
|
||
запрашивал защищённый путь и на каждом рендере получал 401. Обе карточки
|
||
теперь используют один подписыватель, и статическая заодно получила батчи,
|
||
учёт срока годности и периодическое переподписывание, которые были только у
|
||
основной. Её множество ожидающих запросов освобождается в `finally`, так что
|
||
одна неудача больше не блокирует ссылку до конца жизни страницы.
|
||
- Новые тесты: пять backend-сценариев чередования двух клиентов из отчёта
|
||
(поздний коммит, незакоммиченная загрузка, устаревший сирота, чужие файлы,
|
||
отвергнутое сохранение), сборщик вынесен в чистый модуль и покрыт юнит-
|
||
тестами, плюс `smoke_space_card_bg` на подписанный фон — он падает на
|
||
v1.45.0, где в DOM попадает сырой URL.
|
||
|
||
## v1.45.0 — 2026-07-27 (внешнее ревью v1.44.8: R2-1, R2-2, R2-3)
|
||
- **Отвергнутое сохранение больше не может испортить рабочий план (R2-1,
|
||
high).** Файл плана записывался под финальным именем — попутно удаляя вариант
|
||
с другим расширением — *до* проверки ревизии конфига. Если запись потом
|
||
отвергалась (конфликт ревизий, валидация, обрыв связи), живой план оказывался
|
||
уже подменён, а сохранённый конфиг мог ссылаться на удалённый файл. Теперь
|
||
загрузка идёт в версионированное имя (`<space>.<токен>.<ext>`) и ничего не
|
||
удаляется; карточка просит бэкенд убрать устаревшие файлы только после
|
||
принятой записи конфига. Падение между шагами оставляет один осиротевший
|
||
файл, который подберёт следующая успешная загрузка.
|
||
- **Подписанные ссылки больше не протухают навсегда на долгоживущих экранах
|
||
(R2-2).** Бэкенд подписывает не более 200 путей за запрос и молча отбрасывает
|
||
остальные, а карточка отправляла весь кэш одним вызовом и считала любую
|
||
запись годной вечно. Начиная с 201-го вложения поздние ссылки переставали
|
||
обновляться и через 24 часа тихо ломались. Теперь запросы бьются на батчи по
|
||
общему лимиту, записи помнят свой возраст (стареющая ссылка работает, пока
|
||
едет замена, протухшая не отдаётся вовсе), а кэш чистится до ссылок, на
|
||
которые конфиг всё ещё ссылается.
|
||
- **Климат комнат считается один раз на обновление, а не на каждую комнату
|
||
(R2-3).** Каждая комната запрашивала температуру и влажность по отдельности,
|
||
и каждый запрос заново обходил весь реестр сущностей: 60 комнат и 2000
|
||
сущностей — это ~120 обходов на рендер, целый кадр на метаданные, которые не
|
||
менялись. Теперь один проход строит карту по всем зонам с привязкой к снимку
|
||
Home Assistant: свежие состояния видны всегда, а посторонние перерисовки не
|
||
стоят ничего. Замер в смоуке: 133 обхода реестра на обновление до, 2 после —
|
||
и число больше не растёт с числом комнат.
|
||
- `smoke_ux_fixes` писал скриншот по жёстко зашитому пути `/tmp` и не запускался
|
||
на Windows — теперь берёт временную папку у ОС.
|
||
- Новые тесты: `smoke_plan_upload_reject` (чистка только после принятого
|
||
сохранения), `smoke_sign_cap` (201 ссылка, батчи, чистка, срок годности),
|
||
`smoke_climate_once` (число обходов не растёт с числом комнат), плюс
|
||
backend-покрытие версионированных имён и юнит-тесты новых хелперов.
|
||
|
||
## v1.44.8 — 2026-07-27
|
||
- **Загруженная подложка действительно привязывается к пространству.**
|
||
`_saveSpaceDialog` держал ссылку на объект пространства через `await`
|
||
загрузки картинки. Любое событие `houseplan_config_updated` запускает
|
||
`_reloadConfigOnly()`, а оно *заменяет* `_serverCfg` — ссылка становилась
|
||
осиротевшей, и `plan_url`, `aspect`, заголовок и все настройки отображения
|
||
писались в отсоединённый объект, тогда как на сервер уходил нетронутый
|
||
конфиг. Файл попадал на диск, подложка не появлялась, пересохранение не
|
||
помогало. Создание пространства в этот момент теряло пространство целиком.
|
||
Теперь загрузка идёт *до* обращения к конфигу, и ни одна ссылка не живёт
|
||
через await.
|
||
- **`_saveConfigNow` помечает запись как выполняющуюся** (`_cfgWriting`) — так
|
||
же, как отложенный писатель, — поэтому чужая ревизия, пришедшая посреди
|
||
сохранения, откладывает перечитывание вместо подмены конфига (аудит L2,
|
||
расширен на этот путь).
|
||
- Регрессионный тест `demo/smoke_plan_upload_race.mjs` падает на v1.44.7 и
|
||
проходит здесь.
|
||
|
||
## v1.44.7 — 2026-07-27
|
||
- **Подложки снова отображаются (регрессия с v1.44.5).** Эндпоинт с файлами
|
||
требует авторизации, поэтому карточка просит бэкенд подписать ссылку на план —
|
||
но подпись подставлялась внутри *мемоизированной* модели пространства, а она
|
||
кэшируется по отпечатку конфига. Неподписанная ссылка «замерзала» в кэше,
|
||
подпись до элемента `<image>` не доезжала, и план не грузился никогда. Теперь
|
||
ссылка вычисляется в момент отрисовки, вне кэша. (Ссылки на PDF не страдали —
|
||
там она и так вычислялась при отрисовке.)
|
||
- **Больше нет «неудачной попытки входа» с собственного IP.** Пока подложка была
|
||
сломана, браузер продолжал дёргать неподписанный путь, тот отвечал 401, и
|
||
Home Assistant поднимал предупреждение о неудачном входе с адреса самого
|
||
зрителя. Теперь до получения подписи не рисуется ничего, и неподписанный
|
||
запрос не уходит вовсе.
|
||
- **Долгоживущие экраны не моргают.** Переподписывание раз в 12 часов раньше
|
||
сбрасывало все подписи и ждало новые; теперь текущие ссылки держатся до
|
||
прихода замены, так что настенный планшет не показывает пустой план.
|
||
- Регрессионный тест `demo/smoke_plan_signed.mjs` падает на v1.44.6 и проходит
|
||
здесь.
|
||
|
||
## v1.44.6 — 2026-07-27
|
||
- **Климатом комнаты считается только температура *воздуха*.** После v1.44.5,
|
||
когда данные стали браться из реестра зон, а не с видимых значков,
|
||
кандидатами стали все скрытые датчики температуры в зоне — в том числе те,
|
||
что меряют вовсе не воздух. Перед усреднением теперь работают три фильтра:
|
||
пропускаются сущности с категорией диагностика/настройка, сущности
|
||
исключённых интеграций и сущности, в id которых назван не-воздушный носитель
|
||
(`water`, `coolant`, `flow_temp`, `return_temp`, `target`, `setpoint`, `chip`,
|
||
`cpu`, `processor`, `board`, `device_temp`, `batter`, `freezer`, `fridge`,
|
||
`oven`, `kettle`, `boiler`).
|
||
На живой установке с 60 зонами это убрало четыре реальных ложных
|
||
срабатывания: температуру процессора NAS, воду в умном чайнике, сауну с 90 °C
|
||
и виртуальный `better_thermostat`, дублирующий настоящий датчик.
|
||
- **Новые правила иконок:** чайники и термопоты получают `mdi:kettle`, сауны
|
||
(`sauna`, `harvia`, `парная`) — `mdi:hot-tub`. Раньше и те и другие попадали
|
||
под общее правило термометра, из-за чего и учитывались в климате комнаты.
|
||
|
||
## v1.44.5 — 2026-07-27
|
||
- **Климат комнаты считается по всем датчикам зоны**, включая устройства,
|
||
которых нет на плане (скрыты курированием или вами). Раньше среднее бралось
|
||
только по видимым значкам, поэтому скрытый термометр молча выпадал из
|
||
карточки комнаты, подсказки и температурной заливки. Курирование сохранено
|
||
(холодильники, термоголовки и розетки с температурой чипа не считаются), а
|
||
явно выбранный источник в настройках комнаты по-прежнему главнее.
|
||
- Из подсказки к комнате убрана фраза «открыть зону» — клик по комнате перестал
|
||
никуда вести ещё в v1.40.1, для перехода есть значок-ссылка у названия.
|
||
|
||
|
||
## v1.44.4 — 2026-07-27 (доработка по аудиту: B2, B5, L4)
|
||
- **Единая политика авторизации (B2).** HTTP-загрузка по-прежнему **разрешала**
|
||
запись, когда запись о конфигурации недоступна, тогда как WebSocket-путь уже
|
||
отказывал — они разошлись. Теперь оба вызывают общий помощник `may_write`,
|
||
который в неопределённой ситуации пропускает только администраторов.
|
||
- **NaN/Infinity отвергаются во всех координатах (B5).** Проверка на конечность
|
||
числа стояла только у позиций раскладки; прямоугольники комнат, вершины
|
||
полигонов, `view_box` и координаты проёмов принимали `"NaN"`, который при
|
||
записи превращается в `null` и необратимо портит геометрию. Ограничение
|
||
`MAX_OPENINGS` было объявлено, но нигде не использовалось — список проёмов
|
||
оставался безразмерным.
|
||
- **Укрепление перетаскивания (часть L4).** Безопасная обёртка над
|
||
`setPointerCapture` теперь используется во всех сценариях перетаскивания
|
||
(устройства, подписи, изменение размера), а не только у проёмов — «мёртвый»
|
||
идентификатор указателя мог оборвать перетаскивание. Фигуры декора получили
|
||
ограничение по границам: их больше нельзя утащить далеко за пределы плана и
|
||
сохранить там.
|
||
|
||
## v1.44.3 — 2026-07-27 (исправление: планы и инструкции снова загружаются)
|
||
- **У аутентифицированной выдачи контента не было рабочего пути для браузера.**
|
||
Версия v1.43.0 закрыла дыру правильно, но Home Assistant аутентифицирует
|
||
HTTP-запросы либо заголовком Bearer, либо подписанным путём `authSig` — а
|
||
`<image href>` внутри SVG и обычная ссылка `<a href>` не отправляют ни того,
|
||
ни другого. На настоящем дашборде фоны планов и ссылки на PDF отдавали
|
||
**401** (воспроизведено вживую до исправления). Теперь карточка просит бэкенд
|
||
подписать то, что собирается показать (`houseplan/content/sign`, 24 часа,
|
||
привязано к токену сессии, только для нашего эндпоинта), перерисовывается,
|
||
когда подписи приходят, и обновляет их каждые 12 часов, чтобы настенные
|
||
планшеты продолжали работать. Тест бэкенда скачивает подписанный адрес **без**
|
||
заголовка авторизации и проверяет 200, а без подписи — 401.
|
||
|
||
## v1.44.2 — 2026-07-27 (внешнее код-ревью: CR-1…CR-3)
|
||
|
||
Второе, состязательное ревью (версии v1.44.0) дало три находки — все закрыты.
|
||
|
||
- **Правило про замки теперь сформулировано точно и проверяется (CR-1).**
|
||
Рецензент справедливо отметил, что утверждение «замок нельзя открыть с плана»
|
||
было слишком абсолютным: кнопка в карточке двери действительно вызывает
|
||
сервис. Эта кнопка — осознанное продуктовое решение, поэтому правило
|
||
переписано там, где ему место («никогда случайным нажатием; ровно одна
|
||
подписанная поверхность»), отпирание теперь **спрашивает подтверждение**, а
|
||
новый смок-тест проверяет все пять путей управления и доказывает, что значки,
|
||
`controls[]` и карточка устройства по-прежнему отказывают замкам.
|
||
- **Перенос вложений стал транзакционным (CR-2).** При смене привязки маркера
|
||
файлы раньше ПЕРЕМЕЩАЛИСЬ до сохранения конфига с проверкой ревизии: если
|
||
сохранение отклонялось, на сервере оставались старые ссылки, а файлы уже
|
||
уехали. Теперь сервер копирует, конфиг фиксируется, и только после этого
|
||
старая папка удаляется (`houseplan/files/cleanup`).
|
||
- **Неудачный или частичный перенос больше не переписывает ссылки (CR-3).**
|
||
Копирование возвращает точное соответствие «исходное имя → записанное»;
|
||
переписываются только подтверждённые копии, при совпадении имён файл получает
|
||
уникальное имя вместо молчаливой ссылки на чужой файл, а ошибка переноса
|
||
показывается тостом.
|
||
|
||
## v1.44.1 — 2026-07-27
|
||
|
||
- Ссылка на чат сообщества добавлена везде, где её ищут:
|
||
**https://t.me/ha_houseplan** (бейдж и строка в шапке обоих README, раздел
|
||
«Помощь и обмен опытом», контакт-ссылки в шаблонах issue, CONTRIBUTING,
|
||
STATUS и SCOPE).
|
||
|
||
## v1.44.0 — 2026-07-27 (отзыв пользователя: сначала управление)
|
||
|
||
- **Карточка устройства стала поверхностью управления.** Она открывается со
|
||
списка управляемых сущностей: лампы, розетки и вентиляторы переключаются
|
||
прямо здесь кнопками под палец, шторы, замки и климат передают управление в
|
||
штатный more-info Home Assistant. Модель, ссылки и PDF-инструкции ушли ниже —
|
||
на настенном планшете эта карточка нужна для управления домом, а не для
|
||
чтения документации (из полевого отзыва). Служебные (config/diagnostic)
|
||
сущности в списке не показываются, замки по-прежнему не переключаются
|
||
нажатием в карточке.
|
||
- **«Это устройство — источник света»** — новый флаг у устройства. Умный
|
||
выключатель с обычными (не умными) светильниками теперь даёт ореол в заливке
|
||
«Свет по источникам» без создания хелпера-группы: свечение следует за самим
|
||
выключателем либо за лампами, привязанными в «Управляет источниками света».
|
||
|
||
## v1.43.3 — 2026-07-27 (отзыв пользователя: обнаруживаемость и тач)
|
||
|
||
- **Настройки комнаты невозможно было найти.** Шестерёнка из v1.42.0 жила
|
||
внутри подписи комнаты размером 0.9em от её шрифта и с прозрачностью 60% —
|
||
несколько бледных пикселей на обычном плане. Теперь это кнопка-пилюля
|
||
«⚙ Комната» фиксированного читаемого размера, не зависящая от масштаба
|
||
карточки, и она появляется **даже у комнат без имени** (их там и называют).
|
||
Заодно разблокировались слайдеры размеров шрифта, до которых никто не мог
|
||
добраться.
|
||
- **Строка показателей увеличена** с 0.62 до 0.75 от размера названия — автор
|
||
отзыва мог увеличить название, но строка датчиков оставалась нечитаемой на
|
||
планшете. Множители комнаты и пространства работают поверх.
|
||
- **Тултипы на тач-устройствах, вторая попытка.** Проверки `(hover: none)`
|
||
оказалось мало: некоторые устройства, оболочки, стилусы и подключённые мыши
|
||
сообщают `hover: hover`, и подсказки продолжали висеть под пальцем. Теперь
|
||
карточка запоминает первое же касание (touch/pen) и гасит открытую подсказку.
|
||
|
||
## v1.43.2 — 2026-07-27 (внешний аудит: слой тестов)
|
||
|
||
- **Смок-тесты наконец умеют падать (T1).** Все 48 браузерных смоков печатали
|
||
булевы значения и всегда завершались с кодом 0 — регрессия была видна в их
|
||
собственном выводе, а прогон считался успешным. `demo/serve.mjs` теперь
|
||
экспортирует `check`/`checkAll`/`finish`: каждый факт проверяется по имени,
|
||
несовпадения и необработанные исключения внутри карточки дают ненулевой код
|
||
возврата. Проверено намеренной поломкой блокировки редакторов в киоске —
|
||
соответствующий смок покраснел.
|
||
- **Набор гоняется в CI (T2)** отдельной джобой `smoke` после `frontend`,
|
||
против свежесобранного бандла (закоммиченная копия в `demo/srv/assets` —
|
||
снимок, на нём легко получить «зелёный» отчёт о несуществующем коде), с
|
||
выгрузкой логов при падении.
|
||
- **`docs/TESTING.md` приведён в соответствие (T3).** `[auto]` теперь означает
|
||
«существует именованная проверка, которая падает», и рядом написано, где она;
|
||
72 пункта, где автоматизация была намерением, честно помечены `[manual]`.
|
||
Исправлены два давних противоречия: строка про «ноль кнопок редактирования в
|
||
Просмотре» (неверна с v1.30.1) и строка про клик по проёму (снова верна
|
||
с v1.43.1).
|
||
- Три смока проверяли поведение, которого уже нет (ожидания времён v1.39.0 и
|
||
v1.25); теперь они тестируют текущий контракт.
|
||
|
||
## v1.43.1 — 2026-07-27 (внешний аудит: исправления P1)
|
||
|
||
- **Стоимость отрисовки (L1).** Home Assistant подменяет объект `hass` при
|
||
любом изменении состояния в доме, и каждая такая отрисовка пересчитывала всю
|
||
геометрию плана — `_openPairs()` вызывался по разу на комнату (кубическая
|
||
математика коллинеарных наложений), модель пространства строилась дважды.
|
||
Теперь и то, и другое мемоизируется по структурному отпечатку конфига и
|
||
вынесено из цикла по комнатам; сброс кэша происходит синхронно в момент
|
||
мутации, а не внутри дебаунса.
|
||
- **Тап против перетаскивания у проёмов (L4).** У перетаскивания двери или окна
|
||
не было порога движения, поэтому любое дрожание пальца считалось
|
||
перетаскиванием: диалог свойств не открывался, а в конфиг писалось
|
||
неизменённое состояние (что подпитывало гонку L2). Теперь порог 3 px, как во
|
||
всех остальных сценариях перетаскивания, и запись только при реальном
|
||
изменении геометрии.
|
||
- **Вогнутые комнаты (G2).** Вложенность определялась через среднее арифметическое
|
||
вершин — а оно лежит СНАРУЖИ U- и L-образных комнат, поэтому комнаты-острова
|
||
в них отвергались как пересечение, а дырка в заливке не рисовалась. Теперь
|
||
вычисляется настоящая внутренняя точка (`interiorPoint`).
|
||
- **Дедупликация стен (G3).** `segKey` сортировал концы по сырым float, а
|
||
печатал округлённые, поэтому одна общая стена могла дать два ключа и
|
||
рисовалась дважды. Сначала округление, потом сортировка.
|
||
- **Укрепление бэкенда (B2–B5).** Проверка прав на запись теперь **отказывает**,
|
||
когда запись о конфигурации недоступна (раньше во время перезагрузки
|
||
интеграции запись разрешалась); `layout/set` поддерживает `expected_rev` и
|
||
сообщает о конфликте так же, как хранилище конфига; `config/set` без
|
||
`expected_rev` поверх непустого хранилища пишет предупреждение в лог;
|
||
координаты отвергают NaN/Infinity, а у пространств, комнат, маркеров, декора
|
||
и раскладки появились щедрые ограничения размера.
|
||
|
||
## v1.43.0 — 2026-07-27 (внешний аудит: исправления P0)
|
||
|
||
Внешний аудит кода версии v1.41.1 нашёл четыре критические проблемы. Все четыре
|
||
исправлены и покрыты регрессионными тестами.
|
||
|
||
- **Молчаливая потеря правок при сохранении (L2).** Отложенная запись конфига
|
||
читала его в момент срабатывания, поэтому пришедшее в промежутке событие
|
||
`houseplan_config_updated` подменяло конфиг, и правка пользователя исчезала
|
||
без единой ошибки — воспроизводилось даже в одной вкладке. Теперь дебаунс
|
||
умеет `flush()`/`pending()`, перезагрузка сперва дописывает отложенную
|
||
запись и откладывается, пока запись в полёте, а неудачная перезагрузка
|
||
наконец сообщает о себе вместо молчания.
|
||
- **Разрез разрушал геометрию комнаты (G1).** Разрез, начинающийся и
|
||
заканчивающийся на ОДНОЙ стене (вырезание ниши — совершенно естественное
|
||
действие), давал две самопересекающиеся комнаты, суммарная площадь которых
|
||
вдвое превышала исходную, и проверка пересечений это не ловила. Теперь такие
|
||
разрезы корректно вырезают нишу, а инвариант разбиения (части в сумме дают
|
||
исходную площадь) отклоняет всё остальное.
|
||
- **Планы и загруженные файлы отдавались без авторизации (B1).** Любой, кто мог
|
||
достучаться до вашего Home Assistant, скачивал планы этажей и вложенные
|
||
инструкции без входа в систему. Теперь их отдаёт аутентифицированный
|
||
обработчик; сохранённые старые адреса переписываются на чтении, так что
|
||
ничего не ломается. **Старые публичные пути исчезают только после
|
||
перезапуска Home Assistant.**
|
||
- **Диалоги могли воскреснуть и обнулить карточку (L3).** Закрытие диалога во
|
||
время неудачного сохранения превращало его состояние в пустую «оболочку»,
|
||
отрисовщик падал, и карточка оставалась пустой до перезагрузки страницы.
|
||
Защита добавлена во все четыре процедуры сохранения, тост об ошибке
|
||
по-прежнему показывается.
|
||
|
||
## v1.42.2 — 2026-07-26
|
||
|
||
- На тач-устройствах подсказки при наведении больше не выскакивают при каждом
|
||
касании (из отзыва: «на планшете при тапе вылезают доп. надписи — мешают»).
|
||
Подсказки теперь только для мыши; на тач та же информация есть в карточках
|
||
комнат и в карточке устройства по долгому нажатию.
|
||
|
||
## v1.42.1 — 2026-07-26 (размеры шрифтов карточек комнат)
|
||
|
||
- Закрываем отзыв «нельзя настроить размер шрифта»: **три слайдера**. В
|
||
настройках пространства появился базовый размер шрифта карточек комнат для
|
||
всего пространства; в настройках комнаты — независимые размеры **названия** и
|
||
**строки показателей** (50–300% каждый). Эффекты перемножаются и складываются
|
||
с растягиванием карточки за уголки и множителем экрана в киоск-режиме.
|
||
- В обоих диалогах показывается **живой пример карточки**, который меняется
|
||
прямо во время перетаскивания слайдеров.
|
||
|
||
## v1.42.0 — 2026-07-26 (настройки комнаты — третий уровень)
|
||
|
||
- **У настроек теперь четыре уровня**: общие → пространство → комната →
|
||
устройство; более конкретный уровень переопределяет более общий (решение
|
||
владельца, зафиксировано в ARCHITECTURE). В этом релизе добавлен уровень
|
||
КОМНАТЫ.
|
||
- У каждой карточки комнаты в редакторе плана появилась **шестерёнка**:
|
||
переименовать комнату, сменить её зону HA, переопределить **тип заливки**
|
||
только для этой комнаты (работает и в glow-пространствах — «без заливки»
|
||
выводит комнату из темноты) и выбрать явный **источник температуры и
|
||
влажности** — любое устройство или сущность HA вместо среднего по комнате.
|
||
Источник питает карточку комнаты, всплывающую подсказку и температурную
|
||
заливку и работает даже у комнат без зоны HA (случай из отзыва: собственный
|
||
template-сенсор, привязанный к помещению).
|
||
- Тот же раздел настроек появляется в диалоге комнаты сразу после замыкания
|
||
контура.
|