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;
}