Once you've finished setting up your Matrix Portal S3 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import gc
import ssl
import time
import wifi
import socketpool
import adafruit_requests
import adafruit_display_text.label
import board
import terminalio
import displayio
import framebufferio
import rgbmatrix
import adafruit_json_stream as json_stream
import microcontroller
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
from adafruit_datetime import datetime, timedelta
import neopixel
displayio.release_displays()
# font color for text on matrix
font_color = 0xFFFFFF
# your timezone UTC offset and timezone name
timezone_info = [-4, "EDT"]
# the name of the sports you want to follow
sport_name = ["football", "baseball", "soccer", "hockey", "basketball"]
# the name of the corresponding leages you want to follow
sport_league = ["nfl", "mlb", "usa.1", "nhl", "nba"]
# the team names you want to follow
# must match the order of sport/league arrays
# include full name and then abbreviation (usually city/region)
team0 = ["New England Patriots", "NE"]
team1 = ["Boston Red Sox", "BOS"]
team2 = ["New England Revolution", "NE"]
team3 = ["Boston Bruins", "BOS"]
team4 = ["Boston Celtics", "BOS"]
# how often the API should be fetched
fetch_timer = 300 # seconds
# how often the display should update
display_timer = 30 # seconds
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness = 0.3, auto_write=True)
# matrix setup
base_width = 64
base_height = 32
chain_across = 2
tile_down = 2
DISPLAY_WIDTH = base_width * chain_across
DISPLAY_HEIGHT = base_height * tile_down
matrix = rgbmatrix.RGBMatrix(
width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, bit_depth=3,
rgb_pins=[
board.MTX_R1,
board.MTX_G1,
board.MTX_B1,
board.MTX_R2,
board.MTX_G2,
board.MTX_B2
],
addr_pins=[
board.MTX_ADDRA,
board.MTX_ADDRB,
board.MTX_ADDRC,
board.MTX_ADDRD
],
clock_pin=board.MTX_CLK,
latch_pin=board.MTX_LAT,
output_enable_pin=board.MTX_OE,
tile=tile_down, serpentine=True,
doublebuffer=False
)
display = framebufferio.FramebufferDisplay(matrix)
# connect to WIFI
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
# add API URLs
SPORT_URLS = []
for i in range(5):
d = (
f"https://site.api.espn.com/apis/site/v2/sports/{sport_name[i]}/{sport_league[i]}/scoreboard"
)
SPORT_URLS.append(d)
context = ssl.create_default_context()
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, context)
# arrays for teams, logos and display groups
teams = []
logos = []
groups = []
# add team to array
teams.append(team0)
# grab logo bitmap name
logo0 = "/team0_logos/" + team0[1] + ".bmp"
# add logo to array
logos.append(logo0)
# create a display group
group0 = displayio.Group()
# add group to array
groups.append(group0)
# repeat:
teams.append(team1)
logo1 = "/team1_logos/" + team1[1] + ".bmp"
logos.append(logo1)
group1 = displayio.Group()
groups.append(group1)
teams.append(team2)
logo2 = "/team2_logos/" + team2[1] + ".bmp"
logos.append(logo2)
group2 = displayio.Group()
groups.append(group2)
teams.append(team3)
logo3 = "/team3_logos/" + team3[1] + ".bmp"
logos.append(logo3)
group3 = displayio.Group()
groups.append(group3)
teams.append(team4)
logo4 = "/team4_logos/" + team4[1] + ".bmp"
logos.append(logo4)
group4 = displayio.Group()
groups.append(group4)
# initial startup screen
# shows the five team logos you are following
def sport_startup(logo):
try:
group = displayio.Group()
bitmap0 = displayio.OnDiskBitmap(logo[0])
grid0 = displayio.TileGrid(bitmap0, pixel_shader=bitmap0.pixel_shader, x = 0)
bitmap1 = displayio.OnDiskBitmap(logo[1])
grid1 = displayio.TileGrid(bitmap1, pixel_shader=bitmap1.pixel_shader, x = 32)
bitmap2 = displayio.OnDiskBitmap(logo[2])
grid2 = displayio.TileGrid(bitmap2, pixel_shader=bitmap2.pixel_shader, x = 64)
bitmap3 = displayio.OnDiskBitmap(logo[3])
grid3 = displayio.TileGrid(bitmap3, pixel_shader=bitmap3.pixel_shader, x = 96)
bitmap4 = displayio.OnDiskBitmap(logo[4])
grid4 = displayio.TileGrid(bitmap4, pixel_shader=bitmap4.pixel_shader, x = 48, y=32)
group.append(grid0)
group.append(grid1)
group.append(grid2)
group.append(grid3)
group.append(grid4)
display.root_group = group
# pylint: disable=broad-except
except Exception:
print("Can't find bitmap. Did you run the get_team_logos.py script?")
# takes UTC time from JSON and reformats how its displayed
def convert_date_format(date, tz_information):
# Manually extract year, month, day, hour, and minute from the string
year = int(date[0:4])
month = int(date[5:7])
day = int(date[8:10])
hour = int(date[11:13])
minute = int(date[14:16])
# Construct a datetime object using the extracted values
dt = datetime(year, month, day, hour, minute)
# Adjust the datetime object for the target timezone offset
dt_adjusted = dt + timedelta(hours=tz_information[0])
# Extract fields for output format
month = dt_adjusted.month
day = dt_adjusted.day
hour = dt_adjusted.hour
minute = dt_adjusted.minute
# Convert 24-hour format to 12-hour format and determine AM/PM
am_pm = "AM" if hour < 12 else "PM"
hour_12 = hour if hour <= 12 else hour - 12
minute = f"{minute:02}"
# Determine the timezone abbreviation based on the offset
time_zone_str = tz_information[1]
return f"{month}/{day} - {hour_12}:{minute} {am_pm} {time_zone_str}"
# the actual API and display function
# pylint: disable=too-many-locals, too-many-branches, too-many-statements
def get_data(data, team, logo, group):
pixel.fill((0, 0, 255))
print(f"Fetching data from {data}")
playing = False
names = []
scores = []
info = []
index = 0
# the team you are following's logo
bitmap0 = displayio.OnDiskBitmap(logo)
grid0 = displayio.TileGrid(bitmap0, pixel_shader=bitmap0.pixel_shader, x = 2)
home_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
away_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
vs_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
vs_text.anchor_point = (0.5, 0.0)
vs_text.anchored_position = (DISPLAY_WIDTH / 2, 14)
info_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
info_text.anchor_point = (0.5, 1.0)
info_text.anchored_position = (DISPLAY_WIDTH / 2, DISPLAY_HEIGHT)
# make the request to the API
resp = requests.get(data)
# stream the json
json_data = json_stream.load(resp.iter_content(32))
for event in json_data["events"]:
# clear the date and then add the date to the array
# the date for your game will remain
info.clear()
info.append(event["date"])
# check for your team playing
if team[0] not in event["name"]:
continue
for competition in event["competitions"]:
for competitor in competition["competitors"]:
# if your team is playing:
playing = True
# get team names
# index indicates home vs. away
names.append(competitor["team"]["abbreviation"])
# the current score
scores.append(competitor["score"])
# gets info on game
info.append(event["status"]["type"]["shortDetail"])
break
if playing and len(names) != 2:
print("did not get expected response, fetching full JSON..")
try:
resp.close()
# pylint: disable=broad-except
except Exception as e:
print(f"{e}, continuing..")
# pylint: disable=unnecessary-pass
pass
names.clear()
scores.clear()
info.clear()
resp = requests.get(data)
response_as_json = resp.json()
for e in response_as_json["events"]:
if team[0] in e["name"]:
print(index)
info.append(response_as_json["events"][0]["date"])
names.append(response_as_json["events"][0]["competitions"]
[0]["competitors"][0]["team"]["abbreviation"])
names.append(response_as_json["events"][0]["competitions"]
[0]["competitors"][1]["team"]["abbreviation"])
scores.append(response_as_json["events"][0]["competitions"]
[0]["competitors"][0]["score"])
scores.append(response_as_json["events"][0]["competitions"]
[0]["competitors"][1]["score"])
info.append(response_as_json["events"][0]["status"]["type"]["shortDetail"])
else:
index += 1
# debug printing
print(names)
print(scores)
print(info)
if playing and len(names) == 2:
# pull out the date
date = info[0]
# convert it to be readable
date = convert_date_format(date, timezone_info)
print(date)
# pull out the info
info = info[1]
# check if it's pre-game
if str(info) == date or str(info) == "Scheduled":
status = "pre"
print("match, pre-game")
else:
status = info
# home and away text
# teams index determines which team is home or away
home_text.text="HOME"
away_text.text="AWAY"
if team[1] is names[0]:
home_game = True
home_text.anchor_point = (0.0, 0.5)
home_text.anchored_position = (5, 37)
away_text.anchor_point = (1.0, 0.5)
away_text.anchored_position = (124, 37)
vs_team = names[1]
else:
home_game = False
away_text.anchor_point = (0.0, 0.5)
away_text.anchored_position = (5, 37)
home_text.anchor_point = (1.0, 0.5)
home_text.anchored_position = (124, 37)
vs_team = names[0]
# if it's pre-game, show "VS"
if status == "pre":
vs_text.text="VS"
info_text.text=date
# if it's active or final show score
else:
info_text.text=info
if home_game:
vs_text.text=f"{scores[0]} - {scores[1]}"
else:
vs_text.text=f"{scores[1]} - {scores[0]}"
# load in logo from other team
vs_logo = logo.replace(team[1], vs_team)
# if there is no game matching your team:
else:
status = "pre"
vs_logo = logo
info_text.text="NO DATA AVAILABLE"
# load in the other team's logo
bitmap1 = displayio.OnDiskBitmap(vs_logo)
grid1 = displayio.TileGrid(bitmap1, pixel_shader=bitmap1.pixel_shader, x = 94)
print("done")
# update the display group. try/except in case its the first time it's being added
try:
group[0] = grid0
group[1] = grid1
group[2] = home_text
group[3] = away_text
group[4] = vs_text
group[5] = info_text
except IndexError:
group.append(grid0)
group.append(grid1)
group.append(home_text)
group.append(away_text)
group.append(vs_text)
group.append(info_text)
# close the response
try:
# sometimes an OSError is thrown:
# "invalid syntax for integer with base 16"
# the code can continue depite it though
resp.close()
# pylint: disable=broad-except
except Exception as e:
print(f"{e}, continuing..")
# pylint: disable=unnecessary-pass
pass
pixel.fill((0, 0, 0))
# return that data was just fetched
fetch_status = True
return fetch_status
# index and clock for fetching
fetch_index = 0
fetch_timer = fetch_timer * 1000
# index and clock for updating display
display_index = 0
display_timer = display_timer * 1000
# load logos
sport_startup(logos)
# initial data fetch
for z in range(5):
try:
just_fetched = get_data(SPORT_URLS[z],
teams[z],
logos[z],
groups[z])
display.root_group = groups[z]
# pylint: disable=broad-except
except Exception as Error:
print(Error)
time.sleep(10)
gc.collect()
time.sleep(5)
microcontroller.reset()
# start clocks
just_fetched = True
fetch_clock = ticks_ms()
display_clock = ticks_ms()
while True:
try:
if not just_fetched:
# garbage collection for display groups
gc.collect()
# fetch the json for the next team
just_fetched = get_data(SPORT_URLS[fetch_index],
teams[fetch_index],
logos[fetch_index],
groups[fetch_index])
# advance index
fetch_index = (fetch_index + 1) % len(teams)
# reset clocks
fetch_clock = ticks_add(fetch_clock, fetch_timer)
display_clock = ticks_add(display_clock, display_timer)
# update display seperate from API request
if ticks_diff(ticks_ms(), display_clock) >= display_timer:
print("updating display")
display.root_group = groups[display_index]
display_index = (display_index + 1) % len(teams)
display_clock = ticks_add(display_clock, display_timer)
# cleared for fetching after time has passed
if ticks_diff(ticks_ms(), fetch_clock) >= fetch_timer:
just_fetched = False
# pylint: disable=broad-except
except Exception as Error:
print(Error)
time.sleep(10)
gc.collect()
time.sleep(5)
microcontroller.reset()
Upload the Code and Libraries to the Matrix Portal S3
After downloading the Project Bundle, plug your Matrix Portal S3 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear 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 S3's CIRCUITPY drive.
- lib folder
- code.py
Your Matrix Portal S3 CIRCUITPY drive should look like this after copying the lib folder and the code.py file.
Add Your settings.toml File
As of CircuitPython 8.0.0, there is support for Environment Variables. Environment variables are stored in a settings.toml file. Similar to secrets.py, the settings.toml file separates your sensitive information from your main code.py file. Add your settings.toml file as described in the Create Your settings.toml File page earlier in this guide. You'll need to include your CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD.
CIRCUITPY_WIFI_SSID = "your-ssid-here" CIRCUITPY_WIFI_PASSWORD = "your-ssid-password-here"
Add Your Team Logo Bitmaps
You'll need to run the get_team_logos.py script that is included on the Prep the Team Logos page earlier in this guide to download the team logo bitmaps to display on the RGB LED matrices.
When the script finishes, you'll see a folder called /sport_logos in the same directory where you have the get_team_logos.py script saved. If you go into the /sport_logos folder, you'll see the folders containing the team logos:
- /team0_logos
- /team1_logos
- /team2_logos
- /team3_logos
- /team4_logos
You'll drag and drop these five folders onto the main directory of your Matrix Portal S3 CIRCUITPY drive.
How the CircuitPython Code Works
At the top of the code you can find all of the parameters that you can edit to customize the project. You can add your time zone, sports, leagues and team names. There are also two timers: fetch_timer determines how often the API should be pinged and display_timer determines the speed of the team display rotation.
# font color for text on matrix font_color = 0xFFFFFF # your timezone UTC offset and timezone name timezone_info = [-4, "EDT"] # the name of the sports you want to follow sport_name = ["football", "baseball", "soccer", "hockey", "basketball"] # the name of the corresponding leages you want to follow sport_league = ["nfl", "mlb", "usa.1", "nhl", "nba"] # the team names you want to follow # must match the order of sport/league arrays # include full name and then abbreviation (usually city/region) team0 = ["New England Patriots", "NE"] team1 = ["Boston Red Sox", "BOS"] team2 = ["New England Revolution", "NE"] team3 = ["Boston Bruins", "BOS"] team4 = ["Boston Celtics", "BOS"] # how often the API should be fetched fetch_timer = 300 # seconds # how often the display should update display_timer = 30 # seconds
Matrix
An RGBMatrix object is instantiated to be 128 pixels wide by 64 pixels high. It is then passed to be a FramebufferDisplay.
# matrix setup
base_width = 64
base_height = 32
chain_across = 2
tile_down = 2
DISPLAY_WIDTH = base_width * chain_across
DISPLAY_HEIGHT = base_height * tile_down
matrix = rgbmatrix.RGBMatrix(
width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, bit_depth=3,
rgb_pins=[
board.MTX_R1,
board.MTX_G1,
board.MTX_B1,
board.MTX_R2,
board.MTX_G2,
board.MTX_B2
],
addr_pins=[
board.MTX_ADDRA,
board.MTX_ADDRB,
board.MTX_ADDRC,
board.MTX_ADDRD
],
clock_pin=board.MTX_CLK,
latch_pin=board.MTX_LAT,
output_enable_pin=board.MTX_OE,
tile=tile_down, serpentine=True,
doublebuffer=False
)
display = framebufferio.FramebufferDisplay(matrix)
URLs
The ESPN API URLs are added to the SPORT_URLS array by passing the entries from the sport_name and sport_league arrays to the base URL with an f-string.
# add API URLs
SPORT_URLS = []
for i in range(5):
d = (
f"https://site.api.espn.com/apis/site/v2/sports/{sport_name[i]}/{sport_league[i]}/scoreboard"
)
SPORT_URLS.append(d)
Logos
Each team logo is added to the logos array. The logos are named for the team abbreviations, which allows the code to pass the second entry from the team# array to find the logo in the appropriate logo folder.
# arrays for teams, logos and display groups teams = [] logos = [] groups = [] # add team to array teams.append(team0) # grab logo bitmap name logo0 = "/team0_logos/" + team0[1] + ".bmp" # add logo to array logos.append(logo0) # create a display group group0 = displayio.Group() # add group to array groups.append(group0) # repeat:
Start-Up Screen
The sport_startup() function runs at the start of the code. It displays all five of your team logos.
# initial startup screen
# shows the five team logos you are following
def sport_startup(logo):
try:
group = displayio.Group()
bitmap0 = displayio.OnDiskBitmap(logo[0])
grid0 = displayio.TileGrid(bitmap0, pixel_shader=bitmap0.pixel_shader, x = 0)
bitmap1 = displayio.OnDiskBitmap(logo[1])
grid1 = displayio.TileGrid(bitmap1, pixel_shader=bitmap1.pixel_shader, x = 32)
bitmap2 = displayio.OnDiskBitmap(logo[2])
grid2 = displayio.TileGrid(bitmap2, pixel_shader=bitmap2.pixel_shader, x = 64)
bitmap3 = displayio.OnDiskBitmap(logo[3])
grid3 = displayio.TileGrid(bitmap3, pixel_shader=bitmap3.pixel_shader, x = 96)
bitmap4 = displayio.OnDiskBitmap(logo[4])
grid4 = displayio.TileGrid(bitmap4, pixel_shader=bitmap4.pixel_shader, x = 48, y=32)
group.append(grid0)
group.append(grid1)
group.append(grid2)
group.append(grid3)
group.append(grid4)
display.root_group = group
# pylint: disable=broad-except
except Exception:
print("Can't find bitmap. Did you run the get_team_logos.py script?")
UTC to Your Time Zone
The convert_date_format() function is used to reformat the time that is fetched from the ESPN API. It rearranges the string to be formatted as "MM/DD - HH:MM AM/PM TZ" and converts the time from UTC to your defined time zone.
# takes UTC time from JSON and reformats how its displayed
def convert_date_format(date, tz_information):
# extract year, month, day, hour, and minute from the string
year = int(date[0:4])
month = int(date[5:7])
day = int(date[8:10])
hour = int(date[11:13])
minute = int(date[14:16])
# make a datetime object using the extracted values
dt = datetime(year, month, day, hour, minute)
# adjust the datetime object for the time zone
dt_adjusted = dt + timedelta(hours=tz_information[0])
# pull out the data from the datetime
month = dt_adjusted.month
day = dt_adjusted.day
hour = dt_adjusted.hour
minute = dt_adjusted.minute
# convert 24 hour time to 12 hour time and determine AM/PM
am_pm = "AM" if hour < 12 else "PM"
hour_12 = hour if hour <= 12 else hour - 12
minute = f"{minute:02}"
# bring in time zone name for display
time_zone_str = tz_information[1]
return f"{month}/{day} - {hour_12}:{minute} {am_pm} {time_zone_str}"
MVP of the Code: Fetch the Data
The get_data() function takes care of making a request to the ESPN API and updating the display attributes for each team group. The URL, team, team logo and team display group are passed to the function.
The function starts by bringing in the team logo as an OnDiskBitmap and prepping the different text elements.
def get_data(data, team, logo, group):
pixel.fill((0, 0, 255))
print(f"Fetching data from {data}")
playing = False
names = []
scores = []
info = []
# the team you are following's logo
bitmap0 = displayio.OnDiskBitmap(logo)
grid0 = displayio.TileGrid(bitmap0, pixel_shader=bitmap0.pixel_shader, x = 2)
home_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
away_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
vs_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
vs_text.anchor_point = (0.5, 0.0)
vs_text.anchored_position = (DISPLAY_WIDTH / 2, 14)
info_text = adafruit_display_text.label.Label(terminalio.FONT, color=font_color,
text=" ")
info_text.anchor_point = (0.5, 1.0)
info_text.anchored_position = (DISPLAY_WIDTH / 2, DISPLAY_HEIGHT)
Then the request is made to the ESPN API using the json_stream library. This streams the JSON rather than storing the entire JSON response. This is a lot faster and uses less memory. However, because the data is literally streaming by, you have to be thoughtful about how you are logging the information from the JSON. JSON entries have to be accessed in the order in which they are listed in the JSON response. This is why the date entry is continually added and cleared from the info array, since it is listed before you know if it matches your team's game.
# make the request to the API
resp = requests.get(data)
# stream the json
json_data = json_stream.load(resp.iter_content(32))
for event in json_data["events"]:
# clear the date and then add the date to the array
# the date for your game will remain
info.clear()
info.append(event["date"])
# check for your team playing
if team[0] not in event["name"]:
continue
for competition in event["competitions"]:
for competitor in competition["competitors"]:
# if your team is playing:
playing = True
# get team names
# index indicates home vs. away
names.append(competitor["team"]["abbreviation"])
# the current score
scores.append(competitor["score"])
# gets info on game
info.append(event["status"]["type"]["shortDetail"])
break
If your team shows up in the API response, the date is converted using the convert_date_format() function. There are checks to see if the game is active and which team is home and away. These checks determine the content of the text elements. The opposing team's logo is accessed by replacing your team's abbreviation name with the opposing team's abbreviation.
if playing:
# pull out the date
date = info[0]
# convert it to be readable
date = convert_date_format(date, timezone_info)
print(date)
# pull out the info
info = info[1]
# check if it's pre-game
if str(info) == date or str(info) == "Scheduled":
status = "pre"
print("match, pre-game")
else:
status = info
# home and away text
# teams index determines which team is home or away
home_text.text="HOME"
away_text.text="AWAY"
if team[1] is names[0]:
home_game = True
home_text.anchor_point = (0.0, 0.5)
home_text.anchored_position = (5, 37)
away_text.anchor_point = (1.0, 0.5)
away_text.anchored_position = (124, 37)
vs_team = names[1]
else:
home_game = False
away_text.anchor_point = (0.0, 0.5)
away_text.anchored_position = (5, 37)
home_text.anchor_point = (1.0, 0.5)
home_text.anchored_position = (124, 37)
vs_team = names[0]
# if it's pre-game, show "VS"
if status == "pre":
vs_text.text="VS"
info_text.text=date
# if it's active or final show score
else:
info_text.text=info
if home_game:
vs_text.text=f"{scores[0]} - {scores[1]}"
else:
vs_text.text=f"{scores[1]} - {scores[0]}"
# load in logo from other team
vs_logo = logo.replace(team[1], vs_team)
If your team does not match any of the entries in the JSON response, then your team's logo is shown twice and the text "NO DATA AVAILABLE" is shown.
# if there is no game matching your team:
else:
status = "pre"
vs_logo = logo
info_text.text="NO DATA AVAILABLE"
Finally the display group is updated with the logo and text elements and the response is closed.
# update the display group. try/except in case its the first time it's being added
try:
group[0] = grid0
group[1] = grid1
group[2] = home_text
group[3] = away_text
group[4] = vs_text
group[5] = info_text
except IndexError:
group.append(grid0)
group.append(grid1)
group.append(home_text)
group.append(away_text)
group.append(vs_text)
group.append(info_text)
# close the response
resp.close()
The Loop
Two processes are happening concurrently in the loop with the help of ticks. The matrices are cycling through the five sport display groups by advancing through the groups array.
# update display seperate from API request
if ticks_diff(ticks_ms(), display_clock) >= display_timer:
print("updating display")
display.root_group = groups[display_index]
display_index = (display_index + 1) % len(teams)
display_clock = ticks_add(display_clock, display_timer)
The different ESPN API URLs are being fetched on a rotation. The display groups are updated in the get_data() function. As a result, when a team display group is shown it will have the updated data.
if not just_fetched:
# garbage collection for display groups
gc.collect()
# fetch the json for the next team
just_fetched = get_data(SPORT_URLS[fetch_index],
teams[fetch_index],
logos[fetch_index],
groups[fetch_index])
# advance index
fetch_index = (fetch_index + 1) % len(teams)
# reset clocks
fetch_clock = ticks_add(fetch_clock, fetch_timer)
display_clock = ticks_add(display_clock, display_timer)
# cleared for fetching after time has passed
if ticks_diff(ticks_ms(), fetch_clock) >= fetch_timer:
just_fetched = False
All of this is wrapped in a try/except in case any errors occur while making a request to the ESPN API. If an error occurs, the Matrix Portal S3 resets itself.
try:
...
except Exception as Error:
print(Error)
time.sleep(10)
gc.collect()
time.sleep(5)
microcontroller.reset()
Page last edited February 24, 2025
Text editor powered by tinymce.