Manually calibrating the S8 CO2 sensor

The Senseair S8 sensor has an automatic baseline calibration (ABC). This means that it looks for the lowest value of the CO2 in the last 7-14 days and resets itself to this value. So it assumes that the room that you have the sensor in gets outside CO2 values every week or so.

Sometimes, especially in newly build sensors, the CO2 value can be totally off. This will fix by itself by waiting for 1-2 weeks until the baseline calibration kicks in. However if you want to manually force a calibration you can do so as well by following these steps:

  1. Power on the DIY air quality sensor
  2. Make sure you have outside CO2 levels around the sensor. Best you do this calibration outside. Also make sure the sensor was surrounded by outside CO2 levels for at least 15 minutes.
  3. Use a jumper cable (male to male) and connect the bCAL_in pin of the Senseair S8 to the Ground (e.g. the GND pin on the Wemos)
  4. Connect them for more than 4 seconds but less than 8 seconds. It is very important that you exactly hit this range. So I recommend using a stopwatch and time 6 seconds.

By the way, if you hold the connection for more than 16 seconds it will calibrate to a Zero baseline. So make sure you not holding it too long.

Sometimes it takes a few tries until the calibration is successful.

4 Likes

Well I tried resetting my SenseAir and all I get now is a starting value which starts low around 300ish, then jumps up to 65342, which should not be the case. I tried resetting multiple times, and even tried to reset to 0 by connecting the 2 pins for over 16 seconds.
Pins are all soldered properly, and was previously getting values of around 1200 which I believe were normal.

Any suggestions?

It seems the S8 manual calibration needs quite a few tries sometimes. I would make sure you do not go longer than 8 seconds because otherwise you calibrate it to 0ppm but you want to calibrate to 400ppm which is the CO2 value outside.

My Senseair somehow managed to get miscalibrated - values when taken outside were hovering around 1400 and inside were in the 1700s. I didn’t have much luck with the manual calibration using the Ground pin, what did work is the manual calibration sketch example from the S8_UART library. (The RX and TX pin for the AirGradient are 2,0).

/******************************
   To do a manual calibration 
 ******************************/

#include <Arduino.h>
#include "s8_uart.h"   


/* BEGIN CONFIGURATION */
#define DEBUG_BAUDRATE 115200

#if (defined USE_SOFTWARE_SERIAL || defined ARDUINO_ARCH_RP2040)
  #define S8_RX_PIN 2        // Rx pin which the S8 Tx pin is attached to (change if it is needed)
  #define S8_TX_PIN 0         // Tx pin which the S8 Rx pin is attached to (change if it is needed)
#else
  #define S8_UART_PORT  1     // Change UART port if it is needed
#endif

#define COUNTDOWN (6*60)      // Time in seconds to wait outside before a manual calibration starts
/* END CONFIGURATION */


#ifdef USE_SOFTWARE_SERIAL
  SoftwareSerial S8_serial(S8_RX_PIN, S8_TX_PIN);
#else
  #if defined(ARDUINO_ARCH_RP2040)
    REDIRECT_STDOUT_TO(Serial)    // to use printf (Serial.printf not supported)
    UART S8_serial(S8_TX_PIN, S8_RX_PIN, NC, NC);
  #else
    HardwareSerial S8_serial(S8_UART_PORT);   
  #endif
#endif


S8_UART *sensor_S8;
S8_sensor sensor;


