Skip to content

Commit 476c738

Browse files
committed
Adding code for the desktop air quality monitor
Adding code for the desktop air monitor project. Logging data with PM2.5 and SCD40 to a display and IO
1 parent 14d3756 commit 476c738

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

Desktop_Air_Monitor/code.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
import os
5+
import ssl
6+
import time
7+
import microcontroller
8+
import board
9+
import wifi
10+
import socketpool
11+
import adafruit_requests
12+
import neopixel
13+
import displayio
14+
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
15+
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
16+
from adafruit_pm25.i2c import PM25_I2C
17+
import adafruit_scd4x
18+
from adafruit_display_text import bitmap_label
19+
from adafruit_bitmap_font import bitmap_font
20+
from adafruit_display_shapes.roundrect import RoundRect
21+
22+
# connect to SSID
23+
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
24+
25+
pool = socketpool.SocketPool(wifi.radio)
26+
requests = adafruit_requests.Session(pool, ssl.create_default_context())
27+
28+
pool = socketpool.SocketPool(wifi.radio)
29+
30+
# adafruit IO info
31+
aio_username = os.getenv('aio_username')
32+
aio_key = os.getenv('aio_key')
33+
location = "America/New York"
34+
35+
# io HTTP for getting the time from the internet
36+
io = IO_HTTP(aio_username, aio_key, requests)
37+
38+
def reset_on_error(delay, error):
39+
print("Error:\n", str(error))
40+
print("Resetting microcontroller in %d seconds" % delay)
41+
time.sleep(delay)
42+
microcontroller.reset()
43+
44+
def c_to_f(temp_data):
45+
temperature_celsius = temp_data
46+
temperature_fahrenheit = temperature_celsius * 9 / 5 + 32
47+
return int(temperature_fahrenheit)
48+
49+
# setup NeoPixels
50+
pixel_pin = board.D13
51+
num_pixels = 8
52+
53+
pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False)
54+
55+
red = (255, 0, 0)
56+
yellow = (255, 125, 0)
57+
green = (0, 255, 0)
58+
59+
i2c = board.STEMMA_I2C()
60+
61+
reset_pin = None
62+
63+
pm25 = PM25_I2C(i2c, reset_pin)
64+
aqdata = pm25.read()
65+
66+
scd4x = adafruit_scd4x.SCD4X(i2c)
67+
scd4x.start_periodic_measurement()
68+
69+
time.sleep(2)
70+
71+
co2 = int(scd4x.CO2)
72+
temp = c_to_f(scd4x.temperature)
73+
humidity = int(scd4x.relative_humidity)
74+
75+
pm2 = int(aqdata["pm25 standard"])
76+
pm2_x = [94, 94, 94, 94, 140, 185]
77+
pm2_colors = [green, green, green, green, yellow, red]
78+
79+
# display setup
80+
display = board.DISPLAY
81+
82+
bitmap = displayio.OnDiskBitmap("/airBG.bmp")
83+
84+
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
85+
group = displayio.Group()
86+
group.append(tile_grid)
87+
88+
small_font_file = "/OCRA_small.pcf"
89+
small_font = bitmap_font.load_font(small_font_file)
90+
big_font_file = "/OCRA_big.pcf"
91+
big_font = bitmap_font.load_font(big_font_file)
92+
93+
pm2_text = bitmap_label.Label(big_font, text="%d" % pm2, x=42, y=40, color=0xFFFFFF)
94+
group.append(pm2_text)
95+
96+
co2_text = bitmap_label.Label(small_font, text="%d" % co2, x=50, y=107, color=0xFFFFFF)
97+
temp_text = bitmap_label.Label(small_font, text="%d" % temp, x=130, y=107, color=0xFFFFFF)
98+
humid_text = bitmap_label.Label(small_font, text="%d" % humidity, x=205, y=107, color=0xFFFFFF)
99+
group.append(co2_text)
100+
group.append(temp_text)
101+
group.append(humid_text)
102+
103+
pm2_outline = RoundRect(pm2_x[pm2], 19, 46, 46, 10, fill=None, outline=0xFFFFFF, stroke=3)
104+
group.append(pm2_outline)
105+
106+
pixels.fill(pm2_colors[pm2])
107+
pixels.show()
108+
109+
display.show(group)
110+
111+
sensor_texts = [pm2_text, co2_text, temp_text, humid_text]
112+
sensor_data = [pm2, co2, temp, humidity]
113+
114+
sensor_clock = ticks_ms()
115+
io_clock = ticks_ms()
116+
117+
sensor_check = 30000
118+
io_check = 300000
119+
first_run = True
120+
121+
try:
122+
# get feed
123+
pm25_feed = io.get_feed("pm25")
124+
except AdafruitIO_RequestError:
125+
# if no feed exists, create one
126+
pm25_feed = io.create_new_feed("pm25")
127+
try:
128+
# get feed
129+
temp_feed = io.get_feed("temp")
130+
except AdafruitIO_RequestError:
131+
# if no feed exists, create one
132+
temp_feed = io.create_new_feed("temp")
133+
try:
134+
# get feed
135+
co2_feed = io.get_feed("co2")
136+
except AdafruitIO_RequestError:
137+
# if no feed exists, create one
138+
co2_feed = io.create_new_feed("co2")
139+
try:
140+
# get feed
141+
humid_feed = io.get_feed("humid")
142+
except AdafruitIO_RequestError:
143+
# if no feed exists, create one
144+
humid_feed = io.create_new_feed("humid")
145+
146+
sensor_feeds = [pm25_feed, co2_feed, temp_feed, humid_feed]
147+
148+
while True:
149+
try:
150+
if first_run or ticks_diff(ticks_ms(), sensor_clock) > sensor_check:
151+
if scd4x.data_ready:
152+
co2 = int(scd4x.CO2)
153+
temp = c_to_f(scd4x.temperature)
154+
humidity = int(scd4x.relative_humidity)
155+
pm2 = int(aqdata["pm25 standard"])
156+
pm2_outline.x = pm2_x[pm2]
157+
pixels.fill(pm2_colors[pm2])
158+
pixels.show()
159+
for s in range(4):
160+
sensor_texts[s].text = "%d" % sensor_data[s]
161+
print("updated %d data" % sensor_data[s])
162+
time.sleep(0.2)
163+
sensor_clock = ticks_add(sensor_clock, sensor_check)
164+
165+
if first_run or ticks_diff(ticks_ms(), io_clock) > io_check:
166+
for z in range(4):
167+
io.send_data(sensor_feeds[z]["key"], sensor_data[z])
168+
print("sent %d to io" % sensor_data[z])
169+
time.sleep(1)
170+
io_clock = ticks_add(io_clock, io_check)
171+
if first_run:
172+
sensor_clock = ticks_ms()
173+
io_clock = ticks_ms()
174+
first_run = False
175+
# pylint: disable=broad-except
176+
except Exception as e:
177+
reset_on_error(10, e)

0 commit comments

Comments
 (0)