Update CircuitPython

First make sure you are running the latest version of Adafruit CircuitPython for your board. 

See the guide page Install CircuitPython in the Adafruit Learning System guide Adafruit PyPortal for more information.

Library Files

Next you'll need to install the latest libraries to use the hardware.

Please follow the guide page CircuitPython Libraries in the Adafruit PyPortal guide.

Before continuing, please make sure to copy at least these files and folders into your board's lib folder.

  • adafruit_bitmap_font
  • adafruit_bus_device
  • adafruit_display_shapes
  • adafruit_display_text
  • adafruit_esp32spi
  • adafruit_io
  • adafruit_logging.mpy
  • adafruit_pyportal.mpy
  • adafruit_requests.mpy
  • adafruit_sdcard.mpy
  • adafruit_touchscreen.mpy
  • neopixel.mpy

Grab the Project Files

Once you have your CircuitPython libraries installed, you can grab the rest of the project files. Use the download "Project Zip" link in the code window below to download the code, fonts, background bitmap and a starter secrets.py file.

Using your computer, unzip the files and copy the contents of the zip file to your PyPortal CIRCUITPY drive.

import time
import random
import board
from adafruit_pyportal import PyPortal
from adafruit_display_shapes.circle import Circle

WIDTH = board.DISPLAY.width
HEIGHT = board.DISPLAY.height

#pylint: disable=line-too-long

# these lines show the entire collection
APIURL = "https://openaccess-api.clevelandart.org/api/artworks?cc0=1&has_image=1&indent=2&limit=1&skip="
IMAGECOUNT = 31954

# uncomment these lines to show just paintings
# APIURL = "https://openaccess-api.clevelandart.org/api/artworks?cc0=1&has_image=1&indent=2&limit=1&type=Painting&skip="
# IMAGECOUNT = 3223

BACKGROUND_FILE = "/background.bmp"
if WIDTH > 320:
    BACKGROUND_FILE = "/background_480.bmp"

pyportal = PyPortal(default_bg=BACKGROUND_FILE,
                    image_json_path=["data", 0, "images", "web", "url"],
                    image_dim_json_path=(["data", 0, "images", "web", "width"],
                                         ["data", 0, "images", "web", "height"]),
                    image_resize=(WIDTH, HEIGHT - 15),
                    image_position=(0, 0),
                    text_font="/fonts/OpenSans-9.bdf",
                    json_path=["data", 0, "title"],
                    text_position=(4, HEIGHT - 9),
                    text_color=0xFFFFFF)

circle = Circle(WIDTH - 8, HEIGHT - 7, 5, fill=0)
pyportal.splash.append(circle)
loopcount = 0
errorcount = 0
while True:
    response = None
    try:
        circle.fill = 0xFF0000
        itemid = random.randint(1, IMAGECOUNT)
        # itemid = 20 # portrait mode example
        # itemid = 21 # landscape mode example
        print("retrieving url:", APIURL + str(itemid))
        response = pyportal.fetch(APIURL + str(itemid))
        circle.fill = 0
        print("Response is", response)
        loopcount = loopcount + 1

    except (RuntimeError, KeyError, TypeError) as e:
        print("An error occured, retrying! -", e)
        print("loop counter:", loopcount)
        assert errorcount < 20, "Too many errors, stopping"
        errorcount = errorcount + 1
        time.sleep(60)
        continue

    errorcount = 0
    stamp = time.monotonic()
    # wait 5 minutes before getting again
    while (time.monotonic() - stamp) < (5*60):
        # or, if they touch the screen, fetch immediately!
        if pyportal.touchscreen.touch_point:
            break

Your CIRCUITPY drive should now contain at least these files and folders:

  • background_480.bmp
  • background.bmp
  • code.py
  • fonts (folder):
    • OpenSans-9.bdf
  • lib (folder):
    • adafruit_bitmap_font (folder)
    • adafruit_bus_device (folder)
    • adafruit_display_shapes (folder)
    • adafruit_display_text (folder)
    • adafruit_esp32spi (folder)
    • adafruit_io (folder)
    • adafruit_logging.mpy
    • adafruit_pyportal.mpy
    • adafruit_requests.mpy
    • adafruit_sdcard.mpy
    • adafruit_touchscreen.mpy
    • neopixel.mpy
  • secrets.py
  • unsafe_boot.py

Secrets File Setup

Next is to get the PyPortal connected to the internet. To do this, we need to create a secrets file. If you have not yet set up a secrets.py file in your CIRCUITPY drive and connected to the internet using it, follow this guide and come back when you've successfully connected to the internet

Using Mu or any text editor, you should add your Adafruit IO Username and Adafruit IO Key to the secrets.py file. This project connects to Adafruit IO to convert JPEG images to BMP images sized to the PyPortal screen. Adafruit IO is 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.

Once you have logged into your account, there are two pieces of information you'll need to place in your secrets.py 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.

Then, update the aoi_username and aio_key values in the secrets.py file. Your secrets.py file should look like this:

# This file is where you keep secret settings, passwords, and tokens!
# If you put them in the code you risk committing that info or sharing it

secrets = {
    'ssid' : 'CHANGE ME',
    'password' : 'CHANGE ME',
    'aio_username' : 'CHANGE ME',
    'aio_key' : 'CHANGE ME',
}

Fonts

A font is used to display the title of the artwork on the PyPortal. You will need to create a fonts folder on your CircuitPython CIRCUITPY drive and download the font file from the project's GitHub repository.

The Background Image

The background image is used when the art frame initially starts. It is an image of the Cleveland Museum of Art name. The background.bmp and background480.bmp files are placed in the main (root) directory of the CIRCUITPY drive. The background480.bmp is used with the Titano's larger screen.

The unsafe_boot.py File

This project contains the unsafe_boot.py file to switch the CircuitPython filesystem to read-write mode, allowing the artwork to be downloaded locally prior to displaying it. This is a safeguard mechanism, since having two different processors writing to the same filesystem can be a bit risky. It is not a problem here unless you heavily customize this project, which you may want to backup the files. Once the project is installed onto the PyPortal, rename this file to boot.py and reboot the PyPortal. Your PyPortal art frame is now ready to display 31,000+ images from the Cleveland Museum of Art.

import time
import storage

print("**************** WARNING ******************")
print("Using the filesystem as a write-able cache!")
print("This is risky behavior, backup your files!")
print("**************** WARNING ******************")

storage.remount("/", disable_concurrent_write_protection=True)
time.sleep(5)
This guide was first published on Jan 29, 2020. It was last updated on Jan 29, 2020. This page (Code) was last updated on Feb 20, 2020.