Skip to main content

Python HID Automation

Use Python for direct hardware control

Python is excellent when the Stream Deck is part of your own local application. It is not the normal path for a Marketplace plugin inside the Stream Deck desktop app.

1. What the Python library does​

python-elgato-streamdeck is a Python 3 library for controlling Stream Deck devices directly. It can enumerate devices, open a deck, set brightness, draw key images, read key states, and register callbacks for keys, dials, and touch events on supported hardware.

That makes it ideal for:

  • local automation panels,
  • home lab controls,
  • monitoring dashboards,
  • CI/CD control desks,
  • OBS or media control outside the official plugin model,
  • hardware prototyping,
  • kiosk-style dashboards.

2. What it does not do​

It does not automatically give you:

  • Stream Deck app action registration,
  • Marketplace plugin packaging,
  • property inspectors,
  • user profile integration,
  • the official plugin manifest workflow.

If you need those, use the official TypeScript SDK.

3. Install​

python -m venv .venv
source .venv/bin/activate
pip install streamdeck pillow

On Linux, HID access commonly requires udev rules or running with elevated permissions. Prefer a udev rule over running automation as root.

4. Minimal direct controller​

from PIL import Image, ImageDraw
from StreamDeck.DeviceManager import DeviceManager
from StreamDeck.ImageHelpers import PILHelper


def render_key(deck, text: str):
image_format = deck.key_image_format()
image = Image.new("RGB", (image_format["size"][0], image_format["size"][1]), "black")
draw = ImageDraw.Draw(image)
draw.text((10, 10), text, fill="white")
return PILHelper.to_native_key_format(deck, image)


decks = DeviceManager().enumerate()

if not decks:
raise RuntimeError("No Stream Deck devices found")

deck = decks[0]
deck.open()
deck.reset()
deck.set_brightness(40)

for key in range(deck.key_count()):
deck.set_key_image(key, render_key(deck, str(key + 1)))


def on_key_change(deck, key, state):
if state:
deck.set_key_image(key, render_key(deck, "ON"))
else:
deck.set_key_image(key, render_key(deck, "OFF"))


deck.set_key_callback(on_key_change)

input("Press Enter to exit...")
deck.reset()
deck.close()

5. Device ownership​

Direct HID control usually means your process owns the device. If the official Stream Deck app is also trying to use the same hardware, expect conflicts.

Practical rules:

  • Stop the Stream Deck app when testing direct Python control.
  • Close the deck cleanly on exit.
  • Keep reconnect logic simple and visible.
  • Do not assume every model has the same key count, screen size, dials, or touch events.

6. Good Python architecture​

Separate device rendering from business logic:

app/
├── deck/
│ ├── devices.py
│ ├── renderer.py
│ └── callbacks.py
├── integrations/
│ ├── home_assistant.py
│ ├── prometheus.py
│ └── github_actions.py
└── main.py

Keep callbacks small. A key callback should enqueue work or flip state, not block on slow HTTP calls.

7. Image rendering tips​

  • Render at the device key image size returned by the library.
  • Use PILHelper.to_native_key_format before sending images to the deck.
  • Cache static images.
  • Rate-limit frequent state updates.
  • Use high-contrast text and icons.
  • Test on the physical model you plan to use.

8. Async and long-running work​

For dashboards that poll services:

  • keep one loop responsible for polling,
  • keep one layer responsible for rendering,
  • debounce updates so keys do not flicker,
  • handle API failures with a visible degraded state,
  • reconnect devices after sleep or USB disconnects.

9. When Python beats TypeScript​

Python is better when:

  • the deck is only for your own machine or team,
  • direct hardware ownership is acceptable,
  • you need scientific, automation, Linux, or ops libraries,
  • you want fast glue code around local APIs,
  • packaging through Stream Deck Marketplace is irrelevant.

10. When Python is the wrong fit​

Use the official SDK instead when:

  • users should install the plugin through Stream Deck,
  • actions should appear in the Stream Deck action list,
  • each action needs a property inspector,
  • users should mix your actions with other profiles,
  • Marketplace distribution matters.