2020-10-31 16:06:36 +01:00
# include <Arduino.h>
# include "MHZ19.h"
# include "SSD1306Wire.h"
# include <Adafruit_NeoPixel.h>
2020-11-19 13:13:10 +01:00
# include "fonts-custom.h"
2020-11-23 22:50:05 +01:00
# include <Preferences.h>
2020-10-31 16:06:36 +01:00
// Maximum CO² levels for green and yellow, everything above is considered red.
# define GREEN_CO2 800
2020-11-12 19:46:23 +01:00
# define YELLOW_CO2 1000
2020-10-31 16:06:36 +01:00
// Measurement interval in miliseconds
2020-11-19 13:13:10 +01:00
# define INTERVAL 15000
2020-10-31 16:06:36 +01:00
// Pins for MH-Z19
# define RX_PIN 16
# define TX_PIN 17
// Pins for SD1306
# define SDA_PIN 21
# define SCL_PIN 22
// Pin for LED
# define LED_PIN 4
2020-11-12 19:46:23 +01:00
// number of LEDs connected
# define NUMPIXELS 12
2020-11-23 22:50:05 +01:00
Preferences preferences ;
2020-11-19 13:13:10 +01:00
2020-10-31 16:06:36 +01:00
MHZ19 myMHZ19 ;
HardwareSerial mySerial ( 1 ) ;
SSD1306Wire display ( 0x3c , SDA_PIN , SCL_PIN ) ;
2020-11-12 19:46:23 +01:00
Adafruit_NeoPixel pixels = Adafruit_NeoPixel ( NUMPIXELS , LED_PIN , NEO_RGB + NEO_KHZ400 ) ;
2020-10-31 16:06:36 +01:00
unsigned long getDataTimer = 0 ;
int lastvals [ 120 ] ;
int dheight ;
2020-11-23 22:50:05 +01:00
String ampelversion = " 0.1 " ;
int safezone = 1 ;
int tocalibrateornot ;
2020-10-31 16:06:36 +01:00
void setup ( ) {
Serial . begin ( 9600 ) ;
2020-11-19 13:13:10 +01:00
Serial . println ( " boot... " ) ;
2020-11-23 22:50:05 +01:00
preferences . begin ( " co2 " , false ) ;
2020-11-23 23:50:36 +01:00
tocalibrateornot = preferences . getUInt ( " cal " , 69 ) ; // wir lesen unser flag ein, 23 = reboot vor safezone, wir wollen kalibrieren, 42 = reboot nach safezone, wir tun nichts
2020-11-23 22:50:05 +01:00
preferences . putUInt ( " cal " , 23 ) ; // wir sind gerade gestartet
2020-11-19 13:13:10 +01:00
Serial . println ( ampelversion ) ;
2020-10-31 16:06:36 +01:00
mySerial . begin ( 9600 , SERIAL_8N1 , RX_PIN , TX_PIN ) ;
myMHZ19 . begin ( mySerial ) ;
2020-11-12 19:46:23 +01:00
pixels . clear ( ) ;
2020-10-31 16:06:36 +01:00
display . init ( ) ;
2020-11-23 23:50:36 +01:00
display . setFont ( Cousine_Regular_54 ) ;
2020-10-31 16:06:36 +01:00
display . setContrast ( 255 ) ;
2020-11-23 22:50:05 +01:00
delay ( 500 ) ;
2020-10-31 16:06:36 +01:00
display . clear ( ) ;
2020-11-12 19:46:23 +01:00
display . flipScreenVertically ( ) ;
2020-11-23 22:50:05 +01:00
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 0 , String ( ampelversion ) ) ;
display . display ( ) ;
2020-10-31 16:06:36 +01:00
dheight = display . getHeight ( ) ;
2020-11-23 22:50:05 +01:00
// myMHZ19.autoCalibration();
Serial . print ( " read EEPROM value: " ) ;
Serial . println ( tocalibrateornot ) ;
if ( tocalibrateornot = = 23 ) {
Serial . println ( " brace yourself, calibration starting! things either be better or all fucked up beyond this point... " ) ;
2020-11-23 23:50:36 +01:00
display . drawString ( 64 , 20 , " CAL! " ) ;
2020-11-23 22:50:05 +01:00
display . display ( ) ;
2020-11-23 23:50:36 +01:00
for ( int i = 60 ; i > 0 ; i - - ) {
display . clear ( ) ;
display . drawString ( 64 , 0 , String ( i ) ) ;
display . display ( ) ;
delay ( 1000 ) ;
}
myMHZ19 . setRange ( 5000 ) ;
delay ( 500 ) ;
2020-11-23 22:50:05 +01:00
myMHZ19 . calibrateZero ( ) ;
2020-11-23 23:50:36 +01:00
delay ( 500 ) ;
2020-11-23 22:50:05 +01:00
myMHZ19 . autoCalibration ( false ) ;
2020-11-23 23:50:36 +01:00
delay ( 500 ) ;
display . clear ( ) ;
display . drawString ( 64 , 0 , " DONE " ) ;
display . display ( ) ;
char myVersion [ 4 ] ;
myMHZ19 . getVersion ( myVersion ) ;
Serial . print ( " \n Firmware Version: " ) ;
for ( byte i = 0 ; i < 4 ; i + + )
{
Serial . print ( myVersion [ i ] ) ;
if ( i = = 1 )
Serial . print ( " . " ) ;
}
Serial . println ( " " ) ;
Serial . print ( " Range: " ) ;
Serial . println ( myMHZ19 . getRange ( ) ) ;
Serial . print ( " Background CO2: " ) ;
Serial . println ( myMHZ19 . getBackgroundCO2 ( ) ) ;
Serial . print ( " Temperature Cal: " ) ;
Serial . println ( myMHZ19 . getTempAdjustment ( ) ) ;
2020-11-23 22:50:05 +01:00
Serial . println ( " calibration done " ) ;
Serial . print ( " ABC Status: " ) ; myMHZ19 . getABC ( ) ? Serial . println ( " ON " ) : Serial . println ( " OFF " ) ;
}
else if ( tocalibrateornot = = 42 ) {
Serial . println ( " fake news, nobody has the intention to do calibration.... " ) ;
}
2020-10-31 16:06:36 +01:00
// Fill array of last measurements with -1
for ( int x = 0 ; x < = 119 ; x = x + 1 ) {
lastvals [ x ] = - 1 ;
}
2020-11-12 19:46:23 +01:00
2020-10-31 16:06:36 +01:00
pixels . begin ( ) ;
2020-11-12 19:46:23 +01:00
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
pixels . setPixelColor ( i , pixels . Color ( 0 , 0 , 50 ) ) ;
pixels . show ( ) ;
}
2020-10-31 16:06:36 +01:00
}
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
2020-11-12 19:46:23 +01:00
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
pixels . setPixelColor ( i , 30 , 0 , 0 ) ;
pixels . show ( ) ;
}
2020-10-31 16:06:36 +01:00
} else if ( co2 < YELLOW_CO2 ) {
// Yellow
2020-11-12 19:46:23 +01:00
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
pixels . setPixelColor ( i , 40 , 40 , 0 ) ;
pixels . show ( ) ;
}
2020-10-31 16:06:36 +01:00
} else {
// Red
2020-11-12 19:46:23 +01:00
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
pixels . setPixelColor ( i , 0 , 90 , 0 ) ;
pixels . show ( ) ;
}
2020-10-31 16:06:36 +01:00
}
pixels . show ( ) ;
}
void loop ( ) {
2020-11-23 22:50:05 +01:00
if ( safezone = = 1 ) {
if ( millis ( ) = = 10000 ) {
Serial . println ( " safe zone, sensor stayed up longer than 10s " ) ;
preferences . putUInt ( " cal " , 42 ) ; // wir haben die safe zone erreicht, beim naechsten boot nicht kalibrieren!
safezone = 0 ;
}
}
2020-10-31 16:06:36 +01:00
if ( millis ( ) - getDataTimer > = INTERVAL ) {
// Get new CO² value.
int CO2 = myMHZ19 . getCO2 ( ) ;
// Shift entries in array back one position.
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.
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 ) ;
}
}
// Set LED color and print value on display
set_led_color ( CO2 ) ;
display . setLogBuffer ( 1 , 30 ) ;
2020-11-12 19:46:23 +01:00
display . setFont ( Cousine_Regular_54 ) ;
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 0 , String ( CO2 ) ) ;
2020-10-31 16:06:36 +01:00
display . drawLogBuffer ( 0 , 0 ) ;
display . display ( ) ;
// Debug output
Serial . print ( " CO2 (ppm): " ) ;
2020-11-19 13:13:10 +01:00
Serial . print ( CO2 ) ;
2020-11-23 23:50:36 +01:00
Serial . print ( " Background CO2: " ) ;
Serial . print ( myMHZ19 . getBackgroundCO2 ( ) ) ;
2020-11-19 13:13:10 +01:00
Serial . print ( " uptime (seconds): " ) ;
Serial . println ( millis ( ) / 1000 ) ;
2020-10-31 16:06:36 +01:00
getDataTimer = millis ( ) ;
}
2020-11-12 19:46:23 +01:00
}