Files
FrameAssistant/README.md
T
matzmanandClaude Opus 5.5 c5c176644a 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>
2026-10-05 23:04:24 +02:00

8.0 KiB
Raw Blame History

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 built: so far the settings file. See docs/REQUIREMENTS.md, docs/DESIGN.md and 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=<sdk> to build offline).

cmake --preset native-debug && cmake --build --preset native-debug
ctest --preset native-debug

build/native-debug/bin/frame-assistant --desktop            # UI in windows, 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

Overlay and desktop mode need a settings file (below); --snapshot and --benchmark don't.

On the Steam Frame:

scripts/package-release.sh                 # → dist/frame-assistant-0.1.0-linux-arm64.tar.gz
scripts/deploy-to-frame.sh <user>@<frame>  # copy over SSH and install (SteamVR must run)

Details are in docs/STEAM-FRAME.md.

Settings

FrameAssistant reads its settings from ~/.config/frameassistant/config.json ($XDG_CONFIG_HOME is respected; --config <path> picks another file). Start from resources/config.example.json, which packages ship as share/frameassistant/config.example.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's address; reserved for the dashboard, not used yet
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.

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()) 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.

How the pieces fit together: 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
--config <path> Settings file (default ~/.config/frameassistant/config.json)
--snapshot <png> Render one frame per surface off-screen and save it (<name>-<id>.png with several surfaces)
--benchmark <frames> 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 <key>, --app-name <name> Override app key and name, e.g. to run a second instance
--max-fps <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 <path> Manifest for the two options above (default: the app's own)
--log-file <path> Also log to a file (relative paths: relative to the install folder)

Testing

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/config/ Settings file (frameassistant_lib)
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, 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, design, progress, architecture, Steam Frame notes

License

MIT, see LICENSE. Third-party components (OpenVR SDK, Qt; in bundled builds also their dependencies) are listed in THIRD_PARTY_NOTICES.md.