SCD30 and ESPhome negative temperature

Hello

I have the SCD30 on a Wemos D1 mini.
The temperature and humidity values were correct until I changed the temperature_offset value from 0°C to -2°C. As a result, the sensor gave negative temperature readings and infinite humidity %.

To check, I later changed the temperature_offset from -2°C to 0°C. However, the sensor continues to give negative temperature values.

Can someone help me further?

Below the log:

[19:03:09][C][scd30:121]: scd30:
[19:03:09][C][scd30:122]:   Address: 0x61
[19:03:09][C][scd30:140]:   Altitude compensation: OFF
[19:03:09][C][scd30:144]:   Automatic self calibration: ON
[19:03:09][C][scd30:145]:   Ambient pressure compensation: 0mBar
[19:03:09][C][scd30:146]:   Temperature offset: 0.00 °C
[19:03:09][C][scd30:147]:   Update interval: 10s
[19:03:09][C][scd30:148]:   CO2 'SCD30 CO2 44'
[19:03:09][C][scd30:148]:     State Class: 'measurement'
[19:03:09][C][scd30:148]:     Unit of Measurement: 'ppm'
[19:03:09][C][scd30:148]:     Accuracy Decimals: 1
[19:03:09][C][scd30:148]:     Icon: 'mdi:molecule-co2'
[19:03:09][C][scd30:149]:   Temperature 'SCD30 TEMP 44'
[19:03:09][C][scd30:149]:     Device Class: 'temperature'
[19:03:09][C][scd30:149]:     State Class: 'measurement'
[19:03:09][C][scd30:149]:     Unit of Measurement: '°C'
[19:03:09][C][scd30:149]:     Accuracy Decimals: 2
[19:03:09][C][scd30:150]:   Humidity 'SCD30 HUMIDITY 44'
[19:03:09][C][scd30:150]:     Device Class: 'humidity'
[19:03:09][C][scd30:150]:     State Class: 'measurement'
[19:03:09][C][scd30:150]:     Unit of Measurement: '%'
[19:03:09][C][scd30:150]:     Accuracy Decimals: 1
[19:03:09][C][captive_portal:151]: Captive Portal:
[19:03:09][C][ota:082]: Over-The-Air Updates:
[19:03:09][C][ota:083]:   Address: espd1mini3.local:8266
[19:03:09][C][ota:086]:   Using Password.
[19:03:09][C][api:134]: API Server:
[19:03:09][C][api:135]:   Address: espd1mini3.local:6053
[19:03:09][C][api:139]:   Using noise encryption: NO
[19:03:09][C][mdns:084]: mDNS:
[19:03:09][C][mdns:085]:   Hostname: espd1mini3
[19:03:18][D][scd30:187]: Got CO2=974.57ppm temperature=-48.60°C humidity=14907.10%
[19:03:18][D][sensor:113]: 'SCD30 CO2 44': Sending state 974.56750 ppm with 1 decimals of accuracy
[19:03:18][D][sensor:113]: 'SCD30 TEMP 44': Sending state -48.59838 °C with 2 decimals of accuracy
[19:03:18][D][sensor:113]: 'SCD30 HUMIDITY 44': Sending state 14907.09961 % with 1 decimals of accuracy
[19:03:30][D][scd30:187]: Got CO2=975.50ppm temperature=-47.88°C humidity=13683.24%
[19:03:30][D][sensor:113]: 'SCD30 CO2 44': Sending state 975.49506 ppm with 1 decimals of accuracy
[19:03:30][D][sensor:113]: 'SCD30 TEMP 44': Sending state -47.87605 °C with 2 decimals of accuracy
[19:03:30][D][sensor:113]: 'SCD30 HUMIDITY 44': Sending state 13683.24121 % with 1 decimals of accuracy
[19:03:41][D][scd30:187]: Got CO2=973.89ppm temperature=-47.12°C humidity=12593.79%
[19:03:41][D][sensor:113]: 'SCD30 CO2 44': Sending state 973.89496 ppm with 1 decimals of accuracy
[19:03:41][D][sensor:113]: 'SCD30 TEMP 44': Sending state -47.11678 °C with 2 decimals of accuracy
[19:03:41][D][sensor:113]: 'SCD30 HUMIDITY 44': Sending state 12593.78809 % with 1 decimals of accuracy

