#include #include "MHZ19.h" #include "SSD1306Wire.h" #include #include "fonts-custom.h" #include #include "uptime_formatter.h" // Grenzwerte für die CO2 Werte für grün und gelb, alles überhalb davon bedeutet rot #define GREEN_CO2 800 #define YELLOW_CO2 1000 // CO2 Messintervall in Milisekunden #define INTERVAL 15*1000 // Dauer der Kalibrierungsphase in Milisekunden #define CALINTERVAL 180*1000 // Boot-Mode Konstanten #define BOOT_NORMAL 42 #define BOOT_CALIBRATE 23 #define BOOT_UNKNOWN 63 // Pins für den MH-Z19b #define RX_PIN 16 #define TX_PIN 17 // Pins für das SD1306 OLED-Display #define SDA_PIN 21 #define SCL_PIN 22 // Pin für den LED-Ring #define LED_PIN 4 // Anzahl der angeschlossenen LEDs am Ring #define NUMPIXELS 8 Preferences preferences; MHZ19 myMHZ19; HardwareSerial mySerial(1); SSD1306Wire display(0x3c, SDA_PIN, SCL_PIN); Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, LED_PIN, NEO_RGB + NEO_KHZ800); String ampelversion = "0.12"; unsigned long getDataTimer = 0; unsigned long getDataTimer1 = 0; int countdown = 0; int lastvals[120]; int dheight; int safezone = false; int tocalibrateornot; void switchBootMode(int bm){ switch (bm){ case BOOT_CALIBRATE: preferences.putUInt("cal", BOOT_NORMAL); Serial.println("Startmodus nächster Reboot: Messmodus"); break; case BOOT_NORMAL: preferences.putUInt("cal", BOOT_CALIBRATE); Serial.println("Startmodus nächster Reboot: Kalibrierungsmodus"); break; case BOOT_UNKNOWN: Serial.println("EEPROM lesen war nicht möglich!"); break; default: Serial.print("EEPROM lesen lieferte unerwarteten Wert: "); Serial.println(bm); break; } } void setup() { Serial.begin(115200); Serial.println("Starte..."); Serial.print("CO2-Ampel Firmware: ");Serial.println(ampelversion); // Ab hier Bootmodus initialisieren und festlegen preferences.begin("co2", false); tocalibrateornot = preferences.getUInt("cal", BOOT_UNKNOWN); // wir lesen unser flag ein, // 23 = reboot vor safezone, wir wollen kalibrieren, // 42 = reboot nach safezone, wir tun nichts preferences.putUInt("cal", BOOT_CALIBRATE); // wir sind gerade gestartet switch(tocalibrateornot){ case BOOT_CALIBRATE: Serial.println("Startmodus Aktuell: Kalibrierungsmodus"); break; case BOOT_NORMAL: Serial.println("Startmodus Aktuell: Messmodus"); break; } // Ab hier Display einrichten display.init(); display.setFont(Cousine_Regular_54); display.setContrast(255); delay(500); display.clear(); display.flipScreenVertically(); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64 ,0 , String(ampelversion)); display.display(); dheight = display.getHeight(); // Ab hier Sensor einrichten mySerial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); myMHZ19.begin(mySerial); myMHZ19.autoCalibration(false); // "Automatic Baseline Calibration" (ABC) erstmal aus char myVersion[4]; myMHZ19.getVersion(myVersion); Serial.print("\nMH-Z19b Firmware Version: "); Serial.print(myVersion[0]);Serial.print(myVersion[1]);;Serial.print(".");Serial.print(myVersion[2]);Serial.println(myVersion[3]); Serial.print("Range: "); Serial.println(myMHZ19.getRange()); Serial.print("Background CO2: "); Serial.println(myMHZ19.getBackgroundCO2()); Serial.print("Temperature Cal: "); Serial.println(myMHZ19.getTempAdjustment()); Serial.print("ABC Status: "); myMHZ19.getABC() ? Serial.println("ON") : Serial.println("OFF"); Serial.print("read EEPROM value: "); Serial.println(tocalibrateornot); // Liste der Messwerte mit "-1" befüllen ("-1" wird beinm Graph nicht gezeichnet) for (int x = 0; x <= 119; x = x + 1) { lastvals[x] = -1; } // Ab hier LED-Ring konfigurien pixels.begin(); pixels.clear(); pixels.fill(pixels.Color(0,0,0)); pixels.show(); switchBootMode(tocalibrateornot); // beim nächsten boot im anderen modus starten } int calc_vpos_for_co2(int co2val, int display_height) { return display_height - int((float(display_height) / 3000) * co2val); } void set_led_color(int co2) { if (co2 < GREEN_CO2) { pixels.fill(pixels.Color(10,0,0)); // Grün } else if (co2 < YELLOW_CO2) { pixels.fill(pixels.Color(40,40,0)); // Gelb } else { pixels.fill(pixels.Color(0,0,90)); // Rot } pixels.show(); } void rainbow(int wait) { for(long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) { for(int i=0; i= INTERVAL) { // Neuen CO2 Wert lesen int CO2 = myMHZ19.getCO2(); // Alle Werte in der Messwertliste um eins verschieben for (int x = 1; x <= 119; x = x + 1) { lastvals[x - 1] = lastvals[x]; } // Aktuellen Messer am Ende einfügen lastvals[119] = CO2; // Display löschen und alles neu schreiben/zeichnen display.clear(); for (int h = 1; h < 120; h = h + 1) { int curval = lastvals[h]; if (curval > 0) { int vpos = calc_vpos_for_co2(lastvals[h], dheight); int vpos_last = calc_vpos_for_co2(lastvals[h - 1], dheight); display.drawLine(h - 1, vpos_last, h, vpos); } } // Farbe des LED-Rings setzen if (tocalibrateornot == BOOT_NORMAL) { set_led_color(CO2); } //display.setLogBuffer(1, 30); display.setFont(Cousine_Regular_54); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(64 ,0 , String(CO2)); //display.drawLogBuffer(0, 0); display.display(); // Ein wenig Debug-Ausgabe Serial.print("Neue Messung - Aktueller CO2-Wert: "); Serial.print(CO2); Serial.print("; Background CO2: " + String(myMHZ19.getBackgroundCO2())); Serial.print("; Temperatur: " + String(myMHZ19.getTemperature()) + " Temperature Adjustment: " + String(myMHZ19.getTempAdjustment())); //Serial.print(myMHZ19.getBackgroundCO2()); Serial.println("; uptime: " + uptime_formatter::getUptime()); getDataTimer = millis(); } } void loop() { if (millis() > 10000) { Serial.println("=== 10 Sekunden im Betrieb, nächster Boot im Normalmodus ==="); switchBootMode(BOOT_CALIBRATE); // preferences.putUInt("cal", NORMAL); // wir haben die safe zone erreicht, beim naechsten boot nicht kalibrieren! safezone = true; } if (safezone){ if (tocalibrateornot == BOOT_CALIBRATE){ if (millis() - getDataTimer1 <= CALINTERVAL) { rainbow(10); display.clear(); display.setTextAlignment(TEXT_ALIGN_CENTER); //countdown = (CALINTERVAL - (getDataTimer1 + millis() * -1)) / 1000; //countdown = (millis() + getDataTimer1 - CALINTERVAL) * -1 / 1000; countdown = ((getDataTimer1 + CALINTERVAL) - millis()) / 1000; Serial.println("Countdown: " + String(countdown)); display.drawString(64, 0, String(countdown)); display.display(); } else if (millis() - getDataTimer1 >= CALINTERVAL) { calibrateCO2(); getDataTimer1 = millis(); } } } readCO2(); }