Building a Slack Printer for Remote Retrospectives

…with a little help from a Thermal Printer, a Raspberry Pi and Slack’s Slash Commands.

Besides having a good time tinkering, our new invention at Geckoboard — the retro printer — is also useful (and fun!) for our remote folks.

In this article, I’ll explain how we got a thermal printer to print messages from Slack with a Raspberry Pi. I’ve also included technical instructions for anyone who’d like to build something similar. I share all the pitfalls we encountered since that’s where we spent most of our time. ;) And I’ll show how it’s useful for people working at Geckoboard.

Retro printer prints its first words

The inspiration for the printer

At Geckoboard, the engineering team has a retrospective every second Wednesday where we mull over the past two weeks. To get the brain cells going, we start by drawing a timeline on the chalkboard and put up a few hints of activities or milestones that have happened.

Team members who are in the office that day write anything we want to discuss on some post-it notes and stick them onto the board. Inevitably though, there are always some members of the team working remotely, and we want them to be able to take part and to have a good experience too.

Up until recently, remote folks would nominate a surrogate (basically a proxy) to write post-it notes for them. Depending on how many people are working remotely that day and how many contributions they have, this can be a lot of writing and can take up a lot of time for the people in the office.

Chalkboard with retrospective cards

Tom Randle and I thought it would be fun and useful to try to automate this process. On one of our “Innovation Wednesdays” — when we set aside time to work on side projects every other Wednesday— we started looking into different approaches.

Our dream scenario would’ve been to print on post-it notes directly. Unfortunately, though, we couldn’t find a printer that would do that. Some people put stick post-its on a piece of paper and run that through a standard office laser printer. But that approach seemed a bit fiddly. Not to mention the risk of a post-it note falling off in the deep dark bowels of the machine.

After some research into the various options, we decided a thermal printer together with a handy Slack Command should be enough for now.

Below I’ll explain how we got the project working and will walk you through:

  • the hardware setup of the printer and Raspberry Pi
  • how we managed to print from the Raspberry Pi
  • how we use Slack Slash Commands to print messages
  • all the problems we encountered

If you’re familiar with setting up a Raspberry Pi, you’ve spent some time in the deep dark network jungle and if you’ve already had some decoding/encoding fun with Python, building a printer like this probably won’t be much of a challenge.

If you don’t have much experience with any of these though, it might be a little tricky, like it was for us!

Setting up the printer and Raspberry Pi

Hardware we used:

  • Thermal Receipt Printer (we got it from here)
  • Thermal Printer Paper (also from here)
  • Raspberry Pi version 1
  • 5V power supply (2A or larger) and DC jack adapter

Before getting anything done, we already encountered our first little issue. At first, we were using a Raspberry Pi version 3, which didn’t work because it doesn’t support the TTL interface used by the printer. That’s why we had to change to version 1 (the Raspberry Pi 2 should also be compatible).

After downloading and installing the Raspbian OS, we followed this tutorial from Adafruit. It effectively explains how to configure various additional settings needed by the printer and how to connect the wires and the power supply.

Tom connecting the wires

Finally, our setup looked like this:

Wiring of Raspberry Pi and thermal printer

Another big mistake we made was to power both the Raspberry Pi and the printer off a single 5V 2A power supply, which led to erratic printing. For two days, the printer was printing only one line at a time and we got really scared it wouldn’t support multiple lines. When powering both separately, it worked perfectly fine. We could probably get it all powered off a 5V 3A rather than having the Pi separate, but we’d have to do a bit of rewiring.

We also connected the Pi to the network to have access to the command line from our computer. Finding the Pi in the network can be a little bit tricky too, but you should be able to find it within a few minutes after it’s booted by typing the following command into the terminal of your computer:

arp -na | grep -i b8:27:eb

This gives you an IP address. If nothing shows up you’re probably on the wrong network! If something shows up you can now connect to the Pi with SSH:

ssh pi@ipAddress

Next, you’ll be prompted for the password for the Pi login. On Raspbian, the default password is raspberry. After hitting enter, you should now be able to execute commands on the Raspberry Pi.

Printing from the Raspberry Pi

Before getting our hands dirty, we wanted to verify it was possible to print with the setup described and depicted above. That’s why we executed the following command taken from Adafruit’s tutorial on the Raspberry Pi after connecting with SSH:

stty -F /dev/ttyAMA0 19200
echo -e "BOOM first line.\\n\\n\\n" > /dev/ttyAMA0

