Particle Powered Air Quality Sensor Logging to Google Docs
-
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
Particle^2 Air Quality Sensor
The CO2 measurement seems to be based on AMS CCS811. What is your experience with this sensor?
I was comparing this sensor with Netatmo (+-50 ppm accuracy according to the website) and a MH-Z14A. Maybe you can tell me from my graph, if my sensor is broken and I should consider oredering another:

@FotoFieber btw which code are you using? Adafruit's library?
-
@alowhum said in Particle Powered Air Quality Sensor Logging to Google Docs:
Nice work.
Does it use the temperature and humidity values to optimise the fine dust calculation?
No it doesn't.
And by the way PM10 values are worthless, they are evaluated based on PM2.5 values. Meaning if you put the sensor in an environment with only 2.5-10 µm sized particles, it will say 0ug/m3.
Not saying the sensor is bad, it's good but only for pm2.5. I suspect it's just a remake of a PMS5003 with longer lasting laser and fan.@nca78 said in Particle Powered Air Quality Sensor Logging to Google Docs:
@alowhum said in Particle Powered Air Quality Sensor Logging to Google Docs:
Nice work.
Does it use the temperature and humidity values to optimise the fine dust calculation?
No it doesn't.
And by the way PM10 values are worthless, they are evaluated based on PM2.5 values. Meaning if you put the sensor in an environment with only 2.5-10 µm sized particles, it will say 0ug/m3.
Not saying the sensor is bad, it's good but only for pm2.5. I suspect it's just a remake of a PMS5003 with longer lasting laser and fan.I would have to agree with this observation thus far. The PM10 readings correlate 1:1 with the PM2.5. Good thing PM2.5 is what we really care about! For anyone who's curious, the sensor saturates at 1000µg/m3. Just had an interesting experience with that... 😬
-
@FotoFieber btw which code are you using? Adafruit's library?
@jaredwolff
I am using the adafruit library and compensating temp/hum with the measurements of a SI7021. The results are really bad and I have ordered another CCS811 for comparison.void readCCS811(JsonObject &root) { static bool bFirst = true; static Adafruit_CCS811 sensor; if (bFirst) { DEBUG_PRINTLN("Initializing CCS811"); if (!sensor.begin()) { DEBUG_PRINTLN("CCS811 Initialization failed."); } else { sensor.setDriveMode(CCS811_DRIVE_MODE_IDLE); delay(10000); sensor.setDriveMode(CCS811_DRIVE_MODE_60SEC); bFirst = false; } } if (sensor.available()) { // setEnvironmentalData(uint8_t humidity, double temperature); sensor.setEnvironmentalData(lasthum, lasttemp); if (!sensor.readData()) { uint16_t lastppm = sensor.geteCO2(); if (lastppm > 0) { JsonObject rootCCS811 = root.createNestedObject("ccs811"); rootCCS811["co2"] = lastppm; rootCCS811["tvoc"] = sensor.getTVOC(); } } else { DEBUG_PRINTLN("CCS811 ERROR!"); } } } -
@jaredwolff
I am using the adafruit library and compensating temp/hum with the measurements of a SI7021. The results are really bad and I have ordered another CCS811 for comparison.void readCCS811(JsonObject &root) { static bool bFirst = true; static Adafruit_CCS811 sensor; if (bFirst) { DEBUG_PRINTLN("Initializing CCS811"); if (!sensor.begin()) { DEBUG_PRINTLN("CCS811 Initialization failed."); } else { sensor.setDriveMode(CCS811_DRIVE_MODE_IDLE); delay(10000); sensor.setDriveMode(CCS811_DRIVE_MODE_60SEC); bFirst = false; } } if (sensor.available()) { // setEnvironmentalData(uint8_t humidity, double temperature); sensor.setEnvironmentalData(lasthum, lasttemp); if (!sensor.readData()) { uint16_t lastppm = sensor.geteCO2(); if (lastppm > 0) { JsonObject rootCCS811 = root.createNestedObject("ccs811"); rootCCS811["co2"] = lastppm; rootCCS811["tvoc"] = sensor.getTVOC(); } } else { DEBUG_PRINTLN("CCS811 ERROR!"); } } }@fotofieber you're not alone in this. I've actually stopped setting the environmental data.
I don't see as many random spikes as with. I've asked AMS about the frequency or when the data should be updated. I have a feeling it's supposed to be sparingly..
-
@jaredwolff
I am using the adafruit library and compensating temp/hum with the measurements of a SI7021. The results are really bad and I have ordered another CCS811 for comparison.void readCCS811(JsonObject &root) { static bool bFirst = true; static Adafruit_CCS811 sensor; if (bFirst) { DEBUG_PRINTLN("Initializing CCS811"); if (!sensor.begin()) { DEBUG_PRINTLN("CCS811 Initialization failed."); } else { sensor.setDriveMode(CCS811_DRIVE_MODE_IDLE); delay(10000); sensor.setDriveMode(CCS811_DRIVE_MODE_60SEC); bFirst = false; } } if (sensor.available()) { // setEnvironmentalData(uint8_t humidity, double temperature); sensor.setEnvironmentalData(lasthum, lasttemp); if (!sensor.readData()) { uint16_t lastppm = sensor.geteCO2(); if (lastppm > 0) { JsonObject rootCCS811 = root.createNestedObject("ccs811"); rootCCS811["co2"] = lastppm; rootCCS811["tvoc"] = sensor.getTVOC(); } } else { DEBUG_PRINTLN("CCS811 ERROR!"); } } }@fotofieber I've had some luck with removing the fraction portion of the temperature readings. It looks like the Adafruit code does use it. The suggested code from AMS does not use it.
I'm also tooling around with saving the baseline. They suggest every 24h. That should help bring your readings back up to where they were in the event of a reset.
-
@fotofieber I've had some luck with removing the fraction portion of the temperature readings. It looks like the Adafruit code does use it. The suggested code from AMS does not use it.
I'm also tooling around with saving the baseline. They suggest every 24h. That should help bring your readings back up to where they were in the event of a reset.
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
@fotofieber I've had some luck with removing the fraction portion of the temperature readings. It looks like the Adafruit code does use it. The suggested code from AMS does not use it.
Could you please share your code?
There is an application note about update frequency on https://ams.com/documents/20143/36005/CCS811_AN000369_2-00.pdf/fb08da36-5b40-732b-39b0-62d2d9db5a3c
It is recommended that the T+RH data is read from the ENS210 at the same frequency as the
CCS811 generates eCO2 and TVOC outputs. For example in mode 3, 60 second mode, the
application software should read the ENS210 data once every minute.The code in the application notes
i2c_buff[0] = ((RH % 1000) / 100) > 7 ? (RH/1000 + 1)<<1 : (RH/1000)<<1; i2c_buff[1] = 0; if(((RH % 1000) / 100) > 2 && (((RH % 1000) / 100) < 8)) { i2c_buff[0] |= 1; }looks quit different to the adafruit implementation:
uint8_t hum_perc = humidity << 1; // other code uint8_t buf[] = {hum_perc, 0x00, (uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)};In the same document the handling of baseline is described. I think the adafruit code may be incomplete... :)
I'll try the sparkfun lib, it hase baseline support and looks more like the programming note from aws.
-
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
@fotofieber I've had some luck with removing the fraction portion of the temperature readings. It looks like the Adafruit code does use it. The suggested code from AMS does not use it.
Could you please share your code?
There is an application note about update frequency on https://ams.com/documents/20143/36005/CCS811_AN000369_2-00.pdf/fb08da36-5b40-732b-39b0-62d2d9db5a3c
It is recommended that the T+RH data is read from the ENS210 at the same frequency as the
CCS811 generates eCO2 and TVOC outputs. For example in mode 3, 60 second mode, the
application software should read the ENS210 data once every minute.The code in the application notes
i2c_buff[0] = ((RH % 1000) / 100) > 7 ? (RH/1000 + 1)<<1 : (RH/1000)<<1; i2c_buff[1] = 0; if(((RH % 1000) / 100) > 2 && (((RH % 1000) / 100) < 8)) { i2c_buff[0] |= 1; }looks quit different to the adafruit implementation:
uint8_t hum_perc = humidity << 1; // other code uint8_t buf[] = {hum_perc, 0x00, (uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)};In the same document the handling of baseline is described. I think the adafruit code may be incomplete... :)
I'll try the sparkfun lib, it hase baseline support and looks more like the programming note from aws.
The CCS81 seems to be much more complicated to handle than the MH-Z14A. There is an MCU on the sensor and you can make firmware upgrades which should reduce the burn in time. After burn in, you shoul save the actual baseline from time to time (e.g. every 24 hours) and restore it, when you reboot.
My hacked code looks now much more complicated:
void readCCS811(JsonObject &root) { static int loopCount = 0; static bool bFirst = true; static CCS811 myCCS811(CCS811_ADDR); JsonObject rootCCS811; loopCount++; if (bFirst) { DEBUG_PRINTLN("Initializing CCS811"); CCS811Core::status returnCode = myCCS811.begin(); DEBUG_PRINT("CCS811 begin exited with: "); printDriverError(returnCode); DEBUG_PRINTLN(""); if (returnCode == CCS811Core::SENSOR_SUCCESS) bFirst = false; //This sets the mode to 60 second reads, and prints returned error status. returnCode = myCCS811.setDriveMode(3); DEBUG_PRINT("Mode request exited with: "); printDriverError(returnCode); DEBUG_PRINTLN(""); if ((EEPROM.read(0) == 0xA5) && (EEPROM.read(1) == 0xB2)) { DEBUG_PRINTLN("EEPROM contains saved data."); //The recovered baseline is packed into a 16 bit word unsigned int baselineToApply = ((unsigned int)EEPROM.read(2) << 8) | EEPROM.read(3); DEBUG_PRINT("Saved baseline: 0x"); if (baselineToApply < 0x100) DEBUG_PRINT("0"); if (baselineToApply < 0x10) DEBUG_PRINT("0"); DEBUG_PRINT(baselineToApply, HEX); //This programs the baseline into the sensor and monitors error states CCS811Core::status errorStatus = myCCS811.setBaseline(baselineToApply); if (errorStatus == CCS811Core::SENSOR_SUCCESS) { DEBUG_PRINTLN("Baseline written to CCS811."); } else { printDriverError(errorStatus); } } } if (myCCS811.dataAvailable()) { myCCS811.readAlgorithmResults(); myCCS811.setEnvironmentalData(lasthum, lasttemp); uint16_t lastppm = myCCS811.getCO2(); if (lastppm > 0) { // bis und mit 400 nur an der Initialisierung rootCCS811 = root.createNestedObject("ccs811"); rootCCS811["co2"] = lastppm; rootCCS811["tvoc"] = myCCS811.getTVOC(); } } // save Baseline every 24 hours if (loopCount >= 24 * 60) { // read baseline unsigned int baseline = myCCS811.getBaseline(); rootCCS811["baseline"] = baseline; DEBUG_PRINTLN("baseline for this sensor: 0x"); if (baseline < 0x100) DEBUG_PRINT("0"); if (baseline < 0x10) DEBUG_PRINT("0"); DEBUG_PRINTLN(baseline, HEX); //The baseline is saved (with valid data indicator bytes) EEPROM.write(0, 0xA5); EEPROM.write(1, 0xB2); EEPROM.write(2, (baseline >> 8) & 0x00FF); EEPROM.write(3, baseline & 0x00FF); EEPROM.commit(); loopCount = 0; } }The results in the first 24 hours don't seem better. Hope they will getting better after 48 hours. :(
I am not really keen on programming a firmware upgrade program for the CCS811. The second sensor I ordered from aliexpress is hopefully better.
-
I have no experience with the MH-Z14A but compared to other comparable parts I think the CCS811 is a bit more simple to implement. (And less costly, despite it's $$$ price)
Since my firmware improvements here (MSB for temp and humidity for saving the environmental data) seems to have helped tremendously. I have implemented the baseline save/restore but I haven't seen any crazy jumps or differences in operation. Maybe your MOX sensor is contaminated.
I'm playing with some other sensors to see how they compare. I'll share my results here too.
-
I have no experience with the MH-Z14A but compared to other comparable parts I think the CCS811 is a bit more simple to implement. (And less costly, despite it's $$$ price)
Since my firmware improvements here (MSB for temp and humidity for saving the environmental data) seems to have helped tremendously. I have implemented the baseline save/restore but I haven't seen any crazy jumps or differences in operation. Maybe your MOX sensor is contaminated.
I'm playing with some other sensors to see how they compare. I'll share my results here too.
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
I have no experience with the MH-Z14A but compared to other comparable parts I think the CCS811 is a bit more simple to implement. (And less costly, despite it's $$$ price)
The MH-Z14A is really simple to implement. Just send some characters over serial interface and get the CO2 value. You don't need to think about baselines and firmware versions. A cheap sensor is of no use, if you can't get correct readings. Maybe I am doing something wrong? :)
But maybe you can share your code and I can get better results?
The CCS811 I have here maybe cheap….

-
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
I have no experience with the MH-Z14A but compared to other comparable parts I think the CCS811 is a bit more simple to implement. (And less costly, despite it's $$$ price)
The MH-Z14A is really simple to implement. Just send some characters over serial interface and get the CO2 value. You don't need to think about baselines and firmware versions. A cheap sensor is of no use, if you can't get correct readings. Maybe I am doing something wrong? :)
But maybe you can share your code and I can get better results?
The CCS811 I have here maybe cheap….

@fotofieber after assembling and testing a few more boards. I've noticed that the fresh sensors, do need some time to "burn-in." I'm seeing wild values in the 1000's whereas the one I've been using for a few weeks is rock solid.
Here's a capture of one I'm testing right now:

The blue is the one that's been running for a while. The red is a fresh unused sensor.
I haven't had a chance to play with the MH-Z14A. I'm currently doing an eval of all sensors that I can (easily) get my hands on to compare side by side.
All the latest and greatest code for my project is located under the Beam me Up section in my original post above. #3 I think. Here's the link again though.
-
@fotofieber after assembling and testing a few more boards. I've noticed that the fresh sensors, do need some time to "burn-in." I'm seeing wild values in the 1000's whereas the one I've been using for a few weeks is rock solid.
Here's a capture of one I'm testing right now:

The blue is the one that's been running for a while. The red is a fresh unused sensor.
I haven't had a chance to play with the MH-Z14A. I'm currently doing an eval of all sensors that I can (easily) get my hands on to compare side by side.
All the latest and greatest code for my project is located under the Beam me Up section in my original post above. #3 I think. Here's the link again though.
@jaredwolff
Thx for the link to your sourcecode.
How long is the time interval on the graph in your post?I tried to use drive mode 1 (measurement every second) with an average calculation for every minute. But it didn't get better... :(
I added now a MH-Z19B to the testbed.
Awaiting still from aliexpress:
SGP30
MICS-VZ-89TE
GY-MCU680V1 BME680
Senseair S8-0053
and another CCS811.

-
@jaredwolff
Thx for the link to your sourcecode.
How long is the time interval on the graph in your post?I tried to use drive mode 1 (measurement every second) with an average calculation for every minute. But it didn't get better... :(
I added now a MH-Z19B to the testbed.
Awaiting still from aliexpress:
SGP30
MICS-VZ-89TE
GY-MCU680V1 BME680
Senseair S8-0053
and another CCS811.

@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
How long is the time interval on the graph in your post?
The interval was either 20 seconds or 2 minutes. My code defaults to 2 minutes. There's just no reason to be checking it that often.
The CCS811 on the other hand takes a measurement every second. (I left it in the default mode) I just take the latest measurement when it's time to send the update to the server.
Curious to see what conclusions you come to with your tests. I think we'll get there right around the same time!
-
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
How long is the time interval on the graph in your post?
The interval was either 20 seconds or 2 minutes. My code defaults to 2 minutes. There's just no reason to be checking it that often.
The CCS811 on the other hand takes a measurement every second. (I left it in the default mode) I just take the latest measurement when it's time to send the update to the server.
Curious to see what conclusions you come to with your tests. I think we'll get there right around the same time!
@jaredwolff
The MHZ19B is working out of the box without tuning. NDIR sensors seem to be easier to handle but are more power hungry.

In addition to the CO2 ppm, it has a temperature reading, which is not to bad:

The temperature of the BMP280 and ST7012 are quite high. They are on the same small pcb as the CCS811. -
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
The MHZ19B is working out of the box without tuning. NDIR sensors seem to be easier to handle but are more power hungry.
Nice! Glad to see something working for you. The MHZ19B seems like a good option when you have the space. I wonder how it is long term.
How many hours have you continuously run your CCS811? I'm seeing the fresh one I had normalize to zero over almost 24h of continuous running. (See the blue trace below for TVOC & C02)

I'm also not surprised by the readings you're getting on temp. Unless you get a sensors that is specifically more precise you could get some significant deviations. I would expect ±1 °C from most sensors though..
-
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
The MHZ19B is working out of the box without tuning. NDIR sensors seem to be easier to handle but are more power hungry.
Nice! Glad to see something working for you. The MHZ19B seems like a good option when you have the space. I wonder how it is long term.
How many hours have you continuously run your CCS811? I'm seeing the fresh one I had normalize to zero over almost 24h of continuous running. (See the blue trace below for TVOC & C02)

I'm also not surprised by the readings you're getting on temp. Unless you get a sensors that is specifically more precise you could get some significant deviations. I would expect ±1 °C from most sensors though..
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
Nice! Glad to see something working for you. The MHZ19B seems like a good option when you have the space.
The MH-Z19B does use less space than the MH-Z14B. I thinkt the footprint is similar to my CCS811 PCB from aliexpress. But it is taller. I think the main argument against the MH-Z19B could be power consumption.
I wonder how it is long term.
I have some MH-Z14B working fine for more than two years. Accoriding to the datasheet, the MH-Z19B should last more than 15 years.
How many hours have you continuously run your CCS811?
More than two days. It didn't get better.
I'm seeing the fresh one I had normalize to zero over almost 24h of continuous running. (See the blue trace below for TVOC & C02)
I can't see the time on your graph. I only see 2019-0... would it be possible to show the time?
The manufacturer has improved accuracy with the last firmware of the CCS811. Which version of firmware do you have on your CCS811?
-
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
The manufacturer has improved accuracy with the last firmware of the CCS811. Which version of firmware do you have on your CCS811?
Good question. According to my code: 1.1.0
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
I can't see the time on your graph. I only see 2019-0... would it be possible to show the time?
Hmm. Yea they're full timestamps. Pretty useless huh? What are you using to create your graphs? That way we're looking at the same thing.
On another note: I did get SPG30 and BME680 up and running. I ran the SPG30 while I was tinkering with the BME680. It's about 12 hours of data. (Sorry the x axis is not quite working out.)

My initial impressions from the integration:
SPG30 is about as easy as the CCS811. As you can see it has its own demons. It does require another power supply (1.8V typical for this part) And it can get power hungry if you run it tons (48mA when the heater is on).
The BME680 is not so easy to integrate into the Particle platform. Mostly due to the added archive file (i.e. static library, i.e..a file). After tinkering with what they had I have it taking in and processing data. The only thing I really care about is the IAQ calculation which is not open source. It does some other calculations on the temperature and humidity if you choose to integrated it with a space heater. (or HVAC unit for that matter)
-
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
The manufacturer has improved accuracy with the last firmware of the CCS811. Which version of firmware do you have on your CCS811?
Good question. According to my code: 1.1.0
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
I can't see the time on your graph. I only see 2019-0... would it be possible to show the time?
Hmm. Yea they're full timestamps. Pretty useless huh? What are you using to create your graphs? That way we're looking at the same thing.
On another note: I did get SPG30 and BME680 up and running. I ran the SPG30 while I was tinkering with the BME680. It's about 12 hours of data. (Sorry the x axis is not quite working out.)

My initial impressions from the integration:
SPG30 is about as easy as the CCS811. As you can see it has its own demons. It does require another power supply (1.8V typical for this part) And it can get power hungry if you run it tons (48mA when the heater is on).
The BME680 is not so easy to integrate into the Particle platform. Mostly due to the added archive file (i.e. static library, i.e..a file). After tinkering with what they had I have it taking in and processing data. The only thing I really care about is the IAQ calculation which is not open source. It does some other calculations on the temperature and humidity if you choose to integrated it with a space heater. (or HVAC unit for that matter)
@jaredwolff said in Particle Powered Air Quality Sensor Logging to Google Docs:
Hmm. Yea they're full timestamps. Pretty useless huh? What are you using to create your graphs? That way we're looking at the same thing.
I am using grafana with influxdb (both in docker).
SPG30 is about as easy as the CCS811. As you can see it has its own demons. It does require another power supply (1.8V typical for this part) And it can get power hungry if you run it tons (48mA when the heater is on).
Awaiting mine impatiently. :) Power consumption is not a real problem in my usage scenario.
The BME680 is not so easy to integrate into the Particle platform. Mostly due to the added archive file (i.e. static library, i.e..a file).
Do you build with platform.io? I only found instructions for the arduino ide...
Temp and hum are measured on the heated sensor and must be calibrated to be useful according to some discussions I read.
-
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
I am using grafana with influxdb (both in docker).
I like it. It may make sense to have my own infrastructure in the future. But then again, I don't feel like dealing with it all. :laughing:
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
Do you build with platform.io? I only found instructions for the arduino ide...
I'm building using the Particle SDK on my machine. They can build Arduino libraries but can't quite include external/static libraries yet (As far as I can tell) out of the box. The Particle platform, in general, has been for convenience and getting to proof of concept (really) fast. Plus they're an awesome company.
As for the data, I'm just pushing the data from the Particle platform into Google docs (as my original post described). It's great for short tests but longer data streams you definitely need a time-based database and some nice front end graphing capabilities. :smile:
Another update on the TVOC eval. Looks like the BME680 outputs on the same scale as the SPG30 and CCS811. (i.e. 500ppb == a reading of 500 IAQ on the BME680)

(The timestamps are there if you click on the image itself. )
@fotofieber said in Particle Powered Air Quality Sensor Logging to Google Docs:
Temp and hum are measured on the heated sensor and must be calibrated to be useful according to some discussions I read.
I was thinking about this more considering the discrepancy I'm seeing in temperatures and humidity. If you're serious about the results and the accuracy of the temp & humidity it may require a 3rd temperature sensor with no heater inside.
Supposedly the BME680 has a calibrated output but it hasn't fired up. I'll have to figure that out..
-
Firmware upgrade time!
My CCS811 has bootloader version: 1000
and had application version: 1100
I upgraded to the newest firmware (2.0.1). Now waiting for another two days.... :) Hope then I get reasonable results like you have....
-
Firmware upgrade time!
My CCS811 has bootloader version: 1000
and had application version: 1100
I upgraded to the newest firmware (2.0.1). Now waiting for another two days.... :) Hope then I get reasonable results like you have....
@fotofieber yeehaw. I hope that fixes the craziness you were seeing. I'm curious if that will fix the early unreliable data I've been seeing too..