Stream Deck for Developers

I've always been keen on creating shortcuts and macros for everything and this is how I'm using a Stream Deck XL to make things even easier.

Stream Deck for Developers

I've always been keen on creating shortcuts and macros for everything that I do on a regular basis to make things as easy as possible for myself. To date, I've mostly used Alfred to achieve this but, more recently, I've been running out of buttons on my keyboard and forgetting the various shortcodes I've chosen. I'd been hearing good things about the Elgato Stream Deck for a few years and thought it was probably about time I gave it a go for myself.

I've had my Stream Deck XL for just over a week now and I'm delighted with it. It's certainly taken me a fair amount of effort to achieve certain things but I am already noticing I am more efficient when working.

Everything from its name to the built-in actions and icons in the software really solidify who Elgato is aiming this at - and that's really not me. I went into this project suspecting that my experience of this would be very different from the target audience - firstly, I don't stream and, secondly, I don't use Windows. While Elgato do provide a macOS version of the software and support Mac users, many plugins on the store (including Elgato provided ones) are only available on Windows or lacking features when used on a Mac (for example, the Elgato Spotify plugin has significantly less functionality on Mac than it is on Windows).

For the remainder of this post, I'm going to just go through the key things I have setup on my Stream Deck and how I have achieved some of the less common actions.

My home screen