void setup() {

  // Configure serial port, we need it for debug
  Serial.begin(DEBUG_BAUDRATE);

  // Wait port is open or timeout
  int i = 0;
  while (!Serial && i < 50) {
    delay(10);
    i++;
  }
  
  // First message, we are alive
  Serial.println("");
  Serial.println("Init");

  // Initialize S8 sensor
  S8_serial.begin(S8_BAUDRATE);
  sensor_S8 = new S8_UART(S8_serial);

  // Check if S8 is available
  sensor_S8->get_firmware_version(sensor.firm_version);
  int len = strlen(sensor.firm_version);
  if (len == 0) {
      Serial.println("SenseAir S8 CO2 sensor not found!");
      while (1) { delay(1); };
  }

  // Show basic S8 sensor info
  Serial.println(">>> SenseAir S8 NDIR CO2 sensor <<<");
  printf("Firmware version: %s\n", sensor.firm_version);
  sensor.sensor_id = sensor_S8->get_sensor_ID();
  Serial.print("Sensor ID: 0x"); printIntToHex(sensor.sensor_id, 4); Serial.println("");

  // Countdown waiting outside
  Serial.println("Now, you put the sensor outside and wait.");
  Serial.println("Countdown begins...");
  unsigned int seconds = COUNTDOWN;
  while (seconds > 0) {
    printf("Time remaining: %d minutes %d seconds\n", seconds / 60, seconds % 60);
    delay(1000);
    seconds--;
  }
  Serial.println("Time reamining: 0 minutes 0 seconds");

  // Start manual calibration
  Serial.println("Starting manual calibration...");
  if (!sensor_S8->manual_calibration()) {
    Serial.println("Error setting manual calibration!");
    while (1) { delay(10); }
  }

  
}


void loop() {

  static unsigned int elapsed = 0;

  // Wait 2 sec lamp cycle
  delay(2000);   
  elapsed += 2;

  // Check if background calibration is finished
  sensor.ack = sensor_S8->get_acknowledgement();
  if (sensor.ack & S8_MASK_CO2_BACKGROUND_CALIBRATION) {
    printf("Manual calibration is finished. Elapsed: %u seconds\n", elapsed);
    while (1) { delay(10); }
  } else {
    Serial.println("Doing manual calibration...");
  }


}

I plugged the USB into a laptop and took the sensor outside, the serial showed a 6 minute countdown at the end of which the sensor calibrated.

3 Likes

could this be the reason why one of my SensAir S8 shows me 495ppm and another 385 ppm and they are placed next to each other? I finished the installation 2 days ago, so it hasn’t gone 2 week.

Yes, that is likely a calibration issue and overtime they should come to the same level with the Automatic Baseline Calibration.

My senseair s8 shows me 8 728 ppm outside. Autocalibration is not working, and calibration using GND is not working too…

Can you send some pictures of the S8 and the PCB with both sides. I would like to see the soldering points.
Also, did you try and keep it running for more than a week to see if the automatic baseline calibration kicks in?

Do the Co2 sensors keep their calibration when the device is rebooted or when the there is a power cut? I have a minimum of 130ppm in the last two weeks, so I assume my calibration is off.

Yes they keep it during reboot.

There is an example code in our Arduino library for manual calibration that you can use.

How long does it take to calibrate a Senseair s8?
if I calibrate using the arduino code in the library, do I have to use a cable jumper as in the instructions?

The calibration code in the Arduino library you don’t need a jumper cable. Just follow the instructions.

Baseline calibration is around 8 days.

Does it needs around 8 days too if i calibrate using code in the Arduino library?

No, the manual calibration is immediate. Just follow the instructions at the beginning of the code.

If I installed these sensors indoors with limited fresh air passing through, would I need to take them outside every week to calibrate? Or if I calibrated outside before installation, how long would the calibration last?

I want to monitor enclosed spaces for air quality

I’ve had the same question and not sure what the official answer is, but I just setup a second device and out of the box, it matched my original sensor near perfectly. After a day, it started reading very low, but this second sensor had never been outdoors, so I brought it outside and did a calibration which got it reading around 400. After 1 hour outside I brought it back in and set it next to my original sensor that has been inside for 6+ months and they both are back perfectly in sync. So it seems like it keeps calibration even if it stays inside which I was kind of surprised about. I’m using ESPHome.

In more then 95% of the indoor rooms we monitor we see ambient levels at least once a week. So the ABC in most cases is not an issue.

Hmmm. Unless I leave the house for 3+ days, I don’t get to ambient in my basement, at least according to the S8. Not sure if my house is too tight to allow for much air exchange.

We don’t monitor many basements so these might be more tough for fresh air…