BME680 Breakout Board - Quality Calculation etc



Hooked it up, and getting values back, was wondering if the air quality value you calculate in the example equates to the bosch “indoor air quality” that ranges from 0 - 500 ?

OK, so question answered in another post, the example is not the bosch IAQ but between 0 and 100% but factors in humidity to that 100% rating.

So, reckon I will split that and just have a GAS sensor air quality and a humidity target reading.

Also you are heating to 320 for 150ms, when example in datasheet is 300 for 100ms, any reason for doing that?

The temperature reads high (22.5c when ambient about 19.5c) and humidity reads low (37.35 when about 45RH% ambient) which of course makes sense when there is a heater heating to 300c on the same little chip

Then again, always a question about which device is actually the accurate one.

The pressure value is accurate compared to a couple of bme280 chips.


I reckon the bosch datasheet is missing a lot of information (i.e. gas response curves) that they have hidden in their proprietary BSEC software

using the example

The sensors gas value/resistance varies depending on polling rate

at 60 seconds per reading max resistance 65000 after 5 hours
at 10 seconds per reading max resistance 132000 after 10 mins
at 5 seconds per reading max resistance 222569 after 10 mins

at 1 seconds per reading max resistance 222278 after 10 mins then is stable-ish at about 280000 after 20 mins

at 2 seconds per reading max resistance 233345 after 10 mins then is stable-ish at about 234000 after 20 mins

consequtive tests and air quality not changed that much, been running MQ137 and other analog gas sensors for several months already.

can someone else confirm this with another sensor.


So, it sounds like once they’ve stabilised then it doesn’t make much difference? I’d guess this is related to how stable the temperature of the heating plate is, but that’s pure speculation.

It’s worth mentioning that Bosch have now made a binary of their BSEC software for the Pi available, so you might like to try that and compare results…


Actually, that is my point, it makes a big difference, you cannot change the sampling period once you have baselined it at a fixed sampling period, and probbaly more sensitive to fluctuation at one end or the other of the periods length.

I had already tested the bosch C interface following this guide

and I can see the raw values are in same ballpark as your python library

using the BSEC library requires more knowledge of how to link to the static library they provide than I have. Where do you need to put what files?

I stuck all the header and c files in the examples directory and copied library for pi zero to /usr/lib

I am just getting shed loads of errors

gcc -Wall bsec_iot_example.c bsec_integration.c -lalgobsec -o test

