Remixing the guide from the Ruiz brothers: https://learn.adafruit.com/aqi-case/overview and retrofitting it for the Feather RP2040 & the Adafruit FeatherWing OLED - 128x32 OLED Add-on For Feather
The OLED is quite limited in colors & the Feather RP2040 has a single LED available. Given these constraints this is what I was able to achieve.
All the text on the third row are my own interpretations of the values of each of the categories. Here's an example of how I assigned a text value to the data around the PM2.5 data.
def rate_pm25(pm25_data):
if pm25_data <= 12:
pm25_color = green
pm25_extra = "OK"
elif pm25_data <= 35:
pm25_color = yellow
pm25_extra = "MID"
else:
pm25_color = red
pm25_extra = "BAD"
return pm25_color, pm25_extra
Below is the full code I used to implement this functionality. Here's a list of libraries you'll need (any listing without a .mpy at the end means that it is a directory):
- adafruit_bus_device
- adafruit_display_text
- adafruit_pm25
- adafruit_displayio_ssd1306.mpy
- adafruit_pixelbuf.mpy
- adafruit_scd4x.mpy
- adafruit_ticks.mpy
- adafruit_neopixel.mpy
These libraries can be found here: https://circuitpython.org/libraries (version 9.x was used for this project)
import time
import board
import displayio
import neopixel
import terminalio
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
from adafruit_pm25.i2c import PM25_I2C
import adafruit_scd4x
import adafruit_displayio_ssd1306
from adafruit_display_text import label
# Set up pixel coloring
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.1, auto_write=False)
red = (80, 0, 0)
yellow = (75, 80, 0)
green = (0, 80, 0)
reset_pin = None
i2c = board.STEMMA_I2C()
# Set-up pm25 air sensor
pm25 = PM25_I2C(i2c, reset_pin)
# Set-up scd4x CO2 sensor
scd4x = adafruit_scd4x.SCD4X(i2c)
scd4x.start_periodic_measurement()
time.sleep(5)
# pm25 air sensor data set-up
try:
aqdata = pm25.read()
pm25Data = int(aqdata["pm25 standard"])
except RuntimeError:
pm25Data = 0
co2Sensor = scd4x.CO2
tempSensor = scd4x.temperature
humiditySensor = scd4x.relative_humidity
def rate_pm25(pm25_data):
if pm25_data <= 12:
pm25_color = green
pm25_extra = "OK"
elif pm25_data <= 35:
pm25_color = yellow
pm25_extra = "MID"
else:
pm25_color = red
pm25_extra = "BAD"
return pm25_color, pm25_extra
def rate_co2(co2_data):
if co2_data <= 500:
co2_extra = "OK"
elif co2_data <= 1000:
co2_extra = "MEH"
elif co2_data <= 1400:
co2_extra = "-15%"
elif co2_data <= 1600:
co2_extra = "-50%"
elif co2_data <= 2000:
co2_extra = "VENT"
else:
co2_extra = "BAD!"
return co2_extra
def rate_temperature(temp_data):
if temp_data <= 30:
temp_extra = "COLD"
elif temp_data <= 80:
temp_extra = "OK"
elif temp_data <= 90:
temp_extra = "WARM"
else:
temp_extra = "HOT"
return temp_extra
def rate_humidity(humidity_data):
if humidity_data < 55:
humidity_extra = "DRY"
elif humidity_data == 55 and humidity_data <= 65:
humidity_extra = "OK"
else:
humidity_extra = "WET"
return humidity_extra
def c_to_f(temp_data):
temperature_celsius = temp_data
temperature_fahrenheit = temperature_celsius * 9 / 5 + 32
return temperature_fahrenheit
# display set-up
displayio.release_displays()
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
group = displayio.Group()
display.root_group = group
# Background set-up
color_bitmap = displayio.Bitmap(128, 32, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # black
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
group.append(bg_sprite)
TOTAL_WIDTH = 128
TOTAL_HEIGHT = 32
SECTION_WIDTH = (TOTAL_WIDTH - 10) // 4
SECTION_HEIGHT = (TOTAL_HEIGHT // 3) - 1
# PM2.5 text set-up
pm25_title = label.Label(
terminalio.FONT, text="PM25", color=0xFFFFFF, x=0, y=SECTION_HEIGHT
)
pm25_text = label.Label(
terminalio.FONT, text="%d" % pm25Data, color=0xFFFFFF, x=0, y=(SECTION_HEIGHT * 2)
)
pm25_extra_text = label.Label(
terminalio.FONT, text="", color=0xFFFFFF, x=0, y=(SECTION_HEIGHT * 3)
)
group.append(pm25_title)
group.append(pm25_text)
group.append(pm25_extra_text)
# CO2 text set-up
co2_title = label.Label(
terminalio.FONT, text="CO2", color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT)
)
co2_text = label.Label(
terminalio.FONT, text="%d" % co2Sensor, color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)
)
co2_extra_text = label.Label(
terminalio.FONT, text="", color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)
)
group.append(co2_title)
group.append(co2_text)
group.append(co2_extra_text)
# Temperature text set-up
temp_title = label.Label(
terminalio.FONT, text="TEMP", color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT)
)
temp_text = label.Label(
terminalio.FONT, text="%d" % c_to_f(tempSensor), color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)
)
temp_extra_text = label.Label(
terminalio.FONT, text="", color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)
)
group.append(temp_title)
group.append(temp_text)
group.append(temp_extra_text)
# Humidity text set-up
humidity_title = label.Label(
terminalio.FONT, text="HUMD", color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT)
)
humidity_text = label.Label(
terminalio.FONT, text="%d" % humiditySensor, color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)
)
humidity_extra_text = label.Label(
terminalio.FONT, text="", color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)
)
group.append(humidity_title)
group.append(humidity_text)
group.append(humidity_extra_text)
sensor_texts = [pm25_text, co2_text, temp_text, humidity_text]
sensor_data = [pm25Data, co2Sensor, tempSensor, humiditySensor]
sensor_extra_texts = [pm25_extra_text, co2_extra_text, temp_extra_text, humidity_extra_text]
sensor_clock = ticks_ms()
sensor_check = 5000
first_run = True
while True:
if scd4x.data_ready:
if first_run or ticks_diff(ticks_ms(), sensor_clock) > sensor_check:
co2Sensor = scd4x.CO2
tempSensor = c_to_f(scd4x.temperature)
humiditySensor = scd4x.relative_humidity
try:
aqdata = pm25.read()
pm25Data = int(aqdata["pm25 standard"])
except RuntimeError:
print("Unable to read from PM2.5 sensor, no new data...")
continue
pm25_color, pm25_extra = rate_pm25(pm25Data)
pixel.fill(pm25_color)
pixel.show()
# updating the array of sensor data values
sensor_data = [pm25Data, co2Sensor, tempSensor, humiditySensor]
sensor_extra = [pm25_extra, rate_co2(co2Sensor), rate_temperature(tempSensor), rate_humidity(humiditySensor)]
for s in range(4):
sensor_texts[s].text = "%d" % sensor_data[s]
sensor_extra_texts[s].text = sensor_extra[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
This page (Air Quality Monitor for the Feather RP2040) was last updated on September 01, 2024.
Text editor powered by tinymce.