Compare commits

...

39 Commits

Author SHA1 Message Date
Stefan Heinrichsen c26370f4f1 Merge branch 'main' of git.un-hack-bar.de:smash/ebk-unhb-co2ampel into main 2021-01-26 10:26:25 +01:00
Stefan Heinrichsen 51c654f7fb Updated MH-Z19 Libary to 1.5.3; moved to new calibrate() instead of calibrateZero() 2021-01-26 10:25:24 +01:00
Stefan H. b5e88075ed Nochmal den Link zum Download geändert 2021-01-24 11:56:20 +01:00
Stefan H. d966d3ed41 Download Link korrigiert 2021-01-24 11:55:31 +01:00
Stefan H. bd38c87149 Formatierung geändert 2021-01-24 11:52:13 +01:00
Stefan H. ee5c507b32 Hinweis auf fertige firmware eingefügt 2021-01-24 11:51:14 +01:00
root c9d207104a Firmware File eingefügt 2021-01-24 11:47:32 +01:00
Stefan Heinrichsen d435f5bb5b Skalierung des Graphen angepasst (250=Pixel 0, 5000ppm=Pixel 16) 2020-12-03 19:51:46 +01:00
Stefan Heinrichsen 6ec60273ea Div. Meldungen geändert/vereinfacht 2020-12-03 19:24:02 +01:00
Stefan Heinrichsen 0f1f0b0067 Mehr Infos auf dem Display im Kalibrationsmodus und beim starten 2020-12-03 18:58:28 +01:00
Stefan Heinrichsen 207224fa05 Display wird in eigener Methode aktuallisiert (unabhängig vom CO2-Wert lesen) 2020-12-03 16:43:22 +01:00
Stefan Heinrichsen 0304cdf8b2 Direkt nach dem Booten schonmal einen CO2 Wert lesen weil da meistens zuerst Mist kommt. 2020-12-03 16:08:37 +01:00
Stefan Heinrichsen 177a90e773 Nach Diskussion mit meinem Sohn das "Gelb" etwas "gelber" gemacht... 2020-11-29 20:10:49 +01:00
Stefan Heinrichsen 5af758fd8b LED und CO2 Update an die korrekte Stelle verschoben, Version auf 0.13 geändert. 2020-11-29 20:02:37 +01:00
Stefan Heinrichsen 8aa507f34b Auf Wunsch eines Individum: Konstanten-Wert für "Unbekannter Flashinhalt" angepasst. 2020-11-29 19:49:28 +01:00
Stefan Heinrichsen aaf6b83c46 LED update aus CO2 Auslesemethode ausgelagert; LED "Blinken" für rot eingefügt 2020-11-29 19:47:41 +01:00
Stefan Heinrichsen 0cd36178ec Pixelreihenfolge korrigiert 2020-11-29 18:25:14 +01:00
Stefan Heinrichsen e9a4729c62 rot und blau waren vertauscht... :-p 2020-11-26 21:19:38 +01:00
Stefan Heinrichsen 85074e8aed Helligkeit von "grün" deutlich reduziert, erste Versuche den Ablauf zum Kalibrieren zu vereinfachen 2020-11-26 21:12:48 +01:00
Stefan Heinrichsen 488f6a62b9 Variable für aktuellen Modus eingefügt, Methode zum setzen des Bootmodes angelegt, switchBootMode zu toggleBootMode umbenannt 2020-11-26 19:02:56 +01:00
Stefan Heinrichsen 93f0947a93 Defined names for bootmode and removed one unneeded variable 2020-11-26 17:35:41 +01:00
Stefan Heinrichsen 2955909a89 calibrateCO2 Methode neu formatiert 2020-11-26 16:33:32 +01:00
Stefan Heinrichsen 77ff9169d8 Ansteuerung LED Ring vereinfacht 2020-11-26 16:13:16 +01:00
Stefan Heinrichsen 94c47504e4 Kommentare übersetzt 2020-11-26 16:07:29 +01:00
Stefan Heinrichsen 529dc9b818 Reihenfolge der Setup() Methode sortiert 2020-11-26 15:52:07 +01:00
Stefan Heinrichsen cf13f25c97 removed upload_port from config (so platformio will search automatically for correct port) 2020-11-26 15:24:42 +01:00
smash cfdac0de79 irgendwas mit nem kaputten countdown und mehr debug 2020-11-25 23:22:48 +01:00
smash ddb1377175 what am i doing here? 2020-11-25 21:33:28 +01:00
smash 038120d3de i sure will burn in hell for this mess of spaghetti code... 2020-11-24 01:19:10 +01:00
smash b0d5df86ed fix to prevent us trapped in calibration mode forever 2020-11-24 00:05:05 +01:00
smash 32287a18b4 Merge branch 'main' of git.un-hack-bar.de:smash/ebk-unhb-co2ampel into main 2020-11-23 23:59:25 +01:00
smash 65991da03a fix: write preferences after calibration to prevent calibration loop 2020-11-23 23:58:24 +01:00
Michael Biermann 2d6464fa7d Merge branch 'main' of https://git.unhb.de/smash/ebk-unhb-co2ampel into main 2020-11-23 23:52:15 +01:00
smash 327ab2547a added countdown, removed span calibration 2020-11-23 23:50:36 +01:00
Michael Biermann a256c1540c COM5 als Standard. 2020-11-23 23:13:36 +01:00
smash 9830ad9984 experimental feature: calibration when rebootet before 10s uptime 2020-11-23 22:50:05 +01:00
smash 822429e456 settings for serial debug 2020-11-23 22:49:10 +01:00
smash 314a39619e more debug output via serial, interval 15s, custom font inclusion 2020-11-19 13:13:10 +01:00
smash ec3ecb4abd added custom-fonts.h for our font choosing 2020-11-19 13:12:12 +01:00
5 changed files with 302 additions and 1740 deletions

