No description
  • Python 96.2%
  • Shell 3.8%
Find a file
2026-06-25 15:45:26 +01:00
systemd cleanup example config and fix git urls 2026-06-25 03:17:57 +01:00
vendor Initial commit: steamdeck2mqtt 2026-06-25 00:01:56 +01:00
.gitignore Initial commit: steamdeck2mqtt 2026-06-25 00:01:56 +01:00
CLAUDE.md Add CLAUDE.md for future Claude Code instances 2026-06-25 13:45:50 +01:00
config.example.toml Rename entities to consistent prefixed IDs; refresh info on game-poll loop 2026-06-25 14:58:57 +01:00
install.sh Initial commit: steamdeck2mqtt 2026-06-25 00:01:56 +01:00
LICENSE Initial commit 2026-06-24 23:37:23 +01:00
README.md Tighten game-detection blurb: lead with streaming, mark emulator detection best-effort 2026-06-25 15:45:26 +01:00
steamdeck2mqtt.py Rename entities to consistent prefixed IDs; refresh info on game-poll loop 2026-06-25 14:58:57 +01:00

steamdeck2mqtt

A battery-efficient, event-driven bridge that pushes live Steam Deck status to Home Assistant over MQTT.

  • Survives SteamOS updates. It lives under $HOME and never touches the read-only rootfs, so there's no steamos-readonly disable to redo after each update (the thing that breaks go-hass-agent).
  • Easy on the battery. One mostly-idle main loop, driven by D-Bus and udev events instead of polling, so changes reach HA in about a second.
  • Knows what you're playing, everywhere. Detects the running game in Gaming and Desktop Mode, reports Steam Remote Play and Moonlight streams, and tells native from Proton. It also makes a best-effort attempt to pull the console and ROM out of emulator front-ends.

Documentation

Everything appears as one Home Assistant device, Steam Deck. The ID column is the MQTT object id; HA exposes it as e.g. sensor.steam_deck_battery. Whole groups can be toggled off in config.toml under [entities].

Battery & power

Live on change; power, temperatures, time remaining and the charge limit refresh every ~90 s.

Entity ID Type Notes
Battery battery sensor %
Battery charging battery_charging binary
AC power ac_power binary charger connected
Battery power battery_power sensor W charge/discharge magnitude
Battery state battery_state sensor charging, discharging, full, pending_charge, etc.
Battery temperature battery_temperature sensor °C
Battery charge limit battery_charge_limit sensor % 100 = no limit
Battery time to full battery_time_to_full sensor min while charging
Battery time to empty battery_time_to_empty sensor min while discharging

Dock & display

Live on change.

Entity ID Type Notes
External display external_display binary DP/HDMI connected
USB host usb_host binary dock or hub attached
Docked docked binary external display or USB host

There's no real "docked" bit on SteamOS, and a wall charger gives neither a display nor a USB host, so the raw signals are exposed separately. Build your own meaning in HA if you like.

Session

Suspended is instant; Wi-Fi values refresh every ~90 s.

Entity ID Type Notes
Suspended suspended binary
Wi-Fi SSID wifi_ssid sensor empty when not connected
Wi-Fi signal wifi_signal sensor dBm

Game

Instant in Gaming Mode; otherwise polled every 5 s on AC, 15 s on battery.

Entity ID Type Notes
Game game sensor running title, or emulated ROM; empty when no game
Game state game_state sensor (enum) in-game / steam-ui / none / desktop-mode
Gaming mode gaming_mode binary on in Gaming Mode, off in Desktop Mode
Game platform game_platform sensor Native / Proton / emulated (e.g. SNES) / Remote Play / Moonlight
Game App ID game_app_id sensor Steam AppID

The neat part is how far detection reaches. Anything launched through Steam shows up in both Gaming Mode and Desktop Mode, with the right Game platform attached: Native, Proton, the emulated console behind a front-end (like ES-DE or RetroArch) with Game showing the inner ROM, or Remote Play / Moonlight when you're streaming the Deck from another machine. Apps started outside Steam aren't tracked.

