stream-deck-ts
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

elgato-stream-deck

Build Status npm version license dependencies Status Coverage Status

This is a library for developers to use. It is not a program for end users. It cannot and will not replace the official Stream Deck program. That is not its goal. However, it does enable someone to more easily write a program which does do that.

Supported devices

Any additional devices would be appriciated. If you are able to control another device than those listed - please send a PR.

Elgato

Install

$ npm install --save stream-deck-ts

All of this library's native dependencies ship with prebuilt binaries, so having a full compiler toolchain should not be necessary to install stream-deck-ts.

However, in the event that installation does fail (or if you are on a platform that our dependencies don't provide prebuilt binaries for, such as a Raspberry Pi), you will need to install a compiler toolchain to enable npm to build some of stream-deck-ts's dependencies from source. Expand the details block below for full instructions on how to do so.

Compiling dependencies from source
  • Windows
    npm install --global windows-build-tools
  • MacOS
    • Install the Xcode Command Line Tools:
    xcode-select --install
  • Linux (including Raspberry Pi)
    • Follow the instructions for Linux in the "Compiling from source" steps for node-hid:
      sudo apt-get install build-essential git
      sudo apt-get install gcc-4.8 g++-4.8 && export CXX=g++-4.8
      sudo apt-get install sudo apt install libusb-1.0-0 libusb-1.0-0-dev
    • Install a recent version of Node.js.:
      curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
      sudo apt-get install -y nodejs 
    • Try installing stream-deck-ts
    • If you still have issues, ensure everything is updated and try again:
      sudo apt-get update && sudo apt-get upgrade

Table of Contents

Example

import { resolve } from "path";
import { selectDevice } from "stream-deck-ts";
 
(async function asyncMain() {
    // Automatically discovers connected Stream Decks, and attaches to the first one.
    // Returns `null` if there are no connected stream decks.
    // You also have the option of providing the numeric vendor identifier and product identifier.
    // For example: `const myStreamDeck = await selectDevice(VENDOR_ELGATO, PRODUCT_ELGATO_STREAMDECK_MINI);`
    const myStreamDeck = await selectDevice();
    if (!myStreamDeck) {
        throw new Error("No StreamDeck found.");
    }
 
    myStreamDeck.on('down', (keyIndex) => {
        console.log('key %d down', keyIndex);
    });
 
    myStreamDeck.on('up', (keyIndex) => {
        console.log('key %d up', keyIndex);
    });
 
    // Fired whenever an error is detected by the `node-hid` library.
    // Always add a listener for this event!
    myStreamDeck.on('error', (error) => {
        console.error(error);
    });
 
    // Fill button 3 with an image of the GitHub logo.
    // This is asynchronous and returns a promise.
    myStreamDeck.fillImageFromFile(3, resolve(__dirname, 'github_logo.png')).then(() => {
        console.log('Successfully wrote a GitHub logo to key 3.');
    });
 
    // Fill the first button form the left in the first row with a solid red color. This is synchronous.
    myStreamDeck.fillColor(4, 255, 0, 0);
    console.log('Successfully wrote a red square to key 4.');
}());

Features

  • Multiplatform support: Windows 7-10, MacOS, Linux, and even Raspberry Pi!
  • Key down and key up events
  • Fill keys with images or solid RGB colors
  • Fill the entire panel with a single image, spread across all keys
  • Set the Stream Deck brightness
  • TypeScript support
  • Multi device support
  • Optional user supplier image processing library

API

Constants

Constant: DEVICE_MODELS

  • <Object<number, Object<number, Object>>>

An object containing devices which are supported.

  • DEVICE_MODELS[vendor][device].import <string> A path to the device implementation.
  • DEVICE_MODELS[vendor][device].productName <string> A name representing the product of the device.
  • DEVICE_MODELS[vendor][device].vendorName <string> A name representing the vendor of the device.

To get specific product information getStreamDeckProduct is the preferred solution.

Constant: PRODUCT_ELGATO_STREAMDECK

export const PRODUCT_ELGATO_STREAMDECK = 96;

Exported constant to use as the product filter while selecting a device.

Constant: PRODUCT_ELGATO_STREAMDECK_MINI

export const PRODUCT_ELGATO_STREAMDECK_MINI = 99;

Exported constant to use as the product filter while selecting a device.

Constant: VENDOR_ELGATO

export const VENDOR_ELGATO = 4057;

Exported constant to use as the vendor filter while selecting a device.

devices ()

  • Returns: <Promise<Object[]>>
  • object.vendorId <number> Numeric vendor id.
  • object.productId <number> Numeric product id.
  • object.release <number> Numeric release value.
  • object.interface <number> Interface number.
  • object.path <string> Path to the specific device.

Get a list of connected HID devices.

getStreamDeckProduct (vendor, product)

  • vendor <number> A vendor identity number to register the product to.
  • product <number> A product identity number to register the product to.
  • Returns: <Object | undefined> Configuration if one exists.
  • object.import <string> Module name of the device implementation.
  • object.productName <string> Name of the product.
  • object.vendorName <string> Name of the vendor.

Register a StreamDeck compatable product. When a device matching the product is selected the module path in config.import is loaded and instantiated.

The module referenced by config.import must export a class named default. The exported class SHOULD extend StreamDeckBase.

registerStreamDeckProduct (vendor, product, config)

  • vendor <number> A vendor identity number to register the product to.
  • product <number> A product identity number to register the product to.
  • config <Object> The configuration object describing the product.
  • Returns: <Object | undefined> Previous configuration if one existed.
  • config.import <string> Module name of the device implementation.
  • config.productName <string> Name of the product.
  • config.vendorName <string> Name of the vendor.

Register a StreamDeck compatable product. When a device matching the product is selected the module path in config.import is loaded and instantiated.

The module referenced by config.import must export a class named default. The exported class SHOULD extend StreamDeckBase.

selectDevice ([vendor[, product]])

  • vendor <number> An optional vendor identity number to limit which device will be selected.
  • product <number> An optional product identity number to limit which device will be selected.
  • Returns: <Promise<StreamDeck | null>>

Select the first supported device. If no supported device is found null is returned.

selectAllDevices ([vendor[, product]])

  • vendor <number> An optional vendor identity number to limit which devices will be selected.
  • product <number> An optional product identity number to limit which devices will be selected.
  • Returns: <Promise<Array<Promise<StreamDeck>>>>

Get a list of all supported devices while they're being opened.

setHidAsyncType (type)

  • type <string> Sets which type of async provider should be used.

The async provider type handles how async calls are made.

  • auto selects one of the other modes available to the system, based on priority.
  • emulated will emulate an async environment with microtasks while still running synchronously inside the main thread. This might be good for debugging or as a last resort fallback but should be avoided if possible.
  • process creates a forked process to handle the USB communication which is first sent serialized over an IPC channel.
  • worker spins up a Worker to handle the USB communication, which should be the most performant mode by using transferrable ByteArrays. But workers are not currently supported by node-hid.

Class: StreamDeck

Instances of the StreamDeck class have an active connection to a device.

Event: 'down'

  • keyIndex <number> The index of the key that got pressed.

The down event is triggered when a button on the Stream Deck has been pressed down.

Event: 'up'

  • keyIndex <number> The index of the key that got released.

The up event is triggered when a button on the Stream Deck has been released which previously had been pressed down.

Event: 'error'

  • error <Error> The index of the key that got released.

Fired whenever an error is detected by the node-hid library. Always add a listener for this event! If you don't, errors will be silently dropped.

streamDeck .buttonColumns

  • <number>

Returns the number of button columns available to this StreamDeck.

streamDeck. buttonLength

  • <number>

Returns the number of buttons available to this StreamDeck.

streamDeck .buttonRows

  • <number>

Returns the number of button rows available to this StreamDeck.

streamDeck .hasPressedKeys

  • <boolean>

A boolean showing if there currently are any pressed keys.

streamDeck .iconSize

  • <number>

Returns the size in pixels used for icons.

streamDeck .pressedKeys

  • <Array<number>>

A sorted list of all buttons currently pressed.

streamDeck .buttonIndexFromPosition (x, y)

  • x <number> Cloumn number counted from from the left.
  • y <number> Row number counted from from the top.
  • Returns: <number> The keyIndex at the given position or undefined if out of bounds.

Get the keyIndex at a specific column and row.

streamDeck .checkValidKeyIndex (keyIndex)

  • keyIndex <number> Cloumn number counted from from the left.
  • y <number> Row number counted from from the top.
  • Returns: <number> The keyIndex at the given position or undefined if out of bounds.

Validate a keyIndex. If the number is not valid the function will throw a TypeError, otherwise the same value will be returned.

streamDeck .clearAllKeys ()

  • Returns: <StreamDeck>

Synchronously clears all keys on the device.

Example: clear all keys
// Clear all keys.
streamDeck.clearAllKeys();

streamDeck .clearKey (keyIndex)

  • keyIndex <number> Key to affect.
  • Returns: <StreamDeck>

Synchronously clears the given keyIndex's screen.

Example: clear button 2
// Clear button 2.
streamDeck.clearKey(2);

streamDeck .close ()

Closes this reference to the device.

streamDeck .fillColor (keyIndex, rgb)

  • keyIndex <number> Key to affect.
  • rgb <number> Fill color.

Synchronously sets the given keyIndex's screen to a solid RGB color.

Example: set button 4 to solid red
// Turn key 4 solid red.
streamDeck.fillColor(4, 0xFF0000);

streamDeck .fillColor (keyIndex, r, g, b)

  • keyIndex <number> Key to affect.
  • r <number> Red component between 0 - 255.
  • g <number> Green component between 0 - 255.
  • b <number> Blue component between 0 - 255.

Synchronously sets the given keyIndex's screen to a solid RGB color.

Example: set button 5 to solid blue
// Turn key 5 solid blue.
streamDeck.fillColor(5, 0, 0, 0xFF);

streamDeck .fillImage (keyIndex, buffer)

  • keyIndex <number> Key to affect.
  • buffer <Buffer> Image bytes.
  • Returns: <Promise<StreamDeck>>

Synchronously writes a buffer of streamDeck.iconSize * streamDeck.iconSize RGB image data to the given keyIndex's screen. The buffer must be exactly the expected length of bytes. Any other length will result in an error being thrown.

Example: fill button 2 with an image of the GitHub logo
// Fill button 2 with an image of the GitHub logo.
import * as sharp from "sharp"; // See http://sharp.dimens.io/en/stable/ for full docs on this great library!
import { resolve } from "path";
 
const filepath = resolve(__dirname, 'github_logo.png');
const buffer = await sharp(filepath)
    .flatten() // Eliminate alpha channel, if any.
    .resize(streamDeck.iconSize, streamDeck.iconSize) // Scale up/down to the right size, cropping if necessary.
    .raw() // Give us uncompressed RGB.
    .toBuffer();
 
streamDeck.fillImage(2, buffer);

streamDeck .fillImageFromFile (keyIndex, filePath)

  • keyIndex <number> Key to affect.
  • filePath <string> File system path to an image file.
  • Returns: <Promise<StreamDeck>>

Asynchronously reads an image from filePath and sets the given keyIndex's screen to that image. Automatically scales the image to the expected height and width and strips out the alpha channel. If necessary, the image will be center-cropped to fit into a square.

Example: fill the button 3 with an image of the GitHub logo
// Fill the button 3 with an image of the GitHub logo.
await streamDeck.fillImageFromFile(3, path.resolve(__dirname, 'github_logo.png'));
console.log('Successfully wrote a GitHub logo to key 3.');

streamDeck .fillPanel (imagePathOrBuffer[, rawOptions])

  • imagePathOrBuffer <string | Uint8Array | Buffer> Image data or path to a file.
  • rawOptions <object> Optional options object used if the image buffer contained raw pixel data.
    • rawOptions.channels <number> Number of channels per pixel. RGBA = 4.
    • rawOptions.height <number> Height in pixels.
    • rawOptions.width <number> Width in pixels.
  • Returns: <Promise<StreamDeck>>

Asynchronously applies an image to the entire panel, spreading it over all keys. The image is scaled down and center-cropped to fit. This method does not currently account for the gaps between keys, and behaves as if each key was directly connected to its neighbors. If you wish to account for the gaps between keys, you'll need to do so via other means, and bake that into the image you provide to fillPanel.

This method accepts either a path to an image on the disk, or a buffer. The image path or buffer is passed directly to sharp. Therefore, this method accepts all images and buffers which sharp can accept.

Example: fill the entire panel with a photo of a sunny field
// Fill the entire panel with a photo of a sunny field.
import { resolve } from "path";
 
const filepath = resolve(__dirname, 'examples/fixtures/sunny_field.png');
await streamDeck.fillPanel(filepath);
console.log('Successfully filled the panel with an image.');

streamDeck .forEachKey (callback)

  • callback <Function> The function to call for each button in the stream deck.
  • Returns: <StreamDeck>

Execute a function for each button available to the StreamDeck.

streamDeck .sendFeatureReport (buffer)

  • buffer <Buffer | Uint8Array> The buffer send to the Stream Deck.
  • Returns: <StreamDeck>

Sends a HID feature report to the Stream Deck.

streamDeck .setBrightness (percentage)

  • percentage <number> Percentage of brightness.
  • Returns: <StreamDeck>

Synchronously set the brightness of the Stream Deck. This affects all keys at once. The brightness of individual keys cannot be controlled.

Example: set the Stream Deck to maximum brightness
// Set the Stream Deck to maximum brightness
streamDeck.setBrightness(100);

streamDeck .setImageLibrary (library)

  • library <string | IImageLibraryCreator | Promise<IImageLibraryCreator>> An object capable to create image contexts or a string representing a module exporting such an object as default.
  • Returns: <StreamDeck>

Allows users to switch image processing library to a non standard version. This might be because of the library providing better performance or image quality, or simply to minimize bloat when another image library is used somewhere else.

streamDeck .write (buffer)

  • buffer <Buffer | Uint8Array> Data to write.
  • Returns: <Promise<number>> When written this resolves to the number of bytes

Asynchronously writes an arbitrary Uint8Array instance to the Stream Deck. The promise is rejected if an error is encountered during the write operation.

streamDeck .writeMulti (buffers)

  • buffers <Array<Buffer | Uint8Array>> Data buffers to write.
  • Returns: <Promise<number>> When written this resolves to the number of bytes

Asynchronously writes a bunch of arbitrary Uint8Array instances to the Stream Deck. The promise is rejected if an error is encountered during the write operation.

Example: write a number of zeros to the stream deck
// Writes a total of 32 bytes of zero to the Stream Deck in two pages and waits for the last one to finish.
await streamDeck.writeMulti([
    Buffer.alloc(16), Buffer.alloc(16)
]);

Abstract class: StreamDeckBase

Abstract base class which is a partial implementation and must be extended.

To see which abstract properties and methods are required for a subclass check out the source code for StreamDeck and look for the keyword abstract.

Interface: IImageLibrary

An image instance controlled by an image library.

Any library implementing, or wrapped by an object implementing, this interface could be used for image operations.

IImageLibrary .extract (options)

Extract a section of the image.

If this is a immutable data structure a clone of the original should be returned with the new 2d slice. A mutable structure should return the original but with a view which may be moved with another call to extract.

  • options.left <number> the distance from the left edge of the original
  • options.top <number> the distance from the top edge of the original
  • options.width <number> the width of this subsection
  • options.height <number> the height of this subsection

IImageLibrary .flatten ()

Remove alpha channel if one exists.

IImageLibrary .resize (width, height)

  • width <number> Width of the resulting image.
  • height <number> Height of the resulting image.
  • Returns: <IImageLibrary | Promise<IImageLibrary>>

Resizes an image to the specified size. Interpolation and ratio perservation mode is up to the library or wrapper. However it is recommended that the image be applied in a cover fashion.

IImageLibrary .toUint8Array ()

  • Returns: <Uint8Array | Promise<Uint8Array>>

Get the RGB raw pixel bytes representing the image.

Interface: IImageLibraryCreator

An object implementing this interface is tasked with instantiating image contexts using a library or a custom implementation.

IImageLibraryCreator .createRaw (data, rawOptions)

  • data <Uint8Array> Raw RGB pixel data.
  • rawOptions <Object> Parameters describing the raw image.
  • Returns: <IImageLibrary | Promise<IImageLibrary>>

Creates an image context containing the pixels given in the data argument. The image size and number of channels are specified in the rawOptions argument.

  • rawOptions.channels <number> The number of channels used. 4 is RGBA, 3 is RGB.
  • rawOptions.height <number> The height of the image.
  • rawOptions.width <number> The width of the image.

The total number of bytes should be equal to height * width * channels.

IImageLibraryCreator .loadFile (filepath)

If using a library exposing a way to read a file or support stream decoding such a function sould be used here. If no streaming optimization is available this could be implemented by doing an async readFile and passing the resulting data to loadFileData.

IImageLibraryCreator .loadFileData (filedata)

Creates an image context based on an existing image. Which image encodings is supported is determined by the library or implementor. Recommended formats are PNG, JPEG, and SVG.

Dependencies (2)

Dev Dependencies (11)

Package Sidebar

Install

npm i stream-deck-ts

Weekly Downloads

4

Version

1.0.0

License

MIT

Unpacked Size

302 kB

Total Files

117

Last publish

Collaborators

  • timluq