BME280 Temp Sensor Predictable Error in Reading!?

Well, this is indeed strange…

I have a sensor that is working flawlessly until it gets above 25 degrees C and then it seems to die and start reporting readings of -144.21C.

This was happening Daily and it was thought to be a fragmentation issue from my overly enthusiastic use of Strings. I’ve cleared the use of strings and moved to char arrays (thank you immensely @ScruffR ) but the problem is still persistent…

I have 3 BME280 sensors, all 3 of them are giving the exact same issue, so I am confident it is not the sensor.

It seems to happen irrespective of what voltage the battery is at (or whether there is sunlight charging the battery at the time).

All other sensors seem to keep running whilst this happens, it is just the BME280 temp/humidity/pressure sensor. During these spikes the relative humidity will flick to 100% (as it’s relative to temperature) and the pressure readings will skyrocket…

One random tidbit is that 25 C is quite close to 300 Kelvin. Not sure if this is a convenient coincidence or not though? The sensor is supposed to read to +80C, so i cant see it being a limitation of the sensor. I am also using the same library on another device and it has been reading temps above 30C for months without an issue. For this reason, I am still concerned it’s a library or i2c conflict…

Screenshots and code below.

main .ino

//////////////////////////////
// LIBRARIES
//////////////////////////////
#include "Adafruit_PM25AQI.h"
#include "Adafruit_BME280.h"
#include "application.h"
#include "Arduino.h" // doesnt seem to make a difference with/without...
#include "Particle.h"

//////////////////////////////
// MARKERS
//////////////////////////////
Adafruit_PM25AQI aqi;
Adafruit_BME280 bme;

//////////////////////////////
// CONSTANTS
//////////////////////////////
const int timeStep = 60000;                               // time step 60sec. (DO NOT USE LESS THAN 60s Battery and EEPROM issues will result!!!)
const float VREF = 3.3;                                   // Voltage on sound sensor.
int deviceName_checkValue = 12345;                        // int to check EEPROM deviceName values
int storage_checkValue = 54321;                           // int to check EEPROM storage values
const int pin_AQI = 2;                                    // Pin to power on/off (HI/LOW) AQI sensor.
const int pin_soundSensor = A0;                           // Pin to read sound sensor
const short int hourlyReading_count = 3600000 / timeStep; // e.g. 3600000/60000 = 60 readings

//////////////////////////////
// EEPROM CALL
//////////////////////////////
const int deviceName_addr = 0; 
const int storage_addr = 50;   

//////////////////////////////
// VARIABLES
//////////////////////////////
int lastLoop = millis() - timeStep;
short int hourlyReading_index = 0; // Array index number for storing (and periodically pushing periodic readings)
float lastTemp = 1;
float lastHumi = 1;
int lastPressure = 1;
char msg[128]; // declare it once, use it multiple times

struct
{
  int storage_check;                              // integer to check if stored values exist
  float pm2_5dailyReadings[24];                   // 4 bytes per float + 1 byte per array step
  float pm2_5hourlyReadings[hourlyReading_count]; // 4 bytes per float + 1 byte per array step
  float pm10dailyReadings[24];                    // 4 bytes per float + 1 byte per array step
  float pm10hourlyReadings[hourlyReading_count];  // 4 bytes per float + 1 byte per array step
  short int dailyReadings_index;                  // index for the 24hr hourly readings should a restart be required
  float soundSensorhourlyReadings[hourlyReading_count];
} storage;

struct
{
  int deviceName_check; // 5 digit integer to check if stored values exist
  char name[24];        // name of device handed down from Particle.subscribe
} deviceName;


//////////////////////////////
// INFLUXDB KEY INFO
//////////////////////////////
char *IDB_Name = "test_db";                // InfluxDB database name which information will be saved
char *IDB_deviceTagValue = deviceName.name; // Will be updated on first device check routine
char *IDB_locationTagValue = "home";  // sitebox location

