Code PyPortal with CircuitPython

CircuitPython Code

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_Youtube.

Copy the contents of the PyPortal_Youtube directory to your PyPortal's CIRCUITPY drive, and then be sure to rename the youtube.py file to code.py so it will automatically run when the PyPortal re-starts.

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

YouTube Token

To prevent unwanted bot traffic, Google requires each query of the YouTube stats to be accompanied by a YouTube token.

First, you'll need to get set up with your YouTube Data API key. Follow these instructions to get this set up.

Click the dropdown menu for Select a project.

Then, click the New Project link at the upper right corner.

On the next page, give your project a name, such as PyPortal-YouTube-Stats and then click CREATE.

Next, click the + ENABLE APIS AND SERVICES link at the top of the page.

Now, you'll be able to click the Library link on the left hand side so you can select the YouTube Data API v3 from the available libraries.

Click on the YouTube Data API v3 graphic button.

On the next page, click ENABLE.

Now we'll click on the CREATE CREDENTIALS button.

Choose the YouTube Data API v3 item from the first dropdown menu.

 

In the second menu, choose Other non-UI (e.g. cron job, daemon)

Then, click the Public data radio button.

 

Finally, click the What credentials do I need? button to get your API key.

One last setting to enable - click on the API restrictions tab for your API key and set the dropdown to YouTube Data API v3. Then click Save.

Your credentials will be generated and you should now copy the Key value and paste it into your secrets.py file.

Here's how to enter the token into your secrets.py file.

Download: file
secrets = {
	'ssid' : '_your_wifi_ssid_',
	'password' : '_your_wifi_password_',
	'youtube_token' : 'HUGE_LONG_YOUTUBE_API_TOKEN'
}
"""
This example will access the youtube API, grab a number like number of views
or subscribers... and display it on a screen
If you can find something that spits out JSON data, we can display it!

Requires a youtube API key!
"""
import time
import board
from adafruit_pyportal import PyPortal

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# Set up where we'll be fetching data from
CHANNEL_ID = "UCpOlOeQjj7EsVnDh3zuCgsA" # this isn't a secret but you have to look it up
#CHANNEL_ID = "UC6p-tjZN8s9GBSbiN4K-bwg"
CAPTION = "www.youtube.com/adafruit"
#CAPTION = "www.youtube.com/c/JohnParkMakes"

# pylint: disable=line-too-long
DATA_SOURCE = "https://www.googleapis.com/youtube/v3/channels/?part=statistics&id="+CHANNEL_ID+"&key="+secrets['youtube_token']
DATA_LOCATION1 = ["items", 0, "statistics", "viewCount"]
DATA_LOCATION2 = ["items", 0, "statistics", "subscriberCount"]
# pylint: enable=line-too-long

# the current working directory (where this file is)
cwd = ("/"+__file__).rsplit('/', 1)[0]
pyportal = PyPortal(url=DATA_SOURCE,
                    json_path=(DATA_LOCATION1, DATA_LOCATION2),
                    status_neopixel=board.NEOPIXEL,
                    default_bg=cwd+"/youtube_background.bmp",
                    text_font=cwd+"/fonts/Collegiate-50.bdf",
                    text_position=((100, 129), (155, 180)),
                    text_color=(0xFFFFFF, 0xFFFFFF),
                    caption_text=CAPTION,
                    caption_font=cwd+"/fonts/Collegiate-24.bdf",
                    caption_position=(40, 220),
                    caption_color=0xFFFFFF)

# track the last value so we can play a sound when it updates
last_subs = 0

while True:
    try:
        views, subs = pyportal.fetch()
        subs = int(subs)
        views = int(views)
        print("Subscribers:", subs)
        print("Views:", views)
        if last_subs < subs:  # ooh it went up!
            print("New subscriber!")
            pyportal.play_file(cwd+"/coin.wav")
        last_subs = subs
    except RuntimeError as e:
        print("Some error occured, retrying! -", e)

    time.sleep(60)
If you run into any errors, such as "ImportError: no module named `adafruit_display_text.label`" be sure to update your libraries to the latest release bundle!

How It Works

The PyPortal YouTube display is doing a few things to display the stats you want.

Background

First, it displays a bitmap graphic named youtube_background.bmp as the screen's background. This is a 320 x 240 pixel RGB 16-bit raster graphic in .bmp format.

Font

Then, it displays the YouTube account's name as a caption, created with bitmapped fonts to overlay on top of the background. The fonts used here is are bitmap fonts made from the Collegiate typeface. You can learn more about converting type in this guide.

Next, the PyPortal will display the current number of Views and Subscribers for the account.

JSON

To keep things current, the stats are grabbed from the Google APIs website itself.

