Open source StreamDeck alternative
Tags: productivity, opensource, node, programming
Published: 2023-02-16 11:26:31

I've always been attracted by StreamDeck for developers productivity.

* Mute/unmute microphone ...*
* Open all the needed applications when starting the day at once ...*
* Write log-in information (user/password) ...*

*... with a single click of a button

**But**, you must buy a hardware of thousands of € or pay a smartphone app (monthly 2.99€) just for testing. Only works for windows & mac and writing plugins is not very straighforward (at least for me).

It is very important for me to create my own plugins

## Alternatives

I know there are some alternative solutions that works with smartphones such as [touch-portal](https://www.touch-portal.com/) and [macrodeck](https://macrodeck.org/) but they have some things that I don't like.

* They are closed source (Maybe macrodeck is now open sourced? If it's so, too late, I'm on my way!).
* You have to install some dependencies (java and .net) to run them.
* There is no solution for linux machines
* They have a complex system to create plug-ins (install SDK, create a package...)

So, as any software developer, because the solutions out there weren't satisfing my needs 150%: I created my own solution!

## My own solution (a.k.a. Ideckia)

My main goal was to create a tool which was very easy to write plug-ins for it (and hack the existing ones). A tool which was able to work the same way in windows, macos and linux.

The first I though was the name :-) I had the perfect name for it: **ideckia**

[irekia](https://hiztegiak.elhuyar.eus/eu_en/ireki) means "open" in my mother language, Basque. And `deck`... well, you get the reference, right?

After that come the minor things, the plan for the app:

* Create a server in the computer with duplex communication for the client (smartphone, desktop...).
* Save all the data in a plain json file. Human readable, no crypto-data
* Use NodeJS as it is cross-platform
* Make the actions (or plug-ins) in a single JavaScript file
  * The actions may match a structure which the server expects to call some functions: initializing, item-pressed...
  * As the actions are Javascript files, you can use the vast library from npm
* Load the actions to run at startup from a directory. Making them interchangeable/hackable.

I will dig in the server, actions and client.

### Server side

These are the core concepts of the app:

* Layout: Bunch of items
* Item: An element that has a single or multiple states. It is clickable in the client.
* State: Definition of the item status: text, textColor, bgColor, icon and an action list.
* Action: Action which will be fired (can be more than one in a state) in the host computer when the item is pressed in the client.

The server is a simple app which reads a JSON file which defines the layout. The work of the server is to manage the current directory, send the needed information to show in the client. And when an item is clicked in the client, the servers runs the actions attached to that item or sets the directory to show. This server-client communication is done by Websockets.

The server directory tree looks like this

```
|-- ideckia         -> the app executable
|-- app.props       -> properties for the server (actions directory path, layout file path, log level, listening port...)
|-- layout.json     -> the layout information
|-+ actions         -> directory where the actions are stored
```

The layout can be edited by hand, but the server provides an integrated editor to edit your layout. Open the browser and go to [http://localhost:8888/editor](http://localhost:8888/editor) (the port is the one where the server is running). I know it is not the prettiest thing, but it does get the job done.

Now we'll see how are the actions internals.

### Actions

Actions sources are available in the `actions` folder usually (configurable via `app.props` file next to the executable). Every action is defined in it's own folder and an `index.js` file in it.

```
|-- ideckia
|-- app.props
|-- layout.json
|-- actions
|   |-- my_action
|       |-- index.js
|   |-- another_action
|       |-- index.js
|       |-- dependencies.js
|       |-+ node_modules
```

This `index.js` file must have this functions defined to be called from the server when loaded and executed:

* setup(props, server):Void
  * Server will call to this method to inject the configuration properties of the action instance and some convenient functions from the server.
* init(initialState:ItemState):Promise<ItemState>
  * The server will call to this once, to initialize what you need
* execute(currentState:ItemState):Promise<ItemState>
  * The server will call when the associated item is clicked.
* onLongPress(currentState:ItemState):Promise<ItemState>
  * The server will call when the associated item is long pressed.
* getActionDescriptor():ActionDescriptor
  * This method is used by the editor.

There are some default actions that comes in the default ideckia package:

* [Command](https://github.com/ideckia/action_command): Execute an application or shell file with given parameters 
* [Keyboard](https://github.com/ideckia/action_keyboard): Create hotkeys, write strings... A wrapper for [NutJs](http://nutjs.dev/)
* [Counter](https://github.com/ideckia/action_counter): Count how many times the item is clicked. Can be a countdown too.
* [Random color](https://github.com/ideckia/action_random-color): Generate random color and show it in the item.
* [Stopwatch](https://github.com/ideckia/action_stopwatch): Executing this action, will start and pause a timer shown in the button itself.
* [Timezones](https://github.com/ideckia/action_timezones): Show the time in the configurated timezones.
* [Worklog](https://github.com/ideckia/action_worklog): Log you daily work in a plain json file.
* [FTP-Connect](https://github.com/ideckia/action_ftp-connect): Connect to FTP in a simple and fast way.
* [SSH-Connect](https://github.com/ideckia/action_ssh-connect): Connect to SSH in a simple and fast way.
* [Open weather](https://github.com/ideckia/action_open-weather): Show the weather in the configured towns.
* [Clementine control](https://github.com/ideckia/action_clementine-control): Control [Clementine](https://www.clementine-player.org/).
* [Mute mic](https://github.com/ideckia/action_mute-mic): Mute / unmute microphone.
* [Toot](https://github.com/ideckia/action_toot): Publish a toot in mastodon.
* [Wait](https://github.com/ideckia/action_wait): Waits given milliseconds until the next action.
* [Countdown](https://github.com/ideckia/action_countdown): Countdown timer
* [Log-in](https://github.com/ideckia/action_log-in): Writes username and password and presses 'Enter' (this action uses [Keyboard](https://github.com/ideckia/action_keyboard), it is mandatory).
* [Color-picker](https://github.com/ideckia/action_color-picker): Show in the item the color of the pixel where the mouse is.
* [Obs-control](https://github.com/ideckia/action_obs-control): Control OBS Studio (replacing former [obs-websocket action](https://github.com/ideckia/action_obs-websocket))
* [KeePasXC](https://github.com/ideckia/action_keepassxc): Get write the username and password from [KeePassXC](https://keepassxc.org/). This action uses [Log-in](https://github.com/ideckia/action_log-in), it is mandatory.
* [Emoji](https://github.com/ideckia/action_emoji): Shows a random emoji every time is clicked

### Client

The server sends the panel information to any connected client. And those clients send to the server which item has been clicked. There is a [mobile client](http://github.com/ideckia/mobile_client) written in Flutter.

## What I've achieved

* Cross-platform application (windows, mac and linux)
* Portable (no installation needed)
  * Use [PKG](https://github.com/vercel/pkg) to create a single executable
  * light executable < 40MB
* modular and hackable
  * Any action can be changed
  * The editor can be easily stylized
* All the layout info in a plain json file
* Tons of NPM packages usable
* Easy to create and test new actions

More info [here](https://ideckia.github.io)