void setup()
{
  Serial.begin(115200);
  EEPROM.get(deviceName_addr, deviceName);
  EEPROM.get(storage_addr, storage);
  delay(1000);

  //////////////////////////////
  // Check Daily Reading Index
  //////////////////////////////
  if (storage.dailyReadings_index < 0 || storage.dailyReadings_index >= 24 || !storage.storage_check == storage_checkValue)
  {
    snprintf(msg, sizeof(msg), "EEPROM Storage Check fail. Index = %d, chackVal = %d", storage.dailyReadings_index, storage.storage_check);
    Particle.publish("EEPROM Check", msg, PRIVATE);

    storage.dailyReadings_index = 0;
    storage.storage_check = storage_checkValue;

    for (int i = 0; i < 24; i++)
    {
      storage.pm2_5dailyReadings[i] = 0;
      storage.pm10dailyReadings[i] = 0;
    }

    for (int i = 1; i < hourlyReading_count; i++)
    {
      storage.pm10hourlyReadings[i] = 0;
      storage.pm2_5hourlyReadings[i] = 0;
      storage.soundSensorhourlyReadings[i] = 0;
    }

    EEPROM.put(storage_addr, storage);
    snprintf(msg, sizeof(msg), "daily index reset to: %d", storage.dailyReadings_index);
    Particle.publish("EEPROM Update", msg, PRIVATE);
  }

  //////////////////////////////
  // Setup BME280 - Temp-Humi Sensor
  //////////////////////////////
  bme.begin();
  if (!bme.init())
  {
    Particle.publish("BME280 Status", "init FAILED", PRIVATE);
  }
  else
  {
    Particle.publish("BME280 Status", "init complete", PRIVATE);
  }

  //////////////////////////////
  // Setup Sound Sensor
  //////////////////////////////
  pinMode(pin_soundSensor, INPUT);

  //////////////////////////////
  // Setup Air Quality Meter
  //////////////////////////////
  if (!aqi.begin())
  {
    while (1)
      delay(10);
  }
  pinMode(pin_AQI, OUTPUT); // AQI pin for turning Air Quality Meter on/off
  digitalWrite(pin_AQI, 0); // Set the AQI to off.
}