Google automatically generates a JSON file for each YouTube channel, in this case at the address: https://www.googleapis.com/youtube/v3/channels/?part=statistics&id=UCpOlOeQjj7EsVnDh3zuCgsA&key=YOUR_HUGE_LONG_YOUTUBE_API_TOKEN (Be sure to replace that last part with your actual token!)

This file contains all sorts of information, delivered in an easy-to-parse format. If you visit that URL in Firefox, you'll see the JSON data it returns. You can look at the "beautified" version and the raw data to compare by clicking the buttons at top.

Here it is in a raw-er form, but still using indentation and carriage returns to make it readable:

Download: file
{
 "kind": "youtube#channelListResponse",
 "etag": "\"XpPGQXPnxQJhLgs6enD_n8JR4Qk/XhYU4iTm18Eso0o_j9lmVMs5Va8\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#channel",
   "etag": "\"XpPGQXPnxQJhLgs6enD_n8JR4Qk/Yv8z0Gjan8ixqB_gmDeXPAc--W4\"",
   "id": "UCpOlOeQjj7EsVnDh3zuCgsA",
   "statistics": {
    "viewCount": "55355282",
    "commentCount": "0",
    "subscriberCount": "310178",
    "hiddenSubscriberCount": false,
    "videoCount": "3784"
   }
  }
 ]
}

Keys

If we look through the JSON file, we'll see a key called items with a sub-tree below it hierarchically called 0 and a sub-tree below that called statistics. Within this key we see the two key : value pairs that we want, viewCount that has a value of 55355282 and subscriberCount with a value of 310178

The raw JSON for these key : value pairs look like this: "viewCount": 157262

"subscriberCount" : 310178

Our CircuitPython code is able to grab and parse this data using these variables:

Download: file
DATA_LOCATION1 = ["items", 0, "statistics", "viewCount"]
DATA_LOCATION2 = ["items", 0, "statistics", "subscriberCount"]

You can get your own Channel ID by logging in to YouTube and then going to your advanced account settings page.

There, you'll see your YouTube Channel ID, which you can copy and paste into the code.py file's CHANNEL_ID variable to track that channel's stats.

PyPortal Constructor

When we set up the pyportal constructor, we are providing it with these things:

  • url to query
  • json_path to traverse and find the key:value pair we need
  • status_neopixel pin
  • default_bg path and name to display the background bitmap
  • text_font path and name to the font used for displaying the follower count value
  • text_position on the screen's x/y coordinate system
  • text_color
  • caption_text to display statically -- in this case the name of the repo
  • caption_font
  • caption_position
  • caption_color

Fetch

With the pyportal set up, we can then use pyportal.fetch() to do the query and parsing of the two pieces of YouTube data and then display them on screen along with the caption text on top of the background image.

Ba-Ding!

Additionally, we use the last_value variable's state to compare against the latest value. If they differ, we play the coin.wav file for a satisfying ding over the PyPortal's built in speaker!

To make your own .wav files, check out this guide.

Customization

You can customize this project to make it your own and point to different website APIs as the source of your JSON data, as well as adjust the graphics and text.

Text Position

Depending on the design of your background bitmap and the length of the text you're displaying, you may want to reposition the text and caption. You can do this with the text_position and caption_position options.

The PyPortal's display is 320 pixels wide and 240 pixels high. In order to refer to those positions on the screen, we use an x/y coordinate system, where x is horizontal and y is vertical.

The origin of this coordinate system is the upper left corner. This means that a pixel placed at the upper left corner would be (0,0) and the lower right corner would be (320, 240).

So, if you wanted to move the subscriber count text to the right and up closer to the top, your code may look like this for that part of the pyportal constructor: text_position=(250, 10)

Text Color

Another way to customize your stats trophy is to adjust the color of the text. The line text_color=0xFFFFFF in the constructor shows how. You will need to use the hexidecimal value for any color you want to display.

You can use something like https://htmlcolorcodes.com/ to pick your color and then copy the hex value, in this example it would be 0x0ED9EE

Background Image

If you would like to create your own background, awesome! You'll want to save the file with these specifications:

  • 320 x 240 pixels
  • 16-bit RGB color
  • Save file as .bmp format

You can then copy the .bmp file to the root level of the CIRCUITPY drive. Make sure you refer to this new filename in the pyportal constructor line:

default_bg=cwd+"/youtube_background.bmp"

Change that line to use the new filename name, such as:

default_bg=cwd+"/my_new_background.bmp"

Now, we'll look at mounting the PyPortal onto a stylish stand!

This guide was first published on Mar 15, 2019. It was last updated on Mar 15, 2019. This page (Code PyPortal with CircuitPython) was last updated on Oct 14, 2019.