I was looking for a simple way to interact with the various machines in my house. A lot of the stuff that runs uses simple shell commands. I found a post on how someone did it with Go here: http://techfeast-hiranya.blogspot.com/2015/06/expose-any-shell-command-or-script-as.html
Previously, I've used mixed scripts to run tasks on remote machines over SSH or installed things like EventGhost on Windows to listen for events. While that stuff works, this is an easier way to manage things. So, I thought I would have it autobuild some common binaries for Windows, Linux, and MacOS through docker. https://github.com/leonowski/go-shell-api-docker
It autobuilds on Dockerhub here with this image name:
The container itself is just a dummy container. It won't actually do anything. The best thing to do is to just run it temporarily to copy the automatic builds out. For example:
docker run -v "$(pwd)":/temp --rm -it leonowski/go-shell-api-docker sh -c "cp -R /go-shell-api-bins/* /temp/"
Usage of ./go-shell-api:
Path to the executable binary
HTTP port to listen on (default 8080)
go-shell-api -b ls
This will start an HTTP server listening on port 8080. An HTTP get will return the output of the command 'ls' to the HTTP client.
To add parameters to the shell command, use POST:
curl -X POST -d "-ls /home/user" http://some-server:8080 (equivalent of ls -ls /home/user)
Practical Ways to Use This
I use Home Assistant home automation software to control everything in my home. It integrates with everything imaginable. Exposing things via HTTP makes things easy to work with. One easy thing to do is to use Home Assistant's Command line Switch integration. This allows me to define a switch using shell commands. My particular setup to turn on my Street Fighter V arcade machine looks like this in Home Assistant:
That example is probably bad. Going back and forth between shell and HTTP is confusing. I have since updated my config in Home Assistant to use a special "rest_command" feature along with something called a "light_template" to present the Arcade machine as a "light" in Home Assistant. That way, it understands "on" and "off" and Alexa knows about it too. So, it looks something like this in Home Asisstant:
set_arcade_on: url: 'http://192.168.1.254:8675' method: POST payload: 'ab:cd:6f:f2:04:ac' set_arcade_off: url: 'http://192.168.1.11:8282' method: POST payload: '1' light: - platform: template lights: arcade: friendly_name: "Arcade" turn_on: service: rest_command.set_arcade_on turn_off: service: rest_command.set_arcade_off
You can still use the command line features though in Home Assistant if you need to do something funky with your HTTP request and mix the on or off commands to use some combination. The flexibilty of Home Assistant is its strength. In this better example, I POST a mac address to an endpoint that will run WOL. This endpoint is actually running on my router so I never have to find a binary or do something funky to send a magic WOL packet. I just have to use a REST endpoint now! (I guess that would be another blog post).
The go-shell-api binary is run on startup by a Windows machine using a scheduled task. The command invoked is
go-shell-api.exe -b shutdown. So, when I ask Home Assistant to turn off the machine, it sends a POST to http://10.0.0.4:8080 with the data
"/s /t 0" which tells the machine to shut down immediately. To turn on the machine a wakeonlan request is sent to the specified MAC address. Finally, I can check the state of the machine using a script that calls nc to see if anything is listening on port 8080 on the remote machine. The value template simply checks the exit status of the script and if true, the machine is considered on.
Another way I use it is to control my sprinklers. My frontyard sprinklers are connected to an old Raspberry pi with some relay controlled by GPIO. I simply set up a new systemd unit file to start up with a command line GPIO command:
After that, I simply need to POST a 1 to turn on the sprinkler or a 0 to turn it off.
Now, you can do something crazy with all of this and have it run something like
sh. You can then post something like
"-c 'other commands'" That would then let you do anything you want - but that's crazy and you probably shouldn't do that.