void loop()
{
  if (millis() > lastLoop + timeStep)
  {
    lastLoop = millis();

    //////////////////////////////
    // ENVIRONMENTAL READINGS
    //////////////////////////////

    delay(500);
    float tempVal = bme.readTemperature();
    int pressureVal = bme.readPressure();
    float humiVal = bme.readHumidity();
    float absoluteHumiVal = getAbsoluteHumidity(tempVal, humiVal);

    //////////////////////////////
    // Read Noise Levels
    //////////////////////////////
    float soundSensor_Reading = analogRead(pin_soundSensor);
    float soundSensor_voltage = (soundSensor_Reading / 4095) * VREF;          // note: particle Boron/Argon analogread values go from 0-4095
    float soundSensor_dBA = soundSensor_voltage * 50.0;                       // Convert voltage to decibel
    storage.soundSensorhourlyReadings[hourlyReading_index] = soundSensor_dBA; // add latest soundSensor reading to array for averaging
    float soundSensor_Hourly_avg = avgOf(storage.soundSensorhourlyReadings, hourlyReading_count);

    //////////////////////////////
    // Air Quality Readings
    //////////////////////////////
    PM25_AQI_Data data;

    // Fire up sensor and wait 10sec for first reading.
    digitalWrite(pin_AQI, 1); // Set AQI to HI.
    delay(10000);             // Wait 10sec to take a reading from cold start.

    // Read Data from AQI
    if (!aqi.read(&data))
    {
      Serial.println("Could not read from AQI");
      delay(500); // try again in a bit!
      return;
    }
    Serial.println("AQI reading success");

    // Hourly and Daily Readings
    int pm1Reading = data.pm10_env;
    int pm2_5Reading = data.pm25_env;
    int pm10Reading = data.pm100_env;

    storage.pm2_5hourlyReadings[hourlyReading_index] = pm2_5Reading;
    storage.pm10hourlyReadings[hourlyReading_index] = pm10Reading; // adds current reading to hourlyreadings

    float pm2_5hourly_avg = avgOf(storage.pm2_5hourlyReadings, hourlyReading_count);
    float pm10hourly_avg = avgOf(storage.pm10hourlyReadings, hourlyReading_count);

    storage.pm2_5dailyReadings[storage.dailyReadings_index] = pm2_5hourly_avg;
    storage.pm10dailyReadings[storage.dailyReadings_index] = pm10hourly_avg;

    float pm2_5daily_avg = avgOf(storage.pm2_5dailyReadings, 24);
    float pm10daily_avg = avgOf(storage.pm10dailyReadings, 24);

    digitalWrite(pin_AQI, 0); // Set AQI to LOW.

    //////////////////////////////
    // Battery Voltage
    //////////////////////////////
    float voltage = batteryVoltage();

    //////////////////////////////
    // Update Index Values
    //////////////////////////////
    if (hourlyReading_index < (hourlyReading_count - 1)) // -1 as array count starts at 0
    {
      hourlyReading_index++;
    }
    else
    {
      hourlyReading_index = 0;
      if (storage.dailyReadings_index < (24 - 1)) // -1 as array count starts at 0
      {
        storage.dailyReadings_index++;
      }
      else
      {
        storage.dailyReadings_index = 0;
      }
      EEPROM.put(storage_addr, storage);
    }

    //////////////////////////////
    // InfluxDB WebHooks PAYLOAD
    //////////////////////////////

    // ", \"%s\": \"%s\""
    // ", \"%s\": \"%d\""
    // ", \"%s\": \"%.2f\""
    // Make sure to check %s, %d, %f, (%.1f, %.2f to truncate decimals)

    const char IDB_template[] =
        "{ \"tags\" : {\"influx_db\": \"%s\""
        ", \"device\": \"%s\""
        ", \"location\": \"%s\""
        "}"
        ", \"values\": {"
        "\"%s\": %d"        // value1
        ", \"%s\": %d"      // value2
        ", \"%s\": %d"      // value3
        ", \"%s\": %0.2f"   // value4
        ", \"%s\": %0.2f"   // value5
        ", \"%s\": %0.2f"   // value6
        ", \"%s\": %0.2f"   // value7
        ", \"%s\": %0.2f"   // value8
        ", \"%s\": %0.2f"   // value9
        ", \"%s\": %0.2f"   // value10
        ", \"%s\": %d"      // value11
        ", \"%s\": %0.2f"   // value12
        ", \"%s\": %0.2f"   // value13
        ", \"%s%s\": %0.2f" // value14
        "}}";

    char IDB_data[512];
    snprintf(IDB_data, sizeof(IDB_data),
             IDB_template, // refers to format above

             /////// TAGS ///////
             IDB_Name,             // Influx DB name
             IDB_deviceTagValue,   // device name
             IDB_locationTagValue, // device location
             // Spare tags (unlimited, but also update IDB_template[])
             //  "tag1", tag1Val,
             //  "tag2", tag2Val,
             //  "tag3", tag3Val

             /////// VALUES ///////
             "PM1.0_env", pm1Reading,                // value1
             "PM2.5_env", pm2_5Reading,              // value2
             "PM10_env", pm10Reading,                // value3
             "PM2.5_hourly_avg", pm2_5hourly_avg,    // value4
             "PM10_hourly_avg", pm10hourly_avg,      // value5
             "PM2.5_24hr_avg", pm2_5daily_avg,       // value6
             "PM10_24hr_avg", pm10daily_avg,         // value7
             "outsideTemp", tempVal,                 // value8
             "outsideHumid_rel", humiVal,            // value9
             "outsideHumid_abs", absoluteHumiVal,    // value10
             "outsidePressure", pressureVal,         // value11
             "noise_dBA", soundSensor_dBA,           // value12
             "noise1hr_dBA", soundSensor_Hourly_avg, // value13
             deviceName.name, "Voltage", voltage);   // value14

    Particle.publish("Publish_to_IDB", IDB_data, PRIVATE);
  }
}

float batteryVoltage()
{
#if PLATFORM_ID == PLATFORM_BORON
  FuelGauge fuel;
  float voltage = fuel.getVCell();
  return voltage;
#endif
#if PLATFORM_ID == PLATFORM_ARGON
  float voltage = analogRead(BATT) * 0.0011224;
  return voltage;
#endif
}

