Adafruit Product API

As with most IoT projects on the PyPortal, we are able to do our dynamic data and image gathering through the wonderful magic of a REST Application Programming Interface (API) request, that returns a JSON file.

The Adafruit Products API makes it easy for us to request essential info about a product, including its name, product URL, and product image.

Adafruit IO Image Converter Server

In order to use the Adafruit image converter, this project will require you to have an Adafruit IO username and key. 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 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, add them to the secrets.py file like this:

Download: file
secrets = {
	'ssid' : 'your_wifi_ssid',
	'password : 'your_wifi_password',
	'aio_username' : 'your_aio_username',
	'aio_key' : 'your_big_huge_super_long_aio_key'
}

At this point make sure your WiFi SSID and password are also in secrets.py. You only have to do this once when you set it up. If you move the PyPortal to a different WiFi served location, use a text editor to enter the new values in this file.

Add CircuitPython Code and Assets

In the embedded code element below, click on the Download: Project Zip link, and save the .zip archive file to your computer.

Then, uncompress the .zip file, it will unpack to a folder named PyPortal_NewNewNew.

Copy the contents of the PyPortal_NewNewNew directory to your PyPortal's CIRCUITPY drive, and then be sure to rename the newnewnew.py file to code.py so it will automatically run when the PyPortal restarts.

Editing the Code

You can edit the code.py file with any text editor you like. Adafruit suggests installing the free Mu Python editor as it's super handy, recognizes Adafruit boards, and has a built in serial monitor/REPL to interact with the board. Find out more about Mu here.

boot.py

We're using a special file to ensure the .bmp cache writes to the flash properly. This is the unsafe_boot.py file you copied to the drive. Rename it to boot.py now. Then, press the reset button on the PyPortal.

Note that you'll see this scary looking text appear during restart, don't worry, it's supposed to say that!

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

This is what the final contents of the CIRCUITPY drive will look like:

import time
import board
import adafruit_pyportal

# We can cycle through the latest featured products
#PRODUCTS_TYPE = "featured"
#or we can view the latest new products
PRODUCTS_TYPE = "new"

# Set up where we'll be fetching data from
DATA_SOURCE = "https://www.adafruit.com/api/products?format=micro&"+PRODUCTS_TYPE+"=1&random=1"
# What data we'll be viewing
IMAGE_LOCATION = [0, "image"]
NAME_LOCATION = [0, "name"]
URL_LOCATION = [0, "url"]

# determine the current working directory needed so we know where to find files
cwd = ("/"+__file__).rsplit('/', 1)[0]
pyportal = adafruit_pyportal.PyPortal(url=DATA_SOURCE,
                                      json_path=(NAME_LOCATION, URL_LOCATION),
                                      status_neopixel=board.NEOPIXEL,
                                      default_bg=cwd+"/new_background.bmp",
                                      text_font=cwd+"/fonts/Arial-Bold-12.bdf",
                                      text_position=((5, 35), (5, 225)),
                                      text_color=(0xFFFFFF, 0xFFFFFF),
                                      text_wrap=(35, 35), # characters to wrap
                                      image_json_path=IMAGE_LOCATION,
                                      image_resize=(320, 240),
                                      image_position=(0, 0))
pyportal.preload_font()

while True:
    response = None
    try:
        response = pyportal.fetch()
        print("Response is", response)
    except (IndexError, RuntimeError, ValueError) as e:
        print("Some error occured, retrying! -", e)

    time.sleep(60)

How It Works

The New New New Product Viewer works like this: first, when it starts up it connects to your Wifi access point as specified (and authenticated) in the secrets.py file.

Background Splash Screen

Next, it displays the new_background.bmp image file splash screen. This is a  320x240 pixel RGB 16-bit raster graphic in .bmp format.

JSON

In order to retrieve images, we'll be making a query to the Adafruit products API.

When you make a request of the server, you'll get a JSON file returned as the response.

In fact, you can run the same query as the PyPortal does to see the result. Copy and paste this link https://www.adafruit.com/api/products?format=micro&NEW=1&random=1 into your browser.

When you enter this in your web browser, you'll see a result returned like this (the product returned is randomized, so you will probably see a different one than this):

Download: file
[
  {
    "id": 3315,
    "name": "TFT FeatherWing - 2.4\" 320x240 Touchscreen For All Feathers",
    "description": "A Feather board without ambition is a Feather board without FeatherWings! Spice up your Feather project with a beautiful 2.4\" touchscreen display shield with built in microSD card socket. This TFT display is 2.4\" diagonal with a bright 4 white-LED backlight. You get  240x320 pixels with individual 16-bit color pixel control. It has way more resolution than a black and white 128x64 display. As a bonus, this display comes with a resistive touchscreen attached to it already, so you can detect f...",
    "url": "http://adafru.it/3315",
    "image": "https://cdn-shop.adafruit.com/640x480/3315-03.jpg"
  }
]

That result is a JSON (JavaScript Object Notation) array. It is comprised of a single element with five key:value pairs. For example, there is one key called name which has a value of "TFT FeatherWing - 2.4\" 320x240 Touchscreen For All Feathers"

which is expressed this way:

"name":""TFT FeatherWing - 2.4\" 320x240 Touchscreen For All Feathers""

Since this JSON object array has a consistent way to return the results to us, the code we're running on the PyPortal can easily parse the data and display it!

The image key leads to this value"https://cdn-shop.adafruit.com/640x480/3315-03.jpg"

Here's the image at that url:

We also get the url key, which is the short URL that will be displayed at the bottom of the screen, in this case, "http://adafru.it/3315"

You can see how it's done in this part of code.py:

Download: file
DATA_SOURCE = "https://www.adafruit.com/api/products?format=micro&"+PRODUCTS_TYPE+"=1&random=1"
# What data we'll be viewing
IMAGE_LOCATION = [0, "image"]
NAME_LOCATION = [0, "name"]
URL_LOCATION = [0, "url"]

Then, in the pyportal query we ask for the image name from that URL to get the path to the .jpeg image file, as well as the name and url values.

Download: file
pyportal = adafruit_pyportal.PyPortal(url=DATA_SOURCE,
                                      json_path=(NAME_LOCATION, URL_LOCATION),
                                      status_neopixel=board.NEOPIXEL,
                                      default_bg=cwd+"/new_background.bmp",
                                      text_font=cwd+"/fonts/Arial-Bold-12.bdf",
                                      text_position=((5, 35), (5, 225)),
                                      text_color=(0xFFFFFF, 0xFFFFFF),
                                      text_wrap=(35, 35), # characters to wrap
                                      image_json_path=IMAGE_LOCATION,
                                      image_resize=(320, 240),
                                      image_position=(0, 0))

With all of this prepared, during the main loop of while True: the code will query the page for the JSON data.

When it gets the path of the .jpeg file, the pyportal library passes it along to an Adafruit IO image converter server where the file is converted into the format the PyPortal can display, a 320x240 pixel RGB 16-bit .bmp.

This image is then cached onto the PyPortal's storage and displayed on the PyPortal TFT screen.

Then, the text for both the name and url values are drawn on top of the image background, using the specified font, color, and position in the PyPortal constructor.

Note, we're also specifying the text_wrap amount so that lines of text won't get cut off.

This updates every minute, so your New New New stays New New New!

This guide was first published on Apr 12, 2019. It was last updated on Apr 12, 2019.
This page (Code the New New New Viewer in CircuitPython) was last updated on Oct 24, 2020.