docs: specify device icon redesign

Issue: #179
User-Visible: no
This commit is contained in:
Sergey Matyunin
2026-08-19 21:52:17 +03:00
parent a84338b042
commit 517a7101e7
2 changed files with 536 additions and 1 deletions
+534
View File
@@ -0,0 +1,534 @@
# Issue #179 — новый визуальный язык маркеров устройств
- **Статус:** готово к ревью ТЗ
- **Issue:** https://github.com/Matysh/houseplan-card/issues/179
- **Приоритет:** P1
- **Тип:** feature / polish / accessibility
- **Область:** frontend, общий renderer маркера, preview, статическая карточка,
документация и visual QA
- **Нормативный дизайн-пакет:** `House Plan Icons — Developer Package`,
версия 1.1.1, экспорт 2026-08-18
- **Архив:** https://github.com/user-attachments/files/31235094/House.plan.Icons.-.Developer.Package.2026-08-19.zip
- **SHA-256 архива:**
`63670C73E25D1E59DDAF1BE236F3D7F2FAC827B9B5D6DD4B77125EA9BC012025`
- **Figma frames:** Light `99:1290`, Dark `104:1539`
## 1. Пользовательский сценарий и персона
**Персона:** пользователь House Plan, который одновременно контролирует
устройства разных доменов, читает значения датчиков и оценивает состояние
связи на светлой либо тёмной теме Home Assistant.
**Сценарий:** пользователь открывает план и за один взгляд различает обычное,
активное, тревожное, заблокированное, разблокированное, виртуальное и
недоступное устройство; видит полное значение и Zigbee LQI; получает тот же
результат в полном плане, preview редактора и статической карточке пространства.
## 2. Проблема и результат
### До реализации
- plate маркера является одним заполненным rounded-square без общего внешнего
shell из дизайн-пакета;
- hover применяется и к unavailable-маркеру;
- selected обозначается amber-цветом и конфликтует с семантикой активности;
- value и legacy secondary value рисуются отдельными спутниками, длинные
значения обрезаются ellipsis;
- LQI использует непрерывный HSL-gradient, а не три читаемых диапазона;
- ordinary continuous pulse длится 2,4 с и по умолчанию разрастается до 3×;
- маркер не является клавиатурной целью и не активируется Enter/Space;
- light/dark, focus и semantic states не образуют единой дизайн-системы.
### После реализации
Все поверхности используют один runtime-renderer нового shell/core,
компоновок Text/Double, LQI и motion из пакета. Семантика устройств и действий
остаётся прежней; меняется её единое визуальное и доступное представление.
## 3. Нормативный источник и порядок разрешения расхождений
Единственный дизайн-источник этой задачи — архив #179. Нормативны его
`README.md`, `SPECIFICATION.md`, `ACTIVE_ANIMATION_SPEC.md`,
`DEVELOPER_HANDOFF.md`, `PACKAGE_ANNOTATION.txt`, `manifest.json` и SVG-примеры.
Порядок приоритета:
1. решения владельца в §4;
2. текстовые документы архива;
3. SVG-примеры архива;
4. текущая реализация House Plan — только для поведения, которое пакет не
переопределяет.
Статические SVG являются эталонами геометрии и состояний, а не готовыми
production-иконками: runtime продолжает использовать динамические MDI glyphs,
HA-значения и локализованный текст.
## 4. Принятые решения владельца
1. **Unavailable.** Визуальный hover и motion отсутствуют. Click/tap остаётся
доступен и выполняет текущее действие поверхности (More Info либо открытие
настроек).
2. **Пользовательские pulse-настройки.** Если `ripple_color` или `ripple_size`
явно сохранены, они сохраняют приоритет. При отсутствии поля используются
геометрия и цвет пакета.
3. **Zigbee LQI.** `0…40` — red, `41…179` — amber, `180+` — green.
4. **Клавиатура.** Интерактивный маркер получает focus; Enter и Space выполняют
то же действие, что click на этой поверхности.
5. Специальная кнопка либо новый action для клавиатуры не вводятся.
## 5. Цели
1. Реализовать shell/core, цвета, состояния, focus и motion пакета #179.
2. Сохранить единую проекцию на полном плане, в editor preview и static card.
3. Показывать полное динамическое значение без ellipsis в Text/Double layout.
4. Сделать маркер читаемым в light/dark и на цветном фоне плана.
5. Обеспечить минимум 44×44 CSS px для интерактивной цели и keyboard parity.
6. Сохранить существующую HA-семантику, пользовательские настройки, координаты
и безопасный pipeline действий.
## 6. Не входит в задачу
- новые правила определения `on`, `working`, `open`, alarm и activity;
- новые HA service calls, actions или обход secure confirmation;
- новые display modes и новые пользовательские настройки дизайна;
- смена MDI-иконок либо поставка собственного icon font;
- настройка порогов LQI пользователем;
- автоматическое устранение пересечений соседних маркеров;
- изменение комнатной LQI-заливки, Glow, света, комнатных fills или isometry;
- миграция сохранённых координат и marker config;
- перенос каждого example SVG из архива в production bundle.
## 7. Визуальная система
### 7.1. Геометрия
Маркер состоит из независимых слоёв:
1. прозрачная hit area минимум 44×44 CSS px;
2. внешний shell: прозрачный fill, stroke и внешние shadows;
3. внутренний core с MDI glyph либо динамическим значением;
4. semantic/focus/selection decoration;
5. pulse layer с `pointer-events: none`;
6. LQI и дополнительные секции, если включены.
Для Icon-эталона shell имеет диаметр `101.5/127` viewBox, core — `80/127`;
отношение core/shell равно `0.788` с допустимым расхождением не более 0,5 CSS
px на QA-размерах 32, 56 и 96 px. Координата сохранённого маркера остаётся
центром icon core, поэтому включение Text/Double и смена стороны не двигает
устройство на плане.
Light shell: stroke `#BCBCBC`; core по умолчанию white. У light-варианта
запрещены backdrop blur и inner shadows. Внешние shadows масштабируются от
референса 56 px: `0 1px 2px rgb(0 0 0 / 12%)` и
`0 4px 8px -1.07px rgb(0 0 0 / 18%)`.
Dark использует неизменённую dark-ревизию пакета, включая core `#252525` и её
эталонные эффекты. Тема берётся из актуальных HA theme tokens; переключение
темы не требует remount и не меняет semantic state.
### 7.2. Цвета
Нормативные semantic colors:
| Смысл | Цвет |
|---|---|
| hover / focus / neutral activity | `#0C82F0` |
| active / working / unlocked | `#F0A00C` |
| alert / low LQI | `#F0410C` |
| unavailable core | `#B5BAC1` |
| locked glyph | black |
| high LQI | `#1DC21D` |
Тема не подменяет semantic colors. Контраст glyph/core и читаемость текста
проверяются в light/dark и на светлом, тёмном и насыщенном фоне плана.
### 7.3. Состояния и приоритет
Нормативный визуальный приоритет:
```text
Alert > Focus > Selected > Hover > semantic state > Default
```
- **Default:** theme-default shell/core и обычный glyph.
- **Hover:** blue decoration пакета; не меняет semantic state и не
перезапускает pulse.
- **Focus:** blue keyboard-focus decoration, видимая без hover.
- **Selected:** отдельная selection decoration пакета, не amber semantic fill.
- **Active/working:** amber.
- **Lock:** locked glyph black; **Unlock:** unlocked glyph amber.
- **Alert:** red и всегда выше остальных состояний.
- **Unavailable:** gray core/glyph по текущему правилу прозрачности; без
визуальной реакции на hover и без motion.
- **Virtual:** пунктирный внешний shell. У обычного virtual default/hover
меняется только цвет оформления. Реальная HA unavailable и active pulse для
HA-less virtual device не синтезируются.
Текущая semantic-модель `neutral/open/working/alarm`, activity resolver и
domain-specific HA rules сохраняются. Для lock presentation дополнительно
различает locked/unlocked, не меняя secure action. Generic physical `open`
для cover/contact/valve не переименовывается в lock state и продолжает
существующую отдельную semantic-проекцию.
`display: static_icon` получает новую theme-default shell/core геометрию, но
остаётся нереактивным к HA state, values и pulse. На интерактивной поверхности
он сохраняет разрешённые hover/focus/click; unavailable hover запрещён.
## 8. Text, Double и дополнительные секции
### 8.1. Text
В `display: value` динамический текст находится внутри общего shell. Полная
строка всегда доступна визуально: CSS ellipsis, clipping и скрытие хвоста
запрещены. Сначала шрифт равномерно уменьшается до `0.25 × marker size`
(8 CSS px при размере 32); если этого недостаточно, text section расширяет
shell. Измерение выполняется детерминированно и кэшируемо, без layout-loop и
ResizeObserver на каждый маркер.
### 8.2. Double
Иконка и value badge входят в один общий shell. Поддерживаются сохранённые
позиции `right`, `bottom`, `left`, `top`; icon core остаётся anchor. Высота
внутренней value-секции равна `0.7875 × icon core`, как в референсе.
Если у нетронутой legacy-конфигурации одновременно разрешены два значения,
второе становится третьей секцией того же shell, а не отдельным спутником.
Новая пользовательская модель второго бейджа не вводится.
Длинное значение проходит тот же auto-fit, что Text: полная строка без
ellipsis, а shell при необходимости расширяется. Динамический текст остаётся
текстом DOM, а не SVG path; шрифт — HA/system Roboto с weight 600 и безопасным
system fallback.
## 9. Zigbee LQI
Числовое LQI располагается под shell по геометрии пакета и окрашивается
категориально:
- `<= 40` — `#F0410C`;
- `41…179` — `#F0A00C`;
- `>= 180` — `#1DC21D`.
Границы применяются к текущему resolved average LQI без изменения источника,
агрегации, форматирования и флагов `show_signal`. Значение `0` валидно. Для
missing/unavailable LQI сохраняется текущая политика отсутствия подписи.
Категориальная функция применяется только к marker LQI. Непрерывный
HSL-gradient комнатной LQI-заливки остаётся неизменным.
В `Light/Zigbee LQI Low.svg` архива low ошибочно окрашен amber. Текстовая
спецификация архива и решение владельца имеют приоритет: production low — red.
## 10. Motion
### 10.1. Continuous
- одно кольцо;
- duration `3.6s`, infinite;
- easing `cubic-bezier(.45,.05,.55,.95)`;
- scale `1 → 1.5`, opacity `.55 → 0`;
- цвет соответствует resolved ordinary activity.
### 10.2. Short
- три кольца;
- каждое длится `1.1s`;
- delays `0`, `1.1s`, `2.2s`;
- общий цикл `3.3s`;
- новое событие перезапускает цикл через существующий generation/runtime.
### 10.3. Alert
- red независимо от custom pulse color;
- wave stroke 3 reference units;
- scale до `1.5`;
- два wave-starts с интервалом `1.2s`, цикл `2.4s`;
- alert имеет приоритет над ordinary short/continuous.
### 10.4. Пользовательские настройки и fallback
Явно сохранённые `ripple_color` и `ripple_size` сохраняются без миграции.
Отсутствующий `ripple_size` использует package scale `1.5`, отсутствующий
`ripple_color` разрешается в порядке:
1. валидный live RGB контролируемого light, если он уже является текущим
источником pulse color;
2. semantic amber для working/open/unlocked;
3. package blue для neutral activity.
UI-default размера меняется на `1.5`, но Open → Save не материализует поле и
не переписывает существующее явно сохранённое значение. Backend допустимый
диапазон и import/export round-trip не меняются.
### 10.5. Reduced motion
При `prefers-reduced-motion: reduce` animated rings отсутствуют. Ordinary
activity обозначается статической semantic point из существующего единого
pulse renderer; alert остаётся красным статическим состоянием. Marker не
создаёт собственную media-query subscription: используется одна подписка на
surface/card host.
## 11. Интерактивность и доступность
- Интерактивные маркеры в View/kiosk и Device editor получают `tabindex="0"`
и button semantics.
- Enter/Space вызывают тот же существующий click handler текущей поверхности:
action/More Info в View и открытие настроек в Device editor.
- Space предотвращает прокрутку только когда активирует marker.
- Pointer/touch поведение, long-press/context action и drag в редакторе не
меняются; keyboard path не создаёт прямой HA service call.
- Background/Plan, read-only static card и неинтерактивный preview не входят в
tab order и не получают ложный button role.
- Minimum hit area 44×44 CSS px центрирована по icon core и не влияет на
visual bounds, координату, pulse либо collision geometry.
- `aria-label` включает локализованное имя, semantic state, activity/alert и,
если LQI показан, число и понятный диапазон «низкий/средний/высокий».
- Цвет и motion не являются единственным носителем alert, availability, lock
или LQI band.
- Focus после закрытия открытого marker dialog возвращается на исходный
marker по существующему dialog contract.
Secure lock/cover/valve actions продолжают проходить через текущий action
resolver и confirmation policy. Новый DOM-shell и keyboard handler не имеют
отдельного пути обхода подтверждения.
## 12. Совместимость и данные
- config schema version не меняется;
- `display`, `value_badge`, `value_badge_position`, `ripple_color`,
`ripple_size`, `show_signal` и legacy fields сохраняют формат и round-trip;
- существующие координаты относятся к icon core и не мигрируют;
- явно сохранённые pulse color/size воспроизводятся как раньше, кроме нового
shell и motion geometry;
- отсутствующие поля не материализуются при Open → Save;
- старые версии карточки читают тот же config; downgrade меняет только
внешний вид;
- runtime не зависит от наличия в bundle статических SVG-примеров;
- ru/en i18n parity обязательна.
## 13. Архитектурный контракт
```text
HA/device registry + marker config
→ existing semantic/activity resolvers
→ resolveDevicePresentation
→ resolveDevicePulse
→ renderDeviceFace (shell/core/text/LQI/motion)
→ full plan | editor preview | static space card
```
Один resolved presentation и один `renderDeviceFace()` остаются источником
истины всех поверхностей. Surface передаёт только interaction/theme context и
не вычисляет semantic state повторно.
Рекомендуемые зоны изменений:
- `src/device-visual.ts` — lock presentation facet без смены action semantics;
- `src/device-presentation.ts` — theme/semantic projection, marker-only LQI
band, defaults pulse;
- `src/device-pulse.ts` — package timings/scale/reduced motion;
- `src/device-face.ts` — единый shell и Text/Double/third section DOM;
- `src/styles.ts` — tokens, geometry, states, focus, auto-fit и motion;
- `src/houseplan-card.ts` и общие surface adapters — role/tabindex/keydown;
- i18n, unit, smoke, golden fixtures и документация.
Нельзя вводить surface-specific копию state mapping, formatter либо motion
runtime. Text auto-fit не должен читать layout на каждом render/animation
frame. Pulse использует transform/opacity и не меняет layout.
## 14. Эдж-кейсы
- light/dark hot switch во время continuous/short pulse;
- colored room background и минимальный marker size 32;
- marker sizes 32/56/96, user scale 0.5…3 и explicit ripple size 1…20;
- alarm во время hover/focus/selected и снятие alarm;
- unavailable во время active pulse, затем reconnect baseline без false short;
- locked, unlocked, locking и unlocking с secure action;
- virtual default/hover без HA entity и linked virtual with resolved controller;
- `static_icon` при реальном alarm/working/unavailable;
- `0`, `false`, very long localized string, unit symbol и third legacy value;
- Double на четырёх сторонах вместе с LQI;
- LQI exactly `0`, `40`, `41`, `179`, `180`, missing;
- rapid short retrigger, short поверх continuous, reduced-motion hot switch;
- keyboard activation после drag, click confirmation и dialog focus return;
- несколько cards одного плана с независимыми runtime и theme context;
- hidden/HA-disabled/orphaned marker и read-only static card.
## 15. Acceptance criteria
- [ ] **AC1 — shell/theme.** Icon, Text и Double используют package shell/core
geometry и Light/Dark tokens; light не содержит blur/inner shadow.
**Доказательство:** unit token assertions + reviewed golden 32/56/96.
- [ ] **AC2 — states.** Default, Hover, Focus, Selected, Active, Lock, Unlock,
Alert, Virtual и Unavailable соблюдают §7.3 и нормативный приоритет.
**Доказательство:** presentation unit matrix + light/dark state-table
golden.
- [ ] **AC3 — unavailable.** Unavailable не получает visual hover/motion, но
click/tap по-прежнему открывает текущее действие поверхности.
**Доказательство:** unit + browser smoke.
- [ ] **AC4 — secure locks.** Locked black, unlocked amber, locking/unlocking
continuous; pointer и keyboard проходят один action/confirmation path.
**Доказательство:** unit + secure-action smoke.
- [ ] **AC5 — virtual/static.** Virtual имеет dashed shell; HA-less virtual не
синтезирует unavailable/activity. `static_icon` использует theme-default
shell и не реагирует на live state/value/pulse.
**Доказательство:** unit + existing static-icon smoke.
- [ ] **AC6 — Text/Double.** Полные строки видимы без ellipsis; четыре стороны,
anchor, auto-fit и третья legacy section соответствуют §8.
**Доказательство:** unit layout facts + browser smoke + long-value golden.
- [ ] **AC7 — LQI.** Marker LQI использует red/amber/green thresholds на
границах, а room fill сохраняет continuous gradient.
**Доказательство:** boundary unit tests + room-fill regression test.
- [ ] **AC8 — motion.** Continuous/short/alert timings, ring counts, retrigger,
scale и colors соответствуют §10; explicit color/size сохраняются.
**Доказательство:** pure resolver tests + DOM/style smoke.
- [ ] **AC9 — reduced motion.** Rings отсутствуют, ordinary point и static red
alert остаются; одна subscription на host.
**Доказательство:** unit + reduced-motion browser smoke.
- [ ] **AC10 — keyboard/a11y.** Только интерактивные surfaces получают focus;
Enter/Space эквивалентны click, hit area >=44×44, aria-label содержит
state/LQI, focus возвращается после dialog.
**Доказательство:** keyboard/touch/browser smoke.
- [ ] **AC11 — parity.** Full plan, editor preview и static card используют
один presentation/face renderer и дают одинаковую read-only projection.
**Доказательство:** existing preview/static parity smokes.
- [ ] **AC12 — совместимость.** Schema и saved config не мигрируют; Open → Save
не материализует defaults; explicit pulse settings round-trip.
**Доказательство:** frontend/backend config tests.
- [ ] **AC13 — производительность.** Нет per-frame JS, per-marker media query,
ResizeObserver/layout loop или SVG example assets в production bundle;
transform/opacity motion не вызывает layout.
**Доказательство:** code assertion + `performance_smoke.mjs` перед beta.
- [ ] **AC14 — release artifacts.** ru/en copy, guides, architecture/testing
docs, changelogs, targeted smokes и golden review актуальны.
## 16. Тестирование
### 16.1. Цикл реализации
После каждого логического блока:
```bash
npm run typecheck
npm test
npm run build
```
Unit coverage:
- полная state/priority/theme/display matrix;
- lock/unlock и generic open не смешиваются;
- LQI boundaries и неизменность room gradient;
- pulse kinds, timings, fallback/explicit settings и reduced motion;
- Text/Double/third section facts, long values и anchor;
- keyboard surface policy и accessible labels;
- config/default/round-trip compatibility.
### 16.2. Targeted browser smoke перед S7
Добавить `demo/smoke_device_icon_design.mjs` и прогнать его вместе с:
- `demo/smoke_device_preview_parity.mjs`;
- `demo/smoke_static_icon.mjs`;
- `demo/smoke_state_value.mjs`;
- `demo/smoke_disabled_device.mjs`;
- релевантным secure-action/keyboard smoke из существующего набора.
Новый smoke проверяет light/dark, все состояния, Text/Double, четыре позиции,
long value, LQI boundaries, unavailable click, 44×44 hit area, keyboard и
reduced motion.
### 16.3. Mutation gates
Зарегистрировать targeted mutants, которые обязаны быть пойманы тестами:
1. generic hover снова применяется к `.unavail`;
2. LQI `40/180` уходит в соседний диапазон либо меняет room gradient;
3. Text/Double снова получает ellipsis;
4. keyboard activation вызывает отдельный action path.
### 16.4. Golden и pre-beta
Golden matrix: desktop/mobile, light/dark, neutral/hover/focus/selected,
active/lock/unlock/alert/virtual/unavailable, Text, четыре Double, third section,
LQI low/mid/high, reduced motion, sizes 32/56/96 и цветной фон.
Golden принимается только по Linux CI artifact согласно HP-QA-01. Перед beta
запускаются полный golden, smoke и performance наборы по release runbook;
Windows не является каноном полного HA harness из-за `fcntl`.
## 17. Риски и откат
### Риски
- рост shell у длинных значений может чаще пересекаться с соседями;
- old explicit ripple size 3+ визуально заметно больше package default;
- dark package намеренно отличается от light по blur/shadow;
- новый focus/tab order увеличивает число клавиатурных остановок на больших
планах;
- ошибочная привязка общего `lqiColor()` изменит комнатную заливку;
- новый DOM может изменить snapshot/golden fingerprint всех поверхностей.
### Митигации
- центр icon core и saved coordinates неизменны;
- explicit settings не переписываются скрыто;
- marker-only LQI helper отделён и покрыт regression test;
- интерактивность добавляется только существующим actionable surfaces;
- один renderer и одна token table исключают drift;
- targeted golden содержит контрастные backgrounds и dense layout.
### Откат
Откат выполняется одним revert implementation commit. Миграции данных нет,
поэтому rollback возвращает старый renderer без преобразования config. ТЗ и
архив остаются диагностическим контрактом.
## 18. Release-артефакты
В том же user-visible implementation commit обновить:
- `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` со ссылкой на #179;
- `docs/USER-GUIDE.md` и `docs/USER-GUIDE.ru.md`: состояния, Text/Double,
LQI, keyboard и static mode;
- `docs/ARCHITECTURE.md`: общий presentation/face pipeline и theme context;
- `docs/TESTING.md`: новый smoke, mutation и golden matrix;
- ru/en i18n для доступных state/LQI descriptions и изменённого static hint;
- screenshot/golden fingerprints и review manifest по HP-QA-01.
Release note: единая новая визуальная система устройств на светлой и тёмной
теме, полные значения, читаемый LQI и клавиатурное управление. Поставка сначала
в beta; stable — только после release gates.
## 19. План реализации
1. Зафиксировать package tokens и pure projection facts unit-тестами.
2. Расширить presentation lock/LQI/theme facts без изменения semantic/action
resolvers.
3. Перевести `renderDeviceFace()` на shell/core и общие Text/Double sections.
4. Реализовать package states, focus, unavailable и light/dark CSS.
5. Обновить pulse timings/defaults/reduced motion.
6. Подключить keyboard/hit area/accessibility к интерактивным surfaces.
7. Обновить preview/static parity, settings default и i18n/docs.
8. Добавить unit, mutation, targeted smoke и golden fixtures.
9. Прогнать typecheck, unit, build и named smokes; отправить в S7.
10. Перед beta выполнить полный golden/smoke/performance gate в Linux CI.
## 20. Принятые технические предположения
1. Package SVGs — visual reference; runtime DOM/SVG строится из тех же ratios и
tokens, потому что MDI glyph, HA text и theme динамические.
2. `Light/Zigbee LQI Low.svg` содержит ошибочный amber; red из textual spec и
решения владельца нормативен.
3. Package не задаёт minimum font size для бесконечно длинного значения:
используется floor `0.25 × marker size`, затем расширяется shell.
4. Generic physical `open` сохраняет текущую отдельную semantic-проекцию;
специальные black/amber Lock/Unlock применяются только к lock domain.
5. `static_icon` остаётся нереактивным, но default plate становится
theme-aware, потому что package задаёт разные Light/Dark defaults.
6. Отсутствующий pulse color сохраняет существующий validated live-light RGB
раньше semantic fallback; это единственный package-compatible способ не
потерять текущий пользовательский light-color effect.
7. Marker LQI меняет только цвет подписи; room LQI fill остаётся непрерывным.
8. Preview и static card показывают новый дизайн, но не получают ложную
интерактивность либо tab stop.
+2 -1
View File
@@ -1,6 +1,6 @@
# Спецификации задач
Актуально на 2026-08-17.
Актуально на 2026-08-19.
GitHub Issues и GitHub Projects (v2) остаются единственным каноническим backlog проекта. Этот каталог содержит развёрнутые ТЗ: каждое ТЗ ссылается на issue, а issue — на соответствующий файл. Статус, приоритет и факт завершения меняются только в GitHub.
@@ -53,6 +53,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
| [#166](https://github.com/Matysh/houseplan-card/issues/166) Солнечные лучи зеркально учитывают направление севера | [166-sun-north-rotation.md](166-sun-north-rotation.md) |
| [#167](https://github.com/Matysh/houseplan-card/issues/167) Экспорт «только планировка» | [167-plan-only-export.md](167-plan-only-export.md) |
| [#170](https://github.com/Matysh/houseplan-card/issues/170) HA-устройство не привязывается к комнате без HA-зоны | [170-room-without-area.md](170-room-without-area.md) |
| [#179](https://github.com/Matysh/houseplan-card/issues/179) Новый визуальный язык маркеров устройств | [179-device-icons-redesign.md](179-device-icons-redesign.md) |
| [#205](https://github.com/Matysh/houseplan-card/issues/205) Продолжение следа после короткой остановки пылесоса | [205-vacuum-trail-resume-grace.md](205-vacuum-trail-resume-grace.md) |
## P2