S8 CO2 reading of -1

Hey @Indymx , any success with the new board layout ?
Do you mind sharing it?

I have really weird issues on my 2nd Board CO2 sensor and I’m checking what I can improve as I want to build 3 more.

Sometimes one really does escalate

yeah, I have had 2 of them in use for 3 weeks with no issues. I very firmly believe that the issues being seen with these sensors is not a power issue at all, but a noise issue. I have run the sensor down as far as 3.73 volts with no issues at the CO2 sensor, on my revised board.

My board has almost all traces on the front. I think there are a couple very short traces on the back, but they are in a position that they don’t hurt the signal paths.

You can download the gerber files from github. I had JLCPCB make mine, I think it was about 6 bucks for 5 boards.

1 Like

Does it make sense to add a capacitor to cover the temporary power drain of the co2 sensor when measuring? it seems to have overall a pretty low power consumption and then spiking to up to 1A or probably more. I changed my usb power supply for the affected airgradient and the issue seem to be gone.

But question is, is it possible to use a cap, so you are less reliant on an “high power” usb supply ?
So you can stick with older 1A than 1.2A or 1.5A just for the spikes?

Experienced the same issue with the latest Pro kit.

We tested this recently but did not find any difference with/without cap.

I have created my own version of the PCB and added the cap. I still think its super helpful because now its easily running on an 1A power supply without issues. Not related to the -1 issue tho.

Yes, that’a a good point. I will keep that in mind for a future update of the board.

We most likely found the reason for the “-1” issue. It seems to be related to the software serial.

There is a D1 mini with an ESP32. The ESP32 has several hardware serial ports and we used the same code as for the normal D1 mini (ESP8266) and just changed from software serial to hardware serial. Everything unchanged (same PCB, sensors etc) and the “-1” completely disappeared.

The next step is that we will make our Arduino library ESP32 compatible and then we might switch from the ESP8266 to an ESP32.

So does this means that this “-1” issue can’t be resolved with a D1 mini ESP8266 ?

It happens very infrequent. In our test maybe only a few times per day. There is probably a way to suppress it with the software. Long term solution would be to switch to esp32 which probably has a few other advantages.

I’m having this problem with the diy pro as well. However the co2 sensor oscillates between ~65k and -1! Before this I was getting readings but they seemed likely high still above 1k ppm co2 levels.

Are there any fixes currently?

Side question, if I pull the plug does the co2 calibration reset, or will it pick up where it left off?

Check your soldering points, sometimes it’s caused by this. >1k CO2 indoors is quite typical if you do not have a window open or fresh air through your HVAC.

The S8 will not pick up your previous readings but will do an automatic baseline calibration every 7 days.

Thanks for the quick reply, I got the pre-soldered version, how should I go about checking the soldering points? Thanks so much, for your help.

The pre-soldered version we check and test before shipment and are soldered by professionals. How long did it work? Did you do anything specific before it stopped, e.g. added a component or changes the software?

I flashed with the code below. It had been working for a couple days, I just restarted it and it is working again, I modified this file from the airgradient examples included with the package:


#include <AirGradient.h>
// #include <WiFiManager.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>

#include "SGP30.h"
#include <U8g2lib.h>

AirGradient ag = AirGradient();
SGP30 SGP;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()

const int oledInterval = 5000;
unsigned long previousOled = 0;

const int sendToServerInterval = 10000;
unsigned long previoussendToServer = 0;

const int tvocInterval = 1000; // number of millisecs between TVOC measurements
unsigned long previousTVOC = 0;   // will store last time the TVOC was updated
int TVOC = 0;

const int co2Interval = 5000;
unsigned long previousCo2 = 0;
int Co2 = 0;

const int pm25Interval = 5000;
unsigned long previousPm25 = 0;
int pm25 = 0;

const int tempHumInterval = 2500;
unsigned long previousTempHum = 0;
float temp = 0;
int hum = 0;

String ln1 = "ln1";
String ln2 = "ln1";

String APIROOT = "<ip-address>:8009/metrics";

// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection
const char* ssid = "<ssid>";
const char* password = "<password>";


void setup()
{
  Serial.begin(115200);

  u8g2.begin();
  ln2 = String(ESP.getChipId(), HEX);
  updateOLED();

  Serial.println(SGP.begin());
  SGP.GenericReset();

  ag.CO2_Init();
  ag.PMS_Init();
  ag.TMP_RH_Init(0x44);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

}


