125 lines
3.6 KiB
Python
125 lines
3.6 KiB
Python
# Add a SCD41 sensor breakout to your GFX Pack to make a handy CO2 detector!
|
|
# https://shop.pimoroni.com/products/scd41-co2-sensor-breakout
|
|
# Press A to reset the high/low values.
|
|
|
|
from gfx_pack import GfxPack, SWITCH_A
|
|
import breakout_scd41
|
|
|
|
gp = GfxPack()
|
|
display = gp.display
|
|
|
|
WIDTH, HEIGHT = display.get_bounds()
|
|
display.set_backlight(0) # turn off the white component of the backlight
|
|
|
|
# the range of readings to map to colours (and scale our graph to)
|
|
# https://www.kane.co.uk/knowledge-centre/what-are-safe-levels-of-co-and-co2-in-rooms
|
|
MIN = 400
|
|
MAX = 2000
|
|
|
|
# pick what bits of the colour wheel to use (from 0-360°)
|
|
# https://www.cssscript.com/demo/hsv-hsl-color-wheel-picker-reinvented/
|
|
HUE_START = 100 # green
|
|
HUE_END = 0 # red
|
|
|
|
BRIGHTNESS = 0.5
|
|
|
|
# the area of the screen we want to draw our graph into
|
|
GRAPH_TOP = 24
|
|
GRAPH_BOTTOM = 54
|
|
|
|
|
|
# sets up a handy function we can call to clear the screen
|
|
def clear():
|
|
display.set_pen(0)
|
|
display.clear()
|
|
display.set_pen(15)
|
|
|
|
|
|
# From CPython Lib/colorsys.py
|
|
def hsv_to_rgb(h, s, v):
|
|
if s == 0.0:
|
|
return v, v, v
|
|
i = int(h * 6.0)
|
|
f = (h * 6.0) - i
|
|
p = v * (1.0 - s)
|
|
q = v * (1.0 - s * f)
|
|
t = v * (1.0 - s * (1.0 - f))
|
|
i = i % 6
|
|
if i == 0:
|
|
return v, t, p
|
|
if i == 1:
|
|
return q, v, p
|
|
if i == 2:
|
|
return p, v, t
|
|
if i == 3:
|
|
return p, q, v
|
|
if i == 4:
|
|
return t, p, v
|
|
if i == 5:
|
|
return v, p, q
|
|
|
|
|
|
highest = 0.0
|
|
lowest = 4000.0
|
|
readings = []
|
|
|
|
# set up
|
|
breakout_scd41.init(gp.i2c)
|
|
breakout_scd41.start()
|
|
|
|
gp.set_backlight(0, 0, 0, 127)
|
|
display.set_font("bitmap8")
|
|
display.set_pen(15)
|
|
display.text("Waiting for sensor to be ready", 0, 0, WIDTH, 2)
|
|
display.update()
|
|
|
|
while True:
|
|
if gp.switch_pressed(SWITCH_A):
|
|
# reset recorded high / low values
|
|
highest = 0.0
|
|
lowest = 4000.0
|
|
|
|
if breakout_scd41.ready():
|
|
# read the sensor
|
|
co2, temperature, humidity = breakout_scd41.measure()
|
|
|
|
# update highest / lowest values
|
|
if co2 < lowest:
|
|
lowest = co2
|
|
if co2 > highest:
|
|
highest = co2
|
|
|
|
# calculates a colour from the sensor reading
|
|
hue = max(0, HUE_START + ((co2 - MIN) * (HUE_END - HUE_START) / (MAX - MIN)))
|
|
|
|
# set the leds
|
|
r, g, b = [int(255 * c) for c in hsv_to_rgb(hue / 360, 1.0, BRIGHTNESS)]
|
|
gp.set_backlight(r, g, b, 0)
|
|
|
|
# keep track of readings in a list (so we can draw the graph)
|
|
readings.append(co2)
|
|
# we only need to save a screen's worth of readings, so delete the oldest
|
|
if len(readings) > WIDTH:
|
|
readings.pop(0)
|
|
|
|
# draw the graph
|
|
clear()
|
|
for r in range(len(readings)):
|
|
# this line scales the y axis of the graph into the available space
|
|
y = round(GRAPH_BOTTOM + ((readings[r] - MIN) * (GRAPH_TOP - GRAPH_BOTTOM) / (MAX - MIN)))
|
|
display.pixel(r, y)
|
|
|
|
# draw the text
|
|
display.text("CO2", 0, 0, scale=2)
|
|
display.text(f"Temp {temperature:.0f}°c", 0, 16, scale=1)
|
|
display.text(f"Low {lowest:.0f}ppm", 0, HEIGHT - 8, scale=1)
|
|
# measure the rest of the text before drawing so that we can right align it
|
|
text_width = display.measure_text(f"{co2:.0f}ppm", scale=2)
|
|
display.text(f"{co2:.0f}ppm", WIDTH - text_width, 0, scale=2)
|
|
text_width = display.measure_text(f"Humidity {humidity:.0f}%", scale=1)
|
|
display.text(f"Humidity {humidity:.0f}%", WIDTH - text_width, 16, scale=1)
|
|
text_width = display.measure_text(f"High {highest:.0f}ppm", scale=1)
|
|
display.text(f"High {highest:.0f}ppm", WIDTH - text_width, HEIGHT - 8, scale=1)
|
|
|
|
display.update()
|