From d20b954b9f5ab3172aa20cedf392a1b8e4191da9 Mon Sep 17 00:00:00 2001
From: DeltaLima <marcus@deltalima.org>
Date: Tue, 18 Mar 2025 00:32:36 +0100
Subject: [PATCH] add CCS811 CO2 sensor, untested

---
 Arduino/CanGrow/cangrow.sh                    | 47 +++++++--------
 Arduino/CanGrow/include/CanGrow_Sensor.h      | 38 +++++++++++-
 Arduino/CanGrow/include/Sensor/10_CCS811.h    | 58 +++++++++++++++++++
 .../CanGrow/include/Sensor/Sensor_Common.h    | 19 +++++-
 4 files changed, 135 insertions(+), 27 deletions(-)
 create mode 100644 Arduino/CanGrow/include/Sensor/10_CCS811.h

diff --git a/Arduino/CanGrow/cangrow.sh b/Arduino/CanGrow/cangrow.sh
index 5b96311..eda39dc 100755
--- a/Arduino/CanGrow/cangrow.sh
+++ b/Arduino/CanGrow/cangrow.sh
@@ -9,9 +9,9 @@ test -z $BOARD && BOARD="esp8266:esp8266:d1_mini_clone"
 
 BUILD="$(git rev-parse --short HEAD)-$(echo $BOARD | cut -d : -f1)_$(echo $BOARD | cut -d : -f3)-$(date '+%Y%m%d%H%M%S')"
 
-
+# arduino-cli path and version
 ACLI="$HOME/.local/bin/arduino-cli"
-ACLI_VER="1.1.1"
+ACLI_VER="1.2.0"
 ACLI_CMD="$ACLI --config-file arduino-cli.yml"
 test -z $BUILDDIR && BUILDDIR="build"
 
@@ -41,29 +41,30 @@ case $1 in
 		ACLI_DIR="$(dirname $ACLI)"
     ALIB_DIR="${HOME}/Arduino/libraries/"
 		declare -a CORES=(
-					"esp8266:esp8266@3.1.2"
-					"esp32:esp32@3.0.7"
+      "esp8266:esp8266@3.1.2"
+      "esp32:esp32@3.0.7"
 				)
 		declare -a LIBS=(
-					"Adafruit SSD1306@2.5.12"
-					"Adafruit BME280 Library@2.2.4"
-					"ArduinoJson@7.3.0"
-					"NTPClient@3.2.1"
-					"Time@1.6.1"
-					"ESP Async WebServer@3.6.0"
-					"Async TCP@3.3.2"
-          "Nusabot Simple Timer@1.0.0"
-          "ArduinoLog@1.1.1"
-          "RTClib@2.1.4"
-          "Adafruit BME680 Library@2.0.5"
-          "Adafruit ADS1X15@2.5.0"
-          "Adafruit SHT31 Library@2.2.2"
-          "Adafruit MCP4725@2.0.2"
-          "Adafruit TCS34725@1.4.4"
-          "Adafruit MLX90614 Library@2.1.5"
-          "I2CSoilMoistureSensor@1.1.4"
-          "DFRobot_GP8XXX@1.0.1"
-				)
+      "Adafruit SSD1306@2.5.12"
+      "Adafruit BME280 Library@2.2.4"
+      "ArduinoJson@7.3.0"
+      "NTPClient@3.2.1"
+      "Time@1.6.1"
+      "ESP Async WebServer@3.6.0"
+      "Async TCP@3.3.2"
+      "Nusabot Simple Timer@1.0.0"
+      "ArduinoLog@1.1.1"
+      "RTClib@2.1.4"
+      "Adafruit BME680 Library@2.0.5"
+      "Adafruit ADS1X15@2.5.0"
+      "Adafruit SHT31 Library@2.2.2"
+      "Adafruit MCP4725@2.0.2"
+      "Adafruit TCS34725@1.4.4"
+      "Adafruit MLX90614 Library@2.1.5"
+      "I2CSoilMoistureSensor@1.1.4"
+      "DFRobot_GP8XXX@1.0.1"
+      "Adafruit CCS811 Library@1.1.3"
+    )
     
 		echo ":: Setting up build environment for CanGrow Firmware."
 		echo "   This will download the binary for arduino-cli and install"
