The new Stream Deck SDK is cool

A quick overview of the differences.

The new Stream Deck SDK is cool
Dragon Stickers made by @Ikaika

A few days ago, I wanted to take a new look into the creation of Stream Deck Plugins. The last time I coded a plugin was in 2020, and since then, the new Stream Deck SDK was released.

In this small blog post, I want to say why I think the new SDK is really cool.

Making a plugin - the old way

Before I can talk about how the new SDK makes things easier, I need to talk about how it was done in the beginning.

You had to manually connect and talk to the web socket. When receiving messages, you had to manually assign the correct action and function to it.

websocket.onmessage = function (evt) {
    // Received message from Stream Deck
    var jsonObj = JSON.parse(evt.data);
    var event = jsonObj['event'];
    var action = jsonObj['action'];
    var context = jsonObj['context'];

    if (event === "keyDown") {
        var jsonPayload = jsonObj['payload'];
        var settings = jsonPayload['settings'];
        var coordinates = jsonPayload['coordinates'];
        var userDesiredState = jsonPayload['userDesiredState'];
        counterAction.onKeyDown(context, settings, coordinates, userDesiredState);
    } else if (event === "keyUp") {
        var jsonPayload = jsonObj['payload'];
        var settings = jsonPayload['settings'];
        var coordinates = jsonPayload['coordinates'];
        var userDesiredState = jsonPayload['userDesiredState'];
        counterAction.onKeyUp(context, settings, coordinates, userDesiredState);
    } else if (event === "willAppear") {
        var jsonPayload = jsonObj['payload'];
        var settings = jsonPayload['settings'];
        var coordinates = jsonPayload['coordinates'];
        counterAction.onWillAppear(context, settings, coordinates);
    }
};

*This code only has one action

This was a difficult way to do it and was not easy to learn (as a beginner coder). I never understood how to make options in the inspector, so I just hard-coded my variables.

Testing the changes meant restarting the whole Stream Deck app, just to see whether it works or not.

Making a plugin - with the new SDK

The new SDK comes with a CLI, that allows creating a sample project. This creates the needed project structure and prepares the Stream Deck app to allow hot reloading, development tools and more.

$ streamdeck create

I'll quickly go over a few things that, I think, are cool.

The plugin.ts

import streamDeck, { LogLevel } from "@elgato/streamdeck";
import { IncrementCounter } from "./actions/increment-counter";

streamDeck.logger.setLevel(LogLevel.TRACE);

streamDeck.actions.registerAction(new IncrementCounter());

streamDeck.connect();

Here you can directly see that now it's easier to register actions. Just add the class of the action into the registerAction() function. But... where do these actions come from?

The action

import { action, KeyDownEvent, SingletonAction, WillAppearEvent } from "@elgato/streamdeck";

@action({ UUID: "dev.steffo.pishock-controller.increment" })
export class IncrementCounter extends SingletonAction<CounterSettings> {
	override onWillAppear(ev: WillAppearEvent<CounterSettings>): void | Promise<void> {
		return ev.action.setTitle(`${ev.payload.settings.count ?? 0}`);
	}

	override async onKeyDown(ev: KeyDownEvent<CounterSettings>): Promise<void> {
		const { settings } = ev.payload;
		settings.incrementBy ??= 1;
		settings.count = (settings.count ?? 0) + settings.incrementBy;

		await ev.action.setSettings(settings);
		await ev.action.setTitle(`${settings.count}`);
	}
}

type CounterSettings = {
	count?: number;
	incrementBy?: number;
};

There are predefined functions for each message of the web socket. This makes it, in my opinion, way faster and easier to understand how this all works.

Why all of this?

I wanted to take a look at the new Stream Deck SDK and now finished a cool new Plugin to control PiShock devices.

streamdeck-pishock-controller
Interact with the PiShock API through your Stream Deck.

I definitely have to learn more about using the new SDK, but I think this is already a great start - and it proves that it already helps a lot when creating simpler plugins.