Hello - I had this problem. As far as I can tell, it’s a bug. Here’s what I do:

    temperature:
      name: "Bedroom Temperature"
      accuracy_decimals: 1
      filters:
        - offset: 1.5

BTW, I also observed 2 identical SCD30’s producing wildly different values. Turned out their calibration settings, temperature offsets, and altitudes were different. I modified an Adafruit example script to fire them both up, sit for 5 minutes (outside), force calibrate the CO2 sensor to 400ppm, then turn off autocalibrate.

// Firmware to force calibrate an SCD30 to 400 ppm
// Place outdoors. Power up. After 5 minutes, the onboard LED illumates to
// signal calibration compelete.

#include <Adafruit_SCD30.h>
#include <Arduino.h>
#include <SimpleTimer.h>

Adafruit_SCD30 scd30;
SimpleTimer timer_5min(5 * 60 * 1000);  // 5 minute
bool calibrated = false;

void setup(void) {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);  // Off

  Serial.begin(115200);
  while (!Serial)
    delay(10);  // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit SCD30 Sensor adjustment test!");

  // Try to initialize!
  if (!scd30.begin()) {
    Serial.println("Failed to find SCD30 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("SCD30 Found!");

  /***
   * The code below will report the current settings for each of the
   * settings that can be changed. To see how they work, uncomment the setting
   * code above a status message and adjust the value
   *
   * **Note:** Since Automatic self calibration and forcing recalibration with
   * a reference value overwrite each other, you should only set one or the
   *other
   ***/

  /*** Adjust the rate at which measurements are taken, from 2-1800 seconds */
  // if (!scd30.setMeasurementInterval(5)) {
  //   Serial.println("Failed to set measurement interval");
  //   while(1){ delay(10);}
  // }
  Serial.print("Measurement interval: ");
  Serial.print(scd30.getMeasurementInterval());
  Serial.println(" seconds");

  /*** Restart continuous measurement with a pressure offset from 700 to 1400
   * millibar. Giving no argument or setting the offset to 0 will disable offset
   * correction
   */
  // if (!scd30.startContinuousMeasurement(0)){
  //   Serial.println("Failed to set ambient pressure offset");
  //   while(1){ delay(10);}
  // }
  Serial.print("Ambient pressure offset: ");
  Serial.print(scd30.getAmbientPressureOffset());
  Serial.println(" mBar");

  /*** Set an altitude offset in meters above sea level.
   * Offset value stored in non-volatile memory of SCD30.
   * Setting an altitude offset will override any pressure offset.
   */
  // if (!scd30.setAltitudeOffset(110)){
  //   Serial.println("Failed to set altitude offset");
  //   while(1){ delay(10);}
  // }
  Serial.print("Altitude offset: ");
  Serial.print(scd30.getAltitudeOffset());
  Serial.println(" meters");

  /*** Set a temperature offset in hundredths of a degree celcius.
   * Offset value stored in non-volatile memory of SCD30.
   */
  if (!scd30.setTemperatureOffset(0)) {  // 19.84 degrees celcius
    Serial.println("Failed to set temperature offset");
    while (1) {
      delay(10);
    }
  }
  Serial.print("Temperature offset: ");
  Serial.print((float)scd30.getTemperatureOffset() / 100.0);
  Serial.println(" degrees C");

  /*** Force the sensor to recalibrate with the given reference value
   * from 400-2000 ppm. Writing a recalibration reference will overwrite
   * any previous self calibration values.
   * Reference value stored in non-volatile memory of SCD30.
   */
  // if (!scd30.forceRecalibrationWithReference(400)){
  //   Serial.println("Failed to force recalibration with reference");
  //   while(1) { delay(10); }
  // }
  Serial.print("Forced Recalibration reference: ");
  Serial.print(scd30.getForcedCalibrationReference());
  Serial.println(" ppm");

  /*** Enable or disable automatic self calibration (ASC).
   * Parameter stored in non-volatile memory of SCD30.
   * Enabling self calibration will override any previously set
   * forced calibration value.
   * ASC needs continuous operation with at least 1 hour
   * 400ppm CO2 concentration daily.
   */
  // if (!scd30.selfCalibrationEnabled(true)){
  //   Serial.println("Failed to enable or disable self calibration");
  //   while(1) { delay(10); }
  // }
  if (scd30.selfCalibrationEnabled()) {
    Serial.print("Self calibration enabled");
  } else {
    Serial.print("Self calibration disabled");
  }

  Serial.println("\n\n");
}

uint32_t start_millis = millis();

void loop() {
  if (scd30.dataReady()) {
    if (!scd30.read()) {
      Serial.println("Error reading sensor data");
      return;
    }

    Serial.print("Temperature: ");
    Serial.print(scd30.temperature);
    Serial.println(" degrees C");

    Serial.print("Relative Humidity: ");
    Serial.print(scd30.relative_humidity);
    Serial.println(" %");

    Serial.print("CO2: ");
    Serial.print(scd30.CO2, 3);
    Serial.println(" ppm");
    Serial.println("");
  }

  delay(100);

  if (timer_5min.isReady() && !calibrated) {
    if (!scd30.forceRecalibrationWithReference(400)) {
      Serial.println("Failed to force recalibration with reference");
      while (1) {
        delay(10);
      }
    } else {
      if (!scd30.selfCalibrationEnabled(false)) {
        Serial.println("Failed to enable or disable self calibration");
        while (1) {
          delay(10);
        }
      }
      digitalWrite(LED_BUILTIN, LOW);  // On
      Serial.println();
      Serial.println("Forced recalibration with reference 400ppm");
      Serial.println("Self calibration disabled");
      Serial.println();
      calibrated = true;
    }
  }
}

Temperate and humidity were within 1 or 2%, but CO2’s were different by ~10%. So I add this, and add in some averaging:

    co2:
      name: "Bedroom CO2"
      accuracy_decimals: 0
      filters:
        - offset: -50.0
        - exponential_moving_average:
            send_every: 5
2 Likes

Has anyone found a fix to this?

I am having this exact same problem. Problem is I can’t get the bug to go away same as OP. My humidity value quickly converges to infinity.

[22:59:31][D][sensor:125]: 'SCD30 CO2': Sending state 713.61096 ppm with 1 decimals of accuracy
[22:59:31][D][sensor:125]: 'SCD30 Temperature': Sending state -439.50809 °C with 1 decimals of accuracy
[22:59:31][D][sensor:125]: 'SCD30 Humidity': Sending state 0.00000 % with 1 decimals of accuracy

I have set all the values back to normal and even flashed the esp8266 with a new config and still the same thing.

Did you raise an issue?

It would be good to get the calibration code you have found, included into ESPHome :slight_smile:

Same here. I had it working correctly with esp easy before but it started reporting negative temperature when flashed with esphome.

The offset helps but doesn’t seem to work as a simple value offset, maybe it’s actually a factor?

I cannot thank you enough for this Arduino IDE calibration script! Worked like a charm. I calibrated 2 sensors that both had widely different CO2 readings from one other. Same situation as you that got me concerned about accuracy to begin with.

I am not sure if it matters but I added:

automatic_self_calibration: false

To my ESPhome config just in case it reverts back since I think it defaults to true.

Getting the LOLIN/Wemos D1 mini libraries and the Adafruit SDC30 libraries into Arduino IDE was easy enough and the script runs great. I was afraid the calibration wasn’t going to be persistent after reboot but indeed it is.

If only ESPhome could add this as a feature that didn’t require all the extra work with Arduino IDE it would be awesome, none the less it’s much appreciated again.

1 Like

I’ve just run into this. Reverting the offset setting, recalibrating the SCD30 or unpowering the ESP32 did not help. Seems like this bug is still present. Any hints what I could try to recover a working state?

Did anyone find a reliable fix for this? I just encountered the same problem.

Edit: Did what I should have in the first place and went to the ESPHome bugtracker. This is a known issue it seems, but hasn’t been fixed: Setting SCD30 temperature offset causes the sensor to report bogus values · Issue #3063 · esphome/issues · GitHub