Library & downloads

Updates live during a download (installed games only).

Entity ID Type Notes
Games installed games_installed sensor across internal + SD
Updates queued updates_queued sensor
Downloading downloading binary
Downloading game downloading_game sensor
Download progress download_progress sensor %
Download paused download_paused binary

System

Re-checked every 5 s on AC, 15 s on battery, but only published when a value changes (mostly static, so usually nothing is sent).

Entity ID Type Notes
SteamOS version steamos_version sensor
Kernel version kernel_version sensor
Steam version steam_version sensor
BIOS version bios_version sensor
Model model sensor OLED or LCD
Uptime uptime sensor (timestamp) shown as relative in HA
Storage free / total / used storage_free / storage_total / storage_used sensor GB internal /home
SD Card sd_card binary card inserted
SD Card free / total / used sd_card_free / sd_card_total / sd_card_used sensor GB unknown when no card

Controls

Read-only; refreshed every 5 s on AC, 15 s on battery.

Entity ID Type Notes
Brightness brightness sensor %
Volume volume sensor %
Volume muted volume_muted binary
Microphone microphone sensor % level
Wi-Fi wifi binary radio on/off
Bluetooth bluetooth binary radio on/off
Airplane mode airplane_mode binary
Bluetooth devices bluetooth_devices sensor connected count
Bluetooth device names bluetooth_device_names sensor connected names

Performance

Refreshed every 5 s on AC, 15 s on battery.

Entity ID Type Notes
FPS fps sensor fps Gaming Mode only
GPU usage gpu_usage sensor %
GPU temperature gpu_temperature sensor °C
GPU power gpu_power sensor W
CPU usage cpu_usage sensor %
CPU temperature cpu_temperature sensor °C
RAM used ram_used sensor %
Fan speed fan_speed sensor rpm

Use cases

A few automations these entities make easy:

  • Cinema mode for the couch. When Game becomes non-empty while Docked is on, dim the room lights and flip the TV to the Deck's input, then bring them back when the game closes.
  • Battery care. Cut a charging smart plug when Battery reaches your Battery charge limit, or ping your phone when Battery runs low while AC power is off.
  • Download babysitting. Get a notification (or turn on a lamp) the moment Downloading flips off, so you know a big install finished without watching Download progress.
  • Now-playing presence. Set a desk lamp colour or a do-not-disturb flag while Game state is in-game, and clear it in the Steam UI or Desktop Mode.
  • Heat watch. If CPU temperature, GPU temperature or Fan speed climbs during a session, switch on a desk fan via a smart plug and nudge you.
  • Wake the host. When Game platform reads Moonlight or Remote Play you're streaming from another machine, so power on that gaming PC or set its scene.
  • Update nudge. When Updates queued goes above zero, remind yourself to dock and update overnight.

How it works

Battery and power come from UPower, suspend from logind, dock and display hotplug from udev, and the running game from gamescope. These all arrive as events, so there's nothing to poll. The only timers are a ~90 s heartbeat (keepalive plus a refresh of slow-moving values) and a game poll every 5 s on AC, 15 s on battery, for the few things Steam doesn't signal.

It publishes a final snapshot before the Deck suspends and refreshes on resume, without blocking sleep. A Last-Will marks the device offline if the Deck drops; it re-announces itself and re-publishes everything when it or Home Assistant reconnects. Idle cost is roughly one or two CPU wakeups per minute.

Install

cd ~/dev/steamdeck2mqtt
./install.sh                       # vendors paho, writes config, installs+enables the user service
$EDITOR ~/.config/steamdeck2mqtt/config.toml   # set broker host / username / password
python3 steamdeck2mqtt.py --dump     # sanity-check: prints every signal it can read, no MQTT
systemctl --user start steamdeck2mqtt
journalctl --user -u steamdeck2mqtt -f

A Steam Deck device appears under Settings > Devices & Services > Devices.

Uninstall

./install.sh uninstall     # stops the service AND removes the retained device from HA