CO2 Ampel für die Schulklasse bauen

Kurz bevor es wieder mit der Schule losging habe ich mich dazu entschlossen für die Schulklasse meiner Tochter eine CO2 Ampel zu bauen um die Aerosolbelastung in der Klasse abschätzen zu können bzw. um die Lüftungsstrategie zu optimieren.

Zu meiner Freude wurde mein Vorschlag dazu von unserer Klassenlehrerin dankend angenommen, da die bisherigen Lüftungsintervalle nur auf Schätzungen basierten.

Bauanleitungen für solche CO2 Ampeln gibt es im Netz ja schon wie Sand am Meer, deshalb habe ich das hier nicht im Detail dokumentiert, sondern sehe das hier eher als Projektvorstellung.

Das schöne was das ich bis auf den CO2 Sensor eigentlich alles in der Bastelkiste hatte und das Gehäuse sowie das Ampelglas aus dem 3D Drucker kommt. Folgendes Bauteile sind verbaut:

Das ganze ist eigentlich recht schnell und Problemlos gedruckt und zusammengebaut:

Wie man sieht habe ich innen noch Alu Folie als Reflektor hineingeklebt, die Gehäusebasis habe ich selbst designed. Ist keine Meisterleistung an Präzision aber reich um das Board etc. zu verstauen. Wenn Interesse besteht kann ich die STL dazu auch noch posten.

Die Software habe ich größtenteils vom Sensirion Sample übernommen und nur um den Code für die APA102 angepasst: https://developer.sensirion.com/tutorials/create-your-own-co2-monitor/

Man muss noch die FastLED Bibliothek hinzufügen, Data und Clock Pin habe ich auf Pin 21 und Pin 22 mit TTGO Board gelegt:

#include "esp_timer.h"
#include <Wire.h>
#include <FastLED.h>
// Go to TTGO T-Display's Github Repository
// Download the code as zip, extract it and copy the Folder TFT_eSPI
// => https://github.com/Xinyuan-LilyGO/TTGO-T-Display/archive/master.zip
// to your Arduino library path
#include <TFT_eSPI.h>
#include <SPI.h>
// Download the SeeedStudio SCD30 Arduino driver here:
// => https://github.com/Seeed-Studio/Seeed_SCD30/releases/latest
#include "SCD30.h"
#include "Sensirion_GadgetBle_Lib.h"
#define SDA_pin 26 // Define the SDA pin used for the SCD30
#define SCL_pin 27 // Define the SCL pin used for the SCD30
#define DATA_PIN 21
#define CLOCK_PIN 22
#define NUM_LEDS 4
CRGB leds[NUM_LEDS];
static int64_t lastMmntTime = 0;
static int startCheckingAfterUs = 1900000;
GadgetBle gadgetBle = GadgetBle(GadgetBle::DataType::T_RH_CO2_ALT);
// Display related
#define SENSIRION_GREEN 0x6E66
#define sw_version "v1.0"
#define GFXFF 1
#define FF99 &SensirionSimple25pt7b
#define FF90 &ArchivoNarrow_Regular10pt7b
#define FF95 &ArchivoNarrow_Regular50pt7b
TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke library, pins defined in User_Setup.h
void displayInit() {
tft.init();
tft.setRotation(1);
}
void displaySplashScreen() {
tft.fillScreen(TFT_WHITE);
tft.setTextColor(SENSIRION_GREEN, TFT_WHITE);
uint8_t defaultDatum = tft.getTextDatum();
tft.setTextDatum(1); // Top centre
tft.setTextSize(1);
tft.setFreeFont(FF99);
tft.drawString("B", 120, 40);
tft.setTextSize(1);
tft.drawString(sw_version, 120, 90, 2);
// Revert datum setting
tft.setTextDatum(defaultDatum);
}
void displayCo2(uint16_t co2) {
if (co2 > 9999) {
co2 = 9999;
}
tft.fillScreen(TFT_BLACK);
uint8_t defaultDatum = tft.getTextDatum();
tft.setTextSize(1);
tft.setFreeFont(FF90);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextDatum(6); // bottom left
tft.drawString("CO2", 10, 125);
tft.setTextDatum(8); // bottom right
tft.drawString(gadgetBle.getDeviceIdString(), 230, 125);
// Draw CO2 number
if (co2 < 9999){
if (co2 >= 2000 ) {
tft.setTextColor(TFT_RED, TFT_BLACK);
for (int i=0; i< NUM_LEDS; i++){
leds[i] = CRGB::Red;
}
FastLED.show();
delay(500);
for (int i=0; i< NUM_LEDS; i++){
leds[i] = CRGB::Black;
}
FastLED.show();
}
else if (co2 >= 1600 ) {
tft.setTextColor(TFT_RED, TFT_BLACK);
for (int i=0; i< NUM_LEDS; i++){
leds[i] = CRGB::Red;
}
FastLED.show();
} else if (co2 >= 1000 ) {
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
for (int i=0; i< NUM_LEDS; i++){
leds[i] = CRGB::Orange;
}
FastLED.show();
} else {
tft.setTextColor(TFT_GREEN, TFT_BLACK);
for (int i=0; i< NUM_LEDS; i++){
leds[i] = CRGB::Green;
}
FastLED.show();
}
}
tft.setTextDatum(8); // bottom right
tft.setTextSize(1);
tft.setFreeFont(FF95);
tft.drawString(String(co2), 195, 105);
// Draw CO2 unit
tft.setTextSize(1);
tft.setFreeFont(FF90);
tft.drawString("ppm", 230, 90);
// Revert datum setting
tft.setTextDatum(defaultDatum);
}
void setup() {
Serial.begin(115200);
delay(100);
// Initialize the GadgetBle Library
gadgetBle.begin();
Serial.print("Sensirion GadgetBle Lib initialized with deviceId = ");
Serial.println(gadgetBle.getDeviceIdString());
// Initialize the SCD30 driver
Wire.begin(SDA_pin, SCL_pin);
scd30.initialize();
scd30.setAutoSelfCalibration(1);
FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(leds, NUM_LEDS);
// Display init and splash screen
displayInit();
displaySplashScreen();
// Enjoy the splash screen for 2 seconds
delay(2000);
}
void loop() {
float result[3] = {0};
if (esp_timer_get_time() – lastMmntTime >= startCheckingAfterUs) {
if (scd30.isAvailable()) {
scd30.getCarbonDioxideConcentration(result);
gadgetBle.writeCO2(result[0]);
gadgetBle.writeTemperature(result[1]);
gadgetBle.writeHumidity(result[2]);
gadgetBle.commit();
lastMmntTime = esp_timer_get_time();
// Provide the sensor values for Tools -> Serial Monitor or Serial Plotter
Serial.print("CO2[ppm]:");
Serial.print(result[0]);
Serial.print("\t");
Serial.print("Temperature[℃]:");
Serial.print(result[1]);
Serial.print("\t");
Serial.print("Humidity[%]:");
Serial.println(result[2]);
// display CO2 value
displayCo2((uint16_t) std::round(result[0]));
}
}
gadgetBle.handleEvents();
delay(3);
}

view raw
CO2Ampel.ino
hosted with ❤ by GitHub

Das ganze kann man auch über eine Powerbank mit Strom versorgen. Ich habe es mit einer billigen 2600mAh Powerbank getestet, die hält zwischen 7-8Std. sollte also einen Schultag überstehen.

Hier noch mal ein Bild wie das ganze von der Rückseite aussieht. Da ist auch das Display zu sehen:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.