After completing the setup process for your Matrix Portal M4 with CircuitPython, you can gather the required code and libraries by downloading the Project Bundle.
To accomplish this task, click the "Download Project Bundle" button in the window below. The file will be saved to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2023 Trevor Beaton for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import displayio
import terminalio
from adafruit_display_text.label import Label
from adafruit_bitmap_font import bitmap_font
from adafruit_matrixportal.matrix import Matrix
# set the timer length
TIMER_LENGTH = 180 # 3 minutes
BLINK = True
DEBUG = False
# --- Display setup ---
matrix = Matrix()
display = matrix.display
# --- Drawing setup ---
group = displayio.Group() # Create a Group
bitmap = displayio.Bitmap(64, 32, 2) # Create a bitmap object,width, height, bit depth
color = displayio.Palette(4) # Create a color palette
color[0] = 0x000000 # black background
color[1] = 0xFF0000 # red
color[2] = 0xFF8C00 # yellow
color[3] = 0x3DEB34 # green
# Create a TileGrid using the Bitmap and Palette
tile_grid = displayio.TileGrid(bitmap, pixel_shader=color)
group.append(tile_grid) # Add the TileGrid to the Group
display.root_group = group
if not DEBUG:
font = bitmap_font.load_font("/IBMPlexMono-Medium-24_jep.bdf")
else:
font = terminalio.FONT
clock_label = Label(font)
def update_time(remaining_time):
now = time.localtime() # Get the time values we need
# calculate remaining time in seconds
seconds = remaining_time % 60
minutes = remaining_time // 60
if BLINK:
colon = ":" if now[5] % 2 else " "
else:
colon = ":"
clock_label.text = "{minutes:02d}{colon}{seconds:02d}".format(
minutes=minutes, seconds=seconds, colon=colon
)
if remaining_time < 60:
clock_label.color = color[1]
elif remaining_time < 90:
clock_label.color = color[2]
elif remaining_time > 90:
clock_label.color = color[3]
bbx, bby, bbwidth, bbh = clock_label.bounding_box
# Center the label
clock_label.x = round(display.width / 2 - bbwidth / 2)
clock_label.y = display.height // 2
if DEBUG:
print("Label bounding box: {},{},{},{}".format(bbx, bby, bbwidth, bbh))
print("Label x: {} y: {}".format(clock_label.x, clock_label.y))
# decrement remaining time
remaining_time -= 1
if remaining_time < 0:
remaining_time = TIMER_LENGTH
return remaining_time
def main():
remaining_time = TIMER_LENGTH
update_time(remaining_time)
group.append(clock_label)
while True:
remaining_time = update_time(remaining_time)
time.sleep(1)
if __name__ == "__main__":
main()
Text Editor
Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide including info on how to use the REPL/serial terminal.
Alternatively, you can use any text editor that saves simple text files.
Upload the Code and Libraries to the Matrix Portal M4
After downloading the Project Bundle, you can plug your Matrix Portal M4 into the computer's USB port with a suitable USB data+power cable. You should see a new flash drive in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Matrix Portal M4's CIRCUITPY drive.
- lib folder
- code.py
- IBMPlexMono-Medium-24_jep.bdf
Your Matrix Portal M4 CIRCUITPY drive should look like this after copying the lib folder, IBMPlexMono-Medium-24_jep.bdf file and the code.py file.
Import Libraries
First thing is to import the modules needed for the code to run. The time module allows you to work with time, while the displayio and terminalio provide classes and methods to render the text to the display.
The adafruit_bitmap_font module supports bitmap fonts, and the adafruit_matrixportal module supports working with the Matrix Portal.
import time import displayio import terminalio from adafruit_display_text.label import Label from adafruit_bitmap_font import bitmap_font from adafruit_matrixportal.matrix import Matrix
Constants
These constants are used throughout the code. TIMER_LENGTH sets the length of the countdown timer in seconds, BLINK determines whether the timer's colon separator blinks, and DEBUG allows you to see debug information in the console.
TIMER_LENGTH = 180 # 3 minutes BLINK = True
Initializing the Matrix Portal
This code initializes the Matrix Portal and sets it up as a display object. Very important.
matrix = Matrix() display = matrix.display
Drawing setup
Now, to set up the display's drawing objects. Create a Group to hold the tile grid and a Bitmap object to represent the display's pixels. You also want to create a Palette to hold the colors used in the display. The TileGrid is created using the Bitmap and Palette and is added to the Group. Finally, the Group is shown on the display.
group = displayio.Group() # Create a Group bitmap = displayio.Bitmap(64, 32, 2) # Create a bitmap object,width, height, bit depth color = displayio.Palette(4) # Create a color palette color[0] = 0x000000 # black background color[1] = 0xFF0000 # red color[2] = 0xFF8C00 # yellow color[3] = 0x3DEB34 # green
Font
This set of code sets up the font for the countdown interval timer. If DEBUG is set to False, a bitmap font is loaded from a file. If not, the font is used.
if not DEBUG:
font = bitmap_font.load_font("/IBMPlexMono-Medium-24_jep.bdf")
else:
font = terminalio.FONT
clock_label = Label(font)
Update Time
This update_time() function takes one argument remaining_time as input.
Within the function, it first calls time.localtime() to observe and store the current local time in the variable.
Next, it calculates the number of minutes and seconds remaining from the input argument remaining_time in seconds.
The code then determines if it displays a blinking colon or not based on the value of the BLINK variable and the current second of the now variable. It sets the colon variable to : if the current second is even and if the current second is odd.
It then sets the text of the clock_label object to display the minutes and seconds, with the colon. The values are formatted to display leading zeros when necessary.
The code block then sets the color of the clock_label object based on the remaining time. Here's the. condition:
- If the remaining time is less than 60 seconds, it sets the color to
color[1]. - If it's less than 90 seconds, it sets the color to
color[2]. - If it's greater than 90 seconds, it sets the color to
color[3].
The code then calculates the bounding box of the clock_label object and centers it horizontally on the screen. If the DEBUG variable is set to True, it prints the bounding box and position of the label.
Finally, the code decrements the remaining_time variable by 1 and checks if it's less than 0. If the remaining_time is equal to 0, it sets remaining_time back to TIMER_LENGTH, another variable that must have been defined elsewhere in the code. The function then returns the remaining_time variable.
The main() function initializes the remaining_time variable to TIMER_LENGTH, calls update_time() with that variable as input, and appends the clock_label object to a group. Then it enters a while loop that repeatedly calls update_time() with the current value of remaining_time, sleeps for 1 second using time.sleep(1), and continues the loop.
def update_time(remaining_time):
now = time.localtime() # Get the time values we need
# calculate remaining time in seconds
seconds = remaining_time % 60
minutes = remaining_time // 60
if BLINK:
colon = ":" if now[5] % 2 else " "
else:
colon = ":"
clock_label.text = "{minutes:02d}{colon}{seconds:02d}".format(
minutes=minutes, seconds=seconds, colon=colon
)
if remaining_time < 60:
clock_label.color = color[1]
elif remaining_time < 90:
clock_label.color = color[2]
elif remaining_time > 90:
clock_label.color = color[3]
bbx, bby, bbwidth, bbh = clock_label.bounding_box
# Center the label
clock_label.x = round(display.width / 2 - bbwidth / 2)
clock_label.y = display.height // 2
if DEBUG:
print("Label bounding box: {},{},{},{}".format(bbx, bby, bbwidth, bbh))
print("Label x: {} y: {}".format(clock_label.x, clock_label.y))
# decrement remaining time
remaining_time -= 1
if remaining_time < 0:
remaining_time = TIMER_LENGTH
return remaining_time
def main():
remaining_time = TIMER_LENGTH
update_time(remaining_time)
group.append(clock_label)
while True:
remaining_time = update_time(remaining_time)
time.sleep(1)
if __name__ == "__main__":
main()
Page last edited February 24, 2025
Text editor powered by tinymce.