This is a Node.js server that exposes @barelyconcealed's 1000 Button Project hardware as a web API available over HTTP and/or WebSockets. Just about every programming environment on the planet can make web requests.
Made for the 100 Button Jam.
- Download the latest binary release.
- Unzip it.
- Copy
config.json.example
toconfig.json
. - Start the server by running
buttons-are-cool-gateway --testmode
- Visit http://localhost:3000 to view the test UI.
- Open the same link in another tab/browser/device. Tapping button numbers in the second copy will make those buttons light up in the first copy. Use this later to test your application.
- Download the latest binary release.
- Unzip it.
- Copy
config.json.example
toconfig.json
and edit it. Enter the serial port(s) the button board is connected to. (You can list all available serial ports by runningbuttons-are-cool-gateway --list
.) - Start the server by running
buttons-are-cool-gateway
. - Visit http://localhost:3000 to see a live visualization of the button board's current state.
You're all set! Use any web or HTTP library in any language to connect to
http://localhost:3000/buttons, then decode the JSON for use in your own
software. You can even rip out the contents of /public
and add your own
web page and javascript there. The server serves any files in /public
.
Or use WebSockets. Connect to ws://localhost:3000 and listen for button press events. They're faster and more efficient than polling.
If you want to modify the server, follow these instructions to set up your development environment.
- Install Node.js and npm.
- Download the latest release (or use the green button at the top right to download or clone the repo).
- At the command line, switch to the project's folder.
- Install yarn:
npm install -g yarn
(optional) - Install project dependencies:
yarn install
(ornpm install
) - Copy
config.json.example
toconfig.json
. - Edit
config.json
; enter the names of your serial port(s) that have button controllers attached. (Leave the defaults if you're testing without hardware.) - Start the server in test mode:
yarn run test-server
(ornpm run test-server
) - Visit http://localhost:3000 to see the test page.
- (with hardware attached) Start the server with the button board attached:
yarn run server
- (with hardware attached) Reload http://localhost:3000 and see that pressing buttons updates the UI.
See config.json.example for details.
The WebSocket address is ws://localhost:3000/
.
WebSocket events arrive as stringified JSON to the WebSocket's onmessage
handler. The JSON objects represent events. Events have a name
and other
associated attributes.
Sent once, immediately after connecting to the server. Lists the states of all
devices and the buttons attached to them. You can get the same information with
an HTTP GET to /buttons
.
{
"name": "deviceStates",
"devices": [
{
"name": "COM1",
"buttonCount": 4,
"buttons": [
false,
false,
false,
false
]
},
{
"name": "COM2",
"buttonCount": 4,
"buttons": [
false,
false,
false,
false
]
}
]
}
Sent once, immediately after connecting to the server. Indicates whether the
server was started with --testmode
. In test mode, the server doesn't try to
open serial ports to talk to real button board hardware.
{
"name": "testMode",
"isTestMode": true
}
Sent when a button is pressed.
{
"name": "buttonDown",
"deviceNum": 1,
"deviceName": "COM2",
"buttonNum": 5
}
Sent when a button is released.
{
"name": "buttonUp",
"deviceNum": 0,
"deviceName": "COM1",
"buttonNum": 8
}
Here's an example JSON payload returned from a regular GET request to /buttons
(trimmed for brevity). The button list is an object with numeric keys because
all button numbers can be remapped non-consecutively via XML. Stock config uses
the XML mappings from the 100 Buttons sample Unity project.
{
"testMode": true,
"devices": [
{
"name": "COM1",
"buttonCount": 4,
"buttons": [
false,
false,
false,
false
]
},
{
"name": "COM2",
"buttonCount": 4,
"buttons": [
false,
false,
false,
false
]
}
]
}
This server's designed to talk to a dirt-simple Arduino sketch (original) that polls input pins and assembles multi-byte bitfields representing those inputs' states. A complete state packet might look like:
02 00 00 00 00 00 00 01
Bytes arrive in that order, left to right. The least-significant bit (LSB) of each byte is reserved; only the top 7 bits of each byte represent Arduino inputs, with 1 for "button down" and 0 for "button up". A byte with the LSB set is an end-of-message indicator, meaning you can append it to the last 7 bytes you received and start decoding the full bitfield.
Each Arduino can serve around 50 buttons. The 100-button board uses two Arduinos that appear as separate serial ports. This server treats each as a separate, numbered device with its own buttons.
- Every development platform and language has a way of talking to the web, so this opens up the 1000 Buttons hardware to lots of potential users.
- The server's not that complex, so it should scale well. Y'know, probably. If not, there's room to optimize.
- Multiple clients can connect at the same time.
- Clients can connect over a network.
- I got to play with neato Javascript features like async/await, generators, and iterables when I was implementing the server.
- Polling latency is bad if you're not using WebSockets. You can poll pretty fast, but you can't possibly poll ths server fast enough for a fighting game to feel good. Definitely use WebSockets if you can. If not, maybe there are other kinds of games you could make?
Likely stuff:
- Deprecate the XML button mappings in favor of
config.json
settings.
Less-likely stuff:
- Add support for server-sent events?
- Add support for gRPC?
- Add support for stdout?
- Add support for named pipes (Linux, Mac)?
- Add support for ZeroMQ?
- Add support for IFTTT?
- Add an example Electron desktop app project?
- Turn this into an npm package, maybe? I dunno.
- Thanks to @barelyconcealed for a cool and ambitious hardware project. So many buttons.
- Super Soul for the example Unity project I examined for info about decoding the serial protocol
This code is licensed under the WTFPL. See LICENSE for details, then Do What You Want.
I like getting credit when you use my stuff, but in this case, you do you.