bsec_integration.c: In function ‘bsec_iot_init’:
bsec_integration.c:161:27: warning: unused variable ‘bsec_status’ [-Wunused-variable]
bsec_library_return_t bsec_status = BSEC_OK;
bsec_integration.c: In function ‘bme680_bsec_trigger_measurement’:
bsec_integration.c:237:12: warning: variable ‘bme680_status’ set but not used [-Wunused-but-set-variable]
int8_t bme680_status = BME680_OK;
bsec_integration.c: In function ‘bme680_bsec_read_data’:
bsec_integration.c:297:12: warning: variable ‘bme680_status’ set but not used [-Wunused-but-set-variable]
int8_t bme680_status = BME680_OK;
/usr/bin/ld: /usr/lib/gcc/armv6l-unknown-linux-gnueabihf/7.2.0/…/…/…/libalgobsec.a(bsec_interface.o): relocation R_ARM_MOVW_ABS_NC against `a local symbol’ can not be used when making a shared object; recompile with -fPIC
/usr/lib/gcc/armv6l-unknown-linux-gnueabihf/7.2.0/…/…/…/libalgobsec.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status


OK, after research (thanks stackexchange) and thinking those functions giving errors are math functions need to also link with math library this command will compile it

gcc -static -static-libgcc -static-libstdc++ bsec_iot_example.c bsec_integration.c bme680.c -lalgobsec -lm -o test

however, got to write your own smbus/i2c comms routines for the example program. I may get round to looking at the ino to see how its done in wire library and then that needs converting to file based io.


You could borrow i2c read/write from here:

The -static-libgcc and -static-libstdc++ parts of your compile magic look odd to me. I’m no C guru, but it’s not typical to statically link these. That said- if it works, it works! You just end up with a slightly larger binary.


may be one advantage of a pure static linked package, might run on a machine with different dynamic c/c++ libraries where they are incompatible in a use case… as long as such and such else pitfall does not exist…

my problem was not linking with math library. you are right, only need the -static directive

I see in the bsec example for arduino document they explain that temp is high and humidity low because of background heat, and that the bsec library does temperature compensation which adjusts the humidity reading, not got that working yet, but the i2c code already in the correct callback routine parameter order I was going to patch in is in the example at

wondering if calibration data can be adjusted at your python library level to set/compensate the temperature that the humidity is calculated at and return correct temp/humidity


We could probably reverse-engineer their compensation formula, at least to some degree, by shoring up the i2c functions to return fake data that runs the whole gamut of possible humidity/temperature readings, graphing the resulting humidity (versus the humidity we fed in) and seeing how it correlates to the temperature. I’m not sure exactly how they’d feel about this- it might be easier just to ask nicely if they’ll give us some pointers on designing our own compensations.

The issue with the heater sounds logical, too, I would fully expect polling frequency to have a small impact on resistivity, since the part would - in theory - stay warm for longer, and bind to more VOC (I’m not really sure how the sensor layer actually works/chemically interacts with the compounds it detects). That said I wouldn’t expect the tiny heating element to have much thermal inertia, so I’m surprised it has the impact that it does. Are other factors are play?

It might be worth us putting together a tutorial, or a GitHub repository, teaching more advanced users how to use the C libraries and binary blobs. It would be less “darkside” than reverse engineering.


the example showed a -5c temp compensation, which ties up with my observations, got a ds18b20 on another pi in proximity to your sensor mounted vertically on a zero and it reads about 5c lower. humidity about 5-10 points low compared to a hygrometer (that reads low/accurate) in proximity to your sensor.


Looking at your python library, should be possible to add a temp_compensation value in the init and then if anyone understands what the calc_temperature which feeds in to calc_humidity routines do then compensate the temperature in calc_temperature which should then automatically correctly calculate the right humidity from the temperature feed forward.

OK so the temperature compensation is easy like I said above, just add an extra parameter to init

BUT the temperature compensation in the humidity calculation works the opposite way, (cooler = less humidity) and hardly makes any difference anyway. 5C cooler only affects humidity calculation by less than 1%

problem with shifting it a fixed percent is that percentage will vary across the temperature range. Ah well, Think I’ll just shift it a fixed percent. About +6% seems about right.

So may as well just adjust it in the logging code.

though hooking up an htu21d as well and maybe a bme280 and cross correlating some data should yield a formula.


I will leave this lot running for a while, some ds18b20 temp sensors, a bme280 and the raspberry with a bme680 see what happens.

I have noticed the gas resistance readings are very steppy

this example I blow some smoke at the sensors


when it clears it will massive switch from 140000 or so up to the 222000 scale again



yeah, I see what’s happening, it’s a good sensor! the datasheet does not explain how it works!

now, if pimoroni want to send me a couple more of them I might explain it LOL

The compensation is not linear, as surroundings get cooler the error gets less… not been able to test in hot surroundings due to utility corporation cartel so and so’s

as a hint… norsky (not great, no worse that met ofice?) xfce plugin link says 92% humidity outside, bme280 by an open window shielded from interior by a venetian blind says 72% (sounds about right) pimoroni bme680 board in very close proximity to chinois bme280 says 60%. (so a 12% rh offset would be quite close across the range I have observed, to what tolerance?)

amazing how a metre in altitude in a room (in cold weather) can be 2c difference eh! (actually that might be a 1C tolerance error and 1C actual difference)


could be a long burn in period, I think it may have improved somewhat.

nope - a red herring, it needs a big largely fixed offset for temp and humidity plus a bit of variable offset for ultra precision.

The gas sensor reading post library is banded, I think the bands it rises up through from start up are the five levels of air quality with a range within each… what centre point of each range is is not specified.


so there is another band on top that only is achieved outside, (never makes it inside) the 400-500 thousand range, the ranges are stepped to roughly double previous range with a variation (probably proportional to the step size) within that band of varying quality within that band I think.

I will do some processing on the data and attempt to estimate high-low for each band.

even outside air quality drops from 400-500k band to 200k band round here when house fires light up and traffic is heavy, busy road and old houses with real fires burning ship oil, primo columbian coke, plastic and lead painted fence posts by the smell of things… (so and so’s at cantrols shut down the quality of english coal…) probably in very attractive packaging at an attractive price eh!

guess what you want is external sensor that drive your indoor positive pressure air input filter that only ever fires up to max at good outside air quality levels…

of course can only really (being an upstanding citizen) run a positive air pressure system in a detached house, unless all connected houses are also in on the complete system…

or just open your windows to get a through draft when it is good and shut down when not… but observe when bad air appears to be being pumped in eh! (they know who they are… so help me I am going to eradicate them!)

got to block indent by 4 spaces on this forum???

'kers aint coders eh! and # makes a line double sized bold wtf??? python 4 indent and no block end… python awesome but flawed eh!

awesome but flawed eh! modern world eh!

#!/usr/bin/env python
# tweak pimoroni example to get some sensible readings
# Paul W. Rogers 2017

import bme680
import time
from datetime import datetime
sensor = bme680.BME680()

# These calibration data can safely be commented
# out, if desired.

print("Calibration data:")
for name in dir(sensor.calibration_data):

    if not name.startswith('_'):
        value = getattr(sensor.calibration_data, name)

        if isinstance(value, int):
            print("{}: {}".format(name, value))

# These oversampling settings can be tweaked to 
# change the balance between accuracy and noise in
# the data.


print("\n\nInitial reading:")
for name in dir(
    value = getattr(, name)

    if not name.startswith('_'):
        print("{}: {}".format(name, value))



# Up to 10 heater profiles can be configured, each
# with their own temperature and duration.
# sensor.set_gas_heater_profile(200, 150, nb_profile=1)
# sensor.select_gas_heater_profile(1)

avgtot = 0.0
avgcount = 0

fixedrate = 3
avgrate = 10

# speed is fixedrate * avgrate seconds per average no long-term smoothing so catch peaks more?
# have to keep fixedrate-is-what? up on this sensor or it retrigs calibration
# 3s per reading works

logf = open('BME680.log','a') 

    while True:
        if sensor.get_sensor_data():

            output ='%Y-%m-%d,%H:%M:%S,')+"{0:.2f},C,{1:.2f},hPa,{2:.2f},%RH" \
                avgtot +=
                if avgcount==avgrate :
                  output += ",{:.0f},Ohms".format(avgtot/avgrate)

                output += ',0,Ohms'
            if avgcount == avgrate :
              avgcount = 0
              output += '\n'


except KeyboardInterrupt:



Great post. I have uped my sampling to 8x and taking reads every 3 seconds to try to replicate what you did.
At the moment if I read the gas reading only it climbs higher then stabilises but when the python script then also starts reading the temp pressure and humidity, the gas reading always drops suddenly. Hopefully your settings will fix this!


You can see the sudden drops on the screenshot. I’ll post a screenshot of the impact of your suggested changes tomorrow and we can compare.


Hmmm - your settings seemed to have improved things. The drop is not so large and the average gas reading has gone down, temp has gone down and humidity up with Air Quality hovering over 80%. The arrows show where the new settings kicked in.


there is another post where I have graphed the comparative results with an analog gas sensor mq135 and mq7. Main improvement regarding temp/humidity wrong readings is not running it vertically mounted on the pi, but make a little ventilated container so you can mount it a cables length.

and then observing the large step jumps the bands of which I have estimated in this post