CNCjs and Stream Deck

I’ve been using the Stream deck(Link Here) as a controller for CM for a while now. Recently I’ve started the move from CM to CNCjs and I figure 'hey why not bring the Stream Deck(SD for short) over to js? ’ I’ve looked around and seen one or two other people that have done something similar but nothing quite fit what I was looking for.

I figure that whatever I do I’ll make available to the C3D community; so why not have a choose your own adventure story? Over the last month of tinkering I’ve come to 3 options, ‘The easy way’ , ‘The open source way’ , ’ and the ‘powerful but hard way’. I can’t guarantee this will have all the features crammed in, or that this will be quick. I can guarantee this will be as fun as drinking a beer and watching a dumpster fire roll down a hill :rofl: .

So here are the option:

  1. The Easy Way:
    Use Elgatos software to make a set of pages with all the needed buttons, everything is set to a hotkey in CNCjs. I will release the Profile and the hotkey file for CNCjs.

    Pros- Quick, easy, guaranteed to work, user customizable.
    Cons- No fancy key settings, limited to sending keystrokes only, Can only be used on PC and OSX.

  2. The Open Source Way:
    I use a Python module and hardcode each page/ key/ and keypress. The Stream Deck sends key presses to CNCjs. I release the Python script and hotkey file for CNCjs.

    Pros- can do fancy key presses (i.e. mm/in key will change what’s displayed for all keys), It can work on any thing that can run Python: PC OSX Linux RasPi.
    Cons- Lot’s of code, to change anything you need to edit the code directly, you need to know how to install python and setup the required dependencies.

  3. The Hard Way:
    Again I use a Python module to do everything. This time I include the code to make it a client for CNCjs. this means we can directly send G-code commands like any other web pendant. We can even display status on keys based on what CNCjs is doing.
    Pros- It can do a lot of cool things even stuff that has no hotkey in CNCjs, it can run on any OS even remote computers, by far the most powerful option.
    Cons- Lot’s of code, to change anything you need to edit the code directly, you need to know how to install python and setup the required dependencies.You might need to edit the code/ a config file each time you reboot or reset the computer…

So what do we think? Is anyone other than me interested in this?


Which size Stream Deck(s) are you planning on supporting?

I’ve been debating getting one for a while now, but waffling on size.

I have the original. The mini would be far too few buttons to be useful for this application. I would like more keys, but that’s mostly for using it in CAD software, and even that I would struggle to fill all the spots on the XL for most applications. it might prove a little more useful for something like a controller, but I personally couldn’t justify the additional expense…
I will be developing for the Classic, first because it’s what I have on hand. Second I feel like that is the price point most people would go for. But my understanding of the Python API, is that if I were to deploy something built for the original on an XL it would display normally except unused keys would be be black.

I will say that if you’re planning on using it with carbide motion it is quite handy, and has this I’m pressing the button if a Hass sort of feeling…
Personally I do not regret my purchase. Somewhere down the road I might buy a second one for my computer, and dedicate my current one just to the CNC.

1 Like

FWIW and since you’re asking, my opinion on the matter:

  1. I would not do the EasyWay because if I’m going to spend $$$ on a StreamDeck, I definitely want it to be able to do more than keypresses a 15$ wireless keypad could do.

  2. the OpenSourceWay is still limited to keypresses (fancy as they could be) implemented in CNCjs, and I found that to be lacking. You’ll find yourself adding code to CNCjs in no time.

  3. The FunHard way: you’ll be able to use CNCjs as a tunnel to the controller and send arbitrary G-code macros to the machine. Yay! Also, when CNCjs goes out of style, you will just have to adapt your code to use NewFancyGCodeSender2022 as a G-code gateway, rather than having to throw away hundreds of lines of CNCjs-specific-shortcuts code. If you are going down that road, and while it’s perfectly possible to do in Python, I found it easier to just go with the wind and use the CNCjs pendant boilerplate code (Node.js). While I’m a Python guy at heart, it was just quicker to learn just enough (broken) javascript to get things to work, than navigating the poorly documented way CNCjs websockets work in Python and finding the right key and…[insert sound of breaking glass and computer flying out of the window]. If you want to get a feel of how a CNCjs pendant that sends G-code snippets looks like, I have documented mine here (the code is linked in there somewhere)


It sounds like you arrived at the same place I did with options 1 and 2.

Before posting this I wanted to make sure I knew what the API was that CNCjs used between client and server, AND how to send commands. I can’t stress enough how much your post helped. I’ts basically what I used to build up some test code. :+1:

This is the point I’m at right now… why they used sockets in place of GET and PUT I’ll never know.

Doing this in js brings up two problems. First, to do this in js I’d have to write the HID library, the image converter, and thread safe interrupts for the stream deck all from scratch and in javascript.
Second, I have developed an irrational, deep, loathing of javascript. Just looking at the boiler plate makes me ask “why would someone make syntax like that?” :confounded: :sob:

Of course there’s always the option of using the boilerplate as a go between. Make it do the work of sending commands over sockets, and setting up the hostname/ comm port. Then, make the stream deck send commands to, and get information from, the boilerplate app. Doing this requires communication between js and Python so that problem still exists…

I personally think option 3 is going to be the way to go though.


(Sorry people, geeky post ahead, feel free to skip)

Should you go the Node.js way, you have node-HID available (which some of the CNCjs pendants use if I recall correctly).

Image converter: you lost me there, what images would you be managing? dynamic generation/updating of the streamdeck’s icons ?

Thread safe interrupts: you lost me there too, but that’s because I have no idea how the Streamdeck API works.

Ok, I’m going to go off-topic for a second. I would have stated the exact same thing 6 months ago. The pendant was a first (and short) encounter with Node.JS, which turned out to be pleasing because it worked and felt easy (well, easy to hack). But what really changed my mind is when I decided a couple of weeks ago to completely redo the user interface of my “do-it-all” touchscreen at home, from scratch. I stumbled upon the MagicMirror framework, which looked fantastic and easy and…turned out to be based on Node.JS.
So I took a deep breath, read a great online book, and to my utter surprise, two weeks later I was done, custom modules development included. While I had literally spent months coding the initial version in Android a few years ago…(and oh my, does Android development s***)

The JS debugger in Chrome developer tools is just wonderful.
I guess what I’m saying is, IF it can help you at some point, give it a chance.

(OK back to your topic!)


You have a point, it wasn’t long ago that I said something along the lines of " What monster made a language where the types are implicit" and here I am with Python.

HA! I made a “quick little app” on Android a while ago, and ended up with the same feeling.
Is that project of yours documented anywhere it looks awesome!

With the Python implementation of Stream Deck(SD from here on out) the application on your computer is responsible for; telling the SD what to display, what to do when there is a key press, and acting upon any keypress events from the SD. So the procedure is to generate the keys, then load them to the operating system on the SD, then wait for any key press events that require servicing.

You got it! They use the Pillow library to convert and resize the .pngs/gifs you provide to a size and format that the SD can display. I’d be surprised if there wasn’t an equivalent function in Node to do the same thing. That said it would still require setting things up in Node where in Python it’s ready to go.

You know what, at the end of that last sentence I just thought ‘WOW I’m surprised no one has done this in node’, it seems like the perfect application… well I just did a google and guess what? npm install --save elgato-stream-deck

Yup, that’s right folks, let this post be a lesen. First, if you only have a hammer everything looks like a nail… I know Python so clearly there are no other options but python. Second it’s always best to admit your mistakes in public, instead of looking like an a** you give others the opportunity to learn.

@Julien I guess it’s time for me to suck it up and go get lost in the node js woods… Once I get a little further along I’ll shoot you a github link. I’d love the help of someone more experienced if your up for it.

1 Like

Since I can’t help documenting what I do in excruciating details, actually I did, it’s here

Shoot, I had my gismo addiction under control and now I want a Stream Deck :slight_smile:

I’m definitely up for it but don’t count on the “more experienced” part too much, at this point I’m just able to spit out beginner-style/hackish JS (I can almost feel experienced JS devs rolling their eyes when I’m coding that stuff). Man I miss the 90’s when a hundred lines of assembly could make you king of the hill.

1 Like

Excellent…Excellent [evil laugh here] :grin:!!!

in the words of one of my personal heros “Give yourself to the dark side…”

Great, you’ve reignited my PTSD from the micro computers course in university. Think of a mechanical engineer learning assembly… :grimacing:


Putting the technical approach aside for a second…

What sort of things do you send to (presumably a CNC machine) that would require this sort of malleable UI? How often do you send them, and what’s the advantage in this scenario of having a mutable LCD screen on a button instead of (say) a printed sticker on a button?

Here’re two dynamic things I’d want a Stream Deck setup to offer:

  • display current machine position (both absolute and in current coordinate space) on a set of otherwise dead buttons
  • movement buttons display (in parentheses, when a specific increment of movement is selected) the relative position which pressing them will move to
1 Like

Interesting. I’m curious as to how would you fold this info into a workflow? I would have thought that most times when positioning the machine it would be relative to something on the bed and the numerical value of the position in itself is of limited use. How do you use the coordinates?

I would want absolute machine position for those occasions when I am working up a new fixture design — I try to do them in absolute machine coordinates, but I want also set them up relative to a local coordinate system (usually one of the rapid position points) — having both sets of numbers displayed w/o having to click on the interface to switch and switch back would save me a bit of time/effort.

Ah… I see. That makes perfect sense! Thanks.

My preference in such a scenario would be to see the position on or near the spindle. Be great to put one of those tiny laser projectors somewhere on the axis so it projected statistics (and maybe a grid) onto the bed.


@Gerry Damnit… now I need to go down to the basement, dig out all my lasers… :joy:

Ooops. :slight_smile:

Well… maybe instead just a small OLED panel attached to a wifi-enabled MCU and bolted onto the spindle mount? Much simpler.

This topic was automatically closed after 30 days. New replies are no longer allowed.