Once you've finished setting up your ESP32-S3 Reverse TFT Feather 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 as a zipped folder.
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import neopixel import displayio from adafruit_ticks import ticks_ms, ticks_add, ticks_diff from adafruit_pm25.i2c import PM25_I2C import adafruit_scd4x from adafruit_display_text import bitmap_label from adafruit_bitmap_font import bitmap_font from adafruit_display_shapes.roundrect import RoundRect pixel_pin = board.D13 num_pixels = 8 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.1, auto_write=False) red = (80, 0, 0) yellow = (75, 80, 0) green = (0, 80, 0) i2c = board.STEMMA_I2C() reset_pin = None pm25 = PM25_I2C(i2c, reset_pin) scd4x = adafruit_scd4x.SCD4X(i2c) scd4x.start_periodic_measurement() time.sleep(5) try: aqdata = pm25.read() pm2 = int(aqdata["pm25 standard"]) except RuntimeError: pm2 = 0 co2 = scd4x.CO2 temp = scd4x.temperature humidity = scd4x.relative_humidity def rate_pm25(pm25_data): if pm25_data <= 12: pm25_outline = 94 pm25_color = green elif pm25_data <= 35: pm25_color = yellow pm25_outline = 140 else: pm25_color = red pm25_outline = 185 return pm25_color, pm25_outline def c_to_f(temp_data): temperature_celsius = temp_data temperature_fahrenheit = temperature_celsius * 9 / 5 + 32 return temperature_fahrenheit # display setup display = board.DISPLAY bitmap = displayio.OnDiskBitmap("/airBG.bmp") tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) group = displayio.Group() group.append(tile_grid) small_font_file = "/OCRA_small.pcf" small_font = bitmap_font.load_font(small_font_file) big_font_file = "/OCRA_big.pcf" big_font = bitmap_font.load_font(big_font_file) pm2_text = bitmap_label.Label(big_font, text="%d" % pm2, x=37, y=40, color=0xFFFFFF) group.append(pm2_text) co2_text = bitmap_label.Label(small_font, text="%d" % co2, x=50, y=107, color=0xFFFFFF) temp_text = bitmap_label.Label(small_font, text="%d" % temp, x=130, y=107, color=0xFFFFFF) humid_text = bitmap_label.Label(small_font, text="%d" % humidity, x=205, y=107, color=0xFFFFFF) group.append(co2_text) group.append(temp_text) group.append(humid_text) pm2_outline = RoundRect(94, 19, 46, 46, 10, fill=None, outline=0xFFFFFF, stroke=3) group.append(pm2_outline) display.root_group = group sensor_texts = [pm2_text, co2_text, temp_text, humid_text] sensor_data = [pm2, co2, temp, humidity] sensor_clock = ticks_ms() sensor_check = 5000 first_run = True while True: if first_run or ticks_diff(ticks_ms(), sensor_clock) > sensor_check: co2 = scd4x.CO2 temp = c_to_f(scd4x.temperature) humidity = scd4x.relative_humidity try: aqdata = pm25.read() pm2 = int(aqdata["pm25 standard"]) except RuntimeError: print("Unable to read from PM2.5 sensor, no new data..") continue pm2_color, pm2_outline.x = rate_pm25(pm2) sensor_data = [pm2, co2, temp, humidity] pixels.fill(pm2_color) pixels.show() for s in range(4): sensor_texts[s].text = "%d" % sensor_data[s] print("updated %d data" % sensor_data[s]) time.sleep(0.2) sensor_clock = ticks_add(sensor_clock, sensor_check) if first_run: sensor_clock = ticks_ms() first_run = False
Upload the Code and Libraries to the ESP32-S3 Reverse TFT Feather
After downloading the Project Bundle, plug your ESP32-S3 Reverse TFT Feather 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 ESP32-S3 Reverse TFT Feather's CIRCUITPY drive.
- lib folder
- OCRA_big.pcf
- OCRA_small.pcf
- airBG.bmp
- code.py
Your ESP32-S3 Reverse TFT Feather CIRCUITPY drive should look like this after copying the lib folder, font files, bitmap file and the code.py file:
How the CircuitPython Code Works
The code begins by setting up the NeoPixel stick. Three colors are defined: red
, yellow
and green
. These colors will be used to represent the AQI reading.
pixel_pin = board.D13 num_pixels = 8 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.1, auto_write=False) red = (80, 0, 0) yellow = (75, 80, 0) green = (0, 80, 0)
i2c = board.STEMMA_I2C() reset_pin = None pm25 = PM25_I2C(i2c, reset_pin) aqdata = pm25.read() scd4x = adafruit_scd4x.SCD4X(i2c) scd4x.start_periodic_measurement() time.sleep(5) co2 = scd4x.CO2 temp = scd4x.temperature humidity = scd4x.relative_humidity pm2 = int(aqdata["pm25 standard"])
Functions
Two functions are used to translate the sensor data. rate_pm25()
passes the AQI reading and determines what color the NeoPixels should show to represent it. It also determines which square on the display should be outlined with a white rectangle.
c_to_f()
converts the temperature reading from Celsius to Fahrenheit.
def rate_pm25(pm25_data): if pm25_data <= 12: pm25_outline = 94 pm25_color = green elif pm25_data <= 35: pm25_color = yellow pm25_outline = 140 else: pm25_color = red pm25_outline = 185 return pm25_color, pm25_outline def c_to_f(temp_data): temperature_celsius = temp_data temperature_fahrenheit = temperature_celsius * 9 / 5 + 32 return temperature_fahrenheit
Display Setup
Then comes the display setup. The background bitmap is loaded using the OnDiskBitmap
function. Two font files are loaded as bitmap fonts.
# display setup display = board.DISPLAY bitmap = displayio.OnDiskBitmap("/airBG.bmp") tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) group = displayio.Group() group.append(tile_grid) small_font_file = "/OCRA_small.pcf" small_font = bitmap_font.load_font(small_font_file) big_font_file = "/OCRA_big.pcf" big_font = bitmap_font.load_font(big_font_file)
Sensor Text
Each sensor reading has a text object to display the data on the screen. The AQI reading utilizes the big_font
and the rest use the small_font
.
A RoundRect
is used to outline one of the green, yellow or red squares on the bitmap to further illustrate the AQI reading. The x
coordinate is changed for the RoundRect
with the rate_pm25()
function.
pm2_text = bitmap_label.Label(big_font, text="%d" % pm2, x=37, y=40, color=0xFFFFFF) group.append(pm2_text) co2_text = bitmap_label.Label(small_font, text="%d" % co2, x=50, y=107, color=0xFFFFFF) temp_text = bitmap_label.Label(small_font, text="%d" % temp, x=130, y=107, color=0xFFFFFF) humid_text = bitmap_label.Label(small_font, text="%d" % humidity, x=205, y=107, color=0xFFFFFF) group.append(co2_text) group.append(temp_text) group.append(humid_text) pm2_outline = RoundRect(94, 19, 46, 46, 10, fill=None, outline=0xFFFFFF, stroke=3) group.append(pm2_outline) display.root_group = group
Arrays and Ticks
There are two arrays: sensor_texts
and sensor_data
. These arrays will be used in the loop to update the on screen texts with the sensor readings.
ticks_ms()
is used to keep time. Every 5 seconds, the sensors will be read in the loop and the screen will be updated.
sensor_texts = [pm2_text, co2_text, temp_text, humid_text] sensor_data = [pm2, co2, temp, humidity] sensor_clock = ticks_ms() sensor_check = 5000 first_run = True
The Loop
In the loop, the SCD40 and PMSA003 sensors are read. The rate_pm25()
function is used to determine which color the NeoPixels should be.
The sensor readings are packed into the sensor_data
array. A for
statement is used to iterate through the array and update the corresponding text objects.
Finally, the sensor_clock
is reset to begin counting up to 5 seconds again.
if first_run or ticks_diff(ticks_ms(), sensor_clock) > sensor_check: co2 = scd4x.CO2 temp = c_to_f(scd4x.temperature) humidity = scd4x.relative_humidity aqdata = pm25.read() pm2 = int(aqdata["pm25 standard"]) pm2_color, pm2_outline.x = rate_pm25(pm2) sensor_data = [pm2, co2, temp, humidity] pixels.fill(pm2_color) pixels.show() for s in range(4): sensor_texts[s].text = "%d" % sensor_data[s] print("updated %d data" % sensor_data[s]) time.sleep(0.2) sensor_clock = ticks_add(sensor_clock, sensor_check)
Text editor powered by tinymce.