# FrameAssistant **Steam Frame companion for Home Assistant.** FrameAssistant runs on the Steam Frame (and on x86_64 Linux PCs with SteamVR). It connects the headset to Home Assistant in both directions: - **Sensors:** it reports the state of the headset and its surroundings to Home Assistant. - **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), > [docs/DESIGN.md](docs/DESIGN.md) and [docs/PROGRESS.md](docs/PROGRESS.md). ### Platform FrameAssistant grew out of a SteamVR dashboard-overlay template, which it still builds on: - **Plain QML UI:** rendered off-screen and shown as a SteamVR dashboard tab. Users can float or pin the tab anywhere, and it stays visible in games. - **Input:** SteamVR's laser (as mouse), thumbstick scrolling, the SteamVR keyboard (opens for text fields), and D-pad/button navigation via rebindable SteamVR Input actions. - **Vulkan** by default, with **OpenGL** as an automatic fallback. On the Frame, Vulkan is about 1.9× faster, since OpenGL runs through zink there. - **Several views per app** ("surfaces"), e.g. several dashboard tabs sharing one QML engine and its data. - **Develop without a headset:** desktop preview window, offscreen snapshots, benchmark. - **Frame packages** of about 3 MB, using SteamOS's own Qt; a self-contained variant with Qt bundled is also available. Packages come with `install.sh`/`uninstall.sh` and a deploy script. ## Quick start Requirements: - CMake ≥ 3.22, Ninja, a C++20 compiler, and Qt ≥ 6.5 (Quick, QuickControls2, OpenGL; Test for the tests) - Vulkan headers (optional; without them the build is OpenGL only) - Docker or Podman, for the Frame builds The OpenVR SDK files are downloaded automatically when CMake configures the build (`-DOPENVR_ROOT=` to build offline). ```sh 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 # as dashboard tab (SteamVR running) build/native-debug/bin/frame-assistant --install-manifest # register + auto-start with SteamVR ``` On the Steam Frame: ```sh scripts/package-release.sh # → dist/frame-assistant-0.1.0-linux-arm64.tar.gz scripts/deploy-to-frame.sh @ # copy over SSH and install (SteamVR must run) ``` Details are in [docs/STEAM-FRAME.md](docs/STEAM-FRAME.md). ## Development - **App identity** (app key `net.matzman.frameassistant`, tab name, executable name `frame-assistant`, texture size) is set in the root `CMakeLists.txt`. The executable must not be named like a SteamVR process such as `vrdashboard` (CMake checks this). - **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. - **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). How the pieces fit together: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). ## Command line `frame-assistant` understands: | Option | Meaning | |--------|---------| | *(none)* | Run as SteamVR dashboard overlay (SteamVR must be running) | | `--desktop` | Show the UI in desktop windows, one per surface; no SteamVR | | `--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 | | `--app-key `, `--app-name ` | Override app key and name, e.g. to run a second instance | | `--max-fps ` | Frame-rate cap (default 60); rendering only happens on change | | `--install-manifest [--launch]` | Register with SteamVR (auto-start) and optionally start it now; works over SSH | | `--uninstall-manifest` | Unregister | | `--manifest ` | Manifest for the two options above (default: the app's own) | | `--log-file ` | Also log to a file (relative paths: relative to the install folder) | ## Testing ```sh ctest --preset native-debug # unit + render tests (GPU tests skip without a GPU context) scripts/container-test.sh # all tests in Debian incl. Vulkan with validation layers VK_DRIVER=lvp scripts/container-test.sh # same on the lavapipe software driver ``` ## Repository layout | Path | Content | |------|---------| | `src/main.cpp`, `src/Dashboard.*`, `src/qml/` | **The app** | | `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 | | `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 | ## 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).