float avgOf(float functionArray[], short int n)
{
  int i;
  float sum = 0;
  for (i = 0; i < n; i++)
  {
    sum += functionArray[i];
  }
  float avg = float(sum) / float(n);
  return avg;
}

uint32_t getAbsoluteHumidity(float temperature, float humidity)
{
  // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
  const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
  const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity);                                                                // [mg/m^3]
  return absoluteHumidityScaled;
}

Update, have switched to a different device (Argon rather than Boron) and getting the same issue (today temp got to 27.59C and then cut out, but drilling down on the individual points of data, it appears that the Humidity and Air Pressure readings actually go erratic before the Temperature drops…

have you tried the example from the library while using just 1 sensor? bme280test.ino

1 Like

Do you mean with the other sensors connected but not calling them? I’ll give it a run and see how it goes for a day. thanks!

No.

I meant to try a simple sketch with just the above sensor using the example program supplied by the library as a guide.

1 Like

Ah, Righto, will do that also (run a few in parallel to figure this out).

@robc, very good insight.

So, running two argons side by side (A2 and A3) with A3 being the one with the other sensors connected. A3 has already started getting haywire readings as the temps started to climb but A2 with the single device connected (but same library) is running fine…

Looks like the Humidity reading is the first to go nuts.

@irwige, the BME280 is great when it works but it seems to go haywire more than I care for. I ended up powering it via a GPIO pin (I have an Adafruit BME280 breakout) and when it doesn’t respond correctly, I cycle the power on it and start over. I found that removing the power was the ONLY way to get it to work again.

1 Like

Cheers for that. I only need a reading every minute, so I’ll power it from a digital pin and turn it off between readings and see if that fixes things.

I already do this for the noise and AQI sensor (because they suck more juice), but didnt think to do it with the BME because it’s so frugal on power.

Cheers!

Hmmmm. I have not used this sensor or library. I am thinking there are addressing issues for the I2C sensors in this particular library. With your single sensor experiment, you may have to force the address for a particular object. Try:

 bme.begin(0x76);    //  or bme.begin(0x77)  instead of   bme.begin();

found the above approach in document:
https://forum.arduino.cc/index.php?topic=400394.30

1 Like

If your communicating with the BME280 over I2C I can tell you that I and others are having issues with reliable communication with Gen3 Devices over I2C and Particle Engineering says they are looking into this.

We found if we put our chips into 400kHZ I2C mode that they start communicating reliably again for some reason. This issue is not present on the Photon series.

1 Like

Cheers, have already confirmed it’s 0x77, so will do this.

Thanks!

edit: I also have another i2c device (though different address) running, which is an Air Quality sensor. The noise sensor is analog, so unlikely to be causing the issue.

Thanks for the heads up!

1 Like

Might be worth trying to put the 400hz I2C mode.

I wonder if that solves your problems also.

1 Like

I had no idea this was even a possibility… will give it a shot.

edit: format appears to be:

// SYNTAX
Wire.setSpeed(CLOCK_SPEED_400KHZ);
Wire.begin();

I didn’t change the speed of the I2C Bus Speed on the Gen3 Device, but instead only enabled the 400hz mode on the actual chip I was communicating with.

So enable that on your sensor if you can and leave the Gen 3 device in the default I2C BUS speed.

1 Like

Ok, so for the sensor below

  //////////////////////////////
  // Setup BME280 - Temp-Humi Sensor
  //////////////////////////////
  bme.begin();

we would add a line to change the speed such as:

  //////////////////////////////
  // Setup BME280 - Temp-Humi Sensor
  //////////////////////////////
  bme.setSpeed(CLOCK_SPEED_400KHZ);
  bme.begin();

Thanks for your help!

1 Like

Yes, that should do the trick of getting the sensor into the quick 400hz i2c mode.

1 Like

So, it looks like the Adafruit_BME280 library isnt using the same instructions?

Assuming this is likely because it is calling Adafruit_sensor.h instead of relying on the Particle i2c?

image

try this

  //////////////////////////////
  // Setup BME280 - Temp-Humi Sensor
  //////////////////////////////
  Wire.setSpeed(CLOCK_SPEED_400KHZ);  // set the I2C clock speed to 400Khz
  bme.begin();

1 Like