CO2-Ampel (3D-Druck oder Lasercutting)

Die CO2-Ampel basiert auf dem Konzept des Verstehbahnhofs. Wir haben die Technik und Programmierung so gelassen wie sie ist, bei den Gehäusen aber einige Modifizierungen vorgenommen. Hier wird eine gedruckte und eine gelaserte Gehäusevariante erklärt.
Die CO2 Ampel soll mit unterschiedlichen Warnfarben den CO2-Gehalt in der Raumluft anzeigen und so Hinweise geben, ob mal wieder gelüftet werden soll.

Für Ampel werden folgende Teile benötigt:

  • MicroController: Wir haben uns für einen ESP8266 entschieden. Durch sein WLAN-Modul sind viele weitere Funktionserweiterungen denkbar.
  • CO2-Sensor: Zum Einsatz kommt ein MH-Z19C
  • NEO Pixelring: gibt es in verschiedenen Größen. Die kleinste Variante mit 12 Pixeln ist ausreichen und passt in beide Gehäuse.
  • Kabel + Lötgerät
  • Lasercutter oder 3D-Drucker + die SVG-Datei oder CAD-Gehäusemodell (s.u.)
  • 3mm Pappelsperrholz (Lasercutter-Variante), PLA-Filament (3D-Druck variante)

Zwei Varianten stehen zur Auswahl

CO2-Ampel aus dem 3D-Drucker

Aufklappen

Die CO2-Ampel der Machbar haben wir etwas kompakter gestaltet.


Farblich markiert sind die Aufnahmen für Pixelring (orange), ESP8266 (blau), CO2-Sensor (grün) und Sicherungsschieber für das Stromkabel (violett).
Die Datei kann entweder direkt gedruckt werden, oder zuvor noch modifiziert werden.
CO2AmpelFablabCB-BodyPad004.stl (12,8 KB)

Hierzu empfiehlt sich z.B. die Browserbasierte Anwendung TinkerCAD (Account benötigt). Wir mit Freecad arbeitet kann sich hier auch die Projektdatei herunterladen:
CO2AmpelFablabCB.FCStd (158,3 KB)

Zur Sicherung des USB-Kabels gibt es hier noch die STL zum fixieren des Kabels:
CO2AmpelFablabCB_Kabelfix.stl (3,6 KB)

Für das Gehäuse und den Schieber ist ein Infill von 7-10% völlig ausreichend.

Am Ende sollte das Gehäuse so aussehen:

Damit das Gehäuse vollständig ist, fehlt noch ein Deckel. Falls ein Lasercutter zur Verfügung steht, bietet sich milchiges Acrylglas an. Alternativ kann auch eine dünnes rechteck mit dem 3D-Drucker gedruckt werden. Die Grundmaße für die Abdeckung betragen bei diesem Modell 51,2 x 106 mm.
Oder als SVG:
CO2Ampel3dAbdeckung abdeckung

Alle weiteren Schritte folgen unter Elektronik und Programmierung

CO2-Ampel aus dem Lasercutter

Aufklappen

Das Gehäuse

Die Einzelteile der CO2-Ampel aus dem Lasercutter haben wir mit dem kostenlosen Box generator boxes.py hergestellt und dann so modifiziert, dass eine Kabelzuführung funktioniert und die Einzelteile einen Platz haben.
Für das Gehäuse ohne die Abdeckung ergibt sich die folgende SVG Datei:
CO2AmpelLaserGehäuseFablabCB

Die Datei kann gerne mit eigenen Schriftzügen etc. modifiziert werden.
Nach dem Cutten sollte sich folgendes Bild ergeben:

Wichtig ist, darauf zu achten, das Kabel vor dem Zusammenstecken an der dafür vorgesehenen Stelle zu platzieren.

Die Abdeckung

Die Abdeckung ist im Prinzip ein Duplikat des Bodens ohne Löcher. Hier können eigene Designs aus Holz eingesetzt werden oder bspw. aus Acrylglas. Damit alles zusammenpasst, sollte auf eine Materialstärke von 3mm geachtet werden.
CO2AmpelAbdeckung.svg

Elektronik und Programmierung

Für beide Gehäusetypen verlaufen die folgenden Schritte gleich. Bevor wir uns ans Verlöten der einzelnen Bauteile machen muss zunächst der Code auf den Microcontroller.

Einrichtung der Arduino IDE

Wir nutzen in diesem Fall die Arduino IDE. Damit diese unseren ESP8266 erkennt sind ein paar Einstellungen notwendig:

Ein paar Vorbemerkungen zum Code:

  • Je nach Pixelring muss die Zeile „#define LED_COUNT 12“ an die tatsächliche Anzahl an Pixeln auf deinem Ring angepasst werden.
  • In der Zeile „strip.setBrightness(200);“ kann die Helligkeit angepasst werden (um Strom zu sparen oder die Augen zu schonen)