View File

@ -42,6 +42,11 @@ Eine RGB-LED zeigt rot, gelb oder grün, je nach Messwert.
Wir benutzen die PlatformIO IDE. Dort kann das Projekt geöffnet und mit Klick auf "Upload" compiliert und auf den ESP32 geladen werden.
Alternativ kann die Datei [unhb-co2-ampel-v0.5.bin](https://git.unhb.de/smash/ebk-unhb-co2ampel/releases/tag/v0.5) hier runtergeladen werden und z.B. mit dem esptool.py mit
esptool.py write_flash 0x0000 unhb-co2-ampel-v0.5.bin
auf dem Mikrocontroller programmiert werden.
## Wiring

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,9 @@
platform = espressif32
board = esp32dev
framework = arduino
upload_port = /dev/ttyUSB0
lib_deps =
adafruit/Adafruit NeoPixel@^1.6.0
wifwaf/MH-Z19@^1.5.2
squix78/ESP8266_SSD1306@^4.1.0
yiannisbourkelis/Uptime Library @ ^1.0.0
wifwaf/MH-Z19@^1.5.3
monitor_speed = 115200

View File

@ -2,116 +2,338 @@
#include "MHZ19.h"
#include "SSD1306Wire.h"
#include <Adafruit_NeoPixel.h>
#include "fonts-custom.h"
#include <Preferences.h>
#include "uptime_formatter.h"
// Maximum CO² levels for green and yellow, everything above is considered red.
// 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
// Measurement interval in miliseconds
#define INTERVAL 60000
// CO2 Mess-Intervall in Milisekunden
#define CO2_INTERVAL 15*1000
// Display Update-Intervall in Milisekunden
#define DISPLAY_INTERVAL 2500
// Dauer der Kalibrierungsphase in Milisekunden
#define CAL_INTERVAL 180*1000
// Pins for MH-Z19
// Boot-Mode Konstanten
#define BOOT_NORMAL 42
#define BOOT_CALIBRATE 23
#define BOOT_UNKNOWN 69
// Pins für den MH-Z19b
#define RX_PIN 16
#define TX_PIN 17
// Pins for SD1306
// Pins für das SD1306 OLED-Display
#define SDA_PIN 21
#define SCL_PIN 22
// Pin for LED
// Pin für den LED-Ring
#define LED_PIN 4
// number of LEDs connected
// 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);
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
unsigned long getDataTimer = 0;
String ampelversion = "0.50";
int lastvals[120];
int dheight;
int currentBootMode;
void setup() {
Serial.begin(9600);
mySerial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN);
myMHZ19.begin(mySerial);
pixels.clear();
display.init();
display.setContrast(255);
delay(1000);
display.clear();
display.flipScreenVertically();
dheight = display.getHeight();
myMHZ19.autoCalibration();
// Fill array of last measurements with -1
for (int x = 0; x <= 119; x = x + 1) {
lastvals[x] = -1;
void setBootMode(int bootMode) {
if(bootMode == BOOT_NORMAL) {
Serial.println("Startmodus nächster Reboot: Messmodus");
preferences.putUInt("cal", bootMode);
if (bootMode != preferences.getUInt("cal", BOOT_UNKNOWN)) Serial.println("Konnte neuen Bootmodus nicht schreiben :-(");
}
pixels.begin();
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, 0,0,50);
pixels.show();
}
}
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) {
// Green
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, 30,0,0);
}
} else if (co2 < YELLOW_CO2) {
// Yellow
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, 40,40,0);
}
else if(bootMode == BOOT_CALIBRATE) {
Serial.println("Startmodus nächster Reboot: Kalibrierungsmodus");
preferences.putUInt("cal", bootMode);
if (bootMode != preferences.getUInt("cal", BOOT_UNKNOWN)) Serial.println("Konnte neuen Bootmodus nicht schreiben :-(");
} else {
// Red
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, 0,90,0);
}
}
pixels.show();
Serial.println("Unerwarteter Boot-Mode soll gespeichert werden. Abgebrochen.");
}
}
void loop() {
if (millis() - getDataTimer >= INTERVAL) {
// Get new CO² value.
int CO2 = myMHZ19.getCO2();
// Shift entries in array back one position.
void toggleBootMode(int bootMode) {
switch (bootMode){
case BOOT_CALIBRATE:
setBootMode(BOOT_NORMAL); break;
case BOOT_NORMAL:
setBootMode(BOOT_CALIBRATE); break;
case BOOT_UNKNOWN:
Serial.println("Bootmode Unbekannt! Neue Ampel? Nächster Start wird Messmodus.");
setBootMode(BOOT_NORMAL); break;
default:
Serial.print("Unerwarteter Bootmode-Wert: "); Serial.println(bootMode);
Serial.println("Nächster Start wird Messmodus.");
setBootMode(BOOT_NORMAL); break;
}
}
int readCO2(){
static int co2=400;
static unsigned long getDataTimer = 0;
if (millis() - getDataTimer >= CO2_INTERVAL) {
// Neuen CO2 Wert lesen
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];
}
// Add new measurement at the end.
lastvals[119] = CO2;
// Clear display and redraw whole graph.
// Aktuellen Messer am Ende einfügen
lastvals[119] = co2;
// 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.println("; uptime: " + uptime_formatter::getUptime());
getDataTimer = millis();
}
return co2;
}
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);
currentBootMode = preferences.getUInt("cal", BOOT_UNKNOWN); // Aktuellen Boot-Mode lesen und speichern
switch(currentBootMode){
case BOOT_CALIBRATE:
Serial.println("Startmodus Aktuell: Kalibrierungsmodus");
toggleBootMode(currentBootMode); // beim nächsten boot ggfs. im anderen modus starten, wird später nach 10 Sekunden zurückgesetzt
break;
case BOOT_NORMAL:
Serial.println("Startmodus Aktuell: Messmodus");
toggleBootMode(currentBootMode); // beim nächsten boot ggfs. im anderen modus starten, wird später nach 10 Sekunden zurückgesetzt
break;
default:
Serial.println("Startmodus Aktuell: Unbekannt oder Ungültig");
Serial.println("Nächster Start im Messmodus");
setBootMode(BOOT_NORMAL);
break;
}
// Ab hier Display einrichten
display.init();
// display.setLogBuffer(5,30);
display.setContrast(255);
delay(500);
display.clear();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64, 0, "Version: " + String(ampelversion));
if(currentBootMode == BOOT_NORMAL) {
display.drawString(64, 17, "Zum Kalibrieren");
display.drawString(64, 34, "jetzt Neustarten" );
} else {
display.drawString(64, 17, "Zum Messen");
display.drawString(64, 34, "jetzt Neustarten" );
}
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(currentBootMode);
Serial.print("First CO2 value (should be 400): "); Serial.println(readCO2());
// 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();
// Wir lesen schonmal einen CO2 Sensorwert, da die erste Werte meist Müll sind
delay(5000);
Serial.print("Second CO2 value: "); Serial.println(readCO2());
Serial.flush();
}
int calc_vpos_for_co2(int co2val, int max_height) {
return int((float(max_height) / (5000-350)) * (co2val-350));
}
void set_led_color(int co2) {
static char blinkState=0;
static signed char blinkDirection=1;
static int blinkOn=0;
static int blinkOff=0;
if (co2 < GREEN_CO2) {
pixels.fill(pixels.Color(0,0,0)); // Grün
pixels.setPixelColor(4,pixels.Color(0,2,0));
} else if (co2 < YELLOW_CO2) {
pixels.fill(pixels.Color(50,30,0)); // Gelb
} else {
blinkState+=blinkDirection;
if( (blinkState<90) & (blinkState>0) ) {
pixels.fill(pixels.Color(blinkState,00,0));
}
else if (blinkState==90) {
blinkDirection=0; blinkOn++;
if(blinkOn==400) {
blinkOn=0; blinkDirection=-1; blinkState=89;
}
}
else if (blinkState==0) {
blinkDirection=0; blinkOff++;
if(blinkOff==50) {
blinkOff=0; blinkDirection=1; blinkState=1;
}
}
}
pixels.show();
delay(10);
}
void rainbow(int wait) {
for(long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) {
for(int i=0; i<NUMPIXELS; i++) {
int pixelHue = firstPixelHue + (i * 65536L / NUMPIXELS);
pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue)));
}
pixels.show();
delay(wait);
}
}
void calibrateCO2() {
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_16);
display.clear();
display.drawString(64, 0, "! Kalibriere !");
display.setFont(ArialMT_Plain_24);
display.drawString(64, 18, "NICHT");
display.setFont(ArialMT_Plain_16);
display.drawString(64, 44, "Neustarten");
display.display();
Serial.println("Kalibrierung startet nun");
myMHZ19.setRange(5000);
delay(500);
myMHZ19.calibrate();
delay(500);
myMHZ19.autoCalibration(false);
delay(500);
display.clear();
display.setFont(ArialMT_Plain_24);
display.drawString(64, 0, "Fertig!");
display.display();
setBootMode(BOOT_NORMAL);
delay(10000);
display.clear();
}
void updateDisplayCO2(int co2) {
static unsigned long getUpdateTimer = 0;
if (millis() - getUpdateTimer >= DISPLAY_INTERVAL) {
// 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);
int vpos = 63 - calc_vpos_for_co2(lastvals[h], 16);
int vpos_last = 63 - calc_vpos_for_co2(lastvals[h - 1], 16);
display.drawLine(h - 1, vpos_last, h, vpos);
}
}
// Set LED color and print value on display
set_led_color(CO2);
display.setLogBuffer(1, 30);
// Aktuellen CO2 Wert ausgeben
display.setFont(Cousine_Regular_54);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64 ,0 , String(CO2));
display.drawLogBuffer(0, 0);
display.drawString(64 ,0 , String(co2));
display.display();
// Debug output
Serial.print("CO2 (ppm): ");
Serial.println(CO2);
getDataTimer = millis();
// Fertig mit update; Zeitpunkt für das nächste Update speichern
getUpdateTimer = millis();
}
}
void loop() {
static unsigned long calibrationStart = 0;
static int countdown = 0;
static int safezone = false;
int co2;
// Nur für die ersten 10 Sekunden wichtig,
if ( (!safezone) & (millis() > 10000) ) {
Serial.println("=== 10 Sekunden im Betrieb, nächster Boot im Messmodus ===");
setBootMode(BOOT_NORMAL);
safezone = true;
}
if (safezone) {
if (currentBootMode == BOOT_CALIBRATE){
if (millis() - calibrationStart <= CAL_INTERVAL) {
rainbow(10);
countdown = ((calibrationStart + CAL_INTERVAL) - millis()) / 1000;
Serial.println("Countdown: " + String(countdown));
display.clear();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, 0, "Kalibrierung");
display.setFont(ArialMT_Plain_10);;
display.drawString(0, 17, "Abbrechen durch Neustart");
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_16);;
display.drawString(64, 35, "Noch: " + String(countdown) + " Sek.");
display.display();
}
else if (millis() - calibrationStart >= CAL_INTERVAL) {
calibrateCO2();
currentBootMode = BOOT_NORMAL; //Fertig, ab jetzt kann es normal weitergehen
}
} else {
// Achtung: readCO2() liefer nur alle "INTERVAL" ms ein neuen Wert, der alte wird aber zwischengespeichert
co2 = readCO2();
// Update Display
updateDisplayCO2(co2);
// Farbe des LED-Rings setzen
if(currentBootMode == BOOT_NORMAL) { set_led_color(co2); }
}
}
}