Remove the HA Dashboard tab and the Qt WebEngine dependency (D40)

DSH-1 ended with a negative result: the Frame's system WebEngine can't be
loaded, and bundling our own failed (no sandbox, ICU resources, Vulkan
abort, empty page). Reverts the tab (60deb43), the container packages
(0676998) and the bundler's WebEngine support (b823ff3, e2cfa8e), and
updates the docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 23:04:24 +02:00
co-authored by Claude Opus 5.5
parent e2cfa8ea5b
commit c5c176644a
19 changed files with 59 additions and 278 deletions
+10 -13
View File
@@ -57,18 +57,15 @@ Three layers; dependencies only go downward (D17).
- **MQTT is the only channel for everything device-related:** entities, services, availability
(D24).
- MQTT can't show HA as a whole (other entities' states, service calls for them), which the
dashboard (DSH-1) needs. The dashboard gets **its own channel, separate from MQTT**:
- MQTT can't show HA as a whole (other entities' states, service calls for them), which a
dashboard needs. The dashboard gets **its own channel, separate from MQTT**:
- Q2a, HA web UI in Qt WebEngine: the browser talks to HA itself (HTTP/WebSocket, HA's own
login); config: HA URL.
login); config: HA URL. **Failed on the Frame (D40)**: the system WebEngine can't be
loaded, a bundled one didn't work (STEAM-FRAME.md).
- Q2b, native QML dashboard: HA's WebSocket API with a token (Q3) as another I/O component;
config: HA URL and token.
- Both fit the three layers. The MVP contains the web UI test (DSH-1, D28), which also serves
as the spike on WebEngine in the off-screen renderer; Q2/Q3 are decided for DSH-2.
- Known DSH-1 risks: WebEngine must be initialised before the `QGuiApplication` (created by the
platform's base constructor), so the platform needs a small change; WebEngine with our
off-screen renderer, especially Vulkan, is untested; text fields inside the page probably
don't open the SteamVR keyboard (fallback: log in once in a desktop mode).
- Both fit the three layers. The web UI test (DSH-1, D28) answered Q2a with "no"; Q2/Q3 are
decided for DSH-2, with the native dashboard as the candidate.
## Start-up and modes
@@ -102,7 +99,7 @@ Two overlay kinds in the platform (D25):
| Main tab "Frame Assistant" (UI-1, later NOT-7, do-not-disturb) | dashboard tab | always there; SteamVR shows/hides it | ✓ |
| Notifications | world overlay | the app (notification manager) shows/hides it | ✓ |
| Status tab (SRV-6) | dashboard tab | exists only while cards exist (D9) | ✗ |
| "HA Dashboard" (DSH-1, web UI test) | dashboard tab | always there | ✓ |
| HA dashboard (DSH-2) | dashboard tab | always there | ✗ (web UI test DSH-1 removed, D40) |
- **World overlays (MVP):** a new overlay kind next to the dashboard tab (CLAUDE.md, "Planned
extension"). The surface gets a kind and a placement; renders only while visible (NFR-3).
@@ -150,7 +147,7 @@ and signals across threads are delivered through the receiver's event loop.
| **I/O wrappers** | Data sources and actuators; know nothing about HA. One wrapper object per OpenVR interface used (e.g. `IVRSystem`, `IVRApplications`, `IVRChaperone`, `IVRSettings`). System wrappers (network, audio) later. | OpenVR ✓, system ✗ |
| **Overlays** | View and controller of MVC (QML), as dashboard tabs or world overlays. Get their data (the model) from other objects. | ✓ |
| **Managers** | One object per stateful feature that manages and coordinates it, using entities, services and overlays. Notification manager (MVP); status card manager (SRV-6/7) later. | notifications ✓ |
| **HA web UI** | Encapsulates Qt WebEngine for the dashboard tab (DSH-1; Q2 for DSH-2). `src/ha/HaWebUi`, a QML singleton in the app itself (not `frameassistant_lib`: QML types must be part of the QML module). | ✓ (DSH-1) |
| **HA web UI** | Was: Qt WebEngine for the dashboard tab (DSH-1). Dropped (D40); a native dashboard (DSH-2) would need its own object class. | ✗ |
| **Configuration** | Settings from the JSON file, loaded once by the app as an immutable value. Each component gets the part it needs through its constructor (D19). | ✓ |
| **App** | The managing object: owns all of the above as components and wires them together. | ✓ |
@@ -307,7 +304,7 @@ Layout follows common practice (e.g. Zigbee2MQTT's `…/<device>/set`); one topi
| `mqtt.tls.ca_file` | no | system certificates | own CA, e.g. a self-signed broker certificate |
| `mqtt.tls.cert_file` / `key_file` | no | none | client certificate, if the broker requires one |
| `homeassistant.discovery_prefix` | no | `homeassistant` | |
| `homeassistant.url` | for DSH-1 only | — | missing: the dashboard tab shows a hint instead of the web UI |
| `homeassistant.url` | no | — | reserved for the dashboard (DSH-2); not used yet (D40) |
| `notifications.timeout_s` | no | 10 | D33 |
- Errors (missing required values, invalid JSON, wrong types): exit with a message and exit
@@ -447,4 +444,4 @@ Collected 2026-10-05 for the notification design.
| D36 | 2026-10-05 | NFR-3 measured as own cost (CPU idle, frames while hidden, GPU per frame) plus an A/B comparison of the game's compositor statistics; manual in the MVP, a `--vr-stats` mode later | Measurable acceptance for NFR-3 without extra code in the MVP |
| D37 | 2026-10-05 | The MVP is implemented in four iterations: 1 DSH-1 + configuration, 2 MQTT/HA device/UI-1, 3 sensors, 4 notifications | Small iterations (working rules); DSH-1 first because the user wants to see it early and it doesn't depend on MQTT |
| D38 | 2026-10-05 | App-specific command-line options: the platform's base constructor takes an optional list of extra options, parses them with its own and exposes their values | The command line is parsed in the base constructor, before the derived app can contribute (`--config`); backward compatible, `--help` stays complete |
| D39 | 2026-10-05 | DSH-1: `QtWebEngineQuick::initialize()` in `main.cpp` (no platform change); a named, persistent WebEngine profile under `~/.local/share/frameassistant/`; tab name "HA Dashboard" | WebEngine must be initialised before the `QGuiApplication`; the HA login must survive restarts |
| D39 | 2026-10-05 | *Superseded by D40 (REQUIREMENTS.md): tab and WebEngine removed.* DSH-1: `QtWebEngineQuick::initialize()` in `main.cpp` (no platform change); a named, persistent WebEngine profile under `~/.local/share/frameassistant/`; tab name "HA Dashboard" | WebEngine must be initialised before the `QGuiApplication`; the HA login must survive restarts |
+12 -7
View File
@@ -5,12 +5,11 @@ CLAUDE.md ("Working rules").
## Current state
- **Implementation iteration 1 (DSH-1 and configuration), phase 3 (implementation) done,
waiting for the user's approval.** All plan steps are implemented and committed; next is
phase 4, testing on the Frame (plan item 10).
- Started by SteamVR, the app now logs to `logs/frame-assistant.log` in the install folder:
the manifest passes `--log-file` (CFG-2 wants the settings error in a log file). Whether
SteamVR on the Frame honours the manifest's `arguments` is checked in phase 4.
- **Implementation iteration 1, phase 4 (testing on the Frame).** DSH-1 is done with a
negative result: HA's web UI via Qt WebEngine doesn't work on the Frame, so the "HA
Dashboard" tab and the WebEngine dependency were removed (D40). What remains of iteration 1
(platform hooks, settings file, `--config`, log file for SteamVR-started instances) still
needs its test on the Frame with the system-Qt package.
## Next steps
@@ -19,7 +18,7 @@ Requirements and design cover the whole MVP; it is **implemented in four small i
| Iteration | Content | Platform change | Checked by |
|---|---|---|---|
| 1 | DSH-1: HA web UI (Qt WebEngine) in a dashboard tab; configuration (D34) with start-up hook and `--config` | start-up hook (D21), WebEngine initialisation before the `QGuiApplication` | HA web UI in the tab on the Frame; result documented |
| 1 | ~~DSH-1: HA web UI in a dashboard tab~~ (failed, removed: D40); configuration (D34) with start-up hook and `--config`; log file for SteamVR-started instances | start-up hook (D21), app command-line options (D38) | DSH-1 result documented; app starts on the Frame with the settings file, settings errors in the log |
| 2 | MQTT client (own thread), HA device with discovery and availability, libmosquitto in the package, status display UI-1 | modes (D22) | device appears in HA, online/offline right, reconnect works |
| 3 | OpenVR wrappers and the 13 sensor entities | `--desktop` with optional SteamVR (D22) | sensor values in HA on the Frame |
| 4 | notification manager, `notify` entity, world overlay | world overlay, premultiplied flag (D25) | notification from HA in VR, also in a game |
@@ -80,6 +79,12 @@ Known limitation: the bundled-Qt package does not support WebEngine in this iter
present (relevant for Q2/Q3).
- libmosquitto ABI check: Debian's 2.0.21 needs at most `OPENSSL_3.0.0`/`GLIBC_2.34`; the
Frame has OpenSSL 3.2.1 and glibc 2.39. No libcjson dependency. D14 holds.
- DSH-1 closed (D40): the bundling experiment failed (sandbox, ICU resources, Vulkan abort,
empty page with OpenGL and in a desktop window; details in STEAM-FRAME.md). At the user's
decision the "HA Dashboard" tab, `HaWebUi`, the WebEngine build dependency and the
bundler's WebEngine support were removed (reverts of the corresponding commits). Qt WebView
is no alternative (WebEngine backend on Linux). `homeassistant.url` stays reserved for
DSH-2, where a native dashboard is the candidate.
- Phase 4 (testing on the Frame), first findings:
- `deploy-to-frame.sh` exited silently without a bundled package in `dist/` (fixed).
- The system-Qt package doesn't start: the Frame's Qt WebEngine is 6.7.0 (rest of Qt 6.8.0)
+6 -5
View File
@@ -103,7 +103,7 @@ FrameAssistant.
| ID | Requirement | Prio | MVP | Acceptance criteria |
|----|-------------|------|-----|---------------------|
| DSH-1 | A dashboard tab shows HA's web UI (Qt WebEngine) at a configured URL, as a "does it work out of the box" test. | M | ✓ | The page loads in VR and can be operated with the laser; whatever doesn't work out of the box is documented and moved to a later iteration. |
| DSH-1 | A dashboard tab shows HA's web UI (Qt WebEngine) at a configured URL, as a "does it work out of the box" test. | M | ✓ | The page loads in VR and can be operated with the laser; whatever doesn't work out of the box is documented and moved to a later iteration. **Result (D40):** fails on the Frame; tab removed. |
| DSH-2 | The full dashboard to control HA entities in VR: everything beyond DSH-1, e.g. login comfort, opening a given HA view (SRV-4), possibly a native approach (Q2, Q3). | S | | Defined after design exploration. |
### Non-functional (NFR)
@@ -133,7 +133,7 @@ FrameAssistant.
| # | Question | Status |
|---|----------|--------|
| Q1 | Several notifications at once: stack, queue, replace by tag? | open, design exploration |
| Q2 | Dashboard: HA's own web UI vs. native VR UI? | open, design exploration (Qt WebEngine exists on the Frame, Appendix C) |
| Q2 | Dashboard: HA's own web UI vs. native VR UI? | open; HA's web UI via Qt WebEngine failed on the Frame (D40), so native is the candidate |
| Q3 | Dashboard data: HA WebSocket API (token) in addition to MQTT, or MQTT only? | open, design |
| Q4 | Which MQTT client library? Licence, availability on SteamOS, TLS/login support. | answered: libmosquitto, shipped in the package (D14, Appendix B) |
| Q5 | Status card: own tab or part of the main tab? | answered: own tab, on demand (D9) |
@@ -163,6 +163,7 @@ FrameAssistant.
| D15 | 2026-10-05 | HA MQTT discovery: **own small layer on Qt's JSON classes**, using device-based discovery (one `<prefix>/device/<id>/config` topic with all entities under `cmps`) | No suitable library (Appendix B); HA recommends device-based discovery for multi-entity devices (NFR-7) |
| D20 | 2026-10-05 | New requirement UI-1 (status display in the main tab), MVP | Helps testing on the device; little effort |
| D28 | 2026-10-05 | DSH-1 split: DSH-1 (MVP) = HA web UI in a tab as an out-of-the-box test; DSH-2 (Should) = the full dashboard. The MVP (D8) now also contains DSH-1 | The user wants to see early whether the simple variant works |
| D40 | 2026-10-05 | DSH-1 done with a negative result: HA's web UI via Qt WebEngine doesn't work on the Frame (system WebEngine not loadable; bundling our own failed). The "HA Dashboard" tab and the WebEngine dependency are removed; the MVP no longer contains a dashboard. `homeassistant.url` stays reserved for DSH-2 | The out-of-the-box test answered its question; a WebEngine dependency would keep the whole app from starting on the Frame |
Design decisions (D16 onward) are in [DESIGN.md](DESIGN.md).
@@ -273,7 +274,7 @@ use Qt's private API, which requires the exact Qt version.
| Sounds, audio from URL | NOT-4, SRV-8 | Qt Multimedia + QtNetwork | ✓ `libQt6Multimedia`, FFmpeg plugin | no |
| HTTPS (downloads, WebSocket) | SRV-8, Q3 | Qt TLS plugin | ✓ `libqopensslbackend.so` | no |
| Translations | NFR-4 | `QTranslator`, `lupdate`/`lrelease` | ✓ (build-time tools) | no |
| Dashboard, HA web UI | DSH-1, DSH-2, Q2 | Qt WebEngine (Quick) | **✗ present but not loadable**: 6.7.0 next to Qt 6.8.0, built against FFmpeg 6, which the Frame lacks (STEAM-FRAME.md) | yes, only bundled with all of Qt (experiment, see PROGRESS.md) |
| Dashboard, HA web UI | DSH-1, DSH-2, Q2 | Qt WebEngine (Quick); **dropped (D40)** | **✗ present but not loadable**: 6.7.0 next to Qt 6.8.0, built against FFmpeg 6, which the Frame lacks (STEAM-FRAME.md) | bundling it with all of Qt was tried and failed (STEAM-FRAME.md) |
| Dashboard, native UI | DSH-2, Q2/Q3 | HA WebSocket API via Qt WebSockets | ✓ `libQt6WebSockets` | no |
| Haptics, fade, apps | SRV-1/2 | OpenVR | ✓ | no |
| Tests | NFR-8 | QtTest | ✓ (host only) | no |
@@ -286,5 +287,5 @@ Also present and possibly useful later: `libQt6TextToSpeech`, Qt's `networkinfor
Open points:
- The Debian build container needs the matching `-dev` packages (amd64 and arm64) for every
module used. Not checked yet.
- WebEngine and Multimedia come with SteamOS's desktop (KDE) packages; a SteamOS update could
remove them.
- Multimedia comes with SteamOS's desktop (KDE) packages; a SteamOS update could remove it.
(WebEngine likewise, but it isn't usable anyway, D40.)
+9 -1
View File
@@ -70,7 +70,8 @@ Without the deploy script: copy the `.tar.gz`, unpack it on the Frame, run `./in
Checked 2026-10-05; details per requirement in [REQUIREMENTS.md](REQUIREMENTS.md), Appendix C.
- **System Qt 6.8.0** under `/usr/lib` includes, besides the base modules: DBus, Network,
Multimedia (FFmpeg plugin), WebSockets, WebEngine (Core, Quick), WebView, TextToSpeech,
Multimedia (FFmpeg plugin), WebSockets, WebEngine (Core, Quick; not loadable, see below),
WebView, TextToSpeech,
Positioning, Sensors, Svg, VirtualKeyboard. TLS plugins: `libqopensslbackend.so`,
`libqcertonlybackend.so`.
- It apparently comes with the KDE Plasma desktop mode (plugins for plasma, kwin, discover).
@@ -84,6 +85,13 @@ Checked 2026-10-05; details per requirement in [REQUIREMENTS.md](REQUIREMENTS.md
depend on it. A program linking WebEngine fails to start ("libavcodec.so.60: cannot open
shared object file"). Other Qt modules are 6.8.0 (`pacman -Q | grep qt6-`). Qt
Multimedia's FFmpeg plugin resolves all its libraries (`ldd`, no "not found").
- **Bundling our own Qt WebEngine failed** (experiment, 2026-10-05; Debian's Qt 6.8.2 incl.
WebEngine with its own FFmpeg, 141 MB package): the helper process (`QtWebEngineProcess`,
needs the executable bit) only starts without Chromium's sandbox (`--no-sandbox`); without
`QTWEBENGINE_RESOURCES_PATH` its child processes find no ICU data ("Invalid file descriptor
to ICU data"); with Vulkan the app aborts ("free(): invalid pointer"); with OpenGL the
dashboard tab stays empty; in a desktop window the page stays white and Chromium's
remote-debugging port never opens. FrameAssistant uses no web engine (D40).
- **Qt add-on modules must come from the system Qt.** Shipping one fails: they use Qt's private
API, and QtCore aborts on any version mismatch ("Cannot mix incompatible Qt library").
- **Not present:** any MQTT library (no `libmosquitto`, no Qt MQTT). FrameAssistant ships