- Python 100%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| streamdeck_controller | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| app.py | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| icon.ico | ||
| icon.png | ||
| install.py | ||
| pyproject.toml | ||
| README.md | ||
| streamdeck.spec | ||
| uninstall.py | ||
| uv.lock | ||
Stream Deck Controller
A configurator and controller for Elgato Stream Deck devices, written in Python.
Supported devices
| Device | Keys | Layout |
|---|---|---|
| Stream Deck Original V2 | 15 | 5×3 |
| Stream Deck MK.2 | 15 | 5×3 |
| Stream Deck XL | 32 | 8×4 |
| Stream Deck Mini | 6 | 3×2 |
| Stream Deck + | 8 | 4×2 |
Features
- 6 always-on core plugins + 7 optional built-in plugins covering media, home automation, shortcuts, and system tools
- Plugin Manager — enable/disable optional plugins and install external
.pyplugins without touching source code - Multi-page layouts with tab or button navigation
- Undo/redo, import/export (
.sdc), and live button preview - Icon picker, custom backgrounds, and multi-key actions
- Multi-device support
- Credentials stored in the OS keychain
- System tray with close-to-tray, start-on-boot, and start-minimized options
- Automatic updates on startup
Getting started
Prerequisites
Windows
Install the WinUSB driver with Zadig. This is a one-time setup per machine:
- Open Zadig and select Options → List All Devices
- Select your Stream Deck
- Choose WinUSB and click Install Driver
Once WinUSB is installed, Elgato's own software can no longer see the device. To revert, uninstall the WinUSB device in Device Manager and Windows will reinstall the HID driver automatically.
Linux
# USB access
sudo apt install libusb-1.0-0
# Tray icon (GNOME / Wayland)
sudo apt install python3-gobject python3-gi gir1.2-ayatanaappindicator3-0.1
# Media controls (Audio plugin)
sudo apt install playerctl
# Keyboard hotkeys on Wayland — ydotool injects at the kernel level (recommended)
sudo apt install ydotool
sudo usermod -aG input $USER # log out and back in after this
systemctl --user enable --now ydotoold
# Keyboard hotkeys on X11 / XWayland only — lighter alternative
sudo apt install xdotool
Install
Windows
- Download the latest
StreamDeckController.zipfrom the Releases page - Extract it anywhere and run
StreamDeckController.exe
The setup wizard opens on first launch.
Linux
- Download the latest
StreamDeckController-linux.tar.gzfrom the Releases page - Extract and run:
tar -xzf StreamDeckController-linux.tar.gz
cd StreamDeckController
./StreamDeckController
The setup wizard opens on first launch and installs the udev USB rule automatically.
Using the app
The configurator window opens and registers in the system tray. If no deck is connected, the app retries every few seconds — buttons can be configured offline.
Closing the window sends the app to the tray. To quit fully, right-click the tray icon and select Quit.
Keyboard shortcuts:
| Shortcut | Action |
|---|---|
| Ctrl+Z | Undo |
| Ctrl+Y | Redo |
| Ctrl+S | Save config |
| Ctrl+N | New page |
| Ctrl+E | Export layout |
| Ctrl+I | Import layout |
| Delete | Clear selected |
Configuration
Settings are stored in:
- Windows:
%LOCALAPPDATA%\streamdeck-controller\config.json - Linux:
~/.config/streamdeck-controller/config.json
App Settings
Open Settings → App Settings to configure:
| Setting | Description |
|---|---|
| Brightness | Deck display brightness (10–100%) |
| Close to tray | Minimize to the system tray instead of quitting when the window closes |
| Start on boot | Launch automatically on login |
| Start minimized | Start with the window hidden in the tray |
Plugins
Plugin Manager
Open Settings → Manage Plugins to control which plugins are active.
| Tier | Description |
|---|---|
| Core | Always active — Navigation, Shell, Keyboard, Audio, Launcher, Clipboard |
| Optional | Bundled with the app, enabled/disabled via Plugin Manager |
| External | Your own .py files, installed via "Install from file…" |
Changes take effect immediately without a restart.
To install an external plugin, click + Install from file… and pick your .py file. The app validates it, copies it
to the plugins directory, and makes it available straight away.
External plugins directory:
- Windows:
%LOCALAPPDATA%\streamdeck-controller\plugins - Linux:
~/.config/streamdeck-controller/plugins
Open Settings → Plugin Settings to enter credentials where required.
Spotify
Requires a Spotify developer app. Set client_id and client_secret, and use http://127.0.0.1:8888/callback as the
redirect URI.
| Action | Description |
|---|---|
| Play / Pause | Toggle playback |
| Previous | Skip to the previous track |
| Next | Skip to the next track |
| Album Cover | Display current album art across a configurable group of keys |
Home Assistant
Requires the instance URL and a long-lived access token.
| Action | Description |
|---|---|
| Toggle Entity | Toggle any light, switch, or entity. Button shows green when on, grey when off. |
| Sensor Display | Live sensor value (temperature, humidity, etc.). Unit comes from HA but can be overridden. Polls every 10 s. |
| Activate Scene | Trigger a scene on press (e.g. scene.gaming). |
OBS Studio
Requires OBS 28+ with obs-websocket v5 (Tools → WebSocket Server Settings). Set host, port (default 4455), and
password. Reconnects automatically when OBS is unavailable.
| Action | Description |
|---|---|
| Start / Stop Recording | Toggle recording. Button turns red while recording. |
| Start / Stop Streaming | Toggle stream. Button turns green while live. |
| Switch Scene | Jump to a named scene on press. |
| Toggle Source Mute | Mute or unmute a named audio source. Shows live mute state. |
Navigation
| Action | Description |
|---|---|
| Go To Page | Jump directly to another configured page |
| Go Back | Return to the previous page |
Shell
Uses cmd /c on Windows and bash -c on Linux.
| Action | Description |
|---|---|
| Run Command | Execute any command on press. Green on success, red on failure. Optional toggle command for two-state buttons. |
Dynamic variables, expanded at press time:
| Variable | Expands to |
|---|---|
{time} |
Current time (HH:MM) |
{date} |
Current date |
{datetime} |
Date and time |
{hostname} |
Machine hostname |
{user} |
Current username |
Enable Show output to display the last line of stdout on the button itself.
Keyboard
| Action | Description |
|---|---|
| Send Hotkey | Send a key combination (e.g. ctrl+shift+t, super+l, f5). Green on success, red on failure. |
| Type Text | Type a string as if entered on a keyboard. |
Modifier names: ctrl, shift, alt, super / win / cmd. On Wayland, ydotool is required (see
Prerequisites).
Clipboard
| Action | Description |
|---|---|
| Paste Text | Type text via keyboard simulation |
| Copy to Clipboard | Copy a fixed string to the clipboard |
Launcher
| Action | Description |
|---|---|
| Open URL | Open any URL in the default browser. Green on success, red on failure. |
| Launch App | Launch any application or command. |
Audio
Volume and mute use Windows Core Audio (pycaw) on Windows and pactl (PulseAudio / PipeWire) on Linux. Media
transport uses Win32 media keys on Windows and playerctl on Linux.
| Action | Description |
|---|---|
| Volume Up | Increase master volume by 5%. Shows current level. |
| Volume Down | Decrease master volume by 5%. Shows current level. |
| Mute Toggle | Toggle mute. Shows current mute state. |
| Volume Display | Read-only volume and mute display. Press to toggle mute. |
| Media Play/Pause | Play or pause the active media player. |
| Media Next | Skip to the next track. |
| Media Previous | Skip to the previous track. |
Pomodoro
The timer is shared across all Pomodoro buttons on a page.
| Action | Description |
|---|---|
| Start / Pause | Live countdown (25 min work, 5 min break). Red during work, blue during break, gold flash on phase end. |
| Reset | Reset to 25:00. |
Countdown
Each button has its own independent timer.
| Action | Description |
|---|---|
| Countdown Timer | Configurable duration, label, and optional shell command on completion. Press to start, pause, or reset. Flashes gold when done. |
System Stats
| Action | Description |
|---|---|
| CPU Usage | Live CPU %. Green below 50%, yellow 50–80%, red above 80%. |
| RAM Usage | Live RAM %. Same color coding. |
| Disk Usage | Disk usage % for a configured mount point or drive. Updates every 10 s. |
Weather
No credentials required. Configure city name and temperature unit.
| Action | Description |
|---|---|
| Current Weather | Icon, temperature, and city name. Refreshes every 10 minutes. |
Development
See CONTRIBUTING.md for the full setup guide, plugin development walkthrough, and PR process.
Quick start
git clone <repo>
cd StreamDeckController
# Linux: create a venv with system-site-packages so PyGObject is available
uv venv --system-site-packages
uv sync
# Run
uv run streamdeck-controller
On Windows, a plain uv sync is sufficient (no --system-site-packages needed).
Project layout
StreamDeckController/
├── streamdeck_controller/
│ ├── __main__.py # entry point
│ ├── config_io.py # config load / save / validation
│ ├── credentials.py # OS keychain helpers (keyring)
│ ├── deck_runner.py # Stream Deck polling & rendering loop
│ ├── plugin_loader.py # plugin discovery & loading (core / optional / external)
│ ├── logging_setup.py # centralized logging (file + stderr)
│ ├── pyusb_transport.py # custom PyUSB HID transport
│ ├── _build.py # PyInstaller build helper
│ ├── plugins/ # action plugins (one file per plugin)
│ │ ├── base.py # BasePlugin / BaseAction API
│ │ ├── _template.py # annotated plugin skeleton
│ │ └── *.py # built-in plugins
│ └── ui/
│ ├── app.py # main window
│ ├── plugin_manager.py # Manage Plugins dialog
│ ├── action_editor.py # button assignment dialog
│ ├── deck_grid.py # visual deck grid widget
│ ├── icon_picker.py # emoji / symbol picker
│ ├── plugin_settings_dialog.py
│ ├── app_settings_dialog.py
│ └── setup_wizard.py # first-run wizard
├── pyproject.toml
└── streamdeck.spec # PyInstaller spec
Building a release
uv run streamdeck-build
Produces a self-contained dist/StreamDeckController/ folder requiring neither Python nor uv on the target machine. Zip
it and publish as a release.
Linting and formatting
uv run ruff format .
uv run ruff check .
uv run mypy streamdeck_controller
Writing a plugin
See CONTRIBUTING.md for a full walkthrough.
Quick start:
- Copy
streamdeck_controller/plugins/_template.pyanywhere on your system and fill in the TODOs - Open Settings → Manage Plugins → + Install from file… and select your
.pyfile - The plugin is installed, enabled, and available immediately
To contribute a plugin back to the project, see the contributing guide.