Add selectable value face sources

Issue: #378
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-08-29 22:20:18 +03:00
parent ad9c634901
commit 591f8f6ac9
51 changed files with 1415 additions and 562 deletions
+12 -5
View File
@@ -214,11 +214,13 @@ Built from the registries (`_buildDevices`), rules carried over 1-to-1 from the
## Live data
- Value satellite: `src/device-value-badge.ts` resolves one explicit
`marker.value_badge` source/position, or projects the legacy automatic
temperature/humidity label when that field is absent. The resolver owns HA
formatting, units, unavailable state, candidate discovery and deterministic
recommendation; renderers consume only `ResolvedDevicePresentation.valueBadge`.
- Value sources: `src/device-value-badge.ts` owns candidate discovery, source
keys, HA formatting, units and unavailable handling for both an explicit
`marker.value_source` inside the **Value + state** face and an explicit
`marker.value_badge` satellite. Absence of `value_source` keeps the legacy
automatic face resolver; absence of `value_badge` projects the legacy
automatic temperature/humidity satellite. Renderers consume only the
corresponding fields of `ResolvedDevicePresentation`.
- LQI (zigbee): the average over `*_linkquality` entities → label under the icon; color via
`lqiColor()`: ≤40 red → ≥180 green (hsl gradient). The room average is shown in the room tooltip.
The same tooltip includes the formatted clean-floor area (inner contour for
@@ -303,6 +305,11 @@ Explicit settings override the global legacy temperature gate; explicit off
suppresses legacy output. Bottom badges stack above system LQI, and a derived
LQI badge de-duplicates that system row. `hp-device-preview` fits and centres
the complete face bounding box rather than allowing satellites to clip.
An optional `marker.value_source` selects the same source kinds for the inner
face when `display: value`. Missing explicit data renders a dash without
falling back to another source or the icon; absence/`null` preserves the old
automatic face selection. Derived marker references share the same rewrite and
space-transfer seam as controls and value badges.
`normalizeDeviceDisplay()` is the mandatory compatibility gate for every consumer and maps
legacy `ripple` to `icon_ripple`. `markerLqiBand()` remains marker-only semantic
metadata for accessibility, while `markerLqiColor()` delegates to the shared
+7
View File
@@ -2,6 +2,13 @@
## Unreleased
- **Value + state** can now show the exact reading the user needs instead of
relying only on the automatically chosen entity state. The Device editor
offers the same states, useful attributes, LQI and linked-light values as
the adjacent value badge; for example, a cover can show `42 %` position
instead of `Open`. Existing markers keep their previous automatic behaviour,
and tapping the value still runs the same action
([#378](https://github.com/Matysh/houseplan-card/issues/378)).
- Glow in `houseplan-space-card` no longer rebuilds its light graph and wall
scene from scratch on every Home Assistant tick: the static path now shares
the caching machinery of the full card (light-graph cache, an LRU pool of
+7
View File
@@ -8,6 +8,13 @@
## Не выпущено
- В режиме **«Значение + состояние»** теперь можно выбрать нужный показатель,
а не полагаться только на автоматически выбранное состояние сущности.
Редактор устройства предлагает те же состояния, полезные атрибуты, LQI и
значения связанных источников света, что внешний бейдж: например, положение
cover отображается как `42 %` вместо `Открыто`. Старые маркеры сохраняют
прежнее автоматическое поведение, а нажатие по значению выполняет то же
действие ([#378](https://github.com/Matysh/houseplan-card/issues/378)).
- Glow в `houseplan-space-card` больше не пересобирает граф света и сцену стен
с нуля на каждый тик Home Assistant: статический путь получил кэш-механику
полной карты (кэш графа света, LRU-пул барьерных сцен — движущаяся дверь
+11
View File
@@ -419,6 +419,17 @@ space transfer remaps an internal target and disables/counts a link whose
target is outside the transfer. Older clients ignore the field and may erase
it if they reconstruct the same marker after a downgrade.
`marker.value_source` is an optional explicit source for the inner face of a
`display: value` marker. Absence or `null` preserves the historical automatic
entity-state choice; an object uses exactly the same discriminated source
contract and formatter as `marker.value_badge.source`. A missing explicit
source stays selected and renders `—` rather than silently falling back. The
top-level schema remains lossless: unchanged future literals round-trip, while
new or changed values receive strict delta validation. Marker-id rewrites and
full/space transfer preserve, remap or report/drop `derived_marker_state.ref`
through the same reference seam as controls and value badges. Older clients
ignore the field and may erase it if they reconstruct the marker.
## Persistent manual virtual-light state
The exact `virtual` + `is_light:true` + `tap_action:toggle` combination has a
+2 -1
View File
@@ -64,7 +64,7 @@ mutation evidence в одном pull request.
| F07 | `live_states:false`, не alarm | `face.live_states_disabled` | neutral/base icon; ordinary activity off | normal | `device-presentation-policy-live-gate`; `presentation-row-contract` |
| F08 | `static_icon` | `face.static` | neutral/base icon; state/RGB/value/metrics/pulse/vacuum off | normal | `device-presentation-policy-static`; `presentation-row-contract` |
| F09 | value + один scalar source | `content.value` | HA-formatted full Text face | normal | `device-presentation-policy-value`; `device-long-value-ellipsis-restored` |
| F10 | value + missing/unavailable/non-scalar | `content.value_fallback_icon` + `content.value_no_state/non_scalar` | icon fallback и точная причина | normal | `device-presentation-policy-value`; `presentation-row-contract` |
| F10 | value auto + missing/unavailable/non-scalar | `content.value_fallback_icon` + `content.value_no_state/non_scalar` | icon fallback и точная причина | normal | `device-presentation-policy-value`; `presentation-row-contract` |
| F11 | value + несколько равноправных sources | `content.value_ambiguous_sources` | icon fallback `value_ambiguous_sources` | normal | `device-presentation-policy-value`; `presentation-row-contract` |
| F12 | value + virtual marker | `content.value_virtual` | icon fallback `value_virtual` | normal | `device-presentation-policy-value`; `presentation-row-contract` |
| F13 | dynamic icon + известный morph | `diagnostics.dynamic_icon` | state icon; действующее cover override сохранено | normal | `device-presentation-policy-diagnostics`; `presentation-row-contract` |
@@ -72,6 +72,7 @@ mutation evidence в одном pull request.
| F15 | legacy automatic metric | `diagnostics.metrics_enabled` | прежняя temperature/humidity эвристика без записи config | normal | `device-presentation-policy-diagnostics`; `presentation-row-contract` |
| F16 | LQI 0/40, 41/179, 180+ | `diagnostics.lqi_low/mid/high` | low/mid/high и continuous canonical colour | normal | `device-marker-lqi-low-boundary-shifted`; `presentation-row-contract` |
| F17 | vacuum dynamic/static | `diagnostics.vacuum_live/vacuum_static` | live overlay только у видимого dynamic face | normal | `device-presentation-policy-diagnostics`; `presentation-row-contract` |
| F18 | value explicit + missing/unavailable/non-scalar | `content.value` + `content.value_no_state/non_scalar` | выбранный source сохраняется, Text face показывает `—` без auto/icon fallback | normal | `device-presentation-policy-value`; `presentation-row-contract` |
## Activity и pulse
+6
View File
@@ -652,6 +652,12 @@ alarm remains clear.
The four display choices are icon + state; icon + state + activity; value +
state; and always-static icon. A separate value badge can show an entity state,
useful attribute, average LQI or linked light state on any side of the marker.
For **value + state**, the Device editor also offers **Value source**. Keep
**Automatic (as before)** for the legacy choice, or select one of those same
readings—for example, cover position—to replace the icon with `42 %` rather
than `Open`. A temporarily unavailable saved source stays selected and shows
`—` until it recovers; it is not silently replaced. Changing this source never
changes what a click or tap does.
Text and adjacent values are sections of the same shell. They shrink to a
readable floor and then expand the shell; they are never ellipsized.
The complete visible value capsule is one hover and action target: clicking or
+8 -3
View File
@@ -1050,12 +1050,17 @@ Hover включается только после события от наст
|---|---:|---:|---:|---:|
| Значок + состояние | Да | Да | Только тревога | Отдельные компактные °/% и LQI возможны |
| Значок + состояние и активность | Да | Да | Да | Отдельные компактные °/% и LQI возможны |
| Значение + состояние | Если значение получить нельзя или источник неоднозначен | Да | Только тревога | Температура/влажность либо числовое или текстовое состояние, отформатированное HA |
| Значение + состояние | При автоматическом выборе — если значение получить нельзя или источник неоднозначен; при явном — только для virtual marker | Да | Только тревога | Автоматическое либо явно выбранное состояние, атрибут, LQI или состояние связанного источника света |
| Всегда статичный значок | Да | Нейтральная в цветах текущей темы | Нет | Нет |
В режиме «Значение вместо иконки» поддерживаются и числа, и локализованные HA
текстовые состояния. Если источник отсутствует, недоступен или неоднозначен,
карточка возвращается к иконке; предпросмотр объясняет причину. Длинный текст
текстовые состояния. Поле **«Источник значения»** позволяет оставить
**«Автоматически (как раньше)»** либо выбрать тот же показатель, который
доступен внешнему бейджу: например, положение cover даст `42 %` вместо
`Открыто`. В автоматическом режиме отсутствующий, недоступный или неоднозначный
источник по-прежнему возвращает иконку. Явно выбранный временно недоступный
источник остаётся выбранным и показывает `—` до восстановления, не подменяясь
другим. Выбор не меняет действие по клику или тапу. Длинный текст
уменьшается до читаемого минимума, затем общий shell расширяется: многоточие и
скрытие хвоста не используются. LQI остаётся отдельной строкой под shell.