This is the main screen that other actions are all invoked from. From here I have access to open the most common applications I use plus access to a number of folders containing more actions for specific things (I'll explain some as I go down). Before we go into the folders, I'll just list the key actions I have on the home screen:

  • Home - I have two buttons to open directories. One is my user's home directory on my Mac itself and the other opens my home directory on my NAS server (where I put most things).
  • Spotify - as I use this for all music playing I have access to open spotify, play and pause the current track plus skip backwards and forwards to other tracks. For this, I'm just using the built-in Spotify plugin - this also loads in the current album art onto the play/pause button when something is playing which is a nice touch.
  • Key applications - I have a few buttons that simply open the key applications that I use on a regular basis. To be honest, I don't use these very often and they may well be removed because I find it quicker to open application using Alfred.
  • Calendars - I have two buttons to open calendars - one opens my Calendar app on my Mac and the other opens my work-specific Google Calendar.
  • Things/Tasks - I use Things for managing my own tasks and having buttons to open the app itself but also open the Quick Task Add screen is very handy.

If you've looked at the picture at the top of this blog, you'll probably notice a number of other icons on my home screen. Let's explore those.

Spotify Albums & Playlists

This folder provides me quick access to open Spotify playlists and albums that I enjoy switching between. These range from spotify generated playlists like Discover Weekly to albums for musicals that I enjoy listening to.

Unfortunately, the macOS version of the Spotify plugin does not support opening playlists automatically so to configure these on a Mac you need to use the Website action and use a Spotify URI. For example, spotify:playlist:4RJOqMomqF2Ckelqj7TlAV. This will simply open the playlist in Spotify but won't start it playing automatically which is a bit annoying.

Zoom

I have a Zoom dashboard which provides quick access to opening the Zoom app, muting/unmuting the microphone, disabling/enabling the camera and leaving meetings. This can be configured quite easily using the Zoom plugin.

Slack

If you use Slack then having a Slack dashboard has proved very handy indeed. I use this to quickly jump to workspaces, people, groups and channels that I use most often.

Setting this up is a little more effort than I would like but not too tricky. The easiest way is to open up the web-based Slack client, download the person's avatar and grab the team and chat ID from the URL. Once you have this, you can use the Website action to simply link to the Slack URI. For example: slack://channel?team=TUST9P1AB&id=DUV3LPALQ. You'll need to grab the team attribute too from the URI. If you just want to link to a specific workspace, you can omit the id parameter from the URL.

Google Docs/Drive

This is a simple one with just a few buttons to common documents that I need to access semi-regularly. I find Google Docs/Sheets navigation to mostly be a pain and can rarely find shared documents that I need so this has already saved me hours of hunting.

GitHub

This is just a very simple set of Website actions to key parts of GitHub that I use on a semi-regular basis. Including:

  • Links to the dashboard and repository lists.
  • Notifications
  • New Gist and Gists list
  • Links to repositories I look at on a regular basis (black are personal project, blue are work and green are other projects).
  • Linsk to manage teams and users on my work GitHub organization which I find myself having to do fairly regularly.
  • Create new repositories

Stripe Test Cards

If you ever have any business to work with Stripe for payment processing, this screen is an invaluable time saver. Using the Text action I've set up a set of buttons to simply type the card numbers for the most common testing scenarios. They're all colour coded based on the actual output. It takes a bit of copy & pasting but very worthwhile. You can grab Stripe test cards from their website.

Now things get trickier

Things were going well but I wanted to start doing slightly more complicated actions. I originally thought that an AppleScript plugin would be helpful and would simply allow me to execute AppleScript when needed. Unfortunately, the plugin seemed to be completely broken for me - it simply wouldn't execute anything and I couldn't find anything resembling a log so that had to go in the bin.

To add to my frustration at this point, there's no other option for simply just running a command on your system so I had to improvise. Such a command may exist on Windows but I haven't explored it too much yet.

My solution to this was to create a little web server using Sinatra and Ruby which I can run on my Mac and simply call endpoints on this web server at the push of a button. The Website action has an option to simply make the request without opening a browser which is perfect for this use case.  A side effect of this is now I have the option to pretty much do anything I want in a language that I enjoy at the push of any button.

Everything that now follows is implemented through this little web server...

Accessing servers using SSH

I occasionally find myself with a need to login to servers using SSH. We have a number of servers at work and remembering the correct hostname can always be tricky to having a screen containing my most comment servers is very handy.

The goal here is quite simple, I need each button to be able to provide a hostname, username and port which will be used to open a new tab in iTerm with the connection to that host. Because the AppleScript plugin didn't work, I implemented this through web server. Because of this, I am able to adjust the script for all buttons simultaenously without the need to update every button individually. (Side note: the UI for editting buttons in the Stream Deck software is awful).

I have an localhost:4040/ssh endpoint which accepts attributes and the runs the following AppleScript. I'll warn you now, I've never used AppleScript before so there may well be better ways to implement this!

property waitedForWindow : false
tell application "iTerm"
  activate
  if current window is equal to missing value then
    set waitedForWindow to true
  end if

  repeat until exists current window
  end repeat
  tell current window
    if waitedForWindow then
      tell current session
        repeat while not (is at shell prompt)
          delay 0.5
        end repeat
        write text "{{ ssh command }}"
      end tell
    else
      create tab with default profile command "{{ ssh command }}"
    end if
  end tell
end tell

Opening VScode Projects

My development environment is entirely remote from my workstation so opening VScode projects isn't simply the case of running code followed by the path to the project.

Using my web server, I have a simple endpoint that allows me to send the path to a project and then run the following command which will automatically open a VScode instance for the folder on my remote development server.

code --folder-uri vscode-remote://ssh-remote+devserver.adam.ac/home/adam/path/to/project

TeamSpeak

At work we have a TeamSpeak server which we can use to talk to each other when needed. Through the Stream Deck, I have the option to quickly switch between channels and mute/unmute my speakers.

If you're a Windows user, you're in luck - there is a TeamSpeak plugin which you can use to do all of this very easily. If you're a Mac user, like me, you're very much not in luck because the plugin isn't available for Mac.

I thought I better try and find a way to interact with the TeamSpeak client. TeamSpeak actually provide a TCP server called ClientQuery which can be enabled in the client allowing you to interact with it in exactly the way I wanted. I knocked up a quick bit of Ruby to support switching channel and muting/unmuting and popped it into my web server.

If you're looking at doing this, the port the ClientQuery TCP server runs on is 25639 and the actions you'll need to send are as follows:

  • auth apikey=xxx - this will authenticate you to the client and needs to be run first. You can get the API key from your TeamSpeak settings.
  • whoami - this will give you your client ID which you will need later
  • channellist - returns a list of all channels where you can find IDs which will be needed later for switching channels.
  • clientmove clid=xxx cid=xxx - where clid is your client ID and cid is the channel ID.
  • clientupdate client_output_muted=1 - will disable all sound output from your client so you can't hear anything
  • clientupdate client_output_muted=0 - does the opposite to the above and re-enables your audio.

Random Password Generator

I often find myself needing to generate random passwords for people when setting up user accounts in some systems. I have a button on my dashboard that will generate a random password and place it on my clipboard.

This isn't terribly secure but for generating temporary or one-time passwords it's very handy.

This is implemented through my webserver using my SecureRandomString  generator and pbcopy.

Conclusion

That's about all I have at the moment. I'm sure I'll find new things I can use this for as time goes on, after all, it's only been a week so far!