Are you new to using CircuitPython? No worries, there is a full getting-started guide here.
Plug the device into your computer with a known good USB cable (not a charge-only cable). The device will appear to your computer in File Explorer or Finder (depending on your operating system) as a flash drive named CIRCUITPY. If the drive does not appear, you can install CircuitPython on your device and then return here.
Download the project files with the Download Project Bundle button below. Unzip the file and copy/paste the code.py and other project files to your CIRCUITPY drive using File Explorer or Finder (depending on your operating system).
Drive Structure
After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum.
The code used by the different sized PyPortals is the same, but they do have different sized graphics. There are drive structure screenshots provided for each device below.
Code
The code.py file for the project is shown below.
The same code.py file is used for both the PyPortal and the PyPortal Titano, however the image assets differ.
PyPortal Standard Bundle
Use this Project Bundle button to download the standard PyPortal project bundle.
# SPDX-FileCopyrightText: 2024 Tim Cocks
#
# SPDX-License-Identifier: MIT
"""
SpiritBoard code.py
Standard PyPortal w/ 320x240 pixel display
Receive and display messages from the spirits.
"""
# pylint: disable=import-error, invalid-name
from os import getenv
import board
from digitalio import DigitalInOut
import adafruit_connection_manager
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_touchscreen
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP
from spirit_board import SpiritBoard
display = board.DISPLAY
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
ssid = getenv("CIRCUITPY_WIFI_SSID")
password = getenv("CIRCUITPY_WIFI_PASSWORD")
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
aio_key = getenv("ADAFRUIT_AIO_KEY")
if None in [ssid, password, aio_username, aio_key]:
raise RuntimeError(
"WiFi and Adafruit IO settings are kept in settings.toml, "
"please add them there. The settings file must contain "
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
)
# Initialize the touch overlay
touchscreen = adafruit_touchscreen.Touchscreen(
board.TOUCH_XL,
board.TOUCH_XR,
board.TOUCH_YD,
board.TOUCH_YU,
calibration=((6584, 59861), (9505, 57492)),
size=(board.DISPLAY.width, board.DISPLAY.height),
)
# Initialize the ES32SPI Coprocessor
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = board.SPI()
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
# connect to wifi network defined in settings.toml
print("Connecting to AP...")
try:
esp.connect_AP(ssid, password)
# Initialize a requests session
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
requests = adafruit_requests.Session(pool, ssl_context)
# Initialize an Adafruit IO HTTP API object
io = IO_HTTP(aio_username, aio_key, requests)
except (RuntimeError, TypeError) as e:
print("could not connect to AP or AdafruitIO: ", e)
io = None
# initialize the SpiritBoard class
spirit_board = SpiritBoard(display)
# get messages from io or the local file
messages = spirit_board.get_messages(io)
# The planchette is already at the home position.
# Slide it to home again to make it jump, in order
# indicate the message is ready to be received.
spirit_board.slide_planchette(SpiritBoard.LOCATIONS["home"], delay=0.02, step_size=6)
# current message index
message_index = 0
while True:
# read the touch screen
p = touchscreen.touch_point
# if the display was touched
if p:
# write the message at the current index
spirit_board.write_message(messages[message_index], step_size=8)
# if there are more messages in the list inside of context
if message_index < len(messages) - 1:
# increment the message index
message_index += 1
else: # there are no more messages in the list
# reset the index to 0
message_index = 0
print("fetching next")
# fetch new messages
messages = spirit_board.get_messages(io)
# make the planchette jump to indicate messages are ready to display
spirit_board.slide_planchette(SpiritBoard.LOCATIONS["home"],
delay=0.02, step_size=6)
PyPortal Titano Bundle
Use this Porject Bundle button to download the PyPortal Titano project bundle.
# SPDX-FileCopyrightText: 2024 Tim Cocks
#
# SPDX-License-Identifier: MIT
"""
SpiritBoard code.py
PyPortal w/ 480x320 pixel display
Receive and display messages from the spirits.
"""
# pylint: disable=import-error, invalid-name
from os import getenv
import board
from digitalio import DigitalInOut
import adafruit_connection_manager
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_touchscreen
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP
from spirit_board import SpiritBoard
display = board.DISPLAY
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
ssid = getenv("CIRCUITPY_WIFI_SSID")
password = getenv("CIRCUITPY_WIFI_PASSWORD")
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
aio_key = getenv("ADAFRUIT_AIO_KEY")
if None in [ssid, password, aio_username, aio_key]:
raise RuntimeError(
"WiFi and Adafruit IO settings are kept in settings.toml, "
"please add them there. The settings file must contain "
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
)
# Initialize the touch overlay
touchscreen = adafruit_touchscreen.Touchscreen(
board.TOUCH_XL,
board.TOUCH_XR,
board.TOUCH_YD,
board.TOUCH_YU,
calibration=((6584, 59861), (9505, 57492)),
size=(board.DISPLAY.width, board.DISPLAY.height),
)
# Initialize the ES32SPI Coprocessor
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = board.SPI()
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
# connect to wifi network defined in settings.toml
print("Connecting to AP...")
try:
esp.connect_AP(ssid, password)
# Initialize a requests session
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
requests = adafruit_requests.Session(pool, ssl_context)
# Initialize an Adafruit IO HTTP API object
io = IO_HTTP(aio_username, aio_key, requests)
except (RuntimeError, TypeError) as e:
print("could not connect to AP or AdafruitIO: ", e)
io = None
# initialize the SpiritBoard class
spirit_board = SpiritBoard(display)
# get messages from io or the local file
messages = spirit_board.get_messages(io)
# The planchette is already at the home position.
# Slide it to home again to make it jump, in order
# indicate the message is ready to be received.
spirit_board.slide_planchette(SpiritBoard.LOCATIONS["home"], delay=0.02, step_size=6)
# current message index
message_index = 0
while True:
# read the touch screen
p = touchscreen.touch_point
# if the display was touched
if p:
# write the message at the current index
spirit_board.write_message(messages[message_index], step_size=8)
# if there are more messages in the list inside of context
if message_index < len(messages) - 1:
# increment the message index
message_index += 1
else: # there are no more messages in the list
# reset the index to 0
message_index = 0
print("fetching next")
# fetch new messages
messages = spirit_board.get_messages(io)
# make the planchette jump to indicate messages are ready to display
spirit_board.slide_planchette(SpiritBoard.LOCATIONS["home"],
delay=0.02, step_size=6)
Page last edited January 21, 2025
Text editor powered by tinymce.