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_shapes
- 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: Project 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 on the CIRCUITPY drive.
You'll also need to copy the following files to the CIRCUITPY drive. See the graphic at the top of the page as to filenames and where they go):
- fonts directory, which contains a .bdf font
- bmp directory, which contains the graphics
- settings.toml (after you edit to put your WiFi and AIO credentials in the file)
# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board from adafruit_matrixportal.matrixportal import MatrixPortal EVENT_YEAR = 2021 EVENT_MONTH = 10 EVENT_DAY = 31 EVENT_HOUR = 17 EVENT_MINUTE = 0 FRAME_DURATION = 3 FRAMES = ( "bmps/jack.bmp", "DAYS", "bmps/ghost.bmp", "HOURS", "bmps/bats.bmp", "MINUTES", "bmps/skull.bmp", "bmps/halloween.bmp", ) EVENT_DAY_IMAGE = "bmps/happy_halloween.bmp" SYNCHRONIZE_CLOCK = True # --- Display setup --- matrixportal = MatrixPortal(status_neopixel=board.NEOPIXEL, debug=True) current_frame = None # Create a new label with the color and text selected matrixportal.add_text( text_font="fonts/Arial-12.bdf", text_position=(4, (matrixportal.graphics.display.height // 2) - 1), text_color=0xEF7F31, ) def set_time_until(unit=None): event_time = time.struct_time( ( EVENT_YEAR, EVENT_MONTH, EVENT_DAY, EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds -1, -1, False, ) ) remaining = time.mktime(event_time) - time.mktime(time.localtime()) if remaining <= 0: # oh, its event time! matrixportal.set_background(EVENT_DAY_IMAGE) return remaining //= 60 mins_remaining = remaining % 60 remaining //= 60 hours_remaining = remaining % 24 remaining //= 24 days_remaining = remaining if unit == "DAYS": text = "{} day".format(days_remaining) if days_remaining != 1: text += "s" if unit == "HOURS": text = "{} hour".format(hours_remaining) if hours_remaining != 1: text += "s" if unit == "MINUTES": text = "{} min".format(mins_remaining) if mins_remaining != 1: text += "s" matrixportal.set_text(text) matrixportal.set_background(0) def set_next_frame(): # pylint: disable=global-statement global current_frame # Advance to next frame if we already have one if current_frame is not None: current_frame += 1 # Loop back or set initial frame if current_frame is None or current_frame >= len(FRAMES): current_frame = 0 # Check if Picture or Text print(FRAMES[current_frame]) if FRAMES[current_frame][-4:] == ".bmp": matrixportal.set_background(FRAMES[current_frame]) matrixportal.set_text("") else: set_time_until(FRAMES[current_frame]) # Simulate the delay in case fetching time is fast set_next_frame() start_time = time.monotonic() if SYNCHRONIZE_CLOCK: matrixportal.get_local_time() while time.monotonic() < start_time + FRAME_DURATION: pass while True: set_next_frame() time.sleep(FRAME_DURATION)
Adafruit IO Time Server
In order to get the precise time, our project will query the Adafruit IO Internet of Things service for the time. 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 settings.toml 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.
More on settings.toml here.
How it Works
Libraries
Here's how the code works. First we import the time
, board, and adafruit_matrixportal
libraries.
Event Time
Then, we'll set the variables for the event year, month, day, hour, and minute. These will be used to calculate the countdown remaining based on the current time.
import time import board from adafruit_matrixportal.matrixportal import MatrixPortal EVENT_YEAR = 2020 EVENT_MONTH = 10 EVENT_DAY = 31 EVENT_HOUR = 17 EVENT_MINUTE = 0
Frames
Next, we set the FRAME_DURATION = 3
which means each image or text screen will hold for three seconds. You can adjust this as you like.
Then, we'll define the order in which the images and text will be displayed. This is pretty cool, as it is essentially making a list of which items you want to see appear sequentially. You can mix and match this as you see fit!
FRAME_DURATION = 3 FRAMES = ( "bmps/jack.bmp", "DAYS", "bmps/ghost.bmp", "HOURS", "bmps/bats.bmp", "MINUTES", "bmps/skull.bmp", "bmps/halloween.bmp", )
We'll also set one image aside as the EVENT_DAY_IMAGE = "bmps/happy_halloween.bmp"
.
MatrixPortal Setup
Next, we'll set up the matrixportal object for the display, and then create a text label.
matrixportal = MatrixPortal(status_neopixel=board.NEOPIXEL, debug=True) current_frame = None # Create a new label with the color and text selected matrixportal.add_text( text_font="fonts/Arial-12.bdf", text_position=(4, (matrixportal.graphics.display.height // 2) - 1), text_color=0xEF7F31, )
Set Time Until Function
This function is used to derive the time until the event based up one the start variables and the current time.
def set_time_until(unit=None): event_time = time.struct_time( ( EVENT_YEAR, EVENT_MONTH, EVENT_DAY, EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds -1, -1, False, ) ) remaining = time.mktime(event_time) - time.mktime(time.localtime()) if remaining <= 0: # oh, its event time! matrixportal.set_background(EVENT_DAY_IMAGE) return # secs_remaining = remaining % 60 remaining //= 60 mins_remaining = remaining % 60 remaining //= 60 hours_remaining = remaining % 24 remaining //= 24 days_remaining = remaining if unit == "DAYS": text = "{} day".format(days_remaining) if days_remaining != 1: text += "s" if unit == "HOURS": text = "{} hour".format(hours_remaining) if hours_remaining != 1: text += "s" if unit == "MINUTES": text = "{} min".format(mins_remaining) if mins_remaining != 1: text += "s" matrixportal.set_text(text) matrixportal.set_background(0)
Set Next Frame Function
We'll use this function to set the next frame to either a bitmap graphic or a text label depending on where we are in the list order.
ef set_next_frame(): global current_frame # Advance to next frame if we already have one if current_frame is not None: current_frame += 1 # Loop back or set initial frame if current_frame is None or current_frame >= len(FRAMES): current_frame = 0 # Check if Picture or Text print(FRAMES[current_frame]) if FRAMES[current_frame][-4:] == ".bmp": matrixportal.set_background(FRAMES[current_frame]) matrixportal.set_text("") else: set_time_until(FRAMES[current_frame])
Main Loop
The main loop of the program is simple -- it calls the set_next_frame()
function and then pauses for the frame duration!
while True: set_next_frame() time.sleep(FRAME_DURATION)
Page last edited January 22, 2025
Text editor powered by tinymce.