void loop()
{
  currentMillis = millis(); 
  updateTVOC();
  updateOLED();
  updateCo2();
  updatePm25();
  updateTempHum();
  sendToServer();
}

void updateTVOC()
{
    if (currentMillis - previousTVOC >= tvocInterval) {
      previousTVOC += tvocInterval;
      SGP.measure(true);
      TVOC = SGP.getTVOC();
      Serial.println(String(TVOC));
    }
}

void updateCo2()
{
    if (currentMillis - previousCo2 >= co2Interval) {
      previousCo2 += co2Interval;
      Co2 = ag.getCO2_Raw();      
      Serial.println(String(Co2));
    }
}

void updatePm25()
{
    if (currentMillis - previousPm25 >= pm25Interval) {
      previousPm25 += pm25Interval;
      pm25 = ag.getPM2_Raw();      
      Serial.println(String(pm25));
    }
}

void updateTempHum()
{
    if (currentMillis - previousTempHum >= tempHumInterval) {
      previousTempHum += tempHumInterval;
      TMP_RH result = ag.periodicFetchData();
      temp = result.t;     
      hum = result.rh; 
      Serial.println(String(temp));
    }
}

void updateOLED() {
   if (currentMillis - previousOled >= oledInterval) {
     previousOled += oledInterval;
     String ln1 = "CO2:" + String(Co2) + " PM:" + String(pm25);
     String ln2 = "T:" + String(temp) + " H:" + String(hum);
     String ln3 = "TVOC:" + String(TVOC) ;
      char buf[9];
        u8g2.firstPage();
          u8g2.firstPage();
          do {
          u8g2.setFont(u8g2_font_t0_16_tf);
          u8g2.drawStr(1, 10, String(ln1).c_str());
          u8g2.drawStr(1, 30, String(ln2).c_str());
          u8g2.drawStr(1, 50, String(ln3).c_str());
            } while ( u8g2.nextPage() );
   }
}

void sendToServer() {
   if (currentMillis - previoussendToServer >= sendToServerInterval) {
     previoussendToServer += sendToServerInterval;
      String payload = "{\"wifi\":" + String(WiFi.RSSI()) 
      + ", \"rco2\":" + String(Co2) 
      + ", \"pm02\":" + String(pm25)
      + ", \"tvoc\":" + String(TVOC)
      + ", \"atmp\":" + String(temp)
      + ", \"rhum\":" + String(hum)
      + "}";
      
      if(WiFi.status()== WL_CONNECTED){
        // String(ESP.getChipId(), HEX) airgradient id
        Serial.println(payload);
        String POSTURL = APIROOT;
        Serial.println(POSTURL);
        WiFiClient client;
        HTTPClient http;
        http.begin(client, POSTURL);
        http.addHeader("content-type", "application/json");
        int httpCode = http.POST(payload);
        String response = http.getString();
        Serial.println(httpCode);
        Serial.println(response);
        http.end();
      }
      else {
        Serial.println("WiFi Disconnected");
      }
   }
}

// Wifi Manager
// void connectToWifi() {
//   WiFiManager wifiManager;
//   //WiFi.disconnect(); //to delete previous saved hotspot
//   String HOTSPOT = "AIRGRADIENT-" + String(ESP.getChipId(), HEX);
//   wifiManager.setTimeout(120);
//   if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
//     Serial.println("failed to connect and hit timeout");
//     delay(3000);
//     ESP.restart();
//     delay(5000);
//   }

// }



UPDATE:
It happened again.
It had been running fine on a slight derivative of the above flashed code for 3 weeks continuously, then all the sudden this (see picture) occurred.

image

Notice the spike, then after that it swings between 1500 and 700, with some -1’s (not visible, due to windowed averaging) thrown in.

Anyone have any suggestions on how to permanently resolve this or at least troubleshoot it?

@Achim_AirGradient ?

Thanks so much for your help and time!

Did it recover by itself or did you reboot the MCU?

We did extensive testings in-house on this issue and it appears most likely a problem that we use software serial with the S8. When switching to hardware serial, the issue completely disappeared in our test environment.

The ESP8266 has only one hardware serial that we would like to use for debugging and thus we currently working on making our code compatible with ESP32 versions of the D1 that has several hardware serials.

I let it run for about 12hrs. No recovery, after a hard reboot it resolved.

This is a lil over my head. What I think I’m understanding is that there isn’t a fix currently because the hardware serial is left open for debugging?