CircuitPython Code
In the embedded code element below, click on the Download Project Bundle button, and save the .zip archive file to your computer.
Then, uncompress the .zip file, it will unpack to a folder named PyPortal_Trivia_Time.
Copy the contents of the PyPortal_Trivia_Time directory to your PyPortal CIRCUITPY drive.
This is what the final contents of the CIRCUITPY drive will look like:

Make sure you are using CircuitPython 4.1.0 or later or text may be slow to display!
# SPDX-FileCopyrightText: 2019 Isaac Wellish for Adafruit Industries # # SPDX-License-Identifier: MIT """ This example uses the Open Trivia Database API to display multiple choice trivia questions. Tap the screen to start, then a question will appear and a 30 second timer will start. The first player to hit their button will get 10 seconds to answer. Hit button again to reveal answer. Tap screen to move to next question. This program assumes two buttons are attached to D3 and D4 on the Adafruit PyPortal. """ import time import random import board from adafruit_pyportal import PyPortal from digitalio import DigitalInOut, Direction, Pull from adafruit_display_text import label from adafruit_bitmap_font import bitmap_font # initialize harware led = DigitalInOut(board.L) # For debugging led.direction = Direction.OUTPUT button1 = DigitalInOut(board.D4) button2 = DigitalInOut(board.D3) button1.direction = Direction.INPUT button2.direction = Direction.INPUT button1.pull = Pull.UP button2.pull = Pull.UP display = board.DISPLAY # determine the current working directory # needed so we know where to find files cwd = ("/"+__file__).rsplit('/', 1)[0] # Set up where we'll be fetching data from DATA_SOURCE = "https://opentdb.com/api.php?amount=1&type=multiple" Q_LOCATION = ['results', 0, 'question'] WA_LOCATION1 = ['results', 0, 'incorrect_answers', 0] WA_LOCATION2 = ['results', 0, 'incorrect_answers', 1] WA_LOCATION3 = ['results', 0, 'incorrect_answers', 2] CA_LOCATION = ['results', 0, 'correct_answer'] # Text info trivia_font = bitmap_font.load_font("/fonts/Arial-ItalicMT-17.bdf") loading_color = 0x8080FF loading_position = (100,120) loading_text_area = label.Label(trivia_font, color=loading_color, x=loading_position[0], y=loading_position[1]) q_color = 0x8080FF q_position = (25, 70) q_text_area = label.Label(trivia_font, x=q_position[0], y=q_position[1], color=q_color, line_spacing = 1) answer_choices = ("A","B","C","D") a_positions = ((25, 145), (25, 165), (25, 185), (25, 205)) a_color = 0xFFFFFF ans_text_areas = [] for answernum in range(4): ans_text_areas.append(label.Label(trivia_font, color=a_color, line_spacing = 1.5, x=a_positions[answernum][0], y=a_positions[answernum][1])) reveal_position = (25, 45) reveal_text_area = label.Label(trivia_font, color=loading_color, x=reveal_position[0], y=reveal_position[1]) timer_position = (25, 215) timer_color = 0xFF00FF timer_text_area = label.Label(trivia_font, color=timer_color, x=timer_position[0], y=timer_position[1]) # A function to shuffle trivia questions def shuffle(aList): for i in range(len(aList)): j = random.randint(0, len(aList)-1) # Swap arr[i] with the element at random index aList[i], aList[j] = aList[j], aList[i] return aList # convert html codes to normal text def unescape(s): s = s.replace(""", "''") s = s.replace("'", "'") s = s.replace("&", "&") return s # A function to handle the timer and determine which player answers first def faceOff(timerLength): timer_text = str(timerLength) + " seconds!" timer_text_area.text = '' timer_text_area.text = str(timer_text) timerStart = time.monotonic() while time.monotonic() - timerStart < timerLength: if button1.value: led.value = False # For debugging else: # If button 1 pressed, print player 1 on screen and exit function led.value = True # For debugging q_text_area.text = '' reveal_text_area.text = "Player 1!" break if button2.value: led.value = False # For debugging else: # If button 2 pressed, print player 2 on screen and exit function led.value = True # For debugging q_text_area.text = '' reveal_text_area.text = "Player 2!" break time.sleep(0.05) # debounce delay else: # Timer runs out q_text_area.text = '' reveal_text_area.text = "Times up!" # PyPortal constructor pyportal = PyPortal(url=DATA_SOURCE, json_path=(Q_LOCATION, CA_LOCATION, WA_LOCATION1, WA_LOCATION2, WA_LOCATION3), status_neopixel=board.NEOPIXEL, default_bg=cwd+"/trivia_title.bmp") pyportal.preload_font() # speed things up by preloading font pyportal.splash.append(loading_text_area) #loading... pyportal.splash.append(q_text_area) pyportal.splash.append(reveal_text_area) pyportal.splash.append(timer_text_area) for textarea in ans_text_areas: pyportal.splash.append(textarea) while True: # Load new question when screen is touched while not pyportal.touchscreen.touch_point: pass reveal_text_area.text = '' q_text_area.text = '' for textarea in ans_text_areas: textarea.text = '' timer_text_area.text = '' pyportal.set_background(cwd+"/trivia.bmp") loading_text_area.text ="Loading question..." while True: try: value = pyportal.fetch() break except RuntimeError as e: print("Some error occured, retrying! -", e) continue print("Response is", value) question = value[0] correct_answer = value[1] answers = shuffle(value[1:5]) loading_text_area.text = '' # Format text and wrap with display text library try: # sometimes gives a runtime error: Group full q_text_area.text = '\n'.join(pyportal.wrap_nicely(unescape(question), 35)) except RuntimeError as e: print("Group full", e) continue for k, answer in enumerate(answers): ans_text_areas[k].text = answer_choices[k]+") "+unescape(answer) faceOff(10) # 10 seconds with question time.sleep(2) # pause for 2 seconds to show which player tapped first faceOff(5) # 5 seconds to answer timer_text_area.text = '' # Show the correct answer k = answers.index(correct_answer) reveal_text = ("Correct Answer:\n"+answer_choices[k]+") " +unescape(answers[k])+"\n(Tap for next question.)") print(reveal_text) reveal_text_area.text = reveal_text
Page last edited January 22, 2025
Text editor powered by tinymce.