Once you've finished setting up your QT Py ESP32-S2 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import os import time import wifi import microcontroller import board import neopixel import adafruit_connection_manager import adafruit_requests from adafruit_io.adafruit_io import IO_HTTP from adafruit_ticks import ticks_ms, ticks_add, ticks_diff timezone = "America/New_York" color = 0xFF00FF # The time of the thing! EVENT_YEAR = 2024 EVENT_MONTH = 8 EVENT_DAY = 16 EVENT_HOUR = 0 EVENT_MINUTE = 0 # we'll make a python-friendly structure event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY, EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds -1, -1, False)) # we dont know day of week/year or DST print("Connecting to WiFi...") wifi.radio.connect( os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD") ) pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio) requests = adafruit_requests.Session(pool, ssl_context) io = IO_HTTP( os.getenv("AIO_USERNAME"), os.getenv("AIO_KEY"), requests ) pixel_pin = board.SCL1 pixel_num = 16 pixels = neopixel.NeoPixel(pixel_pin, n = pixel_num, brightness=1, auto_write=True) pixel_length = 0 last_length = -1 refresh_clock = ticks_ms() refresh_timer = 3600 * 1000 # 1 hour first_run = True finished = False while True: if not finished: if ticks_diff(ticks_ms(), refresh_clock) >= refresh_timer or first_run: try: print("Getting time from internet!") now = time.struct_time(io.receive_time(timezone)) print(now) total_seconds = time.mktime(now) remaining = time.mktime(event_time) - total_seconds if remaining < 0: pixel_length = pixel_num + 1 finished = True else: if now.tm_mon == EVENT_MONTH: pixel_length = now.tm_mday % (pixel_num + 1) refresh_clock = ticks_add(refresh_clock, refresh_timer) except Exception as e: # pylint: disable=broad-except print("Some error occured, retrying via reset in 15 seconds! - ", e) time.sleep(15) microcontroller.reset() if last_length != pixel_length: if not pixel_length: pixels.fill(0x000000) else: for i in range(pixel_length): pixels[i] = color last_length = pixel_length first_run = False
Upload the Code and Libraries to the QT Py ESP32-S2
After downloading the Project Bundle, plug your QT Py ESP32-S2 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the QT Py ESP32-S2's CIRCUITPY drive.
- lib folder
- code.py
Your QT Py ESP32-S2 CIRCUITPY drive should look like this after copying the lib folder and the code.py file.
Add Your settings.toml File
As of CircuitPython 8.0.0, there is support for Environment Variables. Environment variables are stored in a settings.toml file. Similar to secrets.py, the settings.toml file separates your sensitive information from your main code.py file. Add your settings.toml file as described in the Create Your settings.toml File page earlier in this guide. You'll need to include your AIO_USERNAME
, AIO_KEY
, CIRCUITPY_WIFI_SSID
and CIRCUITPY_WIFI_PASSWORD
.
CIRCUITPY_WIFI_SSID = "your-ssid-here" CIRCUITPY_WIFI_PASSWORD = "your-ssid-password-here" AIO_USERNAME = "your-username-here" AIO_KEY = "your-key-here"
How the CircuitPython Code Works
At the top of the code, you'll edit timezone
to reflect your timezone location. You can edit color
to change the color of the NeoPixels. The event time is also set. In this case, it's August 16, 2024 at midnight.
timezone = "America/New_York" color = 0xFF00FF # The time of the thing! EVENT_YEAR = 2024 EVENT_MONTH = 8 EVENT_DAY = 16 EVENT_HOUR = 0 EVENT_MINUTE = 0 # we'll make a python-friendly structure event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY, EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds -1, -1, False)) # we dont know day of week/year or DST
WiFi
The board connects to WiFi and then establishes a connection with Adafruit IO. Adafruit IO is used as a time server for this project.
print("Connecting to WiFi...") wifi.radio.connect( os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD") ) pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio) requests = adafruit_requests.Session(pool, ssl_context) io = IO_HTTP( os.getenv("AIO_USERNAME"), os.getenv("AIO_KEY"), requests )
NeoPixels
The NeoPixels are setup on pin SCL1 for the data connection. This is not the standard use for this STEMMA I2C pin, but using it makes it a solderless project. pixel_length
and last_length
are used in the loop to keep track of which NeoPixels are lit for the countdown.
pixel_pin = board.SCL1 pixel_num = 16 pixels = neopixel.NeoPixel(pixel_pin, n = pixel_num, brightness=1, auto_write=True) pixel_length = 0 last_length = -1
Time and States
adafruit_ticks
is used for timekeeping in the loop. first_run
and finished
are used as states for tracking the state of the timekeeping.
refresh_clock = ticks_ms() refresh_timer = 3600 * 1000 # 1 hour first_run = True finished = False
The Loop
In the loop, the time is checked every hour via Adafruit IO. Since the NeoPixels are representing days until an event, the time does not need to be checked as often as with other countdown projects. The date is used as the count for the NeoPixels. For example, if it's the 6th of the event month, then 6 NeoPixels will be lit. If the countdown is over, then all of the NeoPixels are lit.
while True: if not finished: if ticks_diff(ticks_ms(), refresh_clock) >= refresh_timer or first_run: try: print("Getting time from internet!") now = time.struct_time(io.receive_time(timezone)) print(now) total_seconds = time.mktime(now) remaining = time.mktime(event_time) - total_seconds if remaining < 0: pixel_length = pixel_num + 1 finished = True else: if now.tm_mon == EVENT_MONTH: pixel_length = now.tm_mday % (pixel_num + 1) refresh_clock = ticks_add(refresh_clock, refresh_timer) except Exception as e: # pylint: disable=broad-except print("Some error occured, retrying via reset in 15 seconds! - ", e) time.sleep(15) microcontroller.reset() if last_length != pixel_length: if not pixel_length: pixels.fill(0x000000) else: for i in range(pixel_length): pixels[i] = color last_length = pixel_length first_run = False
Text editor powered by tinymce.