EDIT: solved - see this post. TL;DR - the code in this post works and I'm an idiot.
Hi all,
I have an S8 CO2 sensor that I've used many times before successfully. However, trying to reuse the same code I used before gives me incorrect readings now. Not sure if this is an Arduino IDE issue (maybe board definitions, default libraries or something else changed?) or something wrong with the sensor I'm using. I've tried with two more S8 sensors, both yield the same results.
I'm using their example code on page 6 in this Application Note, and in this post, they say it's the same code for both sensors (K-30 and S8), and I've tested this before as well and it did work previously.
Essentially, you send a command over UART (using a software serial library) and get a response back. Here's the command and response from their communications application note:
in the example response above, the 4th byte (0x01) and 5th byte (0x90) combined gives 0x0190 = 400 ppm
but the response I'm getting is this:
![]()
The proper response format is there, just that the high and low bytes representing the actual value are quite off from what I'm expecting. This response was from the balcony, so was expecting to see something similar to the example response from their guide, i.e., close to fresh air ~400ppm.
I have even tried calibrating the sensor in fresh air and in zero co2 concentration air as well, and while calibration procedure works (the values change), it's still reading the incorrect value. Zero calibrating the sensor it is making it max out at 65535 in normal air, and calibrating it in fresh air is making it read as shown in the screenshot above. In indoor environment, it's reading around 70 ppm.
Again, I've used this code successfully before (maybe a year ago), and the only thing that's updated in this setup is the Arduino IDE - I was using 1.6.x last year, and now I'm using 1.8.9.
Maybe the CO2 sensor is a newer batch and expects different commands or returns different response? I'm powering the sensor via USB, so it's a little under 5V for power, wondering if that might be the issue. Datasheet says it can take 4.5 - 5.2V.
Here's my code for testing:
#include <SoftwareSerial.h>
SoftwareSerial K_30_Serial(7,8); // RX, TX
byte readCO2[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25}; //Command packet to read Co2 (see app note)
byte response[] = {0,0,0,0,0,0,0}; //create an array to store the response
void setup()
{
Serial.begin(115200);
K_30_Serial.begin(9600);
}
void loop()
{
float co2 = getCO2(readCO2);
Serial.print("CO2 concentration: ");
Serial.println(co2);Serial.println();
delay(2000);
}
float getCO2(byte packet[])
{
while(!K_30_Serial.available()) //keep sending request until we start to get a response
{
K_30_Serial.write(readCO2,7);
delay(10);
}
int timeout=0; //set a timeoute counter
while(K_30_Serial.available() < 7 ) //Wait to get a 7 byte response
{
timeout++;
if(timeout > 10) //if it takes to long there was probably an error
{
while(K_30_Serial.available()) //flush whatever we have
K_30_Serial.read();
break; //exit and try again
}
delay(50);
}
for (int i=0; i < 7; i++)
{
response[i] = K_30_Serial.read();
}
Serial.print("Response from sensor: ");
for (int i=0; i < 7; i++)
{
Serial.print(response[i], HEX);
Serial.print(" ");
}
Serial.println();
byte high = response[3]; //high byte for value is 4th byte in packet
byte low = response[4]; //low byte for value is 5th byte in packet
float val = (high*256) + low; //Combine high byte and low byte with this formula to get value
return val;
}
FYI, I did try using NeoSWSerial library as well. Worked well before, now works similarly to how I posted here - i.e., incorrect readings.
any help here is appreciated. Thanks.


