Advertisement
Guest User

Battery/SCD41-powered pocket CO2 sensor

a guest
Jan 23rd, 2025
315
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 32.63 KB | None | 0 0
  1. #include <GxEPD2_BW.h>
  2. #include <Adafruit_AHTX0.h>
  3. #include <Adafruit_BMP280.h>
  4. #include <WiFi.h>
  5. //#include <AsyncTCP.h>
  6. #include <WebServer.h>
  7. //#include <AsyncElegantOTA.h>
  8.   #include <WiFiClient.h>
  9.  
  10. #include <ArduinoOTA.h>
  11. #include <HTTPClient.h>
  12.  
  13. #include <WiFiClientSecure.h>
  14. #include <BlynkSimpleEsp32.h>
  15. #include <SensirionI2CScd4x.h>
  16.  
  17. #include <Preferences.h>
  18.  
  19. Preferences preferences;
  20.  
  21. SensirionI2CScd4x scd4x;
  22.  
  23. Adafruit_AHTX0 aht;
  24. Adafruit_BMP280 bmp;
  25. sensors_event_t humidity, temp;
  26. #include<Wire.h>
  27. #define I2C_ADDRESS 0x48
  28. #include "driver/periph_ctrl.h"
  29. int GPIO_reason;
  30. #include "esp_sleep.h"
  31. #include <ElegantOTA.h>
  32. #include <WiFiManager.h>      
  33. WiFiManager wm;
  34.  WebServer server2(8080);
  35.  
  36. const char* ssid = "xxxxxxxxx";
  37. const char* password = "xxxxxxxxx";
  38. // base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code
  39. // enable GxEPD2_GFX base class
  40. #define ENABLE_GxEPD2_GFX 1
  41. #define TEMP_OFFSET 0.8
  42. #define sleeptimeSecs 300
  43. #define maxArray 501
  44. #define controlpin 10
  45. #define MENU_MAX 7
  46. #define ELEGANTOTA_USE_ASYNC_WEBSERVER 0
  47. RTC_DATA_ATTR float array1[maxArray];
  48. RTC_DATA_ATTR float array2[maxArray];
  49. RTC_DATA_ATTR float array3[maxArray];
  50. RTC_DATA_ATTR float array4[maxArray];
  51. RTC_DATA_ATTR float windspeed, windgust, fridgetemp, outtemp;
  52.  int  timetosleep = 5;
  53. RTC_DATA_ATTR int  failcount = 0;
  54.  
  55. const char* ntpServer = "pool.ntp.org";
  56. const long gmtOffset_sec = -18000;  //Replace with your GMT offset (secs)
  57. const int daylightOffset_sec = 0;   //Replace with your daylight offset (secs)
  58.   float t, h, pres, barx;
  59.   float v41_value, v42_value, v62_value;
  60. char timeString[10]; // "12:34 PM" is 8 chars + null terminator
  61.  RTC_DATA_ATTR   int firstrun = 100;
  62.  RTC_DATA_ATTR   int page = 2;
  63.  int calibTarget = 430;
  64. float abshum;
  65.  float minVal = 3.9;
  66.  float maxVal = 4.2;
  67. RTC_DATA_ATTR int readingCount = 0; // Counter for the number of readings
  68. int readingTime;
  69. int menusel = 1;
  70. uint16_t co2;
  71. float temp2, hum;
  72. bool editinterval = false;
  73. bool editcalib = false;
  74. bool calibrated = false;
  75. bool facreset = false;
  76. bool wifireset = false;
  77.  
  78. #include "bitmaps/Bitmaps128x250.h"
  79. #include <Fonts/FreeMonoBold9pt7b.h>
  80. #include <Fonts/Roboto_Condensed_12.h>
  81. #include <Fonts/FreeSerif12pt7b.h>
  82. #include <Fonts/Open_Sans_Condensed_Bold_54.h>
  83. #include <Fonts/DejaVu_Serif_Condensed_36.h>
  84. #include <Fonts/DejaVu_Serif_Condensed_60.h>
  85. #define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO)
  86. GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(/*CS=5*/ SS, /*DC=*/ 21, /*RES=*/ 20, /*BUSY=*/ 3)); // DEPG0213BN 122x250, SSD1680
  87.  
  88. #define every(interval) \
  89.     static uint32_t __every__##interval = millis(); \
  90.     if (millis() - __every__##interval >= interval && (__every__##interval = millis()))
  91.  
  92.  
  93. const char* bedroomauth = "8_-CN2rm4ki9P3i_NkPhxIbCiKd5RXhK";  //hubert
  94.  
  95. // Virtual Pins
  96. const char* v41_pin = "V41";
  97. const char* v62_pin = "V62";
  98.  
  99. float vBat;
  100.  
  101.  
  102.  
  103.  
  104.  
  105. WidgetTerminal terminal(V20);
  106.  
  107.  
  108. BLYNK_WRITE(V20) {
  109.   if (String("recal") == param.asStr()) {
  110.     uint16_t error;
  111.     scd4x.stopPeriodicMeasurement();
  112.     terminal.println("Recalibrating to 400ppm...");
  113.     scd4x.performForcedRecalibration(400, error);
  114.     terminal.print("Adjusted by: ");
  115.     terminal.println(error);
  116.     terminal.flush();
  117.     scd4x.startPeriodicMeasurement();
  118.   }
  119.   if (String("sleep") == param.asStr()) {
  120.     terminal.println("");
  121.     terminal.println("Going to sleep...");
  122.     terminal.flush();
  123.     gotosleep();
  124.   }
  125.   if (String("scd") == param.asStr()) {
  126.     uint16_t error;
  127.     char errorMessage[256];
  128.     bool isDataReady = false;
  129.     error = scd4x.getDataReadyFlag(isDataReady);
  130.     if (error) {
  131.       terminal.print("Error trying to execute getDataReadyFlag(): ");
  132.       errorToString(error, errorMessage, 256);
  133.       terminal.println(errorMessage);
  134.       terminal.flush();
  135.       return;
  136.     }
  137.     if (isDataReady) {
  138.       error = scd4x.readMeasurement(co2, temp2, hum);
  139.       if (error) {
  140.         terminal.print("Error trying to execute readMeasurement(): ");
  141.         errorToString(error, errorMessage, 256);
  142.         terminal.println(errorMessage);
  143.         terminal.flush();
  144.       } else if (co2 == 0) {
  145.         terminal.println("Invalid sample detected, skipping.");
  146.         terminal.flush();
  147.       } else {
  148.         terminal.print("CO2: ");
  149.         terminal.println(co2);
  150.  
  151.         terminal.print("Temp: ");
  152.         terminal.println(temp2);
  153.  
  154.       }
  155.     }
  156.     terminal.flush();
  157.   }
  158.   if (param.asInt() > 300) {
  159.     uint16_t error;
  160.     int newppm = param.asInt();
  161.     scd4x.stopPeriodicMeasurement();
  162.     terminal.println("");
  163.     terminal.print("Recalibrating to ");
  164.     terminal.print(newppm);
  165.     terminal.println("ppm.");
  166.    
  167.     scd4x.performForcedRecalibration(newppm, error);
  168.     terminal.print("Adjusted by: ");
  169.     terminal.println(32767 - error);
  170.     terminal.flush();
  171.     scd4x.startPeriodicMeasurement();
  172.   }
  173.     if (String("facreset") == param.asStr()) {
  174.     scd4x.stopPeriodicMeasurement();
  175.     scd4x.performFactoryReset();
  176.     //scd4x.performForcedRecalibration(980, error);
  177.  
  178.     scd4x.startPeriodicMeasurement();
  179.     }
  180.   terminal.flush();
  181. }
  182.  
  183.  
  184.  
  185.  
  186. void gotosleep() {
  187.       scd4x.stopPeriodicMeasurement();
  188.       delay(10);
  189.       scd4x.powerDown();
  190.       delay(10);
  191.       WiFi.disconnect();
  192.       display.hibernate();
  193.       SPI.end();
  194.       Wire.end();
  195.       pinMode(SS, INPUT_PULLUP );
  196.       pinMode(6, INPUT_PULLUP );
  197.       pinMode(4, INPUT_PULLUP );
  198.       pinMode(8, INPUT_PULLUP );
  199.       pinMode(9, INPUT_PULLUP );
  200.       pinMode(1, INPUT_PULLUP );
  201.       pinMode(2, INPUT_PULLUP );
  202.       pinMode(3, INPUT_PULLUP );
  203.       pinMode(0, INPUT_PULLUP );
  204.       pinMode(5, INPUT_PULLUP );
  205.       digitalWrite(controlpin, LOW);
  206.       pinMode(controlpin, INPUT);
  207.  
  208.  
  209.       uint64_t bitmask = BUTTON_PIN_BITMASK(GPIO_NUM_0) | BUTTON_PIN_BITMASK(GPIO_NUM_1) | BUTTON_PIN_BITMASK(GPIO_NUM_2) | BUTTON_PIN_BITMASK(GPIO_NUM_3) |  BUTTON_PIN_BITMASK(GPIO_NUM_5);
  210.  
  211.       esp_deep_sleep_enable_gpio_wakeup(bitmask, ESP_GPIO_WAKEUP_GPIO_LOW);
  212.       esp_sleep_enable_timer_wakeup((timetosleep * 60) * 1000000ULL);
  213.       delay(1);
  214.       esp_deep_sleep_start();
  215.       //esp_light_sleep_start();
  216.       delay(1000);
  217. }
  218.  
  219.  
  220.  
  221. void startWifi(){
  222.    bool isDataReady = false;
  223.    WiFi.mode(WIFI_STA);
  224.   if (wm.getWiFiIsSaved() && (failcount < 4)){
  225.       //display.clearScreen();
  226.       display.setPartialWindow(0, 0, display.width(), display.height());
  227.       display.setCursor(0, 0);
  228.  
  229.         display.print("Connecting to: " + (String)wm.getWiFiSSID());
  230.       display.display(true);
  231.       WiFi.begin(wm.getWiFiSSID(), wm.getWiFiPass());
  232.       WiFi.setTxPower (WIFI_POWER_8_5dBm);
  233.       // Wait for connection
  234.       while (WiFi.status() != WL_CONNECTED) {
  235.         if (millis() > 10000) {
  236.           WiFi.setTxPower(WIFI_POWER_8_5dBm);
  237.         }
  238.         if (millis() > 20000) {
  239.             failcount++;
  240.             break;
  241.           }
  242.           display.print(".");
  243.       }
  244.       if (WiFi.status() == WL_CONNECTED) {
  245.         Blynk.config(bedroomauth, IPAddress(xxx,xxx,xxx,xxx), 8080);
  246.         Blynk.connect();
  247.         while ((!Blynk.connected()) && (millis() < 20000)){
  248.             delay(500);}
  249.       }
  250.            
  251.             scd4x.getDataReadyFlag(isDataReady);
  252.   while(!isDataReady){delay(250);
  253.   scd4x.getDataReadyFlag(isDataReady);}
  254.   scd4x.readMeasurement(co2, temp2, hum);
  255.  
  256.       if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  257.                 Blynk.virtualWrite(V91, t);
  258.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  259.               Blynk.virtualWrite(V92, h);
  260.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  261.               Blynk.virtualWrite(V93, pres);
  262.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  263.               Blynk.virtualWrite(V94, abshum);
  264.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  265.               Blynk.virtualWrite(V95, vBat);
  266.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  267.               Blynk.virtualWrite(V96, co2);
  268.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  269.               Blynk.virtualWrite(V97, temp2);
  270.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  271.               Blynk.virtualWrite(V97, temp2);
  272.               if (WiFi.status() == WL_CONNECTED) {Blynk.run();}
  273.         struct tm timeinfo;
  274.         getLocalTime(&timeinfo);
  275.         time_t now = time(NULL);
  276.       localtime_r(&now, &timeinfo);
  277.  
  278.       // Allocate a char array for the time string
  279.      
  280.  
  281.       // Format the time string
  282.       if (timeinfo.tm_min < 10) {
  283.         snprintf(timeString, sizeof(timeString), "%d:0%d %s", timeinfo.tm_hour % 12 == 0 ? 12 : timeinfo.tm_hour % 12, timeinfo.tm_min, timeinfo.tm_hour < 12 ? "AM" : "PM");
  284.       } else {
  285.         snprintf(timeString, sizeof(timeString), "%d:%d %s", timeinfo.tm_hour % 12 == 0 ? 12 : timeinfo.tm_hour % 12, timeinfo.tm_min, timeinfo.tm_hour < 12 ? "AM" : "PM");
  286.       }
  287.   }
  288.   else {
  289.            
  290.             scd4x.getDataReadyFlag(isDataReady);
  291.   while(!isDataReady){delay(250);
  292.   scd4x.getDataReadyFlag(isDataReady);}
  293.   scd4x.readMeasurement(co2, temp2, hum);
  294.   }
  295.  
  296.  
  297. }
  298.  
  299. void startWebserver(){
  300.  
  301.  
  302.  
  303.   if (wm.getWiFiIsSaved()){
  304.   display.setPartialWindow(0, 0, display.width(), display.height());
  305.   wipeScreen();
  306.   display.setCursor(0, 0);
  307.  
  308.  
  309.   display.print("Connecting...");
  310.   display.display(true);
  311.   WiFi.mode(WIFI_STA);
  312.      
  313.       WiFi.begin(wm.getWiFiSSID(), wm.getWiFiPass());
  314.  
  315.   //WiFi.mode(WIFI_STA);
  316.   //WiFi.begin(ssid, password);  
  317.   WiFi.setTxPower (WIFI_POWER_8_5dBm);
  318.   // Wait for connection
  319.   while (WiFi.status() != WL_CONNECTED) {
  320.     if (millis() > 20000) { break;}
  321.     delay(1000);
  322.   }
  323.    if (WiFi.status() == WL_CONNECTED) {
  324.     Blynk.config(bedroomauth, IPAddress(192, 168, 50, 197), 8080);
  325.     Blynk.connect();
  326.     while ((!Blynk.connected()) && (millis() < 20000)){delay(100);}
  327.    
  328.     wipeScreen();
  329.     display.setCursor(0, 0);
  330.     display.firstPage();
  331.     do {
  332.       display.print("Connected! to: ");
  333.       display.println(WiFi.localIP());
  334.     } while (display.nextPage());
  335.     ArduinoOTA.setHostname("epaperdisplay");
  336.     ArduinoOTA.begin();
  337.  
  338.     server2.on("/", []() {
  339.       server2.send(200, "text/plain", "Hi! This is ElegantOTA Demo.");
  340.     });
  341.  
  342.     ElegantOTA.begin(&server2);    // Start ElegantOTA
  343.  
  344.     server2.begin();
  345.    }
  346.   }
  347.   pinMode(0, INPUT);
  348.   vBat = analogReadMilliVolts(0) / 500.0;
  349.   pinMode(0, INPUT_PULLUP);
  350.   bmp.takeForcedMeasurement();
  351.   aht.getEvent(&humidity, &temp);
  352.   t = temp.temperature;
  353.   h = humidity.relative_humidity;
  354.   pres = bmp.readPressure() / 100.0;
  355.   /*abshum = (6.112 * pow(2.71828, ((17.67 * temp.temperature)/(temp.temperature + 243.5))) * humidity.relative_humidity * 2.1674)/(273.15 + temp.temperature);
  356.   bool isDataReady = false;
  357.   scd4x.getDataReadyFlag(isDataReady);
  358.   if (isDataReady) {
  359.   scd4x.readMeasurement(co2, temp2, hum);}*/
  360.   displayMenu();
  361. }
  362.  
  363. void displayMenu(){
  364.   display.setPartialWindow(0, 0, display.width(), display.height());
  365.   display.setTextSize(1);
  366.   display.fillScreen(GxEPD_WHITE);
  367.   display.setCursor(0, 0);
  368.   display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
  369.    if (WiFi.status() == WL_CONNECTED) {
  370.   display.print("Connected! to: ");
  371.   display.println(WiFi.localIP());
  372.   display.print("RSSI: ");
  373.   display.println(WiFi.RSSI());
  374.   display.println("");
  375.    }
  376.    else {display.setCursor(0, 8*3);}
  377.     if (menusel == 1) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  378.     display.println("Start WifiManager");
  379.     if (menusel == 2) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  380.     display.println("Change Interval");
  381.     if (menusel == 3) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  382.     display.println("Set Calibration Value");
  383.     if (menusel == 4) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  384.     display.println("Calibrate");
  385.     if (menusel == 5) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  386.     display.println("Factory Reset SCD41");
  387.     if (menusel == 6) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  388.     display.println("Forget Wifi");
  389.     if (menusel == 7) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  390.     display.println("Exit");
  391.  
  392.     display.setCursor(200, 8*4);
  393.     if (editinterval) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  394.     display.print(timetosleep);
  395.     display.println(" mins");
  396.     display.setCursor(200, 8*5);
  397.     if (editcalib) {display.setTextColor(GxEPD_WHITE, GxEPD_BLACK);} else {display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);}
  398.     display.print(calibTarget);
  399.     display.println(" ppm");
  400.    
  401.     display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
  402.     display.setCursor(200, 8*6);
  403.     if (calibrated) {display.println("Calibrated!");}
  404.     display.setCursor(200, 8*7);
  405.     if (facreset) {display.println("Reset!");}
  406.     display.setCursor(200, 8*8);
  407.     if (wifireset) {display.println("Reset!");}
  408.   display.setCursor(0, 106);
  409.   display.print("CO2: ");
  410.   display.print(co2);
  411.   display.print("ppm | Temp: ");
  412.   display.print(t);
  413.   display.print("c | Hum: ");
  414.   display.print(h);
  415.   display.print("%");
  416.   display.setCursor(0, 114);
  417.   display.print("Pres: ");
  418.   display.print(pres);
  419.   display.print("hPa | vBat: ");
  420.   display.print(vBat);
  421.   display.print("v / ");
  422.   int batPct = mapf(vBat, 3.3, 4.15, 0, 100);
  423.   display.print(batPct);
  424.   display.print("% [10s]");
  425.    display.display(true);
  426. }
  427.  
  428.  
  429.  
  430. void wipeScreen(){
  431.  
  432.     display.setPartialWindow(0, 0, display.width(), display.height());
  433.  
  434.     display.firstPage();
  435.     do {
  436.       display.fillRect(0,0,display.width(),display.height(),GxEPD_BLACK);
  437.     } while (display.nextPage());
  438.     delay(10);
  439.     display.firstPage();
  440.     do {
  441.       display.fillRect(0,0,display.width(),display.height(),GxEPD_WHITE);
  442.     } while (display.nextPage());
  443.     display.firstPage();
  444.  
  445.  
  446.  
  447. }
  448.  
  449. void setupChart(){
  450.        
  451.         display.setCursor(0, 0);
  452.         display.print("<");
  453.         display.print(maxVal, 3);
  454.         display.setCursor(0, 114);
  455.         display.print("<");
  456.         display.print(minVal, 3);
  457.         display.setCursor(110, 114);
  458.         display.print("<--");
  459.         display.print(readingCount - 1, 0);
  460.         display.print("*");
  461.         display.print(timetosleep * 60, 0);
  462.         display.print("s-->");
  463.         vBat = analogReadMilliVolts(0) / 500.0;
  464.         barx = mapf (vBat, 3.3, 4.15, 0, 19);
  465.         display.drawRect(229,114,19,7,GxEPD_BLACK);
  466.         display.fillRect(229,114,barx,7,GxEPD_BLACK);
  467.         display.drawLine(248,115,248,119,GxEPD_BLACK);
  468.         display.drawLine(249,115,249,119,GxEPD_BLACK);
  469.         display.setCursor(125, 0);
  470. }
  471.  
  472. void setupChart2(){
  473.        
  474.         display.setCursor(0, 0);
  475.         display.print("<");
  476.         display.print(maxVal, 0);
  477.         display.setCursor(0, 114);
  478.         display.print("<");
  479.         display.print(minVal, 0);
  480.         display.setCursor(110, 114);
  481.         display.print("<--");
  482.         display.print(readingCount - 1, 0);
  483.         display.print("*");
  484.         display.print(timetosleep * 60, 0);
  485.         display.print("s-->");
  486.         vBat = analogReadMilliVolts(0) / 500.0;
  487.         barx = mapf (vBat, 3.3, 4.15, 0, 19);
  488.         display.drawRect(229,114,19,7,GxEPD_BLACK);
  489.         display.fillRect(229,114,barx,7,GxEPD_BLACK);
  490.         display.drawLine(248,115,248,119,GxEPD_BLACK);
  491.         display.drawLine(249,115,249,119,GxEPD_BLACK);
  492.         display.setCursor(125, 0);
  493. }
  494.  
  495. double mapf(float x, float in_min, float in_max, float out_min, float out_max){
  496.   return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  497. }
  498.  
  499. void doTempChart() {
  500.     // Recalculate min and max values
  501.      minVal = array1[maxArray - readingCount];
  502.      maxVal = array1[maxArray - readingCount];
  503.  
  504.     for (int i = maxArray - readingCount + 1; i < maxArray; i++) {
  505.         if (array1[i] != 0) {  // Only consider non-zero values
  506.             if (array1[i] < minVal) {
  507.                 minVal = array1[i];
  508.             }
  509.             if (array1[i] > maxVal) {
  510.                 maxVal = array1[i];
  511.             }
  512.         }
  513.     }
  514.  
  515.     // Calculate scaling factors
  516.     float yScale = 121.0 / (maxVal - minVal);
  517.     float xStep = 250.0 / (readingCount - 1);
  518.  
  519.     wipeScreen();
  520.    
  521.     do {
  522.         display.fillRect(0, 0, display.width(), display.height(), GxEPD_WHITE);
  523.        
  524.         for (int i = maxArray - readingCount; i < (maxArray - 1); i++) {
  525.             int x0 = (i - (maxArray - readingCount)) * xStep;
  526.             int y0 = 121 - ((array1[i] - minVal) * yScale);
  527.             int x1 = (i + 1 - (maxArray - readingCount)) * xStep;
  528.             int y1 = 121 - ((array1[i + 1] - minVal) * yScale);
  529.  
  530.             // Only draw a line for valid (non-zero) values
  531.             if (array1[i] != 0) {
  532.                 display.drawLine(x0, y0, x1, y1, GxEPD_BLACK);
  533.             }
  534.         }
  535.         setupChart();
  536.         display.print("[");
  537.         display.print("Temp: ");
  538.         display.print(array1[(maxArray - 1)], 3);
  539.         display.print("c");
  540.         display.print("]");
  541.     } while (display.nextPage());
  542.  
  543.     display.setFullWindow();
  544.     gotosleep();
  545. }
  546.  
  547. void doCO2Chart() {
  548.     // Recalculate min and max values
  549.      minVal = array2[maxArray - readingCount];
  550.      maxVal = array2[maxArray - readingCount];
  551.  
  552.     for (int i = maxArray - readingCount + 1; i < maxArray; i++) {
  553.         if ((array2[i] < minVal) && (array2[i] > 0)) {
  554.             minVal = array2[i];
  555.         }
  556.         if (array2[i] > maxVal) {
  557.             maxVal = array2[i];
  558.         }
  559.     }
  560.  
  561.     // Calculate scaling factors
  562.     float yScale = 121.0 / (maxVal - minVal);
  563.     float xStep = 250.0 / (readingCount - 1);
  564.  
  565.     wipeScreen();
  566.    
  567.    
  568.     do {
  569.         display.fillRect(0,0,display.width(),display.height(),GxEPD_WHITE);
  570.        
  571.         for (int i = maxArray - readingCount; i < (maxArray - 1); i++) {
  572.             int x0 = (i - (maxArray - readingCount)) * xStep;
  573.             int y0 = 121 - ((array2[i] - minVal) * yScale);
  574.             int x1 = (i + 1 - (maxArray - readingCount)) * xStep;
  575.             int y1 = 121 - ((array2[i + 1] - minVal) * yScale);
  576.             if (array2[i] > 0) {
  577.                 display.drawLine(x0, y0, x1, y1, GxEPD_BLACK);
  578.             }
  579.         }
  580.         setupChart2();
  581.         display.print("[");
  582.         display.print("CO2: ");
  583.         display.print(array2[(maxArray - 1)], 0);
  584.         display.print("ppm");
  585.         display.print("]");
  586.     } while (display.nextPage());
  587.  
  588.     display.setFullWindow();
  589.     gotosleep();
  590. }
  591.  
  592. void doMainDisplay() {        
  593.   wipeScreen();
  594.   updateMain();
  595.   gotosleep();
  596. }
  597.  
  598. void doPresDisplay() {
  599.     // Recalculate min and max values
  600.      minVal = array3[maxArray - readingCount];
  601.      maxVal = array3[maxArray - readingCount];
  602.  
  603.     for (int i = maxArray - readingCount + 1; i < maxArray; i++) {
  604.         if ((array3[i] < minVal) && (array3[i] > 0)) {
  605.             minVal = array3[i];
  606.         }
  607.         if (array3[i] > maxVal) {
  608.             maxVal = array3[i];
  609.         }
  610.     }
  611.  
  612.     // Calculate scaling factors
  613.     float yScale = 121.0 / (maxVal - minVal);
  614.     float xStep = 250.0 / (readingCount - 1);
  615.  
  616.     wipeScreen();
  617.    
  618.    
  619.     do {
  620.         display.fillRect(0,0,display.width(),display.height(),GxEPD_WHITE);
  621.        
  622.         for (int i = maxArray - readingCount; i < (maxArray - 1); i++) {
  623.             int x0 = (i - (maxArray - readingCount)) * xStep;
  624.             int y0 = 121 - ((array3[i] - minVal) * yScale);
  625.             int x1 = (i + 1 - (maxArray - readingCount)) * xStep;
  626.             int y1 = 121 - ((array3[i + 1] - minVal) * yScale);
  627.             if (array3[i] > 0) {
  628.                 display.drawLine(x0, y0, x1, y1, GxEPD_BLACK);
  629.             }
  630.         }
  631.         setupChart();
  632.         display.print("[");
  633.         display.print("Pres: ");
  634.         display.print(array3[(maxArray - 1)], 2);
  635.         display.print("mb");
  636.         display.print("]");
  637.     } while (display.nextPage());
  638.  
  639.     display.setFullWindow();
  640.     gotosleep();
  641. }
  642.  
  643. void doBatChart() {
  644.     // Recalculate min and max values
  645.      minVal = array4[maxArray - readingCount];
  646.      maxVal = array4[maxArray - readingCount];
  647.  
  648.     for (int i = maxArray - readingCount + 1; i < maxArray; i++) {
  649.         if ((array4[i] < minVal) && (array4[i] > 0)) {
  650.             minVal = array4[i];
  651.         }
  652.         if (array4[i] > maxVal) {
  653.             maxVal = array4[i];
  654.         }
  655.     }
  656.  
  657.     // Calculate scaling factors
  658.     float yScale = 121.0 / (maxVal - minVal);
  659.     float xStep = 250.0 / (readingCount - 1);
  660.  
  661.     wipeScreen();
  662.    
  663.    
  664.     do {
  665.         display.fillRect(0,0,display.width(),display.height(),GxEPD_WHITE);
  666.  
  667.        
  668.         for (int i = maxArray - readingCount; i < (maxArray - 1); i++) {
  669.             int x0 = (i - (maxArray - readingCount)) * xStep;
  670.             int y0 = 121 - ((array4[i] - minVal) * yScale);
  671.             int x1 = (i + 1 - (maxArray - readingCount)) * xStep;
  672.             int y1 = 121 - ((array4[i + 1] - minVal) * yScale);
  673.             if (array4[i] > 0) {
  674.                 display.drawLine(x0, y0, x1, y1, GxEPD_BLACK);
  675.             }
  676.         }
  677.         display.setCursor(0, 0);
  678.         display.print("<");
  679.         display.print(maxVal, 3);
  680.         display.setCursor(0, 114);
  681.         display.print("<");
  682.         display.print(minVal, 3);
  683.         display.setCursor(120, 114);
  684.         display.print("<#");
  685.         display.print(readingCount - 1, 0);
  686.         display.print("*");
  687.         display.print(timetosleep * 60, 0);
  688.         display.print("s>");
  689.         display.setCursor(175, 114);
  690.         vBat = analogReadMilliVolts(0) / 500.0;
  691.         int batPct = mapf(vBat, 3.3, 4.15, 0, 100);
  692.         display.setCursor(125, 0);
  693.         display.print("[vBat: ");
  694.         display.print(vBat, 3);
  695.         display.print("v/");
  696.         display.print(batPct, 1);
  697.         display.print("%]");
  698.     } while (display.nextPage());
  699.  
  700.     display.setFullWindow();
  701.     gotosleep();
  702. }
  703.  
  704.  
  705. void takeSamples(){
  706.         for (int i = 0; i < (maxArray - 1); i++) {
  707.             array3[i] = array3[i + 1];
  708.         }
  709.         array3[(maxArray - 1)] = pres;
  710.  
  711.         if (readingCount < maxArray) {
  712.             readingCount++;
  713.         }
  714.  
  715.         for (int i = 0; i < (maxArray - 1); i++) {
  716.             array1[i] = array1[i + 1];
  717.         }
  718.         array1[(maxArray - 1)] = t;
  719.  
  720.         for (int i = 0; i < (maxArray - 1); i++) {
  721.             array2[i] = array2[i + 1];
  722.         }
  723.         array2[(maxArray - 1)] = co2;
  724.  
  725.         for (int i = 0; i < (maxArray - 1); i++) {
  726.             array4[i] = array4[i + 1];
  727.         }
  728.         array4[(maxArray - 1)] = vBat;
  729. }
  730.  
  731. void updateMain(){
  732.  
  733.  
  734.     display.setPartialWindow(0, 0, display.width(), display.height());
  735.     display.fillScreen(GxEPD_WHITE);
  736.         float co2todraw = array2[(maxArray - 1)];
  737.         float temptodraw = array1[(maxArray - 1)];
  738.        
  739.         display.drawLine(122, 0, 122, 122, GxEPD_BLACK);
  740.         display.drawLine(123, 0, 123, 122, GxEPD_BLACK);
  741.         display.drawLine(0, 60, 250, 60, GxEPD_BLACK);
  742.         display.drawLine(0, 61, 250, 61, GxEPD_BLACK);
  743.  
  744.         display.setTextSize(2);
  745.         display.setCursor(32,2);
  746.         display.print("CO2:");
  747.         display.setCursor(158,2);
  748.         display.print("Temp:");
  749.         display.setCursor(8,64);
  750.         display.print("Humidity:");
  751.         display.setCursor(136,64);
  752.         display.print("Pressure:");
  753.  
  754.         display.setTextSize(3);
  755.         display.setCursor(5,26);
  756.         if ((co2todraw > 0) && (co2todraw < 1000)) {display.print(" ");}
  757.         display.print(co2todraw, 0);
  758.         display.setTextSize(2);
  759.         display.print("ppm");
  760.  
  761.  
  762.        
  763.         display.setTextSize(3);
  764.         display.setCursor(148,26);
  765.  
  766.         display.print(temptodraw, 1);
  767.         display.setTextSize(2);
  768.         display.print("c");
  769.  
  770.  
  771.         display.setTextSize(3);
  772.         display.setCursor(20,87);
  773.         display.print(h, 1);
  774.         display.setTextSize(2);
  775.         display.print("%");
  776.         display.setTextSize(1);
  777.         display.setCursor(0, 114-2);
  778.        
  779.         if (WiFi.status() == WL_CONNECTED) {display.print(timeString); display.print(", ");}
  780.         display.print(timetosleep);
  781.         display.print("mins");
  782.  
  783.         display.setTextSize(3);
  784.  
  785.         display.setCursor(148,87);
  786.         display.print(pres, 0);
  787.         display.setTextSize(2);
  788.         display.print("hPa");
  789.         display.setTextSize(3);
  790.         barx = mapf (vBat, 3.3, 4.15, 0, 19);
  791.         if (barx > 19) {barx = 19;}
  792.         display.drawRect(229,114-2,19,7,GxEPD_BLACK);
  793.         display.fillRect(229,114-2,barx,7,GxEPD_BLACK);
  794.         display.drawLine(248,115-2,248,119-2,GxEPD_BLACK);
  795.         display.drawLine(249,115-2,249,119-2,GxEPD_BLACK);
  796.  
  797.         display.display(true);
  798. }
  799.  
  800. void setup(){
  801.  
  802.         barx = mapf (vBat, 3.3, 4.15, 0, 19);
  803.         if (barx > 19) {barx = 19;}
  804.   GPIO_reason = log(esp_sleep_get_gpio_wakeup_status())/log(2);
  805.   preferences.begin("my-app", false);
  806.   timetosleep = preferences.getUInt("timetosleep", 5);
  807.   preferences.end();
  808.   Wire.begin();  
  809.   scd4x.begin(Wire);
  810.   scd4x.wakeUp();
  811.   scd4x.stopPeriodicMeasurement();
  812.   uint16_t error;
  813.   //scd4x.performFactoryReset();
  814.   float toff;
  815.   if (scd4x.getTemperatureOffset(toff) != (4 - TEMP_OFFSET))
  816.     {scd4x.setTemperatureOffset(4 - TEMP_OFFSET);}
  817.   scd4x.startPeriodicMeasurement();
  818.   aht.begin();
  819.   bmp.begin();
  820.   bmp.setSampling(Adafruit_BMP280::MODE_FORCED,     /* Operating Mode. */
  821.                   Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
  822.                   Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
  823.                   Adafruit_BMP280::FILTER_X16,      /* Filtering. */
  824.                   Adafruit_BMP280::STANDBY_MS_500);
  825.   bmp.takeForcedMeasurement();
  826.  
  827.   aht.getEvent(&humidity, &temp);
  828.    t = temp.temperature;
  829.    h = humidity.relative_humidity;
  830.     pres = bmp.readPressure() / 100.0;
  831.    uint16_t pres1 = pres;
  832.    scd4x.setAmbientPressure(pres1);
  833.    
  834.     abshum = (6.112 * pow(2.71828, ((17.67 * temp.temperature)/(temp.temperature + 243.5))) * humidity.relative_humidity * 2.1674)/(273.15 + temp.temperature);
  835.  
  836.   configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  837.   delay(50);
  838.   pinMode(controlpin, OUTPUT);
  839.   digitalWrite(controlpin, HIGH);
  840.   display.init(115200, false, 10, false); // void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 10, bool pulldown_rst_mode = false)
  841.   display.setRotation(3);
  842.   display.setTextSize(1);
  843.   pinMode(0, INPUT_PULLUP );
  844.   pinMode(1, INPUT_PULLUP );
  845.   pinMode(2, INPUT_PULLUP );
  846.   //pinMode(3, INPUT_PULLUP );
  847.   //pinMode(4, INPUT_PULLUP );
  848.   pinMode(5, INPUT_PULLUP );
  849.  
  850.  
  851.  
  852.    
  853.   delay(10);
  854.  
  855.  
  856.  
  857.            
  858.   if (firstrun >= 100) {display.clearScreen();
  859.    if (page == 2){
  860.         wipeScreen();
  861.  
  862.    }
  863.   firstrun = 0;}
  864.   firstrun++;
  865.  
  866.   display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
  867.  
  868.  
  869.  
  870.   vBat = analogReadMilliVolts(0) / 500.0;
  871.   if (GPIO_reason < 0) {
  872.     startWifi();
  873.     takeSamples();
  874.       switch (page){
  875.         case 0:
  876.           doTempChart();
  877.           break;
  878.         case 1: //down
  879.           doTempChart();  
  880.           break;
  881.         case 2: //towards
  882.           doMainDisplay();
  883.           break;
  884.         case 3:  //away
  885.           doCO2Chart();
  886.           break;
  887.         case 4: //up
  888.           doBatChart();
  889.           break;
  890.       }
  891.     }
  892.   switch (GPIO_reason) {
  893.     case 1:
  894.       page = 1;
  895.       doTempChart();
  896.       break;
  897.     case 2:
  898.       page = 2;
  899.         wipeScreen();
  900.         doMainDisplay();
  901.       break;
  902.     case 3:
  903.       page = 3;
  904.       doCO2Chart();
  905.       break;
  906.     case 0:
  907.       page = 4;
  908.       doBatChart();
  909.       break;
  910.     case 5:
  911.     delay(50);
  912.       while (!digitalRead(5))
  913.         {
  914.           delay(10);
  915.           if (millis() > 2000) {
  916.             startWebserver();
  917.           return;}
  918.         }
  919.       wipeScreen();
  920.       display.setPartialWindow(0, 0, display.width(), display.height());
  921.       startWifi();
  922.       takeSamples();
  923.       display.clearScreen();
  924.       switch (page){
  925.         case 0:
  926.           doTempChart();
  927.           break;
  928.         case 1:
  929.           doTempChart();
  930.           break;
  931.         case 2:
  932.           doMainDisplay();
  933.           break;
  934.         case 3:
  935.           doCO2Chart();
  936.           break;
  937.         case 4:
  938.           doBatChart();
  939.           break;
  940.       }
  941.   }
  942.  
  943.  
  944.  
  945. }
  946.  
  947. void loop()
  948. {
  949.   if (WiFi.status() == WL_CONNECTED) {
  950.     ArduinoOTA.handle();
  951.     server2.handleClient();
  952.     ElegantOTA.loop();
  953.   }
  954.   if (Blynk.connected()) {Blynk.run();}
  955.  
  956.  
  957.   if (!digitalRead(5)) {
  958.       switch (menusel) {
  959.         case 1:
  960.           {
  961.                 display.setPartialWindow(0, 0, display.width(), display.height());
  962.                 wipeScreen();
  963.                 display.setCursor(0, 0);                                  //
  964.                 display.println("Use your mobile phone to connect to ");
  965.                 display.println("[CO2 WiFi Setup] then browse to");
  966.                 display.println("http://192.168.4.1 to connect to WiFi");
  967.                 display.display(true);
  968.                 failcount = 0;
  969.                 WiFi.mode(WIFI_STA);
  970.                 wm.setConfigPortalTimeout(300);
  971.                 if (wm.getWiFiIsSaved()) {
  972.                 wm.startConfigPortal("CO2 WiFi Setup");
  973.                 }
  974.                 else {wm.autoConnect("CO2 WiFi Setup");}
  975.                 displayMenu();
  976.                 break;
  977.           }
  978.         case 2:
  979.             editinterval = !editinterval;
  980.             preferences.begin("my-app", false);
  981.             preferences.putUInt("timetosleep", timetosleep);
  982.             preferences.end();
  983.             displayMenu();
  984.             break;
  985.         case 3:
  986.             editcalib = !editcalib;
  987.             displayMenu();
  988.             break;
  989.         case 4:
  990.             scd4x.stopPeriodicMeasurement();
  991.             uint16_t error;
  992.             scd4x.performForcedRecalibration(calibTarget, error);
  993.             scd4x.startPeriodicMeasurement();
  994.             calibrated = true;
  995.             displayMenu();
  996.             break;
  997.         case 5:    
  998.             scd4x.stopPeriodicMeasurement();
  999.             scd4x.performFactoryReset();
  1000.             scd4x.startPeriodicMeasurement();
  1001.             facreset = true;
  1002.             break;  
  1003.         case 6:    
  1004.             wm.resetSettings();
  1005.             wifireset = true;
  1006.             break;  
  1007.         case 7:
  1008.             ESP.restart();
  1009.             break;
  1010.       }
  1011.     }
  1012.   every (100){
  1013.  
  1014.     if (!digitalRead(1)) {
  1015.       calibrated = false;
  1016.       facreset = false;
  1017.       wifireset = false;
  1018.       if (editinterval) {timetosleep--;} else if (editcalib) {calibTarget -= 5;} else {menusel++;}
  1019.       if (menusel > MENU_MAX) {menusel = 1;}
  1020.       if (menusel < 1) {menusel = MENU_MAX;}
  1021.       if (timetosleep < 1) {timetosleep = 1;}
  1022.       if (timetosleep > 999) {timetosleep = 999;}
  1023.       displayMenu();
  1024.     }
  1025.     if (!digitalRead(0)) {
  1026.       calibrated = false;
  1027.       facreset = false;
  1028.       wifireset = false;
  1029.       if (editinterval) {timetosleep++;} else if (editcalib) {calibTarget += 5;} else {menusel--;}
  1030.       if (menusel > MENU_MAX) {menusel = 1;}
  1031.       if (menusel < 1) {menusel = MENU_MAX;}
  1032.       if (timetosleep < 1) {timetosleep = 1;}
  1033.       if (timetosleep > 999) {timetosleep = 999;}
  1034.       displayMenu();
  1035.     }
  1036.  
  1037.   }
  1038.  
  1039.   every (10000) {
  1040.     pinMode(0, INPUT);
  1041.     vBat = analogReadMilliVolts(0) / 500.0;
  1042.     pinMode(0, INPUT_PULLUP);
  1043.     bmp.takeForcedMeasurement();
  1044.     aht.getEvent(&humidity, &temp);
  1045.     t = temp.temperature;
  1046.     h = humidity.relative_humidity;
  1047.     pres = bmp.readPressure() / 100.0;
  1048.     abshum = (6.112 * pow(2.71828, ((17.67 * temp.temperature)/(temp.temperature + 243.5))) * humidity.relative_humidity * 2.1674)/(273.15 + temp.temperature);
  1049.     bool isDataReady = false;
  1050.     scd4x.getDataReadyFlag(isDataReady);
  1051.     if (isDataReady) {
  1052.     scd4x.readMeasurement(co2, temp2, hum);}
  1053.     if (Blynk.connected()) {
  1054.               Blynk.virtualWrite(V91, t);
  1055.               Blynk.virtualWrite(V92, h);
  1056.               Blynk.virtualWrite(V93, pres);
  1057.               Blynk.virtualWrite(V94, abshum);
  1058.               Blynk.virtualWrite(V95, vBat);
  1059.               Blynk.virtualWrite(V96, co2);
  1060.               Blynk.virtualWrite(V97, temp2);
  1061.     }
  1062.     displayMenu();
  1063.   }
  1064.  
  1065.   if (millis() > 30*60*1000) {ESP.restart();} //30 minute timeout
  1066. }
  1067.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement