Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of reading and writing baseline #22

Open
bfaliszek opened this issue Jun 7, 2019 · 9 comments
Open

Example of reading and writing baseline #22

bfaliszek opened this issue Jun 7, 2019 · 9 comments

Comments

@bfaliszek
Copy link

Hi, is there an example of a code with read and write baseline somewhere?

@maarten-pennings
Copy link
Owner

maarten-pennings commented Jun 7, 2019

I remembered that I added that code upon request, and that somebody tested it and said it worked. I looked up who said that, it's you 😉.

I don't have code, but indeed it would be good to have it in some example. Volunteers?

@bfaliszek
Copy link
Author

Yes, I remember that. Maybe someone did it and share their code.

@bfaliszek
Copy link
Author

bfaliszek commented Jun 30, 2019

I found some time and made an example based on https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/blob/master/examples/Example4_SetBaseline/Example4_SetBaseline.ino

To make it work, I changed the get_baseline in ccs811.h to:

uint16_t CCS811::get_baseline(void) { uint8_t buf[2]; wake_up(); bool ok = i2cread(CCS811_BASELINE,2,buf); wake_down(); unsigned int baseline = (buf[0]<<8) + buf[1]; return baseline; }

My example code for ESP32 (I did not test it on ESP8266!) for loading, saving and deleting a baseline: https://pastebin.com/KGigYPr6

@theoroborus
Copy link

Hello,
It looks maarten-pennings wanted to make you work a bit ahaha.
I guess you previously tested baseline on another library.
Here's how to do it with maarten's code, simply ;

uint16_t ccs811Baseline;
ccs811.get_baseline(&ccs811Baseline);

@CelMaiRau
Copy link

Can you post a valid code for ESP8266? And more precisely what needs to be changed in the library to work because the above example gives error.

@maarten-pennings
Copy link
Owner

I'm not sure what you want to see.
The easy part is to actually get and set the baseline.
The hard part is when.
And another hard part is how and where to save the baseline when the Arduino itself will power off.

This is how a main program could be structured

void setup() {
  ... no special code for baseline (the CCS811 will run with "zero baseline" the first 20 min) ...
}

void loop() {
  // Get the baseline from persistent memory and write to CCS811 when the CCS811 is on for 20 min
  if( CCS811 is powered 20 min ) {
    handle_baseline_for_power_on();
  }

  // If there is a reason to switch off the CCS811 and the Arduino
  if( ... reason to switch off ... ) {
    if( CCS811 is powered for at least 20 min) { handle_baseline_for_power_off(); }
    // somehow switch ourselves (Arduino) and CCS811 off
    ...
  }

  ... code that uses the CCS811 ...
}

Then you would need two helpers handle_baseline_for_power_on/off.
They need persistent storage...

// These variable should somehow be made persistent (i.e. saved to some flash)
// In this example I will just pretent they are persistent
uint16_t persistent_baseline;
bool persistent_baseline_available = false;

// Only call after CCS811 is on for 20min
void handle_baseline_for_power_off() {
  uint16_t baseline; 
  bool ok; 

  ok= get_baseline(&baseline);     
  if( ok ) {
    // I2C transaction successful, so save the baseline persistently (and record it is valid)
    persistent_baseline = baseline;
    persistent_baseline_available = true;
  }
}

// Only call after CCS811 is on for 20min
void handle_baseline_for_power_on() {
  // If no baseline is saved persistently, continue with the "zero baseline" from setup()
  if( persistent_baseline_available ) {
    bool ok; 
    ok= set_baseline(persistent_baseline);     
    if( !ok ) { ... I2C transaction failed ... hmm ... what to do ... }
  }
}

This code is not even tested on syntax ...

@JsBergbau
Copy link

JsBergbau commented Jan 7, 2021

I had the impression baseline register can't be written, thats why Google brought me here.
If you save the baseline, be sure to save that values when sensor is outside in fresh air for a few minutes. I've waited at least 20 minutes. Since it is winter now and temperatures are quite cold, please make sure to write environmental calibration settings. This changes the TVOC and thus eCO2 a lot.
Then take the sensor in and restore the baseline calibration.

