The included examples are all ports from previous projects for the PyPortal with associated learn guides. To use each of the examples, you will want to either go to the original Learn Guide click Download Project Zip or go to the original Project Files on GitHub.
While there are other examples besides the ones listed on this page, some of them make use of the some of the onboard sensors such as the light or temperature sensor, which is not present by default on the Pi. However, if you have a PiTFT with additional pins on the back, you could use a 26-pin or 40-pin Pi-Cobbler and connect additional sensors too.
If you are using an FT232H, you could may wire up some additional sensors to this board on some unused GPIO pins, though since the I2C pins are shared with the SPI pins, you won't be able to run and use I2C devices at the same time.
The following examples have been modified to work with the Raspberry Pi, which has a Linux Operating System and no built-in NeoPixel.
Secrets File
To run the examples, you will need to setup a secrets.py file in your script folder. You can copy it below if you don't already have one. Note that unlike the original PyPortal secrets file, you don't need to add your WiFi connection information because your board should already be on the internet.
# 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 = { 'timezone' : "America/New_York", # http://worldtimeapi.org/timezones 'github_token' : 'fawfj23rakjnfawiefa', 'hackaday_token' : 'h4xx0rs3kret', 'openweather_token' : 'xxxxxxxxxxxxxxxxxxxxxxxx', }
PyPortal Startup Image and Sound
The PyPortal library looks to see if the PyPortal Startup Image and Wav file are in the folder that you are running the example from and plays them if they are there. You can download those here if you don't already have a copy. Be sure they are named pyportal_startup.bmp and pyportal_startup.wav.
When you start up each example, you should see the startup image displayed briefly and a hear sound played:
Script changes for the 3.5" HX8357 TFT Display
To use the HX8357 display, we'll need to declare the display object in the example and pass it in since there's no way to detect which display is being used. In fact, it's likely that without modifying the code, the example would still run in a portion of the display with the unused part appearing as random noise.
The first thing you will need to add is some code to setup the display.
# Setup the Display import board import displayio import adafruit_hx8357 displayio.release_displays() spi = board.SPI() tft_cs = board.CE0 tft_dc = board.D25 display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_hx8357.HX8357(display_bus, width=480, height=320, backlight_pin=board.D18)
The other thing you will need to change is to pass in the already initialized display as an additional parameter to the PyPortal Initialization Function. So we will change this line:
pyportal = PyPortal(
to this:
pyportal = PyPortal( display=display,
NASA Image Example
The next example is the Image of the Day from NASA. This will get the current NASA image URL, download the image, resize it, and display it on the screen. You can get the resources for this example from the original PyPortal NASA Example or from the original Learn Guide.
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense """ You can find any resources in the associated Learn Guide at: https://learn.adafruit.com/pyportal-nasa-image-of-the-day-viewer Note: This library is designed to run on CPython and not CircuitPython. """ import os import time from adafruit_pyportal import PyPortal # Set up where we'll be fetching data from DATA_SOURCE = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY" # There's a few different places we look for data in the photo of the day IMAGE_LOCATION = ["url"] TITLE_LOCATION = ["title"] DATE_LOCATION = ["date"] # the current working directory (where this file is) try: cwd = os.path.dirname(os.path.realpath(__file__)) except AttributeError: cwd = ("/" + __file__).rsplit("/", 1)[0] pyportal = PyPortal( url=DATA_SOURCE, json_path=(TITLE_LOCATION, DATE_LOCATION), default_bg=cwd + "/nasa_background.bmp", text_font=cwd + "/fonts/Arial-12.bdf", text_position=((5, 220), (5, 200)), text_color=(0xFFFFFF, 0xFFFFFF), text_maxlen=(50, 50), # cut off characters image_json_path=IMAGE_LOCATION, image_resize=(320, 240), image_position=(0, 0), debug=True, ) while True: response = None try: response = pyportal.fetch() print("Response is", response) except RuntimeError as e: print("Some error occured, retrying! -", e) time.sleep(30 * 60) # 30 minutes till next check
Upload the secrets file, background image, font folder and the above example code to your Pi. If you are using a 3.5" display, be sure to make the necessary changes as well. After that, run the code:
python3 adafruit_blinka_pyportal_nasa.py
You should see the following background appear first:
Following that, it should download and display an image similar to this:
Quote Example
The next example is the Adafruit Quote display. This will go out and fetch a random quote from the Adafruit website and display it on the screen. You can get the resources for this example from the original PyPortal Quote Example or from the original Learn Guide.
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense """ You can find any resources in the associated Learn Guide at: https://learn.adafruit.com/pyportal-adafruit-quote-board Note: This library is designed to run on CPython and not CircuitPython. """ import os import time from adafruit_pyportal import PyPortal # Set up where we'll be fetching data from DATA_SOURCE = "https://www.adafruit.com/api/quotes.php" QUOTE_LOCATION = [0, "text"] AUTHOR_LOCATION = [0, "author"] # the current working directory (where this file is) try: cwd = os.path.dirname(os.path.realpath(__file__)) except AttributeError: cwd = ("/" + __file__).rsplit("/", 1)[0] pyportal = PyPortal( url=DATA_SOURCE, json_path=(QUOTE_LOCATION, AUTHOR_LOCATION), default_bg=cwd + "/quote_background.bmp", text_font=cwd + "/fonts/Arial-ItalicMT-17.bdf", text_position=((20, 120), (5, 210)), # quote location # author location text_color=(0xFFFFFF, 0x8080FF), # quote text color # author text color text_wrap=(35, 0), # characters to wrap for quote # no wrap for author text_maxlen=(180, 30), # max text size for quote & author ) # speed up projects with lots of text by preloading the font! pyportal.preload_font() while True: try: value = pyportal.fetch() print("Response is", value) except (ValueError, RuntimeError) as e: print("Some error occured, retrying! -", e) time.sleep(60)
Upload the secrets file, background image, font folder and the above example code to your Pi. If you are using a 3.5" display, be sure to make the necessary changes as well. After that, run the code:
python3 adafruit_blinka_pyportal_quote.py
You should see something similar to the following:
Discord Counter Example
The next example is the Adafruit Discord Online Counter display. This will go out and find the number of people currently online using the Adafruit Discord Server and display it on the screen. You can get the resources for this example from the original PyPortal Discord Example or from the original Learn Guide.
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense """ This example will access shields.io API, grab the SVG graphic and then use regular expression search to locate the number of online discord users, then display it on a screen. If you can find something that spits out text, we can display it! You can find any resources in the associated Learn Guide at: https://learn.adafruit.com/pyportal-discord-online-count Note: This library is designed to run on CPython and not CircuitPython. """ import os import time from adafruit_pyportal import PyPortal # Set up where we'll be fetching data from DATA_SOURCE = "https://img.shields.io/discord/327254708534116352.svg" # a regular expression for finding the data within the SVG xml text! DATA_LOCATION = [r">([0-9]+ online)<"] try: cwd = os.path.dirname(os.path.realpath(__file__)) except AttributeError: cwd = ("/" + __file__).rsplit("/", 1)[0] pyportal = PyPortal( url=DATA_SOURCE, regexp_path=DATA_LOCATION, default_bg=cwd + "/discord_background.bmp", text_font=cwd + "/fonts/Collegiate-50.bdf", text_position=(70, 216), text_color=0x000000, ) while True: try: value = pyportal.fetch() print("Response is", value) except RuntimeError as e: print("Some error occured, retrying! -", e) time.sleep(60)
Upload the secrets file, background image, font folder and the above example code to your Pi. If you are using a 3.5" display, be sure to make the necessary changes as well. After that, run the code:
python3 adafruit_blinka_pyportal_discord.py
You should see something similar to the following:
Open Weather Example
The last example is the Open Weather display. This will go out and find the weather conditions for the location that you have set and display it on the screen. This example is a little bit more complicated than the other examples. You can get the resources for this example from the original PyPortal Open Weather Example or from the original Learn Guide.
For this example, you will need to go to this link and register for a free account. Once registered, you'll get an email containing your API key, also known as the "openweather token". Edit your secrets.py file and add the token into there.
Look for this line and be sure to change the LOCATION
variable to your location:
# Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" LOCATION = "Manhattan, US"
For this example, you will need 2 files. The main file:
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense """ This example queries the Open Weather Maps site API to find out the current weather for your location... and display it on a screen! if you can find something that spits out JSON data, we can display it You can find any resources in the associated Learn Guide at: https://learn.adafruit.com/pyportal-weather-station Note: This library is designed to run on CPython and not CircuitPython. """ import os import sys import time import adafruit_blinka_pyportal_openweather_graphics as openweather_graphics from adafruit_pyportal import PyPortal # the current working directory (where this file is) try: cwd = os.path.dirname(os.path.realpath(__file__)) except AttributeError: cwd = ("/" + __file__).rsplit("/", 1)[0] sys.path.append(cwd) # 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 # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" LOCATION = "Manhattan, US" # Set up where we'll be fetching data from DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q=" + LOCATION DATA_SOURCE += "&appid=" + secrets["openweather_token"] # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' DATA_LOCATION = [] # Initialize the pyportal object and let us know what data to fetch and where # to display it pyportal = PyPortal(url=DATA_SOURCE, json_path=DATA_LOCATION, default_bg=0x000000) gfx = openweather_graphics.OpenWeather_Graphics( pyportal.splash, am_pm=True, celsius=False ) localtile_refresh = None weather_refresh = None while True: # only query the online time once per hour (and on first run) if (not localtile_refresh) or (time.monotonic() - localtile_refresh) > 3600: try: print("Getting time from internet!") pyportal.get_local_time() localtile_refresh = time.monotonic() except RuntimeError as e: print("Some error occured, retrying! -", e) continue # only query the weather every 10 minutes (and on first run) if (not weather_refresh) or (time.monotonic() - weather_refresh) > 600: try: value = pyportal.fetch() print("Response is", value) gfx.display_weather(value) weather_refresh = time.monotonic() except RuntimeError as e: print("Some error occured, retrying! -", e) continue gfx.update_time() time.sleep(30) # wait 30 seconds before updating anything again
And the Graphics handling file:
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense """ This is a dependency of adafruit_blinka_pyportal_openweather.py and should not be run directly. Note: This library is designed to run on CPython and not CircuitPython. """ import os import time import json import displayio from adafruit_display_text.label import Label from adafruit_bitmap_font import bitmap_font try: cwd = os.path.dirname(os.path.realpath(__file__)) except AttributeError: cwd = ("/" + __file__).rsplit("/", 1)[0] small_font = cwd + "/fonts/Arial-12.bdf" medium_font = cwd + "/fonts/Arial-16.bdf" large_font = cwd + "/fonts/Arial-Bold-24.bdf" # pylint: disable=too-many-instance-attributes class OpenWeather_Graphics(displayio.Group): def __init__(self, root_group, *, am_pm=True, celsius=True): super().__init__(max_size=2) self.am_pm = am_pm self.celsius = celsius root_group.append(self) self._icon_group = displayio.Group(max_size=1) self.append(self._icon_group) self._text_group = displayio.Group(max_size=5) self.append(self._text_group) self._icon_sprite = None self.set_icon(cwd + "/weather_background.bmp") self.small_font = bitmap_font.load_font(small_font) self.medium_font = bitmap_font.load_font(medium_font) self.large_font = bitmap_font.load_font(large_font) glyphs = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: " self.small_font.load_glyphs(glyphs) self.medium_font.load_glyphs(glyphs) self.large_font.load_glyphs(glyphs) self.large_font.load_glyphs(("°",)) # a non-ascii character we need for sure self.city_text = None self.time_text = Label(self.medium_font, max_glyphs=8) self.time_text.x = 200 self.time_text.y = 12 self.time_text.color = 0xFFFFFF self._text_group.append(self.time_text) self.temp_text = Label(self.large_font, max_glyphs=6) self.temp_text.x = 200 self.temp_text.y = 195 self.temp_text.color = 0xFFFFFF self._text_group.append(self.temp_text) self.main_text = Label(self.large_font, max_glyphs=20) self.main_text.x = 10 self.main_text.y = 195 self.main_text.color = 0xFFFFFF self._text_group.append(self.main_text) self.description_text = Label(self.small_font, max_glyphs=60) self.description_text.x = 10 self.description_text.y = 225 self.description_text.color = 0xFFFFFF self._text_group.append(self.description_text) def display_weather(self, weather): weather = json.loads(weather) # set the icon/background weather_icon = weather["weather"][0]["icon"] self.set_icon(cwd + "/icons/" + weather_icon + ".bmp") city_name = weather["name"] + ", " + weather["sys"]["country"] print(city_name) if not self.city_text: self.city_text = Label(self.medium_font, text=city_name) self.city_text.x = 10 self.city_text.y = 12 self.city_text.color = 0xFFFFFF self._text_group.append(self.city_text) self.update_time() main_text = weather["weather"][0]["main"] print(main_text) self.main_text.text = main_text temperature = weather["main"]["temp"] - 273.15 # its...in kelvin print(temperature) if self.celsius: self.temp_text.text = "%d °C" % temperature else: self.temp_text.text = "%d °F" % ((temperature * 9 / 5) + 32) description = weather["weather"][0]["description"] description = description[0].upper() + description[1:] print(description) self.description_text.text = description # "thunderstorm with heavy drizzle" def update_time(self): """Fetch the time.localtime(), parse it out and update the display text""" now = time.localtime() hour = now[3] minute = now[4] format_str = "%d:%02d" if self.am_pm: if hour >= 12: hour -= 12 format_str = format_str + " PM" else: format_str = format_str + " AM" if hour == 0: hour = 12 time_str = format_str % (hour, minute) print(time_str) self.time_text.text = time_str def set_icon(self, filename): """The background image to a bitmap file. :param filename: The filename of the chosen icon """ print("Set icon to ", filename) if self._icon_group: self._icon_group.pop() if not filename: return # we're done, no icon desired with open(filename, "rb") as icon_file: icon = displayio.OnDiskBitmap(icon_file) self._icon_sprite = displayio.TileGrid( icon, pixel_shader=displayio.ColorConverter() ) self._icon_group.append(self._icon_sprite)
Upload the updated secrets file, background image, font folder, icons folder and the above example files to your Pi. If you are using a 3.5" display, be sure to make the necessary changes as well. After that, run the code:
python3 adafruit_blinka_pyportal_openweather.py
You should see something similar to the following: