2. Example Script: Basic Usage
The following is a complete example script to connect to attached StreamDeck devices, display custom image/text graphics on the buttons and respond to press events.
#!/usr/bin/env python3
# Python Stream Deck Library
# Released under the MIT license
#
# dean [at] fourwalledcubicle [dot] com
# www.fourwalledcubicle.com
#
# Example script showing basic library usage - updating key images with new
# tiles generated at runtime, and responding to button state change events.
import os
import threading
from PIL import Image, ImageDraw, ImageFont
from StreamDeck.DeviceManager import DeviceManager
from StreamDeck.ImageHelpers import PILHelper
# Folder location of image assets used by this example.
ASSETS_PATH = os.path.join(os.path.dirname(__file__), "Assets")
# Generates a custom tile with run-time generated text and custom image via the
# PIL module.
def render_key_image(deck, icon_filename, font_filename, label_text):
# Resize the source image asset to best-fit the dimensions of a single key,
# leaving a margin at the bottom so that we can draw the key title
# afterwards.
icon = Image.open(icon_filename)
image = PILHelper.create_scaled_key_image(deck, icon, margins=[0, 0, 20, 0])
# Load a custom TrueType font and use it to overlay the key index, draw key
# label onto the image a few pixels from the bottom of the key.
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(font_filename, 14)
draw.text((image.width / 2, image.height - 5), text=label_text, font=font, anchor="ms", fill="white")
return PILHelper.to_native_key_format(deck, image)
# Returns styling information for a key based on its position and state.
def get_key_style(deck, key, state):
# Last button in the example application is the exit button.
exit_key_index = deck.key_count() - 1
if key == exit_key_index:
name = "exit"
icon = "{}.png".format("Exit")
font = "Roboto-Regular.ttf"
label = "Bye" if state else "Exit"
else:
name = "emoji"
icon = "{}.png".format("Pressed" if state else "Released")
font = "Roboto-Regular.ttf"
label = "Pressed!" if state else "Key {}".format(key)
return {
"name": name,
"icon": os.path.join(ASSETS_PATH, icon),
"font": os.path.join(ASSETS_PATH, font),
"label": label
}
# Creates a new key image based on the key index, style and current key state
# and updates the image on the StreamDeck.
def update_key_image(deck, key, state):
# Determine what icon and label to use on the generated key.
key_style = get_key_style(deck, key, state)
# Generate the custom key with the requested image and label.
image = render_key_image(deck, key_style["icon"], key_style["font"], key_style["label"])
# Use a scoped-with on the deck to ensure we're the only thread using it
# right now.
with deck:
# Update requested key with the generated image.
deck.set_key_image(key, image)
# Prints key state change information, updates rhe key image and performs any
# associated actions when a key is pressed.
def key_change_callback(deck, key, state):
# Print new key state
print("Deck {} Key {} = {}".format(deck.id(), key, state), flush=True)
# Update the key image based on the new key state.
update_key_image(deck, key, state)
# Check if the key is changing to the pressed state.
if state:
key_style = get_key_style(deck, key, state)
# When an exit button is pressed, close the application.
if key_style["name"] == "exit":
# Use a scoped-with on the deck to ensure we're the only thread
# using it right now.
with deck:
# Reset deck, clearing all button images.
deck.reset()
# Close deck handle, terminating internal worker threads.
deck.close()
if __name__ == "__main__":
streamdecks = DeviceManager().enumerate()
print("Found {} Stream Deck(s).\n".format(len(streamdecks)))
for index, deck in enumerate(streamdecks):
# This example only works with devices that have screens.
if not deck.is_visual():
continue
deck.open()
deck.reset()
print("Opened '{}' device (serial number: '{}', fw: '{}')".format(
deck.deck_type(), deck.get_serial_number(), deck.get_firmware_version()
))
# Set initial screen brightness to 30%.
deck.set_brightness(30)
# Set initial key images.
for key in range(deck.key_count()):
update_key_image(deck, key, False)
# Register callback function for when a key state changes.
deck.set_key_callback(key_change_callback)
# Wait until all application threads have terminated (for this example,
# this is when all deck handles are closed).
for t in threading.enumerate():
try:
t.join()
except RuntimeError:
pass