matzmanandClaude Opus 5.5 6cb30913ca Check shipped libraries against the Frame; keep OpenSSL out of the bundle (iteration 2, step 7)
package-release.sh refuses a package whose ELF files need newer glibc or
OpenSSL symbol versions than the Frame has (D35); only the version needs
section counts. The Qt bundler resolved libmosquitto's dependencies and
shipped Debian's OpenSSL 3.5; libssl/libcrypto are now excluded, since
SteamOS provides OpenSSL 3. Phase 3 of iteration 2 is done; PROGRESS.md
has the manual checklist for phase 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:37:12 +02:00

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.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 --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 (needs ca_file)
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); the mosquitto broker for the MQTT integration tests. The containers (docker/) have everything.
  • 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 (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
--ha-remove Remove this device from Home Assistant (clears its retained MQTT topics; needs the settings and the broker) and exit; uninstall.sh calls it. Works over SSH
--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.

S
Description
No description provided
Readme MIT
235 KiB
Languages
C++ 81.6%
CMake 11.2%
Shell 4.2%
QML 1.9%
Dockerfile 0.9%
Other 0.2%