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.