HomeyDuino CO2 sensor

Cool! I also planned to go that way, bought a senseair s8 sensor, but never put it together. Have now three Netatmo healthy home coaches as CO2-sensors which is connected through Homey to control my roof fan.

But now I can just copy your code, hehe?

Hi Wilfred,

The device was constructed with:

The code was flashed to the ESP32 with the Arduino IDE. The libraries used are: TFT_eSPI and HomeyDuino. The TTGO communicates via UART/Serial2 to the Senseair sensor. If you’re handy with Arduino programming and soldering you can easily do it yourself. Most of the code I just borrowed from some samples and adapted it for my own purpose.

The total costs were about 50 Euro which is not much compared to what is available on the market. The sensor was most expensive but I wouldn’t recommand cheap Chinese rubbisch. They are not very accurate, brake easily or are not auto calibrating. Maybe there are some good ones but I haven’t seen any.

With Homey Insights every measurement is logged which can be seen in some nice graphics. When the CO2 values become too high the ventilation system is switched on automatically which prevents me from hallucinating (only when I am not on other stimulants of course) and other nasty things.

If you want I can send you the C++ code.

Hi Lars,

This is unfortunately a little too complex for me.


You don’t feel like experimenting with the VOC-sensor BME680. Seems to be the best VOC sensor, but the issue seems to convert the resistance value you get to ppm.https://www.bosch-sensortec.com/bst/products/all_products/bme680

With some help (thanks to maxxie01 on Slack) I did a Homeyduino CO2 sensor myself. Also a Senseair S8-sensor, connected to a wemos like described here https://www.letscontrolit.com/wiki/index.php/S8.

Here’s the Arduino code if anyone is interested. This is just the code for the board (wemos) and the sensor, no fancy display.

    Basic Arduino example for K-Series sensor
    Created by Jason Berger

    Adjusted to Homeyduino by maxxie01/rindlerblabla

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <SoftwareSerial.h>
#include <Homey.h>

SoftwareSerial S8_Serial(13,15);  //Sets up a virtual serial port
                                  //Using pin 13 for Tx and pin 15 for Rx
unsigned long prevReadTime = 0;
unsigned int ReadTimeInterval = 300000; //Update interval in ms
unsigned long valCO2 = 0;
byte readCO2[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25}; 
byte response[] = {0,0,0,0,0,0,0};  