diff --git a/Arduino/CanGrow/include/CanGrow_Sensor.h b/Arduino/CanGrow/include/CanGrow_Sensor.h
index 8601995..55dc7eb 100644
--- a/Arduino/CanGrow/include/CanGrow_Sensor.h
+++ b/Arduino/CanGrow/include/CanGrow_Sensor.h
@@ -78,6 +78,7 @@
 #include "Sensor/07_ADS1115.h"
 #include "Sensor/08_ADS1015.h"
 #include "Sensor/09_Chirp.h"
+#include "Sensor/10_CCS811.h"
 
 /*
  * Sensor Todo list:
@@ -250,11 +251,24 @@ Sensor_Index SensorIndex[] {
       // SENSOR_READ_TYPE_RAW
     },
     sizeof(Sensor_09_Chirp_Addr),
+  },
+  
+  {
+  /* 10 - CCS811 CO2 I2C sensor */
+    SENSOR_10_NAME,
+    SENSOR_TYPE_I2C,
+    {
+      /* CO2 as parts per million */
+      SENSOR_READ_TYPE_PARTS_PER_MILLION,
+      /* TVOC value (Total Volatile Organic Compouds)*/
+      SENSOR_READ_TYPE_TVOC,
+    },
+    sizeof(Sensor_10_CCS811_Addr),
   }
 };
 
 /* sum up of number of sensors. Dont forget to increment if you add one :) */
