Hacked Together Coffee Pot Control Protocol
Contents
Background
For HackUMBC 2016, the Hackafé crew built an automated coffee maker. This system consisted of a single-cup coffee machine which was then rigged up with pneumatics to open the K-cup receptacle and insert a cup, and a lazy suzan with a servo to serve as a turntable to place multiple cups under the coffee maker. To control the coffee maker, we set up a website and Amazon Echo voice controls.
The Setup
Our initial plan when we arrived at the hackathon was simply to build an automatic coffee maker. We showed up armed with an off brand Keurig-type coffee maker, pneumatic pistons and compressor, some pieces of wood, and, of course, our usual arsenal of Raspberry Pis, Teenseys, variable current/voltage contol power supply, and sacrificial cat-5 cable. Now, normally, with no outside influences, we probably would have just written all of our servers in Python, and possibly run them all on the Raspberry Pi that was attached to the cart that our coffee machine was built on.
Except…
Many hackathons have prizes other than the usual first, second, and third, typically privided by one particular sponsor for some challenge that they set, like “coolest use of our company’s web hosting” or “most awesome use of Raspberry Pis” or “most interesting use of our company’s data-mined data”.
One of the sponsors, BookHolders (which always has interesting sponsored prizes), had a prize for the group with the longest stack name (a software system’s “stack” in this case means the set of technologies that it is based on – a commonly known one is the LAMP stack for web servers: Linux, Apache, MySql, PHP). Challenge Accepted:
That is the stack diagram which we drew up on the white board at the hackathon. It can be broken down into the web client side, central server, coffee machine server, alexa server, hardware controller, and hardware.
The Web Client
Our goal with the web client was to support saving drink setups, that is, how much sugar or creamer to add to a coffee, and to support scheduling drinks to be brewed at particular times on particular days of the week. That way one could, for example, schedule their coffee to always be made for them when they get up in the morning.
The web client was written using AngularJS. Angular essentially implements a model-view-controller all in the client javascript, by providing a system to create templates on the client side and then automatically updates the web page being displayed as the model changes. This makes it really easy to support dynamically updated web pages with Angular. In fact, with Angular, it’s fairly ealy to develop a website that serves a single initial HTML page, and then simulates all the rest of the pages on the client side using REST api calls and client side templates.
The styling for the web client was Material Design, provided by a handy Angular library, Angular Material. The code for the front end lives in the frontend folder.
The Central Server
We didn’t actually do anything for it at the hackathon, obviously, since we only had one coffee machine, but in theory, different people could own different coffee makers, in different places. The simplest way to handle this sort of thing would be to have every coffee machine host its own web portal on the local network and let users connect to it at home, probably by IP address. There are some obvious drawbacks to this. For one thing, users wouldn’t be able to schedule coffee while out of the house, or hit the “brew now” button on the way home to have their coffee ready just as they arrive. More tech savvy users could probably set up all the necessary port forwarding to get remote access, but that’s inconvenient and requires you to know your home IP address or have a home domain name.
The reason it’s usually not possible for an outside computer to reach a server on the local network is because a typical home router does what’s called Network Address Translation; it gets a single IP Address from your ISP, and then gives all your local computers local network IPs, which aren’t visible from the internet. When a computer behind the router makes an outgoing connection, the router changes the IP address and port values in outgoing packets to its own, publicly visible IP address, and then changes the values back when it receives a response. This allows for computers inside the local network to initiate connections to outside the local network. To allow computers outside to initiate connections with computers behind the NAT, the router has to be told to send all external requests to a particular port on its public IP to a particular internal IP (i.e. port forwarding).
Or, you can do what’s called NAT Punch-through. All this means is that, in order to receve messages from outside the local network, a machine on the local network first connects to an external server that does have a public IP address. Then instead of directing traffic to the home router to be port forwarded, clients send data to the public server, which can then send it to the non-public machine that has connected to it.
In our case, this is done by having the central server, the same one that serves the client-side UI, also serve as a NAT Punch-through server. The local coffee server connects to the central server running on Amazon Web Services, and then the central server can send commands back to the local coffee server as long as the connection stays open.
This opens up a lot of possibilities. By having the central server register each coffee machine that connects, it is possible to present a web UI that can control multiple coffee makers in different places. A user can have several coffee makers and select which one to brew on (perhaps they have one at home and one at the office). Besides not needing to set up port forwarding, users could all use the same URL to connect to their individual coffee machines, registered to their individual accounts (with sharing a possibility). This makes the control interface easy to remember for the user – just go to the coffee website, everything else is taken care of behind the scenes.
The central server is written in Go. It runs on an Amazon Web Services instance, and uses SQL for storage, through the Go Object Relational Mapper (gorm). We chose to run on AWS and use Go to add additional languages and services to our stack. The server presents a REST api which is used by the client-side code to send and receive data, and by the Amazon Echo component to send requests through to the local coffee maker. For NAT Punch-through, the Go portion presents a websocket server and communicates with the Python on the Pi by exchanging JSON messages. The central server lives in the awsserver directory.
The Coffee Machine Server
This is the portion of the coffee maker system which runs on the Raspberry Pi attached to the coffee-maker cart. The coffee machine server handles both connecting out to the Go webserver via websocket and connecting to the Teensey hardware controller via serial.
The local coffee server doesn’t know anything about coffee schedules or saved drink recipes. It just waits for the central server to send it a JSON message with a drink to brew, and its only job is to send the right commands to the Teensy to get it brewed. It does do some tracking of the state of the coffee maker, but it doesn’t currently handle timing.
The local coffee server is written in Python and uses Python 3.5’s new async
and await
syntax for handling websocket requests asynchronously. It uses the
websockets library for (surprise) websocket communication, and
PySerial (double surprise) for serial communication. The coffee machine server
lives in the coffeeraspi directory.
Hardware Controller and Hardware
The hardware controller pretty much directly controls the various relays that make the coffee machine work. It runs on a Teensey, which is a small usb development board with an ARM chip, which makes it much more powerful than an Arduino, while still capable of realtime operations, since it doesn’t use an operating system. To control the pneumatics, we got electrically operated valves, and to activate the coffee maker, we took it a apart and wired a relay in parallel with the activation button so we could switch it electronically. The code for the hardware controller lives in the teensey directory.
To physically operate the coffee maker, we used two pneumatic pistons. One was mounted above and behind the coffee maker, and was used to open and close the lid. One was mounded in a track in front of the coffee maker, and was used to dispense additional K-cups. The K-cup dispenser was a vertical PVC tube mounted above the track which would drop a cup into an additional section of PVC which was attached to the piston. When the piston pulls back, it opens the bottom of the magazine and cup drops down. When the piston moves forward, it pushes the cup out over the coffee maker. To remove cups, we used a blast of air from a nozzel to lift the cup out.
In order to be able to brew multiple cups of coffee, we mounted a servo in the middle of a lazy-suzan and placed it under the coffee nozzel. It could be loaded with multiple mugs and could be controlled by the teensey to rotate different mugs under the nozzle to allow the machine to brew multiple cups of coffee without intervention.
Alexa
The Amazon Echo is a high quality directional microphone attached to Amazon’s voice recognition system. The base system can be used to play music from one’s Amazon music library or order things from Amazon using voice commands. The interesting thing for us, however, is that Amazon provides an API whereby the system can be configured to send requests to other systems in response to certain voice commands. In the case of the coffee maker, those special commands would be something like “Alexa, tell breakfastime to make me a coffee.”
Amazon processes the voice recognition, then sends the command result to a server you specify. In our case this was a Raspberry Pi in the Hackafé cloud, which would process the data sent from Amazon using pyalexa, then make a brew request out to the central server, which would pass it along to the local coffee server, which would brew your coffee.
The Stack Name
So alltogether, our stack consists of:
AngularJS/Angular Material communicating via AJAX/REST with a Golang server on AWS storing data in SQLite3, communicating with a Python server on a Raspberry Pi via JSON over Websockets, which communicates with a Teensey over Serial, which operates the Pneumatics, as well as an Amazon Echo which communicates over the REST api with the Go server.
(In case you’re wondering, yes, we did win that prize).
Extras
The coffee-machine cart had a number of extras attached to a network-connected power switch box – essentially a big power strip with the ability to turn individual outlets on or off in response to network commands. In our case, these were GET commands sent to the switch from the coffee server.
Among other things, the switch was able to control a large fire-alarm bell and strobe light. This makes it not just a coffee machine, but a morning machine. Not only does it brew your coffee for you, it makes sure you wake up as well.
In Action
We have a few videos of the coffee machine in action.