Build a DIY IoT home office ‘Busy Light’ with Circuitpython and MatrixPortal

Max McKinney
7 min readNov 14, 2020

Many people are working from home now-a-days due to the current pandemic. While I personally enjoy being remote there are definitely things lost not being in the office. One of those things is clearly identifying to those around you that you are busy or in a meeting. It kind of goes without saying but it’s easy to know when someone is in a meeting in an office environment, but at home not so much! That’s especially true if you have children or use headphones for your meetings. Those outside your office may have no idea you are occupied.

Introducing — ‘Productive Panel’

Sorry for the alliteration, that’s my goto for project names.

Animated preview — We’ll do it live!

This a DIY project I worked up before starting recently at my new employer. I knew I would be engaged with more meetings and wanted an easy way to communicate that to the house.

It is a 64x32 RGB Matrix powered by a MatrixPortal, a micro-controller made by Adafruit designed to easily control RGB matrixes. It comes with a socket that connects with the included 2x10 socket connector on the matrix and includes custom CircuitPython libraries to simplify the setup (while still supporting lower level libraries like displayio). I connected mine to Adafruit IO which allowed me to send data easily via wifi and control the board via a UI dashboard. Adafruit IO also supports IFTTT so you can automate things as needed (think calendar meetings, etc)

What you’ll need (~$80)

Step 1 — Connect the RGB Matrix & MatrixPortal

64x32 RGB Matrix — Adafruit

The RGB Matrix comes with a power cable, one input socket, and one output socket located on the back of the matrix.

MatrixPortal — Adafruit

Connect the power cable to the MatrixPortal micro-controller and push the MatrixPortal into the input socket on the left side of the RGB Matrix (while it is screen down). The right socket is for outputting a daisy-chain friendly signal. When installing the MatrixPortal make sure to orient the board with the PCB overhanging the screen, the orientation matters for the data pins.

MatrixPortal attached to the RGB Matrix

You can use zip-ties to secure the power cable down to the board. This will give you more room to mount the screen against a wall, although I will be using motherboard M3 standoffs to give me some extra space.

Step 2 — Install standoffs and picture brackets

As I mentioned I used M3 threaded motherboard standoffs to give the RGB Matrix some room between it and the wall. They also act as mounting mechanics for the picture bracket solution I ended up using. This is the part of the build that you might want to change depending on where you want to mount your screen. There exist some 3D printable brackets you could use as well.

M3 threaded motherboard standoffs. Black to match the plastic RGB Matrix frame

I used the “middle” size included with this set. It was visually appealing mounted against the wall and gave plenty of room for the components behind the RGB Matrix.

You’ll want to offset the bottom standoffs a bit while installing the top standoffs flush. This will allow the screen to sit parallel to the wall once we mount the picture bracket to the top mounts. That bracket will give the screen a bit of droop but the offset bottom standoff levels it back off. The end product will look perfectly flat and parallel to the wall.

Top standoff — Bottom standoff

Now let’s install the picture brackets. I decided to use these tiny picture brackets so they wouldn’t stand out too much but would still allow the screen to be removed easily for code updates and changes.

Small brackets perfect for attaching to standoffs

They are sized with holes just big enough to allow M3 screws to mount them against the standoffs.

Bracket attached to the standoff

Step 3 — Code

Now we get to the functionality of the system. This is also where you can customize and add features to your heart’s content. I’ll be focusing though on the simple idea of showing a ‘BUSY’ notice and a ‘FREE’ notice. I’ll also have a toggle for turning the display off while keeping the system on. You’ll be able to expand this code base to support all kinds of needs though.

I won’t be covering how to install CircuitPython on the MatrixPortal, Adafruit has a really simple and easy guide for that already, here. You’ll need to do that first.

Assets you need

  • (make this file, place in root directory)
  • (will already be located on your device)
  • IBM Plex Mono BDF font (download this, place in root directory)
  • Adafruit IO account (needed for controlling the screen)

I don’t plan on explaining how every part of the code works line by line, however I do want to explain the structure and highlight interesting parts. If you want to learn CircuitPython there are a ton of great resources out there, including their github!


This is the file CircuitPython uses along with other libraries to connect to your network. The AIO information is about your Adafruit IO account. The libraries we are using take a lot of the work out of connecting to the network and using Adafruit IO’s services. That being said the MatrixPortal can be programmed on a much lower level with it’s ESP32 wifi module if you desired that control.


This is a longer file so I’ll highlight some of the parts you’ll want to be aware of below the code box. That being said if you dig into the file you’ll find most of it is commented for you.

You’ll want to change the Adafruit IO feed names to match the names you used. Lines 76–80.

The way the code is structured the data fetching happens on the main thread, limiting it’s ability to listen to other inputs. This means if you want to interact with the panel it all needs to happen via Adafruit IO or whatever IoT service you are using. You can configure how often it fetches data with the UPDATE_DELAY var at the top of the file. Right now it fetches about every 5 seconds or so, plus the time it takes the download the data and parse it.

Protip: Test the code before mounting it on the wall

Check out the ‘update_text()’ and ‘update_bg()’ methods to configure the color of the background and the words used.

With the current font size you are limited to about 4 characters before it gets cutoff. You can change the font size to allow for more room.

Step 4 — Wall mount

Now that you have the RGB Matrix and MatrixPortal all connected and the code installed it’s time to mount it to the wall. This is probably the easiest part, just requires a bit of planning depending how you plan to power it.

To mount it to the wall I used small nails. The weight of the screen doesn’t require a stud for the nail so you have some flexibility in it’s placement.

Make sure the screen is level!

The next step is powering it! I wanted it to be on 24/7 so I opted for a wall outlet. The MatrixPortal needs 5v 2a+. The board supports USB-C natively but I ended up using a 5.5m barrel plug with an adapter. I used a small cable concealer for a subtle install. This one worked well for me.

Cable management is a priority 👍

This is where you can be more/less creative with power, just depends on your needs. I’m happy with the current setup although I think I’ll change out the power supply one day to one without the ferrite bead at the end so I can remove that gap in the concealer channel. For now it works well and it’s mostly something that I notice, not anyone else.

Step 5 — Usage & additional features

To use this system you make a dashboard on Adafruit IO and that gives you controls to modify the values stored in your Adafruit IO feeds. Feeds act like variables that can be controlled and referenced from other sources.

Simple ‘Productive Panel’ Adafruit IO dashboard

This dashboard lives on the web so you can access it via your phone or through other services like IFTTT for some slick automation.

That’s it though, you are done! This should provide you with a simple to use status indicator for your home office that just works! That being said if you are the tinkering type it is ripe for customization and automation.



Max McKinney

I’m Max McKinney, designing for empathy and humanizing technology. A decade of creating allows me to make seamless experiences.