pimoroni-pico/micropython/examples/pico_enviro/enviro_all.py

310 lines
9.6 KiB
Python

import time
from machine import Pin, UART
from picographics import PicoGraphics, DISPLAY_ENVIRO_PLUS
from pimoroni import RGBLED, Button
from breakout_bme68x import BreakoutBME68X, STATUS_HEATER_STABLE
from pimoroni_i2c import PimoroniI2C
from breakout_ltr559 import BreakoutLTR559
from adcfft import ADCFFT
# comment out the next line if no particulate sensor
from pms5003 import PMS5003
"""
This example reads from all the sensors on Enviro+.
(plus the optional particulate sensor)
Displays the results on screen.
Press A and B to turn the backlight on and off
Press X and Y to switch between sensor mode and graphic equaliser mode!
"""
# change this to adjust temperature compensation
TEMPERATURE_OFFSET = 3
BRIGHTNESS = 0.8
# change this to adjust pressure based on your altitude
altitude = 0
# light the LED red if the gas reading is less than 50%
GAS_ALERT = 0.5
def graphic_equaliser():
m_arr = [0 for _ in range(16)]
i = 0
adcfft.update()
m = 0
for x in range(5, 240):
v = adcfft.get_scaled(x, 144)
m = max(m, v)
v = min(239, v)
v = 239 - v
display.line(x - 5, v, x - 5, 239)
m_arr[i] = min(255, m)
i += 1
if i >= len(m_arr):
i = 0
ms = int(sum(m_arr) / len(m_arr))
led.set_rgb(0, ms, 0)
def adjust_to_sea_pressure(pressure_hpa, temperature, altitude):
"""
Adjust pressure based on your altitude.
credits to @cubapp https://gist.github.com/cubapp/23dd4e91814a995b8ff06f406679abcf
"""
# Adjusted-to-the-sea barometric pressure
adjusted_hpa = pressure_hpa + ((pressure_hpa * 9.80665 * altitude) / (287 * (273 + temperature + (altitude / 400))))
return adjusted_hpa
def describe_pressure(pressure_hpa):
"""Convert pressure into barometer-type description."""
pressure_hpa += 0.5
if pressure_hpa < 970:
description = "storm"
elif 970 <= pressure_hpa < 990:
description = "rain"
elif 990 <= pressure_hpa < 1010:
description = "change"
elif 1010 <= pressure_hpa < 1030:
description = "fair"
elif pressure_hpa >= 1030:
description = "dry"
else:
description = ""
return description
def describe_humidity(corrected_humidity):
"""Convert relative humidity into good/bad description."""
corrected_humidity += 0.5
if 40 < corrected_humidity < 60:
description = "good"
else:
description = "bad"
return description
def describe_light(lux):
"""Convert light level in lux to descriptive value."""
lux += 0.5
if lux < 50:
description = "dark"
elif 50 <= lux < 100:
description = "dim"
elif 100 <= lux < 500:
description = "light"
elif lux >= 500:
description = "bright"
return description
def draw_hist(results_array):
result_index = 0
for result in results_array:
display.set_pen(YELLOW)
display.rectangle(2 * result_index, 240 - result.pm_ug_per_m3(10), 2, 240)
display.set_pen(MAGENTA)
display.rectangle(2 * result_index, 240 - result.pm_ug_per_m3(2.5), 2, 240)
display.set_pen(BLUE)
display.rectangle(2 * result_index, 240 - result.pm_ug_per_m3(1.0), 2, 240)
result_index += 1
# set up the display
display = PicoGraphics(display=DISPLAY_ENVIRO_PLUS)
# set up the LED
led = RGBLED(6, 7, 10, invert=True)
# set up the buttons
button_a = Button(12, invert=True)
button_b = Button(13, invert=True)
button_x = Button(14, invert=True)
button_y = Button(15, invert=True)
# set up the Pico W's I2C
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
# set up BME688 and LTR559 sensors
bme = BreakoutBME68X(i2c, address=0x77)
ltr = BreakoutLTR559(i2c)
# set up ADCFFT library to read mic with fast fourier transform
adcfft = ADCFFT()
# configure the PMS5003 for Enviro+
# comment out this section if no particulate sensor
pms5003 = PMS5003(
uart=UART(1, tx=Pin(8), rx=Pin(9), baudrate=9600),
pin_enable=Pin(3),
pin_reset=Pin(2),
mode="active"
)
# some constants we'll use for drawing
WHITE = display.create_pen(255, 255, 255)
BLACK = display.create_pen(0, 0, 0)
RED = display.create_pen(255, 0, 0)
GREEN = display.create_pen(0, 255, 0)
CYAN = display.create_pen(0, 255, 255)
MAGENTA = display.create_pen(200, 0, 200)
YELLOW = display.create_pen(200, 200, 0)
BLUE = display.create_pen(0, 0, 200)
FFT_COLOUR = display.create_pen(255, 0, 255)
GREY = display.create_pen(75, 75, 75)
WIDTH, HEIGHT = display.get_bounds()
display.set_font("bitmap8")
# some other variables we'll use to keep track of stuff
mode = "sensors" # start off in sensor mode
# these values will get updated later on
min_temperature = 100.0
max_temperature = 0.0
min_gas = 100000.0
max_gas = 0.0
# array for storing particulate readings
results = []
# setup
led.set_rgb(255, 0, 0)
display.set_backlight(BRIGHTNESS)
display.set_pen(RED)
display.text("waiting for sensors", 0, 0, WIDTH, scale=3)
display.update()
# the gas sensor gives a few weird readings to start, lets discard them
temperature, pressure, humidity, gas, status, _, _ = bme.read()
time.sleep(0.5)
temperature, pressure, humidity, gas, status, _, _ = bme.read()
time.sleep(0.5)
while True:
# turn on the backlight with A and turn it back off with B
# switch between sensor and equaliser mode with X and Y
if button_a.is_pressed:
display.set_backlight(BRIGHTNESS)
time.sleep(0.2)
elif button_b.is_pressed:
display.set_backlight(0)
time.sleep(0.2)
elif button_x.is_pressed:
mode = "sensors"
display.set_backlight(BRIGHTNESS)
time.sleep(0.2)
elif button_y.is_pressed:
mode = "equaliser"
display.set_backlight(BRIGHTNESS)
time.sleep(0.2)
if mode == "sensors":
# read BME688
temperature, pressure, humidity, gas, status, _, _ = bme.read()
heater = "Stable" if status & STATUS_HEATER_STABLE else "Unstable"
# correct temperature and humidity using an offset
corrected_temperature = temperature - TEMPERATURE_OFFSET
dewpoint = temperature - ((100 - humidity) / 5)
corrected_humidity = 100 - (5 * (corrected_temperature - dewpoint))
# record min and max temperatures
if corrected_temperature >= max_temperature:
max_temperature = corrected_temperature
if corrected_temperature <= min_temperature:
min_temperature = corrected_temperature
# record min and max gas readings
if gas > max_gas:
max_gas = gas
if gas < min_gas:
min_gas = gas
# convert pressure into hpa
pressure_hpa = pressure / 100
# correct pressure
pressure_hpa = adjust_to_sea_pressure(pressure_hpa, corrected_temperature, altitude)
# read LTR559
ltr_reading = ltr.get_reading()
lux = ltr_reading[BreakoutLTR559.LUX]
prox = ltr_reading[BreakoutLTR559.PROXIMITY]
# read particulate sensor and put the results into the array
# comment out if no PM sensor
data = pms5003.read()
results.append(data)
if (len(results) > 120): # Scroll the result list by removing the first value
results.pop(0)
if heater == "Stable" and ltr_reading is not None:
led.set_rgb(0, 0, 0)
# draw some stuff on the screen
display.set_pen(BLACK)
display.clear()
# draw particulate graph on screen, comment out if no PM sensor
draw_hist(results)
# draw the top box
display.set_pen(GREY)
display.rectangle(0, 0, WIDTH, 60)
# pick a pen colour based on the temperature
display.set_pen(GREEN)
if corrected_temperature > 30:
display.set_pen(RED)
if corrected_temperature < 10:
display.set_pen(CYAN)
display.text(f"{corrected_temperature:.1f}°C", 5, 15, WIDTH, scale=4)
# draw temp max and min
display.set_pen(CYAN)
display.text(f"min {min_temperature:.1f}", 125, 5, WIDTH, scale=3)
display.set_pen(RED)
display.text(f"max {max_temperature:.1f}", 125, 30, WIDTH, scale=3)
# draw the first column of text
display.set_pen(WHITE)
display.text(f"rh {corrected_humidity:.0f}%", 0, 75, WIDTH, scale=3)
display.text(f"{pressure_hpa:.0f}hPa", 0, 125, WIDTH, scale=3)
display.text(f"{lux:.0f} lux", 0, 175, WIDTH, scale=3)
# draw the second column of text
display.text(f"{describe_humidity(corrected_humidity)}", 125, 75, WIDTH, scale=3)
display.text(f"{describe_pressure(pressure_hpa)}", 125, 125, WIDTH, scale=3)
display.text(f"{describe_light(lux)}", 125, 175, WIDTH, scale=3)
# draw bar for gas
if min_gas != max_gas:
# light the LED and set pen to red if the gas / air quality reading is less than 50%
if (gas - min_gas) / (max_gas - min_gas) < GAS_ALERT:
led.set_rgb(255, 0, 0)
display.set_pen(RED)
else:
display.set_pen(GREEN)
display.rectangle(236, HEIGHT - round((gas - min_gas) / (max_gas - min_gas) * HEIGHT), 4, round((gas - min_gas) / (max_gas - min_gas) * HEIGHT))
display.text("gas", 185, 210, WIDTH, scale=3)
display.update()
time.sleep(0.5)
elif mode == "equaliser":
display.set_pen(BLACK)
display.clear()
display.set_pen(FFT_COLOUR)
display.text("mic", 0, 0, WIDTH, scale=3)
graphic_equaliser()
display.update()