int valMultiplier = 1;
void wifi() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin("SSID", "PASSWORD");
    uint8_t timeout = 30;
    while (WiFi.status() != WL_CONNECTED) {
      if (timeout<1) break;
    if (WiFi.status() == WL_CONNECTED) {
      //Print IP address
      Serial.print("Connected to WiFi! (");

void setup()
void loop()
  //to check not every loop use this interval method
  if(millis() - prevReadTime > ReadTimeInterval){
    prevReadTime = millis();
    unsigned long tmpValCO2 = getValue(response);
    if(tmpValCO2 != valCO2){
      valCO2 = tmpValCO2;
      Serial.print("CO2 ppm = ");
      Homey.setCapabilityValue("measure_co2", (int) valCO2 );

void sendRequest(byte packet[])
  while(!S8_Serial.available())  //keep sending request until we start to get a response

  int timeout=0;  //set a timeoute counter
  while(S8_Serial.available() < 7 ) //Wait to get a 7 byte response
    if(timeout > 10)    //if it takes to long there was probably an error
        while(S8_Serial.available())  //flush whatever we have

          break;                        //exit and try again

  for (int i=0; i < 7; i++)
    response[i] = S8_Serial.read();

unsigned long getValue(byte packet[])
    int high = packet[3];                        //high byte for value is 4th byte in packet in the packet
    int low = packet[4];                         //low byte for value is 5th byte in the packet

    unsigned long val = high*256 + low;                //Combine high byte and low byte with this formula to get value
    return val* valMultiplier;
1 Like

Just finished my second version. This time in a 3D printed enclosure and a Bosch BME680 (with official Bosch library). So now I can read CO2/Temp/Humidity/Pressure/VOC/IAQ. The BME680 can also act as a smoke detector. I tried it with setting a piece of paper on fire. The IAQ readings immediately went up to over 400 (range 0-500),

One can do the (WiFi) setup via a WiFi access point to fill in the parameters for WiFi/Homey and a MQTT client. Still need to calibrate the CO2 sensor by the way.



If you use the official Bosch library the IAQ index (based on VOC) is calculated for you.

Did you have to do all steps described here? Do you also got the ppb-value? https://github.com/BoschSensortec/BSEC-Arduino-library/blob/master/README.md#installation-and-getting-started

The VOC sensor also works just fine as a smell detector if you control your ventilation in the bathroom and so on.

If you want to use the Bosch library you indeed need to go through the steps as described. Including a library for the ESP32 is slightly different. To include it it was little bit tricky but it can be done. Once you edit the Arduino files for the ESP32 the library is added for all projects so keep the originals.
I just use the IAQ (indoor air quality) index, I don’t think there is PPB value. There is a VOC resistence value though.

Using it in the WC is one of the main functions of this sensor.

Wow, really nice, wel done!
Any estimates for how much it cost, including the 3D printed enclosure?

Thanks. I would charge € 100,00 which is a bargain compared to what’s on the market.

Okey, solved most of my questions. I just wonder if you can share the code snippet that triggers the smoke alarm out of the IAQ values?

Hi Rindler,


// BME680 setup
iaqSensor.begin(BME680_I2C_ADDR_SECONDARY, Wire);
output = "\nBSEC library version " + String(iaqSensor.version.major) + “.” + String(iaqSensor.version.minor) + “.” + String(iaqSensor.version.major_bugfix) + “.” + String(iaqSensor.version.minor_bugfix);
bsec_virtual_sensor_t sensorList[10] = {
iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
iaqSensor.setTemperatureOffset( tempOffset );


bme680loop(); // sensor values will automatically update only every 3 seconds, no matter how many times it is called

Serial.println( " Raw temp. " + String(iaqSensor.rawTemperature) );
Serial.println( " Raw press. " + String(iaqSensor.pressure) );
Serial.println( " Raw hum. " + String(iaqSensor.rawHumidity) );
Serial.println( " Gas resis. " + String(iaqSensor.gasResistance));
Serial.println( " IAQ " + String(iaqSensor.iaq));
Serial.println( " IAQ accuracy " + String(iaqSensor.iaqAccuracy));
Serial.println( " Comp. temp. " + String(iaqSensor.temperature));
Serial.println( " Comp. hum. " + String(iaqSensor.humidity));
Serial.println( " StaticIAQ " + String(iaqSensor.staticIaq));
Serial.println( " eCO2 " + String(iaqSensor.co2Equivalent));
Serial.println( " BreathVocEq. " + String(iaqSensor.breathVocEquivalent));

Thanks. And the code for the smoke alarm? :slight_smile:

if ( iaqVal >= 250 ) {
  Serial.println("High pollution detected!");
  alarm_smoke = true;
else {
  //Serial.println("No pollution detected");
  alarm_smoke = false;

Homey.setCapabilityValue(“alarm_smoke”, (bool) alarm_smoke );


Maybe I did something wrong, but the code above just spammed my Homey with several alerts every second that there were no fire, ha! For sure it depends on were you put the setCapabilityValue-code. Anyhow, the code below solved it for me.

   if ((iaqSensor.staticIaq >= 250) && (alarm_smoke == false)) {
      Serial.println("High pollution detected!");
      alarm_smoke = true;
      Homey.setCapabilityValue("alarm_smoke", (bool) alarm_smoke );
    else if ((iaqSensor.staticIaq <= 250) && (alarm_smoke == true)){
      Serial.println("No pollution detected");
      alarm_smoke = false;
      Homey.setCapabilityValue("alarm_smoke", (bool) alarm_smoke );

@Lars_Machiels, nice post and thanks for sharing !
Actually interested by this topic, I replied to a copy of your post by an usurper,
Funnily I was asking for more info, and every detail is available here in its original

It is so annoying, I’d like a moderator to check the issue, any idea on how to raise it to moderators ?
@Bram, here is the fraud below (raised it with the flag as spam)

Many thanks

Hi Lars,

Sorry to bump up this topic, but i could not find anything similar with the TTGO ESP32 print in combination with the Senseair S8. Do you still have the code ?