Overview
Quotes! Who doesn't love good quotes? But who's to decide which quotes are "good"? Well, you are, of course!
Now, you can create your own quote board and supply the quotes for it yourself! No need to rely on a website and some other person's curatorial tastes.
With this project, you'll create a custom quote feed right on Adafruit IO, then code your CircuitPython-powered WiFi RGB LED matrix to display your quotes in random order.
Page last edited March 08, 2024
Text editor powered by tinymce.
Using M4 Airlift
If you have a Metro M4 AirLift, you can build this project easily - you just need an RGB Matrix shield to help connect!
You will need a Metro M4 Airlift, matrix shield and matrix
Page last edited March 08, 2024
Text editor powered by tinymce.
Install CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
Set up CircuitPython Quick Start!
Follow this quick step-by-step for super-fast Python power :)
Further Information
For more detailed info on installing CircuitPython, check out Installing CircuitPython.
Click the link above and download the latest UF2 file.
Download and save it to your desktop (or wherever is handy).
Plug your Metro M4 into your computer using a known-good USB cable.
A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.
Double-click the Reset button next to the USB connector on your board (blue arrow), and you will see the NeoPixel RGB (LED circled in red) turn green. If it turns red, check the USB cable, try another USB port, etc.
If double-clicking the Reset button doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!
You will see a new disk drive appear called METROM4BOOT.
Â
Drag the adafruit_circuitpython_etc.uf2 file to METROM4BOOT.
Page last edited March 08, 2024
Text editor powered by tinymce.
Build the Quote Board Matrix Display
Assembly
Talking to an LED matrix display can be tricky! The 64 x 32 LED used here has a whopping 2,048 pixels, and each can display RGB colors, which makes for a whole lot of data to sling around. Thankfully, our RGB Matrix shield paired with the Metro M4 Airlift does most of the heavy lifting.
Let's assemble the boards and the display so we can get things running!
Shields Up
First, add the male headers, screw terminal block, and the 8x2-pin socket to the Matrix shield, by following this guide. Be careful to match the socket polarity to the silkscreen image on the board.
Be sure to also perform the clock pin mod as shown here.
Then plug the shield into the Metro M4 Airlift.
Power Connections
To provide power, we'll screw the wiring harness connectors to the screw terminal blocks of the shield. Be sure to match the black wire to GND and the red wire to +5Vout.
Now, simply plug the other end into the panel's power header. It can only go in one way.
Data Cable
Plug in the two ends of the ribbon cable, note that the connectors are keyed to only fit in the correct orientation.
Jumper
To create the mode jumper, simply solder a three position female header to the GND, D13, D12 pins of the shield.
A pack of these is good to have around, just use some diagonal cutters to clip off three positions (cut along the fourth sacrificial position).
We won't use pin D13, but this makes for a more stable header row vs. two individual ones.
Then, trim the insulation from the ends of a small bit of solid core hook-up wire and ground D12 to GND for imperial, or pull the jumper for metric.
Page last edited March 08, 2024
Text editor powered by tinymce.
Using MatrixPortal
You can build this project with an all-in-one Matrix Portal board, its definitely the easiest and least-expensive way to go about it.
You will need a matrix portal, matrix, and USB C power/data cable
Page last edited March 08, 2024
Text editor powered by tinymce.
Install CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
Set up CircuitPython Quick Start!
Follow this quick step-by-step for super-fast Python power :)
Further Information
For more detailed info on installing CircuitPython, check out Installing CircuitPython.
Click the link above and download the latest UF2 file.
Download and save it to your desktop (or wherever is handy).
Plug your MatrixPortal M4 into your computer using a known-good USB cable.
A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.
Double-click the Reset button (indicated by the green arrow) on your board, and you will see the NeoPixel RGB LED (indicated by the magenta arrow) turn green. If it turns red, check the USB cable, try another USB port, etc.
If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!
You will see a new disk drive appear called MATRIXBOOT.
Â
Drag the adafruit_circuitpython_etc.uf2 file to MATRIXBOOT.
Page last edited March 08, 2024
Text editor powered by tinymce.
Prep the MatrixPortal
Power Prep
The MatrixPortal supplies power to the matrix display panel via two standoffs. These come with protective tape applied (part of our manufacturing process) which MUST BE REMOVED!
Use some tweezers or a fingernail to remove the two amber circles.
Power Terminals
Next, screw in the spade connectors to the corresponding standoff.
- red wire goes to +5VÂ
- black wire goes to GND
Panel Power
Plug either one of the four-conductor power plugs into the power connector pins on the panel. The plug can only go in one way, and that way is marked on the board's silkscreen.
Dual Matrix Setup
If you're planning to use a 64x64 matrix, follow these instructions on soldering the Address E Line jumper.
Board Connection
Now, plug the board into the left side shrouded 8x2 connector as shown. The orientation matters, so take a moment to confirm that the white indicator arrow on the matrix panel is oriented pointing up and right as seen here and the MatrixPortal overhangs the edge of the panel when connected. This allows you to use the edge buttons from the front side.
Â
Check nothing is impeding the board from plugging in firmly. If there's a plastic nub on the matrix that's keeping the Portal from sitting flat, cut it off with diagonal cutters
Page last edited March 08, 2024
Text editor powered by tinymce.
Code the Quote Board
Libraries
We'll need to make sure we have these libraries installed. (Check out this link on installing libraries if needed.)
- adafruit_bitmap_font
- adafruit_bus_device
- adafruit_display_text
- adafruit_esp32spi
- adafruit_io
- adafruit_matrixportal
- adafruit_requests.mpy
- neopixel.mpy
Connect to the Internet
Once you have CircuitPython setup and libraries installed we can get your board connected to the Internet. The process for connecting can be found here.
Text Editor
Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.
Alternatively, you can use any text editor that saves simple text files.
Code
Click the Download: Zip File link below in the code window to get a zip file with all the files needed for the project. Copy code.py from the zip file and place it on the CIRCUITPY drive.
# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Quote board matrix display
# uses AdafruitIO to serve up a quote text feed and color feed
# random quotes are displayed, updates periodically to look for new quotes
# avoids repeating the same quote twice in a row
import time
import random
import board
import terminalio
from adafruit_matrixportal.matrixportal import MatrixPortal
# --- Display setup ---
matrixportal = MatrixPortal(status_neopixel=board.NEOPIXEL, debug=True)
# Create a new label with the color and text selected
matrixportal.add_text(
text_font=terminalio.FONT,
text_position=(0, (matrixportal.graphics.display.height // 2) - 1),
scrolling=True,
)
# Static 'Connecting' Text
matrixportal.add_text(
text_font=terminalio.FONT,
text_position=(2, (matrixportal.graphics.display.height // 2) - 1),
)
QUOTES_FEED = "sign-quotes.signtext"
COLORS_FEED = "sign-quotes.signcolor"
SCROLL_DELAY = 0.02
UPDATE_DELAY = 600
quotes = []
colors = []
last_color = None
last_quote = None
def update_data():
print("Updating data from Adafruit IO")
matrixportal.set_text("Connecting", 1)
try:
quotes_data = matrixportal.get_io_data(QUOTES_FEED)
quotes.clear()
for json_data in quotes_data:
quotes.append(matrixportal.network.json_traverse(json_data, ["value"]))
print(quotes)
# pylint: disable=broad-except
except Exception as error:
print(error)
try:
color_data = matrixportal.get_io_data(COLORS_FEED)
colors.clear()
for json_data in color_data:
colors.append(matrixportal.network.json_traverse(json_data, ["value"]))
print(colors)
# pylint: disable=broad-except
except Exception as error:
print(error)
if not quotes or not colors:
raise RuntimeError("Please add at least one quote and color to your feeds")
matrixportal.set_text(" ", 1)
update_data()
last_update = time.monotonic()
matrixportal.set_text(" ", 1)
quote_index = None
color_index = None
while True:
# Choose a random quote from quotes
if len(quotes) > 1 and last_quote is not None:
while quote_index == last_quote:
quote_index = random.randrange(0, len(quotes))
else:
quote_index = random.randrange(0, len(quotes))
last_quote = quote_index
# Choose a random color from colors
if len(colors) > 1 and last_color is not None:
while color_index == last_color:
color_index = random.randrange(0, len(colors))
else:
color_index = random.randrange(0, len(colors))
last_color = color_index
# Set the quote text
matrixportal.set_text(quotes[quote_index])
# Set the text color
matrixportal.set_text_color(colors[color_index])
# Scroll it
matrixportal.scroll_text(SCROLL_DELAY)
if time.monotonic() > last_update + UPDATE_DELAY:
update_data()
last_update = time.monotonic()
Adafruit IO Setup
Our project will use Adafruit IO to serve up a feed of quotes and colors. Adafruit IO is absolutely free to use, but you'll need to log in with your Adafruit account to use it. If you don't already have an Adafruit login, create one here.
If you haven't used Adafruit IO before, check out this guide for more info.
Once you have logged into your account, there are two pieces of information you'll need to place in your secrets.py file: Adafruit IO username, and Adafruit IO key. Head to io.adafruit.com and simply click the View AIO Key link on the left hand side of the Adafruit IO page to get this information.
Then, add them to the secrets.py file like this:
secrets = {
'ssid' : 'your_wifi_ssid',
'password' : 'your_wifi_password',
'aio_username' : '_your_aio_username_',
'aio_key' : '_your_big_huge_super_long_aio_key_'
}
Problems Getting Quotes
If you have any problems getting the data to display correctly, check that the secrets.py file has the information noted above.
Adafruit IO Group, Feeds, Dashboard
Next, we'll create the necessary Adafruit IO Group, Feeds, and Dashboard to host our quotes and colors.
First, if you're new to Adafruit IO, take a look at this excellent guide on getting started.
Next, we'll create a Group that will contain our two Feeds.
Group Creation
In the Feeds screen click on the Actions menu and then pick Create a New Group from the dropdown menu.
Feed Creation
In the Feeds screen click on the Actions menu and then pick Create a New Feed from the dropdown menu.
Name this feed signcolor, and select Sign Quotes from the Add to groups field, then click Create.
Repeat this process a second time to make a new Feed called signtext.
Dashboard Creation
Now that we have the two feeds we need, let's create a Dashboard with a couple of UI block elements that will make it easy to add data points to our two feeds.
From the Dashboards page, click the Actions dropdown menu and select Create a New Dashboard.
Name the Dashboard as Quotes and then click Create.
Click on the create a new block + sign in the Dashboard page, this will present you with a number of UI element block options.
Pick the Text block.
From the Chose feed pop-up window that appears, chose the signtext feed, then click Next step.
In the Block settings popup window, give the block the title Text quote, then click Update block.
Repeat this process to create a Color picker block, assigning it to the signcolor feed.
Create Quotes
Now, you can pick a few different colors with the color picker to add to your arsenal of sign text colors.
Type in text in the text block to add quotes to your feed.
If you ever decide you don't want one of the colors or quotes, simply head to the relevant feed and click the red 'x' to remove a data point!
import time import random import board import terminalio from adafruit_matrixportal.matrixportal import MatrixPortal
Next, the Display is set up using the matrixportal object. We also create text label objects:
# --- Display setup ---
matrixportal = MatrixPortal(status_neopixel=board.NEOPIXEL, debug=True)
# Create a new label with the color and text selected
matrixportal.add_text(
text_font=terminalio.FONT,
text_position=(0, (matrixportal.graphics.display.height // 2) - 1),
scrolling=True,
)
# Static 'Connecting' Text
matrixportal.add_text(
text_font=terminalio.FONT,
text_position=(2, (matrixportal.graphics.display.height // 2) - 1),
)
Feed Variables
In order to use the feed data, we need a couple of variables to help traverse the AIO json data.
We also create variables for the scroll speed and update time.
QUOTES_FEED = "sign-quotes.signtext" COLORS_FEED = "sign-quotes.signcolor" SCROLL_DELAY = 0.02 UPDATE_DELAY = 600 quotes = [] colors = [] last_color = None last_quote = None
Update Data
The update_data() function is created to handle the quote feed and color feed data queries. This will be the key function that is run each time the code checks for new quotes and colors.
def update_data():
print("Updating data from Adafruit IO")
matrixportal.set_text("Connecting", 1)
try:
quotes_data = matrixportal.get_io_data(QUOTES_FEED)
quotes.clear()
for json_data in quotes_data:
quotes.append(matrixportal.network.json_traverse(json_data, ["value"]))
print(quotes)
# pylint: disable=broad-except
except Exception as error:
print(error)
try:
color_data = matrixportal.get_io_data(COLORS_FEED)
colors.clear()
for json_data in color_data:
colors.append(matrixportal.network.json_traverse(json_data, ["value"]))
print(colors)
# pylint: disable=broad-except
except Exception as error:
print(error)
if not quotes or not colors:
raise "Please add at least one quote and color to your feeds"
matrixportal.set_text(" ", 1)
This is run as soon as the function has been defined, so that we now have a list of quotes and colors to work with.
Main Loop
In the main loop of the code, a random quote is selected from the list that has been returned by the update_data() function. This includes a while loop that ensures we don't get the same quote or color twice in a row!
# Choose a random quote from quotes
if len(quotes) > 1 and last_quote is not None:
while quote_index == last_quote:
quote_index = random.randrange(0, len(quotes))
else:
quote_index = random.randrange(0, len(quotes))
last_quote = quote_index
# Choose a random color from colors
if len(colors) > 1 and last_color is not None:
while color_index == last_color:
color_index = random.randrange(0, len(colors))
else:
color_index = random.randrange(0, len(colors))
last_color = color_index
Display the Quote
Now, the randomly selected quote is displayed using the matrixportal.set_text() and matrixportal.set_text_color() commands, and the text is scrolled using matrixportal.scroll_text().
# Set the quote text
matrixportal.set_text(quotes[quote_index])
# Set the text color
matrixportal.set_text_color(colors[color_index])
# Scroll it
matrixportal.scroll_text(SCROLL_DELAY)
Update Time
After ten minutes, the code will go and fetch the quotes and colors from the AIO feeds anew, in case anything has changed.
if time.monotonic() > last_update + UPDATE_DELAY:
update_data()
last_update = time.monotonic()
Page last edited March 08, 2024
Text editor powered by tinymce.
LED Matrix Diffuser
LED Diffusion Acrylic
You can add an LED diffusion acrylic faceplate to the your LED matrix display. (Pictured here with the ON AIR project)
This can help protect the LEDs as well as enhance the look of the sign both indoors and out by reducing glare and specular highlights of the plastic matrix grid.
Measure and Cut the Plastic
You can use the sign to measure and mark cut lines on the paper backing of the acrylic sheet.
Then, use a tablesaw or bandsaw with a fine toothed blade and a guide or sled to make the cuts.
Note: it is possible to score and snap acrylic, but it can be very tricky to get an even snap without proper clamping.
Peel away the paper backing from both sides and set the acrylic onto your matrix display with the matte finished side facing out.
Uglu Dashes
The best method we've found for adhering acrylic to the matrix display is to use Uglu Dashes clear adhesive rectangles from Pro Tapes. They are incredibly strong (although can be removed if necessary), easy to apply, and are invisible once attached.
Use one at each corner and one each at the halfway point of the long edges, then press the acrylic and matrix panel together for about 20 seconds.
Here you can see the impact of using the diffusion acrylic. (Pictured here with the ON AIR sign project)
Stand
A very simple and attractive way to display your matrix is with the adjustable bent-wire stand.
Alternately, you can use a frame, 3D printed brackets, tape, glue, or even large binder clips to secure the acrylic to the sign and then mount it on on a wall, shelf, or display cabinet.
These mini-magnet feet can be used to stick the sign to a ferrous surface.
Page last edited March 08, 2024
Text editor powered by tinymce.