-const byte SensorIndex_length = 9;
+const byte SensorIndex_length = 10;
 
 byte Sensor_Addr_Init_Update(const byte SensorIndexId, const byte AddrId, const byte mode, const byte Gpio2 = 0) {
   const static char LogLoc[] PROGMEM = "[Sensor:Addr_Init_Update]";
@@ -440,6 +454,23 @@ byte Sensor_Addr_Init_Update(const byte SensorIndexId, const byte AddrId, const
         break;
       }
     break;
+    
+    /* Sensor 10 */
+    case 10:
+      switch(mode) {
+        case 0:
+          return Sensor_10_CCS811_Addr[AddrId];
+        break;
+        
+        case 1:
+          return Sensor_10_CCS811_Init(AddrId);
+        break;
+        
+        case 2:
+          Sensor_10_CCS811_Update(AddrId);
+        break;
+      }
+    break;
         
     /* unknown sensor id */
     default:
@@ -515,6 +546,11 @@ float Sensor_getValue(const byte SensorIndexId, const byte AddrId, const byte Re
       return Sensor_09_Chirp[AddrId][ReadValId];
     break;
     
+    /* Sensor 10 */
+    case 10:
+      return Sensor_10_CCS811[AddrId][ReadValId];
+    break;
+    
     /* unknown sensor id */
     default:
       Log.error(F("%s SensorIndex ID %d not found" CR), LogLoc, SensorIndexId);
diff --git a/Arduino/CanGrow/include/Sensor/10_CCS811.h b/Arduino/CanGrow/include/Sensor/10_CCS811.h
new file mode 100644
index 0000000..11df5d9
--- /dev/null
+++ b/Arduino/CanGrow/include/Sensor/10_CCS811.h
@@ -0,0 +1,58 @@
+/*
+ * 
+ * include/Sensor/10_CCS811_.h - CCS811 CO2 I2C sensor 
+ * 
+ * 
+ *
+ */
+
+#include "Adafruit_CCS811.h"
+
+#define SENSOR_10_NAME "CCS811"
+
+const byte Sensor_10_CCS811_Addr[] = { 0x5a, 0x5b };
+
+Adafruit_CCS811 CCS811[sizeof(Sensor_10_CCS811_Addr)];
+
+/* Create main data array specifying max amount of readings */
+float Sensor_10_CCS811[sizeof(Sensor_10_CCS811_Addr)][4];
+
+void Sensor_10_CCS811_Update(const byte AddrId) {
+  const static char LogLoc[] PROGMEM = "[Sensor:10_CCS811:Update]";
+  if(CCS811[AddrId].available()){
+    if(!CCS811[AddrId].readData()){
+      /* keep the same order as in SensorIndex[].read[] !! */
+      /* CO2 in ppm */
+      Sensor_10_CCS811[AddrId][0] = CCS811[AddrId].geteCO2();
+      /* TVOC (Total Volatile Organic Compouds) */
+      Sensor_10_CCS811[AddrId][1] = CCS811[AddrId].getTVOC();
+    }
+    #ifndef DEBUG
+    else {
+      Log.error(F("%s 0x%x ERROR getting new data" CR), LogLoc, Sensor_10_CCS811_Addr[AddrId]);
+    }
+    #endif
+  }
+
+  
+}
+
+bool Sensor_10_CCS811_Init(const byte AddrId) {
+  /* Sensor Init function
+   * 
+   * returns true (1) when Init was successful
+   * returns false (0) if not.
+   */  
+  const static char LogLoc[] PROGMEM = "[Sensor:10_CCS811:Init]";
+  bool returnCode;
+  
+  if(CCS811[AddrId].begin(Sensor_10_CCS811_Addr[AddrId])) {
+    Log.notice(F("%s found at addr 0x%x" CR), LogLoc, Sensor_10_CCS811_Addr[AddrId]);
+    Sensor_10_CCS811_Update(AddrId);
+    returnCode = true;
+  } else {
+    Log.error(F("%s FAILED! Not found at addr 0x%x" CR), LogLoc, Sensor_10_CCS811_Addr[AddrId]);
+    returnCode = false;
+  }
+  return returnCode;
+}
diff --git a/Arduino/CanGrow/include/Sensor/Sensor_Common.h b/Arduino/CanGrow/include/Sensor/Sensor_Common.h
index b59d3b5..7998335 100644
--- a/Arduino/CanGrow/include/Sensor/Sensor_Common.h
+++ b/Arduino/CanGrow/include/Sensor/Sensor_Common.h
@@ -25,7 +25,7 @@ const byte SENSOR_TYPE_TWOWIRE = 3;
 const byte SENSOR_TYPE_I2C_WITH_GPIO = 4;
 
 /* How many different read types exists */
-const byte SENSOR_READ_TYPE__TOTAL = 12;
+const byte SENSOR_READ_TYPE__TOTAL = 14;
 
 
 const byte SENSOR_READ_TYPE_RAW = 1;
@@ -76,6 +76,15 @@ const byte SENSOR_READ_TYPE_COLOR_BLUE = 12;
 const char SENSOR_READ_TYPE_COLOR_BLUE_descr[] PROGMEM = {"Color blue"};
 const char SENSOR_READ_TYPE_COLOR_BLUE_unit[] PROGMEM = {""};
 
+const byte SENSOR_READ_TYPE_PARTS_PER_MILLION = 13;
+const char SENSOR_READ_TYPE_PARTS_PER_MILLION_descr[] PROGMEM = {"Part per million"};
+const char SENSOR_READ_TYPE_PARTS_PER_MILLION_unit[] PROGMEM = {"ppm"};
+
+const byte SENSOR_READ_TYPE_TVOC = 14;
+const char SENSOR_READ_TYPE_TVOC_descr[] PROGMEM = {"TVOC"};
+const char SENSOR_READ_TYPE_TVOC_unit[] PROGMEM = {""};
+
+
 const char * Sensor_Read_descr[] = {
   NULL, // 0 is unset
   SENSOR_READ_TYPE_RAW_descr,
@@ -89,7 +98,9 @@ const char * Sensor_Read_descr[] = {
   SENSOR_READ_TYPE_LUX_descr,
   SENSOR_READ_TYPE_COLOR_RED_descr,
   SENSOR_READ_TYPE_COLOR_GREEN_descr,
-  SENSOR_READ_TYPE_COLOR_BLUE_descr
+  SENSOR_READ_TYPE_COLOR_BLUE_descr,
+  SENSOR_READ_TYPE_PARTS_PER_MILLION_descr,
+  SENSOR_READ_TYPE_TVOC_descr
 };
 
 const char * Sensor_Read_unit[] = {
@@ -105,7 +116,9 @@ const char * Sensor_Read_unit[] = {
   SENSOR_READ_TYPE_LUX_unit,
   SENSOR_READ_TYPE_COLOR_RED_unit,
   SENSOR_READ_TYPE_COLOR_GREEN_unit,
-  SENSOR_READ_TYPE_COLOR_BLUE_unit
+  SENSOR_READ_TYPE_COLOR_BLUE_unit,
+  SENSOR_READ_TYPE_PARTS_PER_MILLION_unit,
+  SENSOR_READ_TYPE_TVOC_unit
 };