Warning: Contains Flashing Lights

After completing the build of my table, the real fun begins with the lights. I used a set of addressable LED lights, allowing me to set each one to a different color. These are controlled via SPI on the Raspberry Pi.

I wanted the ability to control the lights remotely, so I built a controller application in Python using a Tornado web server to receive commands over HTTP. I set this up as a service on the Raspberry Pi, ensuring that as soon as the table is powered on, the lights start operating automatically.

The controller operates using multiple threads: one handles incoming messages from the asynchronous Tornado service, while another manages the lighting system, processing commands and sending them to the LED strip via SPI.

Each lighting function is implemented as a threaded class. These classes include an update method that runs on each clock cycle, sending commands to the LED strip. They also support receiving updates, allowing for real-time interaction. A prime example of this is my health bar system, which you can see below.

Remote Control

To enable remote control, I’ve been experimenting with Angular to build an app that sends commands to the table. Angular is probably overkill for this, but since I’ve used it in previous jobs, I wanted to keep my skills sharp.

Toggle Mode

In this mode, I designed the controller to take two colours and a toggle time. Using the current clock speed of the lights, I calculated the number of steps available and used NumPy’s linspace to determine the colours for each step. On each clock tick, the controller transitions to the next colour.

Chase Mode

Chase mode allows you to set the chase colour, the length of the chase, the background colour, and the number of chases. It creates a fun animation, reminiscent of KITT from Knight Rider.

Twinkle mode

This was just a bit of fun—I’m not really sure what purpose it will serve. Maybe it could represent a fairy-filled forest in a D&D game or some sort of crazy dream sequence. It was an interesting challenge to get the fade-out effect working smoothly. Once again, NumPy’s linspace proved useful.

Health Bar

This one was a lot of fun to code. I divided the table into six seats—two along each long side and one at each short end. The controller takes in a player’s name, their seat location, and their total health. Each seat consists of 36 lights, with 20 allocated to the health bar.

As players lose health, the colour transitions from green to red, using linspace to fill in the shades in between if they have more than 20 health. The Angular application can send updated health values, and the lights will change to reflect the new health status. For dramatic effect, when a player’s health reaches zero, all their lights go out!

I have plenty more plans for the health bar system and will post updates as I develop it further.

Thanks to my friend Dan for the artistic photo taken during one of our Magic: The Gathering games, capturing the table reflected in the conservatory roof.