Library for directly interacting and controlling an Elgato Stream Deck on Linux.

Overview

Stream Deck

Library for directly interacting and controlling an Elgato Stream Deck on Linux.

This library is designed to take exclusive control over a Stream Deck using USB HID, if you are an end-user looking for software just to control your Stream Deck, this is not what you are looking for. If you are looking to build your own software whether it be a CLI or GUI app to control your Stream Deck, you have come to the right place.

This library was inspired by many of the other go streamdeck libraries, I created this one because all the other ones I could find either didn't work, didn't support the features I wanted, required CGO, or were poorly designed (imo) making them hard to use.

The internal hid package was heavily-based on https://github.com/zserge/hid with some improvements from https://github.com/rafaelmartins/usbfs.

Features

  • Native Linux support (No CGO)
    • Caveat: This library does not support Windows or MacOS, and will not for the conceivable future.
  • Supports GIFs
    • The most uselessful feature
  • Easy to use
  • Performant

Missing

  • Tests
  • More in-depth examples and documentation
  • Probably some other things I had no idea existed

Example

package main

import (
	"context"
	"embed"
	"fmt"
	"image"
	"image/gif"
	"log"
	"os"
	"os/signal"
	"path/filepath"

	"golang.org/x/sys/unix"

	"github.com/matthewpi/streamdeck"
	"github.com/matthewpi/streamdeck/button"
	"github.com/matthewpi/streamdeck/view"
)

//go:embed .embed/*.png .embed/*.gif
var embedFs embed.FS

func main() {
	if err := start(context.Background()); err != nil {
		panic(err)
		return
	}
}

func start(ctx context.Context) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	sd, err := streamdeck.New(ctx)
	if err != nil {
		return fmt.Errorf("failed to find or connect to a streamdeck: %w", err)
	}
	if sd == nil {
		return fmt.Errorf("no streamdeck devices found: %w", err)
	}
	defer func(ctx context.Context, sd *streamdeck.StreamDeck) {
		if err := sd.Close(ctx); err != nil {
			log.Printf("an error occurred while closing the streamdeck: %v\n")
		}
	}(ctx, sd)

	if err := sd.SetBrightness(ctx, 25); err != nil {
		return fmt.Errorf("failed to set streamdeck brightness: %w", err)
	}

	buttons, err := view.NewButtons(sd)
	if err != nil {
		return fmt.Errorf("failed to create button view: %w", err)
	}

	sd.SetHandler(func(ctx context.Context, index int) error {
		switch index {
		case 0:
			fmt.Println("you pressed a button!")
		case 1:
			fmt.Println("you pressed another button!")
		}
		return nil
	})

	buttons.Set(1, button.NewImage(mustGetImage(sd, "spotify_play.png")))
	buttons.Set(2, button.NewGIF(sd, mustGetGIF("peepoDance.gif")))

	ctx3, cancel3 := context.WithCancel(ctx)
	defer cancel3()
	if err := buttons.Apply(ctx3); err != nil {
		return fmt.Errorf("failed to update streamdeck buttons: %w", err)
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt, unix.SIGTERM)
	<-ch
	log.Println("shutting down")
	return nil
}

func getImage(sd *streamdeck.StreamDeck, filename string) ([]byte, error) {
	f, err := embedFs.Open(filepath.Join(".embed", filename))
	if err != nil {
		return nil, err
	}
	defer f.Close()
	img, _, err := image.Decode(f)
	if err != nil {
		return nil, err
	}
	return sd.ProcessImage(img)
}

func mustGetImage(sd *streamdeck.StreamDeck, filename string) []byte {
	img, err := getImage(sd, filename)
	if err != nil {
		panic(err)
		return nil
	}
	return img
}

func getGIF(filename string) (*gif.GIF, error) {
	f, err := embedFs.Open(filepath.Join(".embed", filename))
	if err != nil {
		return nil, err
	}
	defer f.Close()
	g, err := gif.DecodeAll(f)
	if err != nil {
		return nil, err
	}
	return g, nil
}

func mustGetGIF(filename string) *gif.GIF {
	img, err := getGIF(filename)
	if err != nil {
		panic(err)
		return nil
	}
	return img
}

Design

Device

Device is the lowest-level API that is exposed. A Device allows sending raw data as well as providing some convenience functions, it's main purpose is to provide a base that the StreamDeck structure interacts with in order to expose a more user-friendly API.

StreamDeck

StreamDeck provides the user-friendly API that most integrations of this library will use, it allows the use of Views in order to provide an easy way of setting buttons and handling press events.

View

A View is used by a Streamdeck to set the images for all buttons, a View may optionally override the Stream Deck's default button press handler in order to provide a different API for handling button presses.

Example (refer to view/buttons.go)

Button

Button is used for buttons with static content, like a solid color or image button. If you need to change the content of a static button, you can either just create a new button and update the View, or implement a custom button that pulls its content from an external source and is capable of updating the View itself.

Example (refer to button/button.go)

Button (Animated)

Animated is an addon to the Button interface that allows a button to determine when it wants to update itself. A common example of this would be displaying a GIF which from my knowledge the Stream Deck does not natively support, meaning we need to wait the time required for each frame and keep updating the image displayed on the Stream Deck. This interface could also be useful for displaying dynamic content like Spotify Album art for example.

