Guten Abend,
kürzlich kam nach Lieferproblemen endlich mein lang erwarteter CO2-Sensor. Somit konnte ich mein erstes Microkontroller-Projekt endlich abschließen.
Auf einem 1,77" TFT-Display wir die Raumtemperatur, der Luftdruck und der aktuele CO2-Gehalt ausgegeben. Zur Visualisierung des CO2-Wertes habe ich eine Art Tacho mit verschiedenen Farben programmiert. An dieser Stelle ein recht herzliches Dankeschön (!) an @__deets__ und Linus die mich bei der Programmierung unterstützt und bei Problemen Erste-Hilfe geleistet haben.
Was noch fehlt ist ein Gehäuse und vielleicht eine passende Platine. Zu Testzwecken und weil ich euch kein Bild zeigen wollte, auf dem ihr fast nur Kabel seht, habe ich einfach alles in einen kleinen Karton gesteckt. Also nicht erschrecken
Der Tacho zeigt folgendermaßen den CO2-Wert an:
Bei einem C02-Gehalt von 0-400ppm bleibt der Zeiger auf 0 im grünen Bereich. Der gelbe Bereich fängt bei 789ppm an und endet bei 1178ppm.
Der rote Bereich endet bei 1400ppm. Ab diesem Wert erscheint auch ein Text unter dem CO2-Wert mit dem Inhalt "Lüften!".
Eine Messung erfolgt alle zwei Minuten.
Sollte es aus irgendwelchen Gründen Fehler bei der Sensor abfrage geben, dann startet die BüroStation neu.
Falls das jemand auch ganz cool findet oder auch mit einem ESP mal rumspielen möchte, hier meine "Dokumentation":
Verwendete Bauteile:
MH-Z-19 (Aber mit den "normalen" Pin-Anschlüssen)
Für den ersten Aufbau war ein Breadboard sehr hilfreich.
Programmiert wurde mit Micropython. Dazu esptool installieren und Firmeware auf den ESP32 flashen.
Dann habe ich es mir so leicht wie möglich gemacht und vorhandene Bibliotheken verwendet:
Für das Auslesen der Sensoren und die Display-Darstellung habe ich zwei Micropython-Programme geschrieben:
from math import cos, sin, pi
import uarray
from sysfont import sysfont
class Scala():
def __init__(self, tft, x_position, y_position, radius, color_low, color_middle, color_high, pointer_color, width, height, co2, xa_start, ya_start, xa_end, ya_end, color_screen):
self.tft = tft
self.x_position = x_position
self.y_position = y_position
self.radius = radius
self.color_low = color_low
self.color_middle = color_middle
self.color_high = color_high
self.pointer_color = pointer_color
self.width = width
self.height = height
self.co2 = co2
self.xa_start = xa_start
self.ya_start = ya_start
self.xa_end = xa_end
self.ya_end = ya_end
self.black = color_screen
def byteswapping(color):
#
# Byteswapping to creat RGB-Colors
#
color_swapped = color >>8 | (color & 0xff) << 8
return color_swapped
def do_speedo(self):
array_size = self.width * self.height
memory = uarray.array('H', [self.tft.BLACK for _ in range(array_size)])
color_low = Scala.byteswapping(self.color_low)
color_middle = Scala.byteswapping(self.color_middle)
color_high = Scala.byteswapping(self.color_high)
pointer_color = Scala.byteswapping(self.pointer_color)
#
# Textcolor like value-color
#
# '-400' to have a Scale from 400 =0° and 1400 = 180°
#
co2 = self.co2 - 400
if self.co2 < 1400 and self.co2 > 400:
degree = (180/1000) * co2
elif self.co2 < 400:
degree = 0.5
elif self.co2 > 1400:
degree = 180
if degree < 70:
text_color = self.color_low
elif degree > 70 and degree < 140:
text_color = self.color_middle
elif degree > 140 and degree < 181:
text_color = self.color_high
#
# creat half circle with different colors
#
for arc in range(181):
rad = arc / 180 *pi
x = self.x_position - int(cos(rad)*self.radius)
y = self.y_position - int(sin(rad)*self.radius)
if arc < 70:
color = color_low
elif arc >70 and arc < 140:
color = color_middle
elif arc > 140 and arc < 180:
color = color_high
if x in range(self.width) and y in range(self.height):
memory[x + (self.width * y)] = color
#
# creat pointer to show CO2-value
#
for pointer in range(self.radius):
rad = degree /180 * pi
x_pointer = self.x_position - int(cos(rad) * pointer)
y_pointer = self.y_position - int(sin(rad) * pointer)
if x_pointer in range(self.width) and y_pointer in range(self.height):
memory[x_pointer + (self.width * y_pointer)] = pointer_color
#
# creat circle for pointer, just a little bit optic
#
for point in range(359):
rad = point / 180 * pi
x_point = self.x_position - int(cos(rad) * 2)
y_point = self.y_position - int(sin(rad) * 2)
if x_point in range(self.width) and y_point in range(self.height):
memory[x_point + (self.width * y_point)] = pointer_color
#
# write buffer to display
#
self.tft.image(self.xa_start, self.ya_start, self.xa_end, self.ya_end, memory)
self.tft.text((99, 97), "....ppm" , self.black, sysfont, 1, nowrap=True)
self.tft.text((99, 97), "{}ppm".format(self.co2) , text_color, sysfont, 1, nowrap=True)
if self.co2 > 1399:
self.tft.text((99, 107), "Lueften!" , text_color, sysfont, 1, nowrap=True)
else:
self.tft.text((99, 107), "Lueften!" , self.black, sysfont, 1, nowrap=True)
Alles anzeigen
from ST7735 import TFT
from speedo import Scala
from machine import SPI,Pin, I2C
from sysfont import sysfont
from time import sleep
import bme280
import mhz19
spi = SPI(2, baudrate=20000000, polarity=0, phase=0, sck=Pin(23), mosi=Pin(2), miso=Pin(12))
tft=TFT(spi,05,19,16)
tft.initg()
tft.rgb(True)
tft.rotation(1)
tft.fill(TFT.BLACK)
tft.text((10, 5), "Buero-Station", TFT.WHITE, sysfont, 2, nowrap=True)
sleep(0.2)
tft.text((5, 45), "Temperatur:", TFT.WHITE, sysfont, 1, nowrap=True)
tft.text((5, 82), "Luftdruck:", TFT.WHITE, sysfont, 1, nowrap=True)
tft.text((92, 45), "CO2 - Wert", TFT.WHITE, sysfont, 1, nowrap=True)
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
bme = bme280.BME280(i2c=i2c)
co_sensor = mhz19.mhz19(1)
def read_sensor():
try:
temperature = bme.temperature
pressure = bme.pressure
co_sensor.get_data()
co2_out = co_sensor.ppm
except:
return 0
tft.text((5, 60), temperature , TFT.BLUE, sysfont, 1, nowrap=True)
tft.text((5, 97), pressure, TFT.BLUE, sysfont, 1, nowrap=True)
return co2_out
def main():
read_sensor()
if read_sensor == 0:
sleep(10)
read_sensor()
co2 = read_sensor()
create_speedo = Scala(tft, 25, 25, 25, TFT.GREEN, TFT.YELLOW, TFT.RED, TFT.PURPLE, 51, 28, co2, 95, 60, 145, 87, TFT.BLACK)
create_speedo.do_speedo()
sleep(120)
if __name__ == "__main__":
while True:
main()
Alles anzeigen
Alle Programme sind auf dem ESP32 zu speichern. Bei den Programmnamen darauf achten, dass sie mit dem Importen im Programm übereinstimmen.
Habe den Code nicht mehr durchgeschaut, durchaus möglich dass der noch verbessert werden kann.
Dann wäre es hilfreich wenn man die Hardware noch verkabelt, das habe ich so gemacht:
MH-Z-19 | ESP32 |
Tx | D2 |
Rx | D3 |
BME280 | |
SDA | D21 |
SCL | D22 |
1,77" Display | |
1 | GND |
2 | 5V |
3 | 23 |
4 | 2 |
5 | 19 |
6 | 5 |
7 | 16 |
8 | 3V3 |
Der Strom und die Masse bei den Sensoren sollte selbsterklärend sein.
So das wars soweit, wenn ich Gefallen an der Station finde und sie auch einsetze, bekommt sie noch ein 3D-Druck Gehäuse
Grüße
Dennis