Dashboard creates the MQTT client and the HA device with the dummy "Uptime" sensor (D41) in overlay and both desktop modes, connects in started() and disconnects gracefully on aboutToQuit. The new platform mode --desktop-novr behaves like --desktop for now (D22). The main tab shows device, broker, connection state and last error (UI-1) through the ConnectionStatus QML singleton. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.8 KiB
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 and the MQTT connection (the device appears in Home Assistant with a test sensor, "Uptime"; the tab shows the connection status). 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.shand 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 --desktop-novr # same; never uses 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 both desktop modes need a settings file (below) and connect to the MQTT broker;
--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
- Host build dependencies: Qt 6 (≥ 6.5) and libmosquitto with its pkg-config file
(Arch:
mosquitto, Debian:libmosquitto-dev); themosquittobroker for the MQTT integration tests. The containers (docker/) have everything. - App identity (app key
net.matzman.frameassistant, tab name, executable nameframe-assistant, texture size) is set in the rootCMakeLists.txt. The executable must not be named like a SteamVR process such asvrdashboard(CMake checks this). - UI:
src/qml/, withMain.qmlas the root. List new QML files underQML_FILESinvrdash_add_dashboard()insrc/CMakeLists.txt. Iterate with--desktopand--snapshot. - C++ logic: the app class
src/Dashboard.h/.cppderives fromDashboardApplication. It adds views in its constructor (addSurface()) and its own command-line options, keeps its objects as members, loads the settings inprepare()and wires things up in theloading()/started()overrides. Logic without SteamVR or rendering goes into the static libraryframeassistant_lib(e.g.src/config/), which the tests link. - Controller buttons: actions and default bindings are in
resources/input/. - Ship it:
scripts/package-release.shandscripts/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 (from iteration 3: uses SteamVR if it runs) |
--desktop-novr |
Like --desktop, but never connects to SteamVR (e.g. on a PC, with its own --config) |
--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, MQTT and render tests (GPU tests skip without a GPU
# context, MQTT tests without the mosquitto broker)
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/, src/mqtt/, src/ha/ |
Settings file, MQTT client, HA device and entities (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.