/* 
 *  
 *  CO2 Ampel Projekt des Verstehbahnhof
 *  https://www.verstehbahnhof.de
 *  kontakt@verstehbahnhof.de
 *  Twitter @verstehbahnhof
 *  
 *  v0.2
 *  
 *  Der Sketch verwendet
 *    - die MHZ19 Library von Jonathan Dempsey
 *    - die NeoPixel Library von Adafruit
 *    
 *  Features v0.2
 *    - Setzen von 3 Schwellwerten: gut, mittel, schlecht
 *    - Anzeige der Aufwärmphase des Sensors
 *    - Auslesen des CO2 Sensors
 *    - Setzen der Farbe eines 12bit NeoPixel Rings entsprechend
 *      definierter Schwellwerte
 *  
 *  Todo v0.3
 *    - Fünf-maliges Blinken beim Farbübergang zur besseren
 *      Visualisierung
 *    - WiFi und MQTT Integration zum Übermitteln der Daten
 *  
 *  Hardware
 *    - MH-Z19B CO2 Sensor
 *    - 12bit NeoPixel Ring
 *    - Wemos D1 Mini Microcontroller
 *    
 *  Messwerte, Genauigkeit et al
 *    Der MH-Z19B liefert Messwerte die auf +/- 50ppm genau sind.
 *    Ser Sensor misst Werte gegen angenommene 400ppm CO2 in der Luft.
 *    Beim Start dieses Sketches wird eine Kalibrierung des Sensors
 *    durchgeführt und angenommen das ein 400ppm Zustand herrscht.
 *    Räume sollten somit zum Beginn der Messung gut gelüftet sein.
 *     
 */

#include <Arduino.h>
#include "MHZ19.h"                                        
#include <SoftwareSerial.h>

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif


// CO2 Sensor
#define BAUDRATE 9600                                      // Der MH-Z19B verwendet 9600 Baud
#define RX_PIN D7                                          // RX Pin auf dem D1 Mini, verbunden zu TX des MH-Z19B
#define TX_PIN D8                                          // TX Pin auf dem D1 Mini, verbunden zu RX des MH-Z19B

// CO2 Schwellwerte
int co2gut = 500;
int co2mittel = 800;
int co2schlecht = 1100;

// 12er NeoPixel Ring
#define LED_COUNT 12
#define LED_PIN   D5

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

MHZ19 myMHZ19;                                             // Constructor for library

SoftwareSerial mySerial(RX_PIN, TX_PIN);                  
unsigned long messLaufzeit = 0;

void setup()
{
    /* 
     * Start der seriellen Kommunikation
     */
     
    Serial.begin(9600);                                     // Device to serial monitor feedback
    mySerial.begin(BAUDRATE);                               // (Uno example) device to MH-Z19 serial start   
    myMHZ19.begin(mySerial);                                // *Serial(Stream) refence must be passed to library begin(). 

    /*
     * Autokalibrierung des Sensors beim Start (abschalten autoCalibration(false))
     */
     
    myMHZ19.autoCalibration();

    /*                 
     *  
     */
     
    #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
      clock_prescale_set(clock_div_1);
    #endif

    /*
     * Initalisierung des LED Rings
     */
     
    strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
    strip.show();            // Turn OFF all pixels ASAP
    strip.setBrightness(200); // Set BRIGHTNESS to about 1/5 (max = 255)
}

void loop()
{
    /*
     * Der Sensor hat eine Aufwärmzeit von 180 Sekunden bevor er Messwerte liefert. Solange lassen wir
     * einen Regenbogen durch den Ring laufen. 
     */
     
    if (millis() < 180000)
    {
      rainbow(10);
    }

    /*
     *  Nach der Aufwärmzeit von 180 Sekunden läuft diese Schleife alle fünf Sekunden,
     *  fragt Sensorwerte ab, vergleicht diese mit den eingestellten Schwellwerten und
     *  setzt entsprechend die Farbe der Ampel.
     */

    else if (millis() - messLaufzeit >= 5000)
    {
      
        /*
         * Wir definieren eine Variable CO2 und weisen dieser das ausgelesene CO2-Level vom Sensor zu 
         */
         
        int CO2;
        CO2 = myMHZ19.getCO2();                             // Request CO2 (as ppm)

        /*
         * Wir schreiben uns den CO2 Wert in die serielle Konsole. Die Temperatur nehmen wir gleich mit,
         * gibt ja gratis dazu. 
         */
        
        Serial.print("CO2 (in ppm): ");                      
        Serial.println(CO2);                                
        int8_t Temp;
        Temp = myMHZ19.getTemperature();                     // Request Temperature (as Celsius)
        Serial.print("Temperatur (C): ");                  
        Serial.println(Temp);

        /*
         * Je nach CO2 Level ändern wir die LED-Farbe 
         */
         
        if (CO2 <= co2gut) {                             
          colorWipe(strip.Color(  0, 255,   0), 200);
        }
        else if ((CO2 > co2gut) && (CO2 <= co2mittel)) {
          colorWipe(strip.Color(  255, 255,   0), 200);
        }
        else if ((CO2 > co2mittel) && (CO2 <= co2schlecht)) {
          colorWipe(strip.Color(  255, 165,   0), 200);
        }
        else if (CO2 > co2schlecht) {
          colorWipe(strip.Color(  255, 0,   0), 200);
        }
        messLaufzeit = millis();
    }
}


/* 
 * Zwei Anzeigemodi aus dem NeoPixel Beispielcode. 
 */
 
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

void rainbow(int wait) {
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) {
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show();
    delay(wait);
  }
}

Löten

  • Die Groundanschlüsse von CO2-Sensor und Pixelring müssen mit Grund des ESP8266 verlötet werden.
  • Pixelring und CO2-Sensor werden außerdem über den 5V Pin mit Strom versorgt.
  • Bei den Datenleitungen halten wir uns an die Kommentare aus dem Programmcode, d.h.
    • DI Anschluss des Pixelrings an den D5 Pin des ESP8266
    • RX Pin (grünes Kabel) auf D7
    • TX Pin (blaues Kabel) auf D8