Example (refer to button/animated.go)
Issues
  • Discussion: modified hid library

    Discussion: modified hid library

    Just thought I'd ask here why you ended up customizing the hid library and were there some blockers in the libraries that were currently available (mainly in zserge/hid, as all others seem to use cgo)? I'm considering writing Windows support for https://github.com/zserge/hid and if I do that and it gets merged it would be nice if it would enable your library to work with Windows as well.

    opened by errnoh 1
  • modify Devices() to traverse underlying directories

    modify Devices() to traverse underlying directories

    Hi, I was working on some related code and while I really liked the approach of avoiding cgo and doing things more idiomatic way I did notice that this library wasn't working out of the box.

    Issue seems to have been in how the internal hid library traverses forward from the origin point (it tried to open the directory as a file). These changes fix the issue, at least for me.

    opened by errnoh 0
Owner
Matthew Penner
Software Engineer | Golang and TypeScript
Matthew Penner
A Go library for interacting with the Hypixel API.

gopixel gopixel is a Go library for interacting with the Hypixel API. This software is alpha software and is subject to change, including but not limi

null 3 Apr 1, 2022
Connect directly to Docker-for-Mac containers via IP address 🐳 💻

Docker Mac Net Connect Connect directly to Docker-for-Mac containers via IP address. Features L3 connectivity: Connect to Docker containers from macOS

Chipmunk 93 Aug 6, 2022
HCio is a straightforward way to ping Healthchecks.io checks directly from a Go application

HCio HCio is a straightforward way to ping Healthchecks.io checks directly from a Go application. Getting Started Create a simple Check: check := hcio

Daniel Sage 1 Dec 20, 2021
This small Docker project is the easiest way to send notifications directly via .txt files to services like: Gotify, Telegram, SMTP (Email) or Webhook.

This small Docker project is the easiest way to send notifications directly via .txt files to services like: Gotify, Telegram, SMTP (Email) or Webhook.

echGo 5 Jul 10, 2022
A library to simplify writing applications using TCP sockets to stream protobuff messages

BuffStreams Streaming Protocol Buffers messages over TCP in Golang What is BuffStreams? BuffStreams is a set of abstraction over TCPConns for streamin

Sean Kelly 249 Aug 1, 2022
A lightweight stream processing library for Go

go-streams A lightweight stream processing library for Go. go-streams provides a simple and concise DSL to build data pipelines. Wiki In computing, a

Eugene R. 1k Aug 9, 2022
Totem - A Go library that can turn a single gRPC stream into bidirectional unary gRPC servers

Totem is a Go library that can turn a single gRPC stream into bidirectional unar

Joe Kralicky 2 Jan 10, 2022
Moviefetch: a simple program to search and download for movies from websites like 1337x and then stream them

MovieFetch Disclaimer I am NOT responisble for any legal issues or other you enc

Hashm 2 May 12, 2022
mdmb is a tool for simulating Apple devices interacting with Apple MDM servers.

mdmb mdmb — short for MDM Benchmark, à la ab — is a tool for simulating Apple devices interacting with Apple MDM servers. mdmb creates sets of fake Ap

Jesse Peterson 37 Jul 2, 2022
protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text formats

protoCURL protoCURL is cURL for Protobuf: The command-line tool for interacting with Protobuf over HTTP REST endpoints using human-readable text forma

QAware GmbH 17 Jul 30, 2022
Reads MAWS formatted data and converts it into JSON output stream.

maws2json Usage examples Over serial line (stdin pipe) Lets assume that Vaisala weather station is connected via RS232 to USB serial dongle in /dev/tt

Sääsivu 0 Feb 6, 2022
Reads JSON object (stream) from file/stdin and routes it/them to GCP Pub/Sub topics.

json2pubsub Publish JSON object (stream) into GCP Pub/Sub topic based on a field value. Usage: json2pubsub --project=STRING <mapping> ... Reads JSON

Sääsivu 1 Feb 16, 2022
A simple Go library to toggle on and off pac(proxy auto configuration) for Windows, MacOS and Linux

pac pac is a simple Go library to toggle on and off pac(proxy auto configuration

null 0 Dec 26, 2021
A toy project to stream from a Remarkable2

goMarkableStream I use this toy project to stream my remarkable 2 (firmware 2.5) on my laptop using the local wifi. video/demo here Quick start You ne

Olivier Wulveryck 112 Aug 11, 2022
V3IO Frames ("Frames") is a Golang based remote data frames access (over gRPC or HTTP stream)

V3IO Frames ("Frames") is a multi-model open-source data-access library that provides a unified high-performance DataFrame API for working with different types of data sources (backends). The library was developed by Iguazio to simplify working with data in the Iguazio Data Science Platform ("the platform"), but it can be extended to support additional backend types.

null 23 Mar 3, 2022
Stream Camera based on TCP

streamera Term Project of Computer Networking streamera is a Stream Camera based on TCP, which contains client mode and server mode. Features Client M

null 7 Jul 25, 2022
Stream processing stuff for Go

GoStream Type safe Stream processing library inspired in the Java Streams API. Table of contents Requirements Usage examples Limitations Performance C

Mario Macias 50 Aug 8, 2022
Reflex stream client for redis streams

rredis A reflex stream client for a redis streams using the radix client implementation. It provides an API for inserting data into a stream and for c

null 0 Oct 5, 2021
A simple Go server that broadcasts any data/stream

broadcast A simple Go server that broadcasts any data/stream usage data You can POST data. curl -X POST --data-binary "@111.png" localhost:9222/test.p

Zack 11 Aug 6, 2022