summaryrefslogtreecommitdiff
path: root/annotated_example.py
diff options
context:
space:
mode:
Diffstat (limited to 'annotated_example.py')
-rw-r--r--annotated_example.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/annotated_example.py b/annotated_example.py
new file mode 100644
index 0000000..a602a12
--- /dev/null
+++ b/annotated_example.py
@@ -0,0 +1,140 @@
+#!/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