If you restore a baseline calibration value which would lead to no detection of TVOC internal calibration method adjusts baseline calibration register and so it seems your write to the baseline calibration was unsuccessful.

I hope the automatic baseline calibration won't change or adjust this value that after 24 hours the lowest measured TVOC measurement is set as baseline for 0 TVOC / 400 ppm eCO2. Reading the section about automatic calibration could mean this. If so you have to monitor baseline register and write back your value from clean outside air.

If you don't write the baseline calibration register CCS811 adjusts its internal correction after each startup to 0 TVOC / 400 ppm eCO2.

For long running sensors after the first 500 hours manual recommends saving baseline every 5-7 days. So to get a tradeoff between reliable values and comfort I would put it to fresh outside air once month.

Please note that just opening a window can take hours to have really fresh like outside air inside. I've seen this with CO2 sensors. This strongly depends on the position of the sensor inside the room and how wide you open the window. But at cold temperatures outside you lose significant amount of energy until air has really outside quality.

Update: Sensor also adjusts baseline if measured TVOC get too high. So it doesn't just clip and show maximum value until TVOC went down again but instead it adjusts baseline calibration to show again a TVOC value. However because of baseline adjustment you can't compare it with previous values.

@Sindar-sudo
Copy link

I'm experimenting with this library and sensor's baseline for quite a while now. I'm getting some problems setting the correct baseline.
It's winter now so to get clean air means putting it on my balcony where it's quite cold (~0C). I then wait for the baseline to stabilize after about 30-40min.
So first question arises - does the temperature/humidity affect baseline reading? I assume that yes.
Therefore I have DHT22 sensor connected to the same ESP32 and I tried adding corrections via setEnvironmentalData. This changes the baseline significantly, however, in my case for some reson it sets it to "higher" standard. So indoors it shows very high numbers (eCO2 @ 2500+) although air is not nearly that bad. Of course indoor readings also get compensated via setEnvironmentalData.

This leads me to the main question - how to properly get the baseline? Do I need to wait for warmer weather and then take it outside to get proper baseline? Should I somehow get clean air indoors at room tempertures? Are there any general guidelines to get proper baseline?

@maarten-pennings
Copy link
Owner

The MoX sensor has a resistance depending on the gases in the air. The cleaner the air the lower the resistance. Unfortunately, this relation is not stable in time (resistance changes due to what happened in the past). So what the firmware of a MoX sensor does is record the lowest resistance it has seen - the cleanest air. Let's call this R0. When you perform a measurement, the sensor measures the current resistance, let's call it Rc, and it roughly outputs Rc/R0; this is called eqTVOC. The problem is, that the sensor resistance for clean air changes in time, so the sensor needs to adapt R0. The firmware has algorithms to adapt R0 on a daily basis (24 hour cycle). 

The R0 is called the "baseline". As noted above, R0 is maintained by the sensor as long as it is powered. Once the sensor is switched off, R0 is lost. After a new power on, it takes some time before a good R0 is determined by the sensor.

What the chip supports is baseline backup and restore. You can execute x=get_baseline () before you switch off, and set_baseline(x) after you switch on. Make sure that the x=get_baseline() is executed when the chip actually has a good baseline, so it must have run long enough. Also,  execute set_baseline(x) after power on and a delay to wait that the sensor is stable otherwise the written baseline might be overwritten by not-yet-correct Rc (unstable MoX) by the firmware. Read the datasheet  (and separate app note https://www.sciosense.com/wp-content/uploads/documents/Application-Note-Baseline-Save-and-Restore-on-CCS811.pdf) for details on when to do this exactly

Putting it outside does not seem wise: 1) the baseline is constantly adjusted, 2) R0 is now for outside and Rc for inside, so Rc/R0 has a mismatch, 3) ccs811 is in indoor air quality sensor.

Yes humidity and temperature are relevant, so measure them and feed them (use the appropriate function, and take care of the units).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants