Secrets File Setup

In order to get the precise time, our project will query the Adafruit IO Internet of Things service for the time. 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.

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 Adafruit IO Key on the right hand side of the Adafruit IO header to obtain this information.

Using an online time reference means we will account for daylight savings time and never have any drift!

Then, add them to the secrets.py file:

secrets = {
    'ssid' : '_your_wifi_ssid',
    'password' : '_your_wifi_password',
    'aio_username' : '_your_aio_username_',
    'aio_key' : '_your_big_huge_super_long_aio_key_',
    'timezone' : "America/New_York" # http://worldtimeapi.org/timezones
    }

The PyPortal's code determines the local time by checking the internet information using the WiFi connection. It uses your local timezone to fetch and determine the local time. Once you've set up your timezone, you do not need to adjust for daylight savings time or leap years. 

To do this, you'll need to set this line in your secrets file to your local timezone:

'timezone' : "America/New_York"

Don't know your timezone? Here's a great list from the IANA Timezone Database. Simply find the nearest timezone to your desired location, and use that name as displayed in the TZ database name column. 

Install 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_Quarantine_Clock.

# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import board
import busio
import digitalio
from adafruit_esp32spi import adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_requests as requests
from adafruit_pyportal import PyPortal
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label

try:
    from secrets import secrets
except ImportError:
    print("""WiFi settings are kept in secrets.py, please add them there!
the secrets dictionary must contain 'ssid' and 'password' at a minimum""")
    raise

# Label colors
LABEL_DAY_COLOR = 0xFFFFFF
LABEL_TIME_COLOR = 0x2a8eba

# the current working directory (where this file is)
cwd = ("/"+__file__).rsplit('/', 1)[0]
background = None
# un-comment to set background image
# background = cwd+"/background.bmp"

# Descriptions of each hour
# https://github.com/mwfisher3/QuarantineClock/blob/master/today.html
time_names = ["midnight-ish", "late night", "late", "super late",
              "super early","really early","dawn","morning",
              "morning","mid-morning","mid-morning","late morning",
              "noon-ish","afternoon","afternoon","mid-afternoon",
              "late afternoon","early evening","early evening","dusk-ish",
              "evening","evening","late evening","late evening"]

# Days of the week
week_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

esp32_cs = digitalio.DigitalInOut(board.ESP_CS)
esp32_ready = digitalio.DigitalInOut(board.ESP_BUSY)
esp32_reset = digitalio.DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset, debug=False)
requests.set_socket(socket, esp)

# initialize pyportal
pyportal = PyPortal(esp=esp,
                    external_spi=spi)

# set pyportal's backlight brightness
pyportal.set_backlight(0.7)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
    print("Firmware vers.", esp.firmware_version)
    print("MAC addr:", [hex(i) for i in esp.MAC_address])

# Set the font and preload letters
font_large = bitmap_font.load_font("/fonts/Helvetica-Bold-44.bdf")
font_small = bitmap_font.load_font("/fonts/Helvetica-Bold-24.bdf")
font_large.load_glyphs(b'abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ')
font_small.load_glyphs(b'abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()')

# Set up label for the day
label_day = label.Label(font_large, color=LABEL_DAY_COLOR)
label_day.x = board.DISPLAY.width // 7
label_day.y = 80
pyportal.splash.append(label_day)

# Set up label for the time
label_time = label.Label(font_small, color=LABEL_TIME_COLOR)
label_time.x = board.DISPLAY.width // 4
label_time.y = 150
pyportal.splash.append(label_time)

refresh_time = None
while True:
    # only query the network time every hour
    if (not refresh_time) or (time.monotonic() - refresh_time) > 3600:
        try:
            print("Getting new time from internet...")
            pyportal.get_local_time(secrets['timezone'])
            refresh_time = time.monotonic()
            # set the_time
            the_time = time.localtime()
        except (ValueError, RuntimeError, ConnectionError, OSError) as e:
            print("Failed to get data, retrying\n", e)
            esp.reset()
            continue

    # Convert tm_wday to name of day
    weekday = week_days[the_time.tm_wday]

    # set the day label's text
    label_day.text = weekday

    # set the time label's text
    label_time.text = "({})".format(time_names[the_time.tm_hour])

    # update every minute
    time.sleep(60)

Copy the contents of the PyPortal_Quarantine_Clock directory to your PyPortal's CIRCUITPY drive.

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

Code Usage

The code determines the local time by using the WiFi connection to query the Adafruit IO Time Service. It draws two labels to display the day of the week and the estimated time. 

We use a list of time names (time_names) for a description of each hour. The code obtains the number of days since Sunday and calculates the weekday from it.

Each hour, the code fetches the network time from the Adafruit IO Time Service and refreshes the displayed time and date.

Customization

Set a background image

You can customize the background by setting a hex color or by making your own background .bmp file.

Using a hex color picker such as https://htmlcolorcodes.com, pick your color and copy the hex value. change the following line of code from

background = None

to 

background = 0xC91818

You can also customize the background for a different event, by making your own 320x240 16-bit RGB color .bmp file. Name the .bmp file background.bmp and copy it to the CIRCUITPY volume. In the code, change the following lines of code from

background = None
# un-comment to set background image
# background = cwd+"/background.bmp" background = None

to 

# background = None
# un-comment to set background image
background = cwd+"/background.bmp"

Font

The font used for the date and time displayed on the PyPortal are loaded and appended on the display. 

You can change the fonts used by the clock by changing the .bdf files on the two following lines in the code:

font_large = bitmap_font.load_font("/fonts/Helvetica-Bold-44.bdf")
font_small = bitmap_font.load_font("/fonts/Helvetica-Bold-24.bdf")

Text Color

You can also adjust the colors for the time and date labels. Using a hex color picker such as https://htmlcolorcodes.com, pick your color and then copy the hex value. Set LABEL_DAY_COLOR if you want to set the color of the weekday label or LABEL_TIME_COLOR to set the color of the estimated time label.

# Label colors
LABEL_DAY_COLOR = 0xFFFFFF
LABEL_TIME_COLOR = 0x8f42f4

This guide was first published on Apr 24, 2020. It was last updated on Apr 24, 2020.

This page (Code PyPortal with CircuitPython) was last updated on Mar 05, 2023.

Text editor powered by tinymce.