Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Notes on the Stream Deck HID protocol

Stream Deck Protocol

How to interface with a Stream Deck device.

Synopsis

The device uses the HID protocol to communicate with its software.

Configuration

The number of keys can be determined from the HID device descriptors. There is currently no known provision to determine their layout or size. The buttons on the current version of the device (1.0) are arranged in a grid and numbered from top right through to bottom left as follows:

 ------------------------
| 05 | 04 | 03 | 02 | 01 |
|----|----|----|----|----|
| 10 | 09 | 08 | 07 | 06 |
|----|----|----|----|----|
| 15 | 14 | 13 | 12 | 11 |
 ------------------------

Note: the Stream Deck Mini was recently announced, with six buttons. I'll incorporate information about this device as and when I am able.

Host to Device

Feature reports

0x0B RESET

0B 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00

0x05 SET BRIGHTNESS

The brightness on the device is controlled with PWM. This results in a non-linear correlation between set percentage and perceived brightness, and lower values have the most effect.

PC = PERCENTAGE (0-100)

05 55 aa d1 01 PC 00 00 00 00 00 00 00 00 00 00
00

Output reports

0x02 SET KEY IMAGE

Images are 72x72 pixels (5184 pixels total) arranged in a BGR format with 3 bytes per pixel (15552 bytes total).

Images are sent to the device in two packets, the first containing 2583 pixels (7749 bytes) and the second containing the remaining 2601 pixels (7803 bytes). Each packet is a total of 8191 bytes.

Each packet comprises a header and a chunk of image data. The header contains:

  • The index of the key being set (zero based)
  • The packet sequence number (one-based)
  • The previous packet's sequence number (zero if there is no previous packet).

The first packet also contains some extra information that the second does not, the purpose of which is currently unknown.

Including headers, each image packet is exactly 8191 bytes, padded with zeros where appropriate. This leaves up to 8121 bytes available for image data in the first packet and 8175 bytes in the second, but for some reason the official software only sends a maximum of 7749 in the first packet and whatever is left in the second.

I'm assuming that either the device assumes the first packet will contain this amount of data, or that one of the values in the header specifies how long it will be. Experimentation needed.

Header
SE = PACKET SEQUENCE NUMBER
PR = PREVOUS PACKET SEQUENCE NUMBER
KI = KEY INDEX

02 01 SE 00 PR KI 00 00 00 00 00 00 00 00 00 00
First packet

Includes 54 bytes of "extra" information.

.. HEADER
42 4d f6 3c 00 00 00 00 00 00 36 00 00 00 28 00
00 00 48 00 00 00 48 00 00 00 01 00 18 00 00 00
00 00 c0 3c 00 00 13 0e 00 00 13 0e 00 00 00 00
00 00 00 00 00 00
.. 7749 BYTES OF IMAGE
.. ZERO PADDING UP TO 8191 BYTES
Subsequent packets
.. HEADER
.. REMAINING BYTES OF IMAGE
.. ZERO PADDING UP TO 8191 BYTES

Device to Host

Feature reports

0x03 SERIAL

BYTE 6 ONWARDS CONTAINS SERIAL

03 55 aa d3 03 41 4c 31 32 48 31 41 30 37 38 31
36

0x04 VERSION

BYTE 6 ONWARDS CONTAINS STRING VERSION

04 55 aa d4 04 31 2e 30 2e 31 37 30 31 33 33 00
00

Input reports

0x01 KEY STATE CHANGE

When any keys are pressed or released, the device sends an interrupt containing a bit map of the all the current key states. Presumably this means that multiple buttons can be pressed at once, though I haven't yet tested this.

Key 0B pressed (11th)
01 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00
00
Key released
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00

Snooping

Communication between the device and host can be snooped using Wireshark. Please read this page for information on seting up USB capture.

When snooping USB you'll find that there's a lot of chatter from your hubs and other devices, and you'll need to filter it all out to isolate the StreamDeck. To do this, begin by filtering for usb.idVendor == 0x0fd9 && usb.idProduct == 0x0060, which will give you information about the device. Then simply filter "USB device index" to show the relevant packets for your device.

@WitoTV

This comment has been minimized.

Copy link

@WitoTV WitoTV commented Aug 1, 2019

Thanks for the info. I'm gonna use this to make my own raspberry pi zero based "fakedeck" working with current Elgato software 👍

@kinsi55

This comment has been minimized.

Copy link

@kinsi55 kinsi55 commented Jan 5, 2020

@WitoTV soo, anything working you ended up with? :D

@WitoTV

This comment has been minimized.

Copy link

@WitoTV WitoTV commented Jan 5, 2020

@kinsi55 sadly nope. I'm getting stuck at windows not seeing the device as stremdeck even though I set vendorID and productID to match the stremdeck ones. It may be my fault becuase I'm not a master of writing usb devices. Sadly I don't have anyone from my circle of firends who can help me with this so I gave up for now.

I based my thing around RP Zero and https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget?view=all#other-modules + http://www.linux-usb.org/gadget/

@kinsi55

This comment has been minimized.

Copy link

@kinsi55 kinsi55 commented Jan 5, 2020

@WitoTV thought about giving this a try with a Teensy, seems like a more sane approach than using a Pi for it (I think an Atmega / Arduino would be too slow for it in regards to updating the LCD). I dont have a Teensy (Atm) but since its inter-compatible w the Arduino ecosystem (Just slower) I might give it a try.

What was your device recognized as anyways? And where did you source the vendor / product ID from?

@WitoTV

This comment has been minimized.

Copy link

@WitoTV WitoTV commented Jan 6, 2020

@kinsi55 My device was seen as generic hid interface (no more info was given by the system). I have a friend with streamdeck who found vendor / product ID for me, but they seem to match with the ones provided at the end of this gist.

@WitoTV

This comment has been minimized.

Copy link

@WitoTV WitoTV commented Jan 6, 2020

@kinsi55 if you somehow succeed send me some more details.

@kinsi55

This comment has been minimized.

Copy link

@kinsi55 kinsi55 commented Jan 6, 2020

@WitoTV Sure, if I get around to trying this and have any success I'll let you know. Thanks for now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment