Battery monitoring for the Steam Controller 2 ("Triton") on Linux: a daemon that reads battery telemetry straight from the controller's HID reports, and a COSMIC panel applet that displays it.
Supports all three transports: the puck dongle, direct USB, and Bluetooth LE.
The kernel's hid-steam driver doesn't (yet) support the SC2 family, so
nothing shows up in UPower — this fills the gap in userspace.
daemon/— steambatteryd: discovers SC2 devices (wired28de:1302, Bluetooth28de:1303, puck dongle28de:1304) via udev, reads battery reports from hidraw, and publishes state on the session D-Bus.applet/— cosmic-applet-steambattery: panel icon + percentage, with a popup showing charge state, voltages, currents, and temperature.interface/— steambattery-interface: the shared D-Bus contract (constants,ChargeState, andzbusclient proxies for third parties).
The controller pushes input report 0x43 (TritonBatteryStatus_t, from
SDL3's controller_structs.h) roughly every 2.5 s while awake — no query
needed. Units were calibrated against live hardware: voltages in mV, currents
in mA, temperature in milli-°C. The controller-state stream (0x42, or 0x45
over Bluetooth; ~266 Hz) doubles as a liveness signal; 10 s of silence marks
the controller asleep/disconnected.
Protocol research: CouchTurtle/sc2-research and the SDL3 Triton driver.
# flake inputs
inputs.steambattery.url = "github:eva-val/steambattery";
# NixOS configuration
imports = [ inputs.steambattery.nixosModules.default ];
hardware.steambattery.enable = true;The module installs:
- a udev rule granting local users access to SC2 hidraw nodes (via the
usersgroup plusuaccess), - a systemd user service running
steambatteryd, - the applet package with its desktop entry.
Then add the applet: COSMIC Settings → Desktop → Panel → Configure panel applets → Add applet → "Steam Controller Battery".
Session bus name io.github.steambattery.
/io/github/steambattery—io.github.steambattery.DaemonDevices: ao— device object pathsVersion: s
/io/github/steambattery/devN—io.github.steambattery.DeviceName: s,Connected: bChargeState: y— SDL3EChargeState: 0 reset, 1 discharging, 2 charging, 3 charger-validate, 4 done (2 and 3 mean "charging")BatteryLevel: y— 0–100, 255 = no report yetBatteryVoltage,SystemVoltage,InputVoltage: q— mVCurrent,InputCurrent: q— mATemperature: q— milli-°CLastUpdated: t— unix seconds of the last published change, 0 = never (telemetry is deadbanded, so whileConnectedis true the data is live even if this is a little stale)
All properties emit PropertiesChanged. Quick check:
$ busctl --user get-property io.github.steambattery \
/io/github/steambattery/dev0 io.github.steambattery.Device BatteryLevel
y 100$ direnv allow # or: nix develop
$ cargo test
$ cargo run -p steambatteryd # needs hidraw access (udev rule)
$ cargo run -p cosmic-applet-steambattery # runs standalone as a windowGPL-3.0-or-later.
