DALI configurator: live device controls on the device page - #1223
Draft
evgeny-boger wants to merge 16 commits into
Draft
DALI configurator: live device controls on the device page#1223evgeny-boger wants to merge 16 commits into
evgeny-boger wants to merge 16 commits into
Conversation
Embeds the device's runtime controls — the same brightness, state, colour and command controls wb-mqtt-dali publishes over MQTT for the Devices view — into the DALI configurator's device page, so commissioning a device and trying the result happen in one place. Everything flows through the daemon's ordinary retained topics (/devices/<mqtt_id>/controls/... values, /meta JSON, /meta/error, writes to /on), rendered with the existing Cell store and cell widgets, so the panel works identically against a controller's broker and the standalone WASM editor's in-browser loopback broker — no environment-specific code. Verified in the standalone editor against a real WB-DALI with a Skydance DT8 lamp: the panel lists the daemon's full control set (levels, DAPC, step and scene commands, RGB/W), dragging Wanted Level lit the lamp and Actual Level polled back through the daemon. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
evgeny-boger
added a commit
to wirenboard/wb-wasm-device-editor
that referenced
this pull request
Aug 29, 2026
…page Bumps the submodule to wirenboard/homeui#1223: each device page now carries the daemon's runtime controls (levels, commands, colour), rendered from the ordinary MQTT control topics — which the loopback broker serves here exactly as a controller's broker does. Verified against the real WB-DALI: dragging Wanted Level lit the lamp, Actual Level polled back. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
… its own Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
The controls card sat above the config form with nothing signalling that the form continues below it — the page read as one strange form, and users looked for a way to "switch" between controls and configuration. The same collapsible-section idiom the bus page uses for Broadcast settings makes the two-section structure visible and lets the controls fold to one header line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
The stacked controls card failed exactly where live controls matter most: a DALI-2 sensor publishes ~75 cells, 72 of them per-button event indicators, so the three readings someone actually watches while tuning parameters — occupancy, movement, illuminance — scrolled away instantly, buried in noise, above a 14,500 px form. Prototyped six layouts against real hardware; this is the winner. One concept at every width: a small featured set that never leaves the screen, the full control set one gesture away. - Featured cells are chosen by structure, not device-specific names: read-only readings that are not part of a per-instance family (detected by stripping a trailing index and counting siblings — "Button 2".."Button 18" is a 17-member family, "Occupied 0" a singleton), plus the primary actuator range and the Off button. A sensor pins Occupied / Movement / Illuminance; a lamp pins Ok / Actual Level / Current RGB / Current W / Wanted Level / Off. - Wide screens: the featured cells ride in a slim strip, sticky under the toolbar, visible through the whole form scroll. Everything else sits behind a collapsed "All controls" section. - Phones: the same featured set becomes a bottom sheet — a 44 px peek bar with live values in thumb reach, opening to the full grid scrolling inside 60vh while the form keeps the entire screen. Verified on hardware at 1360 px and 390 px: the sensor strip stays pinned at 6,000 px of form scroll; the lamp strip carries its slider and Off; the peek bar live-updates and the sheet opens with all 19 lamp cells. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
…nitor Two findings from the hardware UX review. The content pane had no heading: which device was being edited was carried only by the tree selection — invisible on mobile, where the tree is hidden while a page is open. Bus, device and group pages now carry a title, with the device's bus as context. And a DALI-2 device initializing probes absent features three times per instance, painting the whole monitor viewport red with retries of the same fact. Consecutive identical error rows now collapse into one with a ×N badge — on a real MSensor init, 63 rows become 21. Only error rows collapse: ordinary traffic keeps its one-row-per-frame timeline, and foreign frames their ring counters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
Clicking a cell's name copies its MQTT topic id and shows "copied to clipboard" — useful on a controller, where rules and dashboards take topics. The standalone WASM device editor drives the same cells from an in-browser loopback with no broker to paste into, so the toast there has no possible next step. A small policy switch lets such a host turn the copy (and its tooltip) off once at startup; controllers keep the default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
…; strip-anchored "All controls"
The device, bus and group tabs share a TabToolbar: the page title and the
action buttons (Identify/Reload/Reset/Save, or Rescan) on one sticky row,
instead of the title floating on a line of its own above them.
Bus and group pages gain the live-controls panel the device pages have. The
daemon publishes the bus broadcast and each group as virtual devices
("<bus>_broadcast", "<bus>_group_NN"); pointing DeviceControls at those ids
gives every-member-at-once control right where the settings are — the first
thing one wants after a scan or after editing a group.
The featured-controls strip's "All controls" toggle moved into the strip
itself. As a header below the sticky strip it scrolled underneath it and
became unclickable exactly when reached for; in the strip it is always
on screen. GroupStore exposes its parent bus, like DeviceStore, so the
virtual-device id can be built.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
…or the bus cannot do The featured strip now folds each readback into its setpoint — Wanted Level carries "(actual %)", Set RGB a live colour swatch — so the pair spends one slot, and the freed room features colour pickers, secondary sliders and Recall Max Level next to Off. Readings get a colon and a bold value: "Illuminance 1 576" no longer reads as 1576. A device whose instances use an event addressing scheme that names no sender gets a warning banner with a one-click fix: such events decode in the monitor but can never update the controls (IEC 62386-103 Table 8 — only device short + instance number carries both halves of the attribution). New host-capabilities switchboard: the standalone WASM editor turns off the syslog monitor toggle and the Lunatone WebSocket emulator — a browser page has no syslog and cannot listen on a port. Alert cells stop offering copy-the-topic when the host has no broker, same policy as cell names. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
…strip alignment A failed GetGroup (a busy bus times the RPC out) rendered the group tab as nothing at all; it now says what happened and offers a retry. The command-catalog button hid its label under 990px in favour of an icon it does not have, leaving a label-less pill; the label stays. The featured strip parked at a hard-coded offset under the toolbar — wrong whenever the title or buttons wrapped, letting form rows show through above it or clipping its first line. The toolbar now publishes its measured height (--dali-toolbar-height, ResizeObserver) and the strip parks flush against it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPrWsZjKprJZVq5y6oGQfu
Clicking the Bus Monitor button with every bus's monitor off produced a bare drawer — no tabs, no text, indistinguishable from a rendering bug. The console panel accepts an emptyState node for the no-tabs case, and the DALI page supplies one: why the panel is empty, plus a button per bus that enables monitoring right there (the same action as the toggle at the bottom of that bus's tab, which the hint also points to). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4sGCd4GhAUr3ySuYvAGFk
…ests beside the code The locale files return to their original 3-space formatting: the diff against main shows the eight added keys instead of 4500 reformatted lines. The peek line speaks the UI language (state-on/state-off), the repeat badge gets Russian plural forms, and the orphaned device-controls key is gone. The gateway tab keeps exactly one host-adaptation seam — the WASM editor's build-time module substitution; the capability-flag fallback was unreachable in both hosts and referenced a translation namespace homeui does not own. GroupStore owns the group virtual-device id formula (controlsMqttId); the monitor's error-row folding moves into a pure, tested helper; the cell publish topic has one spelling shared with DevicesStore. Project-rules pass: getters after the constructor, ItemType over bare literals, props in types.ts, a typed InstanceConfig instead of casts, and the inert useMemo wrappers around the strip heuristics are gone. Tests move to where the code merges: the featured-strip heuristics are now covered in this repo (they were guarded only from the embedding repo), plus new tests for error-row folding, the event-scheme guard, mqtt-id mapping, the group id formula and the collapsible panel's single-toggle contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4sGCd4GhAUr3ySuYvAGFk
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4sGCd4GhAUr3ySuYvAGFk
The shared form-buttonGroup never wraps, so on a 390px screen the four device actions stacked on top of each other. Scoped to the DALI toolbar rather than changed globally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On a controller the id is the device's MQTT identity — dashboards, rules and history refer to it, so editing it is meaningful. The WASM editor runs a loopback broker nothing external ever sees; there the field is an implementation detail with no possible next step. A new host capability, externalBroker, lets that host drop the editor while the daemon keeps its default id. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…guration GetGroup merges parameters over the group's members that have finished initializing; while none has — during boot-time initialization, or while the member lamps are unpowered — it legitimately answers an empty schema. The store cached that moment as final, so a group tab opened too early showed only the controls strip for the rest of the session. An empty answer now marks the store as awaiting members: the tab says the devices are still initializing and re-asks every few seconds until the parameters arrive, with no reload needed. A loaded group is still never refetched. Note: the existing "skips if already loaded" test used an empty-schema fixture, which now means "still initializing" by design — its fixture became a non-empty schema so it keeps pinning its original claim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolve conflicts: - bus-tab-content: keep master's 115200-baud note under the bus monitor toggle and the branch's host-capability gating of the syslog toggle - debian/changelog: put 2.250.0 on top of 2.249.1/2.249.2
This was referenced Aug 31, 2026
Member
Author
|
Разбит на независимые PR от
Этот PR остаётся черновиком как интеграционная ветка: на неё указывает сабмодуль |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Встраивает живые контролы устройств прямо в DALI-конфигуратор — коммишенинг устройства и проверка результата происходят в одном месте — и готовит страницу ко второму дому: автономному WASM-редактору устройств.
Как устроено
DeviceControlsна вкладках устройства, группы, шины (broadcast) и датчика; питаются только обычными retained-топиками демона (/devices/<mqtt_id>/controls/…) и переиспользуют существующие сторCellи виджеты контролов.pickFeatured/mergeReadbacks— чистые функции, юнит-тесты лежат рядом с кодом.daliHostCapabilities): контролы, осмысленные только на контроллере («Сохранить в syslog»), закрыты флагами, которые встраивающий хост очищает до первого рендера; подмена вкладки шлюза для WASM делается модульной подстановкой на этапе сборки. Копирование топика по клику — тоже за политикой, для хостов без брокера.TabToolbarпубликует измеренную высоту, чтобы липкая полоса вставала вплотную при любом переносе строк; неудачныйGetGroupпоказывает Retry вместо пустой вкладки;GroupStore.controlsMqttIdвладеет формулой id виртуального устройства группы.Проверено
На реальном железе через автономный редактор (WB-DALI @17, светильники Skydance DT8, датчик Tridonic MSensor): полосы на вкладках устройства, группы и шины; объединение уставок с показаниями вживую; баннер схемы, починивший 18 неверно сконфигурированных инстансов реального датчика; сворачивание строк в мониторе; bottom sheet на телефоне.
Тесты
npm test— 2506 тестов, включая новые сьюты: эвристики полосы, сворачивание строк ошибок, страж схемы, соответствие mqtt-id, формула id группы, контракт единственного переключенияCollapsiblePanel.tsc --noEmitчисто;npm run lintчисто для затронутых файлов. По ветке прошло ревью по 9 аспектам, включая правила проекта; все замечания исправлены в ветке.Связанные: wirenboard/wb-wasm-device-editor#96 (встраивающий хост), SOFT-7398.
Скриншоты
Интерфейс на русском, симулированная шина через автономный редактор (сняты e2e-ригом).
Вкладка шины: широковещательная полоса — яркость, цветовая температура, Выкл, максимальная яркость

Страница светильника: полоса с объединённым показанием «(0 %)» и форма идентификации DT6

Открытый монитор без единой включённой шины объясняет себя и предлагает включить мониторинг по кнопке

Живой монитор: DT8-запросы цвета и ShortPress от стороннего мастера с бейджем «сторонний ×3»

Телефон: полоса контролов складывается в bottom sheet
Точки встраивания для хоста. Флаги
daliHostCapabilitiesзакрывают то, что имеет смысл только на контроллере: переключатель «Сохранить в syslog» и видимость редактора MQTT-id. За политикой же копирование топика по клику — для хостов без брокера. ХелперsendCellValueUpdate— единственное написание команды записи контрола (/devices/<id>/controls/<ctl>/on, non-retained), общее для полосы контролов иDevicesStore. На контроллере всё это по умолчанию ведёт себя как раньше.🤖 Generated with Claude Code
https://claude.ai/code/session_01Q4sGCd4GhAUr3ySuYvAGFk