Firewerx

An excursion in Elixir / Phoenix / Raspberry Pi

The Impetus

Avvo hosts monthly lightning talks. Generally there are three to five presenters covering a range of topics; most are not work related and about varied topics such as Reading a room, Practical knot tying, and How to dig for the elusive Geoduck.

The rules of lightning talks are:

  1. Must be five minutes or less;
  2. Slides should be useful and understandable outside of the talk;

To learn more about Lightning Talks there is a great article written by Diane Geurts available.

When the call came out for presenters this time I started to consider what I could present. A glance around my desk showed the usual things: computer(s), synthesizers, micro-controller programming boards, and a Raspberry Pi 2.

Hmmm.

The Raspberry Pi has been sitting there running for a few months with little-to-no use. Could I do something simple and fun that could be presented in five minutes?

Raspberry Pi and General Purpose Input / Output

One thing that makes Raspberry Pi's interesting is the set of 26 General Purpose Input / Output (GPIO) pins. These pins allow connection with physical devices at a very low level. So it's not like attaching a keyboard, mouse, or other USB peripheral; think LEDs or simple switches.

Fundamentally a GPIO pin is either on or off. When the pin is 'pulled high' there is a voltage present. When the pin is 'pulled low' there is no voltage present. The voltage is usually 3.3V or 5V DC.

With an LED attached, when the pin is pulled high the LED will turn on; conversely when the pin is pulled low the LED will turn off.

This is the simple case of using a GPIO pin.

Raspberry Pi Advanced GPIO

That a single LED or other simple on/off can be controlled with a single GPIO pin is nice and all, but what about more advanced devices. What about an array of LED's? Something along the lines of the Bicolor LED Matrix from AdaFruit?

With 64 different LED's the Bicolor LED Matrix would consume more pins than are available on the Raspberry Pi!

Fortunately there are ways to handle this situation. At least two other protocols can be used:

  1. SPI: Serial Peripheral Interface
  2. I2C: Inter-Integrated Circuit

Full details about these protocols are beyond the scope of this article, but good starting points are SPI and I2C.

The Idea

Recently I have been learning the Phoenix Framework using the Elixir language. Could I get a Phoenix web service running on a Raspberry Pi?

If I could, what could it do that could be interesting enough to demo to a group of 10 - 30 coworkers of various disciplines in five minutes or less?

Given all this I came up with the following plan.

Step One

First, get a simple web service based on the Phoenix Framework that will respond to a /ping endpoint. This would be merely to prove that Phoenix, Elixir, and Erlang can run on the Raspberry Pi (with Raspbian as the OS).

Step Two

Next, have the service blink an LED while it is running. This proves that it is possible to access the GPIO pins from Elixir. Additionally, it uses a Periodic Actor by way of Erlang's and Elixir's lightweight Process implementation.

Step Three

Next up is to control a second LED with an endpoint. So a POST method to /led with body {value: 0} turns the LED off, and {value: 1} turns the LED on.

Step Four

Now things get interesting, provide the ability to control the aforementioned Bicolor LED Matrix. For this case, several predefined patterns are available that can be chosen via a POST method to the /matrix endpoint with body {pattern: n, brightness: x} will cause a pattern to be displayed at the given brightness.

If a pattern number outside the available pattern count is given a pattern is chosen at random and displayed. A pattern value of -2 turns the matrix off.

Step Five

An endpoint that accepts a matrix to be rendered to the Bicolor LED Matrix.

Implementation

As was discussed previously, there are two forms of advanced GPIO use. For this project I2C was used as AdaFruit provides a nice I2C-compatible backpack for the LED Matrix, you can buy the package from AdaFruit (minimal soldering is required).

The Schematic

The schematic is pretty simple. Need a couple of LED's, a resistor for each LED, and the Bicolor LED Matrix soldered on to the I2C backpack.

The Eagle CAD schematic can be found in the repo.

The Code

The source code is available for perusal, and Pull Requests are welcome.

The main points of interest are:

  1. The use of Elixir ALE, to communicate with the GPIO pins; and,
  2. the use of a periodic actor to blink the LED while the service is running.
Elixir ALE

Everything in Unix / Linux is a file. So it is possible to simply write values to files located in the /sys/class/gpio/ directory to control the pins (Hertaville has a more detailed explanation).

A better way, however, is to use system drivers to interface with the GPIO pins. To this end, fhunleth has created a port of the Erlang/ALE library for use with Elixir. This makes it possible to write idiomatic Elixir when working with the GPIO pins.

Periodic Actor

This is a staple of many Actor-based systems. The ability for an actor to send a message to itself. Introducing a time-based dimension allows a solution to be self-contained and obviates the need to use external processes such as cron.

The Repo

The README in the GitHub repo has detailed steps to set up the Raspberry Pi to run the code.

For the Lightning Talk a demo script was written. This was done to exercise the service while the talk was in progress and the slides were presented. This was the easiest way to demo the service as it removed the need to have a network connection on the Raspberry Pi. In order to demo the service from a laptop would have required finding the IP address on the corporate network and introduced risk of demo failure. Creating the script and 'installing' it in /etc/rc.local made the Raspberry Pi a self-running, self-contained demo machine.

This also involved creating the Systemd script to ensure the service started on system boot.

The Lightning Talk

In general I am not a fan of public speaking. I recognize this as a growth opportunity which is what compelled me to do the lightning talk. Five minutes? Meh, that's easy.

For the most part I think the talk went well, but it all happened so fast I was not convinced that anything coherent came out of my mouth.

It is a pretty rich topic to cover in such a limited time which is why I wrote this blog post to add more color and detail to the project.

Future of the project

Well, I don't really know. It was not intended to be a long-lived project. I have made a couple of tweaks here and there, but nothing major. I have no larger plans either. I am definitely open to Pull Requests on the code if you see a better, more Elixiry way of doing things.

I did not use TDD for this either. That is a huge departure for me. Setting up mocks for the GPIO header was not something for which I had the time, nor the inclination to pursue.