It worked! It was time to move on to the next step.

Printing text with the standard font and font size would produce very small text, not suitable for our retrospective as it should ideally be readable from some distance. We started to investigate how to print big text on a thermal printer, and it turns out there is no obvious or easy option.

We had some crazy ideas like creating a bitmap image with text and then scaling it before printing. Or, we could have created an html canvas, drew some text on it, and converted it to an image to eventually print it on the printer. After spending some hours and failing miserably, we went with a library provided from Adafruit. We downloaded the Adafruit_Thermal package onto the Pi and eventually got some bigger text with the following (admittedly easy) Python code:

from Adafruit_Thermal import *
printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout=5)
printer.setSize('L') # Set type size, accepts 'S', 'M', 'L'
printer.println('BOOM second line')

Use a Slack Slash Command to print

Finally, we wanted to connect Slack with the printer. We agreed on using a Slack Slash Command which allows us to listen for custom triggers across all Slack channels. When the Slash Command /print is triggered, we want it to make a POST request to a URL with relevant data.

That’s when we knew that we’ll need a public facing custom URL first, to expose our printer app on the Raspberry Pi to the outside world. There are some tools that will let you open such a window, but we chose ngrok. After downloading ngrok onto the Pi, we used the following command to create a so called tunnel:

./ngrok http 8089

This will output a temporary public facing URL in the terminal (http://a33ebdc6.ngrok.io in this example) that you can use:

Output of ngrok showing a public facing URL

The next step is to let Slack know the Slash Command exists. This can be done by creating a new Slack app where you can choose a command name (/print in our case) and have to fill out some details including the URL which we got from ngrok.

Now, we need a simple http server to handle the data coming from the POST request from Slack. We thought we’d take on the challenge and try using Python again for this:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class S(BaseHTTPRequestHandler):
def do_POST(s):
print "text"
# TODO print text from Slack
return
def run(server_class=HTTPServer, handler_class=S, port=80):
print "Run python server"
server_address = ("", port)
httpd = server_class(server_address, handler_class)
print "Starting httpd..."
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()

The code above prints some text when receiving a POST request from Slack. Then we needed to read the contents of the POST. Not so easy — and not tremendously obvious either since the BaseHTTPRequestHandler leaves processing the request up to you. In order to extract the content, we had to first determine the length of the content and then read the raw data and interpret it using a package called urlparse.

import urlparse
length = int(s.headers['Content-Length'])
post_data = urlparse.parse_qs(s.rfile.read(length))

Finally, we got the Slack response and we could see the text and the user name of the Slack message in our post_data object. The printer was printing text! Everything was perfect... until we typed in the first special character.

Printing ‘that’s weird’ from Slack

We had quite some fun trying to decode the text that’s weird correctly. Along the way it took on many different shapes.

Our attempts to print ‘that’s weird’

We finally found the response from the BaseHTTPServer is in unicode format and the printer only supports ASCII. Again, we discovered a handy package called unidecode, which converts text to ASCII characters and finds a similar character for unsupported ones.

import unidecode
text_response = post_data['text'][0]
text_decoded = text_response.decode('utf-8')
text = unidecode.unidecode(text_decoded)

And that’s it! Here is the final working printer script:

Maybe it’s obvious that it wasn’t easy, but we are exceptionally happy with the result. We have Googled and learned a lot along the way and it’s an absolute joy to use this tiny thing. Nowadays, on Wednesdays at retrospective time we set up the little printer and remote team members can contribute using the simple /print Slack Slash Command.

Each new message announces itself with a satisfying “printing sound.” The only thing left to do for the people in the office is to grab the paper from the printer and to stick it to the chalkboard with some adhesive material — we tried blue tack and masking tape, but we definitely need to optimize that part. Maybe we need magnets with funny faces on…

Retro printer is a taste of teleportation — Vivien, remote worker
Retro printer with a banana for scale

There are many opportunities for improvement with our printer. First of all, we could pay for ngrok to have a fixed subdomain so that we don’t have to change the URL in Slack every time we run the script. Furthermore, the printer script could boot whenever we start the Raspberry Pi.

We could support Slack emojis! We could print images, and even daily metrics from our own internal Geckoboard account. There could be a camera attached to the printer that takes a picture and prints it instantly at the push of a button... so many possibilities!

I hope you had fun while reading, and any comments are welcome!

PS: We’re hiring!