From 179316db5213dd08c665753bbabd4d99410a9f1f Mon Sep 17 00:00:00 2001 From: Matzman Date: Mon, 5 Oct 2026 22:21:34 +0200 Subject: [PATCH] Document iteration 1: settings file, HA Dashboard tab, new hooks README: settings file, --config, the new tab. ARCHITECTURE.md and CLAUDE.md: prepare() hook, app command-line options, app code layout, WebEngine notes, the moc raw-string pitfall. THIRD_PARTY_NOTICES: Qt WebEngine. Ship config.example.json; the package README explains the set-up. PROGRESS.md and DESIGN.md: phase 3 results and deviations. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 42 +++++++++++++++++----- README.md | 68 ++++++++++++++++++++++++++++------- THIRD_PARTY_NOTICES.md | 1 + docs/ARCHITECTURE.md | 33 +++++++++++------ docs/DESIGN.md | 10 +++--- docs/PROGRESS.md | 26 ++++++++++++-- resources/CMakeLists.txt | 4 +++ resources/config.example.json | 20 +++++++++++ scripts/package-release.sh | 8 +++++ 9 files changed, 175 insertions(+), 37 deletions(-) create mode 100644 resources/config.example.json diff --git a/CLAUDE.md b/CLAUDE.md index 5ccb06d..afbd3b5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co **FrameAssistant**, "Steam Frame companion for Home Assistant" (in the spirit of HASS.Agent): it reports headset/environment sensors to Home Assistant, offers services Home Assistant can call (e.g. notifications in the headset), and shows a Home Assistant dashboard as a SteamVR -dashboard tab. Status: the overlay platform works; the Home Assistant parts are being planned. +dashboard tab. Status: the overlay platform works; the Home Assistant parts are being built +(implementation iteration 1: settings file and the "HA Dashboard" web UI tab). **Start every session by reading `docs/PROGRESS.md`** (current state, next steps, log). @@ -60,7 +61,7 @@ cmake --preset native-debug && cmake --build --preset native-debug # system Qt ctest --preset native-debug # all tests build/native-debug/bin/tst_inputbridge clickUsesGlCoordinates # one QtTest function build/native-debug/bin/frame-assistant --desktop # UI preview in a window, no SteamVR -build/native-debug/bin/frame-assistant --snapshot x.png # one frame via the real offscreen path +build/native-debug/bin/frame-assistant --snapshot x.png # x-0.png (main tab), x-dashboard.png scripts/container-build.sh cross # x86_64 → aarch64 against the Frame's system Qt (default) scripts/container-build.sh native # same for the host arch (use on the Frame) scripts/container-build.sh cross-bundle # fallback: self-contained, Qt bundled (also native-bundle) @@ -70,7 +71,11 @@ VK_DRIVER=lvp scripts/container-test.sh # same on lavapipe (software Vulkan) build/native-debug/bin/frame-assistant --graphics-api vulkan --benchmark 600 # frame ms incl. GPU ``` -- Use `--snapshot` and then read the PNG to check UI or rendering changes without a headset. +- Use `--snapshot` and then read the PNGs to check UI or rendering changes without a headset. + With several surfaces it writes `-.png` per surface (`-0` for the main tab's + empty id). Snapshot and benchmark don't load the settings, so the "HA Dashboard" tab shows + its "no URL" hint there. +- Overlay and desktop mode need a settings file; pass a test one with `--config `. - `tst_render` runs once per backend (`VRDASH_TEST_API`, separate CTest entries, because the Qt graphics API is process-global). It QSKIPs without a GPU context or when Vulkan isn't compiled in. @@ -106,11 +111,14 @@ into Qt events. modes (overlay, `--desktop`, `--snapshot`, `--benchmark`, manifest install). - **Inheritance for the app, components for the surfaces** (the user's decision, after trying composition): the app derives from `DashboardApplication`. In its constructor it - configures (`addSurface`, optional `setAppKey`/`setDisplayName`) and it - overrides the hooks `loading()` (backends + shared engine exist, QML not loaded) and - `started()` (everything runs). In the hooks, protected accessors give the running state: - `mode()`, `appKey()`, `appName()`, `engine()`, `surfaces()`, `surface()` (primary), - `surface(id)`, `vrRuntime()`, `navigation()`. The app is `src/Dashboard.h/.cpp`. + configures (`addSurface`, optional `setAppKey`/`setDisplayName`) and passes its own + command-line options (`QCommandLineOption` list) to the base constructor. It overrides + the hooks `prepare(QString*)` (first; mode and app key known, no engine/surfaces/SteamVR + yet; returning false ends `exec()` with exit code 1), `loading()` (backends + shared + engine exist, QML not loaded) and `started()` (everything runs). In the hooks, protected + accessors give the running state: `mode()`, `appKey()`, `appName()`, `isOptionSet()`, + `optionValue()`, `engine()`, `surfaces()`, `surface()` (primary), `surface(id)`, + `vrRuntime()`, `navigation()`. The app is `src/Dashboard.h/.cpp`. - The base constructor creates the `QGuiApplication` (`QCoreApplication` for manifest commands), so derived members can be QObjects with timers. - All QML and surfaces are torn down **at the end of `exec()`**, while the derived object @@ -188,6 +196,22 @@ into Qt events. - **QML singletons owned by the app:** keep them as members of the app class. A singleton must not be default-constructible, or QML builds its own instance instead of calling `create()` (e.g. give the constructor a required `QObject* parent` and init it `{nullptr}`). +- **App code layout:** logic without SteamVR or rendering goes into the static library + `frameassistant_lib` (`src/config/`, …), which the app and its tests link. QML types + (`QML_ELEMENT`, e.g. `src/ha/HaWebUi`) go into `QML_SOURCES` of `vrdash_add_dashboard()`: + they must be part of the QML module. The generated type registration includes their + headers by file name only, so their directory is on the app's include path. +- **Settings** (`src/config/Config`) are loaded once in `Dashboard::prepare()` (overlay and + desktop mode) and passed on as an immutable value (DESIGN.md, D19). +- **Qt WebEngine** ("HA Dashboard" tab): `QtWebEngineQuick::initialize()` runs in `main()` + before the app object, because it must precede the `QGuiApplication`. `HaWebUi` creates a + persistent profile under `~/.local/share/frameassistant/webengine` with the Qt 6.8 API + (setters on `QQuickWebEngineProfile`). Qt ≥ 6.9 logs a hint to use + `WebEngineProfilePrototype` instead, which the Frame's Qt 6.8 doesn't have. +- **moc and raw string literals:** a raw string containing `//` (e.g. a URL) makes moc treat + the rest as a comment; it then misses `Q_OBJECT` classes in that file (link error "vtable + for …"). In moc'ed files, write such text as normal string literals (`tst_config` uses + JSON with `'` quotes and converts them). - Publish per-frame values (frame stats etc.) to QML at most about once per second. Binding per-frame values in QML re-triggers the on-demand renderer forever. - **The executable is `frame-assistant` (`VRDASH_EXECUTABLE_NAME`), never `vrdashboard`.** @@ -307,3 +331,5 @@ Check these when testing on the device, and update this list: - The restructured app code (base class `DashboardApplication`, `Surface`, `Overlay` base, active-surface navigation) has only been tested off the device so far. - Several dashboard tabs from one process (works in `tst_surfaces`, not tried in SteamVR). +- Qt WebEngine in the off-screen renderer (Vulkan and OpenGL), the SteamVR keyboard in web + page input fields, and the persistent login ("HA Dashboard" tab, DSH-1). diff --git a/README.md b/README.md index afde8a5..97c5386 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ the headset to Home Assistant in both directions: - **Services:** Home Assistant can call it, e.g. to show notifications in the headset. - **Dashboard:** a SteamVR dashboard tab to view and control Home Assistant from inside VR. -> **Status:** early development. The overlay platform works on the Frame; the Home Assistant -> parts are being planned; see [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md), +> **Status:** early development. The overlay platform works on the Frame. The Home Assistant +> parts are being built: so far a settings file and an "HA Dashboard" tab with Home +> Assistant's web UI. See [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md), > [docs/DESIGN.md](docs/DESIGN.md) and [docs/PROGRESS.md](docs/PROGRESS.md). ### Platform @@ -33,8 +34,8 @@ FrameAssistant grew out of a SteamVR dashboard-overlay template, which it still ## Quick start Requirements: -- CMake ≥ 3.22, Ninja, a C++20 compiler, and Qt ≥ 6.5 (Quick, QuickControls2, OpenGL; - Test for the tests) +- CMake ≥ 3.22, Ninja, a C++20 compiler, and Qt ≥ 6.5 (Quick, QuickControls2, OpenGL, + WebEngineQuick; Test for the tests) - Vulkan headers (optional; without them the build is OpenGL only) - Docker or Podman, for the Frame builds @@ -45,12 +46,14 @@ The OpenVR SDK files are downloaded automatically when CMake configures the buil cmake --preset native-debug && cmake --build --preset native-debug ctest --preset native-debug -build/native-debug/bin/frame-assistant --desktop # UI in a window, no SteamVR -build/native-debug/bin/frame-assistant --snapshot out.png # one frame through the VR path +build/native-debug/bin/frame-assistant --desktop # UI in windows, no SteamVR +build/native-debug/bin/frame-assistant --snapshot out.png # one frame per tab through the VR path build/native-debug/bin/frame-assistant # as dashboard tab (SteamVR running) build/native-debug/bin/frame-assistant --install-manifest # register + auto-start with SteamVR ``` +Overlay and desktop mode need a settings file (below); `--snapshot` and `--benchmark` don't. + On the Steam Frame: ```sh @@ -60,6 +63,41 @@ scripts/deploy-to-frame.sh @ # copy over SSH and install (SteamVR Details are in [docs/STEAM-FRAME.md](docs/STEAM-FRAME.md). +## Settings + +FrameAssistant reads its settings from `~/.config/frameassistant/config.json` +(`$XDG_CONFIG_HOME` is respected; `--config ` picks another file). Start from +[`resources/config.example.json`](resources/config.example.json), which packages ship as +`share/frameassistant/config.example.json`: + +```json +{ + "device": { "name": "Steam Frame" }, + "mqtt": { "host": "homeassistant.local", "username": "frameassistant", "password": "…" }, + "homeassistant": { "url": "http://homeassistant.local:8123" } +} +``` + +| Key | Required | Default | Meaning | +|-----|----------|---------|---------| +| `device.name` | yes | | Name of this headset in Home Assistant | +| `device.ha_unique_id` | no | derived from the name | Fixed id, so the name can change without creating a new device | +| `mqtt.host` | yes | | MQTT broker | +| `mqtt.port` | no | 1883, 8883 with TLS | | +| `mqtt.username`, `mqtt.password` | no | no login | | +| `mqtt.tls.enabled` | no | `false` | | +| `mqtt.tls.ca_file` | no | system certificates | CA of the broker's certificate | +| `mqtt.tls.cert_file`, `mqtt.tls.key_file` | no | | Client certificate | +| `homeassistant.discovery_prefix` | no | `homeassistant` | | +| `homeassistant.url` | no | | Home Assistant web UI for the "HA Dashboard" tab | +| `notifications.timeout_s` | no | 10 | How long notifications stay | + +Invalid or missing settings stop the app with an error message and exit code 1. Unknown keys +only produce a warning. Keep the file private (`chmod 600`) when it holds a password. + +The "HA Dashboard" tab keeps the Home Assistant login in +`~/.local/share/frameassistant/webengine`. + ## Development - **App identity** (app key `net.matzman.frameassistant`, tab name, executable name @@ -68,8 +106,10 @@ Details are in [docs/STEAM-FRAME.md](docs/STEAM-FRAME.md). - **UI:** `src/qml/`, with `Main.qml` as the root. List new QML files under `QML_FILES` in `vrdash_add_dashboard()` in `src/CMakeLists.txt`. Iterate with `--desktop` and `--snapshot`. - **C++ logic:** the app class `src/Dashboard.h/.cpp` derives from `DashboardApplication`. - It adds views in its constructor (`addSurface()`), keeps its objects as members and wires - them up in the `loading()`/`started()` overrides. + It adds views in its constructor (`addSurface()`) and its own command-line options, + keeps its objects as members, loads the settings in `prepare()` and wires things up in + the `loading()`/`started()` overrides. Logic without SteamVR or rendering goes into the + static library `frameassistant_lib` (e.g. `src/config/`), which the tests link. - **Controller buttons:** actions and default bindings are in `resources/input/`. - **Ship it:** `scripts/package-release.sh` and `scripts/deploy-to-frame.sh`, see [docs/STEAM-FRAME.md](docs/STEAM-FRAME.md). @@ -84,6 +124,7 @@ How the pieces fit together: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). |--------|---------| | *(none)* | Run as SteamVR dashboard overlay (SteamVR must be running) | | `--desktop` | Show the UI in desktop windows, one per surface; no SteamVR | +| `--config ` | Settings file (default `~/.config/frameassistant/config.json`) | | `--snapshot ` | Render one frame per surface off-screen and save it (`-.png` with several surfaces) | | `--benchmark ` | Render frames back to back with a full GPU wait each and print frame times | | `--graphics-api vulkan\|opengl` | Render backend. Default: Vulkan, falling back to OpenGL if Vulkan doesn't start; an explicit choice never falls back | @@ -107,17 +148,20 @@ VK_DRIVER=lvp scripts/container-test.sh # same on the lavapipe software driver | Path | Content | |------|---------| | `src/main.cpp`, `src/Dashboard.*`, `src/qml/` | **The app** | +| `src/config/` | Settings file (`frameassistant_lib`) | +| `src/ha/` | Home Assistant parts: `HaWebUi` (web UI tab) | | `src/app/` | `DashboardApplication` (app base class), `Surface` (one view) | | `src/render/` | Off-screen Qt Quick renderer; Vulkan and OpenGL backends | | `src/vr/` | SteamVR connection, overlays (dashboard tab) | | `src/input/` | Laser/scroll/keyboard → Qt events; SteamVR Input navigation | -| `resources/` | SteamVR manifest template, input actions and bindings | +| `resources/` | SteamVR manifest template, input actions and bindings, example settings | | `tests/` | Unit and render tests | | `cmake/` | `vrdash_add_dashboard()`, OpenVR download, Qt bundling, toolchain | | `docker/`, `scripts/` | Build containers; build, package, deploy and test scripts | -| `docs/` | Requirements, progress, architecture, Steam Frame notes | +| `docs/` | Requirements, design, progress, architecture, Steam Frame notes | ## License -MIT, see [LICENSE](LICENSE). Third-party components (OpenVR SDK, Qt; in bundled builds also -their dependencies) are listed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). +MIT, see [LICENSE](LICENSE). Third-party components (OpenVR SDK, Qt incl. Qt WebEngine; in +bundled builds also their dependencies) are listed in +[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index a25d79f..0a21361 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -7,6 +7,7 @@ This project is MIT-licensed (see `LICENSE`). `` below is the CMake pro |-----------|---------|----------------| | [OpenVR SDK](https://github.com/ValveSoftware/openvr) (`libopenvr_api.so`, `openvr.h`) | BSD-3-Clause | Shipped in `lib/`; license in `share/doc//third-party/openvr.LICENSE` | | [Qt 6](https://www.qt.io/) (Core, Gui, Qml, Quick, Quick Controls, Wayland/XCB plugins) | LGPL-3.0 (Qt open-source license) | Linked dynamically. Default builds use the system's Qt (not shipped). Bundled builds ship Qt's shared libraries unmodified in `lib/`, `plugins/`, `qml/`: replace them to use another compatible Qt build | +| [Qt WebEngine](https://doc.qt.io/qt-6/qtwebengine-index.html) (Quick), for the "HA Dashboard" tab | LGPL-3.0; contains Chromium (BSD-3-Clause and further licenses, listed by Qt WebEngine) | Linked dynamically, from the system's Qt; not shipped. Bundled builds don't support it yet | **Bundled builds** (`--bundle-qt`) also ship further shared libraries that Qt depends on, taken unmodified from Debian. Their copyright and license files are in diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 92ffe83..9225ca6 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -37,13 +37,19 @@ the order in which all of that is created and destroyed. Your app derives from it: - **Constructor:** configuration (`addSurface()`, optionally `setAppKey()`, - `setDisplayName()`, `setQuickStyle()`, `setQmlModule()`). + `setDisplayName()`, `setQuickStyle()`, `setQmlModule()`). The app's own command-line + options go to the base constructor as a list of `QCommandLineOption`s; they are parsed and + listed in `--help` with the built-in ones, and read with `isOptionSet()`/`optionValue()`. - **Hooks:** + - `prepare(QString* error)`: first, once mode and app key are known, before the QML + engine, the surfaces and SteamVR exist (not for manifest commands). Returning `false` + ends `exec()` with the error and exit code 1, e.g. for invalid settings. - `loading()`: the shared QML engine, the surfaces and their render backends exist; QML isn't loaded yet. Set up what the QML needs here. - `started()`: everything runs. Connect to surfaces and input here. -- **Accessors:** `mode()`, `appKey()`, `appName()`, `engine()`, `surfaces()`, `surface()` - (the first), `surface(id)`, `vrRuntime()`, `navigation()`. +- **Accessors:** `mode()`, `appKey()`, `appName()`, `isOptionSet()`, `optionValue()`, + `engine()`, `surfaces()`, `surface()` (the first), `surface(id)`, `vrRuntime()`, + `navigation()`. - **Lifetime:** the base constructor creates the `QGuiApplication`, so your members can be QObjects with timers. All QML and surfaces are torn down at the end of `exec()`, while your object and its members still exist. @@ -121,15 +127,16 @@ sequenceDiagram ## Start and shutdown (overlay mode) 1. **Start:** - 1. Connect to SteamVR (`VR_Init`). - 2. Create one render backend per surface. The first surface decides the API, including a + 1. Call `prepare()`; stop with exit code 1 if it fails. + 2. Connect to SteamVR (`VR_Init`). + 3. Create one render backend per surface. The first surface decides the API, including a fallback to OpenGL; the others use the same API, because Qt's graphics API is process-wide. - 3. Call `loading()`. - 4. Load each surface's QML. - 5. Create the overlays. - 6. Set up controller navigation. - 7. Call `started()`, then run the event loop. + 4. Call `loading()`. + 5. Load each surface's QML. + 6. Create the overlays. + 7. Set up controller navigation. + 8. Call `started()`, then run the event loop. 2. **Shutdown runs in reverse**, with one rule found on the Frame: **overlays first, then SteamVR, then the graphics devices.** OpenVR requires shutting down before the devices it got textures from are destroyed. Otherwise its client library frees objects on a dead @@ -160,3 +167,9 @@ For e.g. a notification app: a `WorldOverlay` (another `Overlay` subclass, creat (`VROverlayFlags_MakeOverlaysInteractiveIfVisible`). The surface structure is ready for it: `SurfaceConfig` would gain a kind and a placement. + +## FrameAssistant on top + +The app itself (`src/Dashboard.*`, `src/config/`, `src/ha/`, `src/qml/`) builds on this +platform; its design (Home Assistant connection, entities, overlays, threads) is in +[DESIGN.md](DESIGN.md). diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 19ee4e8..c6f6e3d 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -150,7 +150,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). | ✓ (DSH-1) | +| **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) | | **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. | ✓ | @@ -314,10 +314,12 @@ Layout follows common practice (e.g. Zigbee2MQTT's `…//set`); one topi code ≠ 0 (CFG-2, via the start-up hook D21). - Unknown keys: a warning in the log, no abort (catches typos without breaking across versions). -- Password in plain text: warn if the file is readable by others; otherwise file permissions - (`chmod 600`). +- Password in plain text: warn if the file holds a password and is readable by others; + otherwise file permissions (`chmod 600`). (Implemented this way: a readable file without a + password is harmless.) - Throttle intervals (SEN-14) are fixed per entity in the code for the MVP. -- A `config.example.json` ships in the package. +- A `config.example.json` ships in the package (`share/frameassistant/`); the package's + README.txt explains how to set it up. - To check on the Frame when TLS is implemented: where the system certificates are (`/etc/ssl/certs`?), for the `ca_file` default. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 48674f7..1bebcb1 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -5,9 +5,12 @@ CLAUDE.md ("Working rules"). ## Current state -- **Implementation iteration 1 (DSH-1 and configuration), phase 3 (implementation).** - Requirements (D13) and design ([DESIGN.md](DESIGN.md)) are approved; the plan below was - approved on 2026-10-05. +- **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). +- **Open point found:** started by SteamVR, the app writes no log file (the manifest passes no + `--log-file`, stderr goes to SteamVR). CFG-2 wants the settings error "in the log file and + on stderr". To be decided. ## Next steps @@ -77,6 +80,23 @@ 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. +- Phase 3 of implementation iteration 1: + - Platform: `prepare()` hook and app-specific command-line options, tested in + `tst_surfaces` (incl. `surfaces_prepare_fail`). + - Settings file (`src/config/`, new library `frameassistant_lib`), `--config`; `tst_config` + (37 cases). `config.example.json` in the package; README.txt explains the set-up. + - "HA Dashboard" tab: `WebEngineView`, `HaWebUi` with a persistent profile, WebEngine + initialisation in `main()`. Host: desktop mode loads a local test page, profile data + lands in `~/.local/share/frameassistant/webengine`; snapshot renders both tabs. + - Build containers with Qt WebEngine. Cross build: the aarch64 binary needs no private Qt + symbols, at most `Qt_6.8` and `GLIBC_2.34`. Container tests 8/8 (incl. Vulkan with + validation layers, no messages). + - Snags: moc misses classes in files with raw strings containing `//` (CLAUDE.md); + generated QML type registration includes headers by file name; Qt ≥ 6.9 hints at + `WebEngineProfilePrototype` (not in the Frame's 6.8). Deviations: `HaWebUi` lives in the + app, not the library; the password warning needs a password in the file. + - Not verified yet: WebEngine with a URL in the off-screen pipeline (Frame, phase 4); the + bundled package (not supported for WebEngine in this iteration). - Plan for implementation iteration 1 approved; phase 3 started. - Plan for implementation iteration 1 written; new tab "HA Dashboard" (D38, D39). - MVP implemented in four iterations; DSH-1 first, at the user's wish (D37). diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index f4f3bd1..a83b745 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -20,3 +20,7 @@ endforeach() install(FILES ${_share}/manifest.vrmanifest DESTINATION ${VRDASH_SHARE_SUBDIR}) install(FILES ${_input_files} DESTINATION ${VRDASH_SHARE_SUBDIR}/input) + +# Example settings file (copy to ~/.config/frameassistant/config.json and edit). +configure_file(config.example.json ${_share}/config.example.json COPYONLY) +install(FILES config.example.json DESTINATION ${VRDASH_SHARE_SUBDIR}) diff --git a/resources/config.example.json b/resources/config.example.json new file mode 100644 index 0000000..6b49033 --- /dev/null +++ b/resources/config.example.json @@ -0,0 +1,20 @@ +{ + "device": { + "name": "Steam Frame" + }, + "mqtt": { + "host": "homeassistant.local", + "port": 1883, + "username": "frameassistant", + "password": "change-me", + "tls": { + "enabled": false + } + }, + "homeassistant": { + "url": "http://homeassistant.local:8123" + }, + "notifications": { + "timeout_s": 10 + } +} diff --git a/scripts/package-release.sh b/scripts/package-release.sh index 2cdd9c0..1270c78 100755 --- a/scripts/package-release.sh +++ b/scripts/package-release.sh @@ -81,6 +81,14 @@ chmod +x "$out/install.sh" "$out/uninstall.sh" echo "SteamOS update, use the -bundled package instead." fi echo + echo "Settings (required before the first start):" + echo " mkdir -p ~/.config/$project" + echo " cp share/$project/config.example.json ~/.config/$project/config.json" + echo " chmod 600 ~/.config/$project/config.json" + echo " then edit it (device name, MQTT broker, Home Assistant URL)." + echo " Without valid settings the app exits; to see why, run" + echo " ./bin/$exe --desktop in a terminal." + echo echo "Install / update: ./install.sh (SteamVR must be running)" echo " SteamVR remembers this folder's location: after moving it," echo " run ./install.sh again."