BME680 module

Since Origin / Contributor Maintainer Source
2017-10-28 vsky279 vsky279 bme680.c

This module provides a simple interface to BME680 temperature/air presssure/humidity sensors/air quality sensor (Bosch Sensortec). Compared to the BME280 module the sensor does not support automatic mode which means that it can be setup to perform regular measurements. Every measurement has to be triggered manually.

In order to measure the air quality the sensor needs to be heated first. In the example provided by the manufacturer the sensor is heated to 300 degrees centigrade for a period of 200 ms and then the measurement is taken. These values are taken as default values in this implementation. I have not tested the impact of different temperatures and heating times on the measurement.

This module is able to measure the gas resistance (see Bosch's datasheet). The gas resistance is not the IAQ (Indoor Air Quality) Index. But apparently it can be used as some proxy. The value still should somehow reflect the air quality. It seems that the higher value the air quality is better.

The algorithm for IAQ calculation from the gas restistances (probably measured at different temperatures) is not publicly available. Bosch says that at this point of time the calculations for the Indoor Air Quality index are offered only as a pre-compiled library (see discussion here: BoschSensortec/BME680_driver#6). It is available as the BSEC Library. The algorithm is implemented in the library bsec/algo/bin/ESP8266/libalgobsec.a. Unfortunately I did not even manage to run the Bosch BSEC example on ESP8266 using this library.

bme680.altitude()

For given air pressure and sea level air pressure returns the altitude in meters as an integer multiplied with 100, i.e. altimeter function.

Syntax

bme680.altitude(P, QNH)

Parameters

  • P measured pressure
  • QNH current sea level pressure

Returns

altitude in meters of measurement point

bme680.dewpoint()

For given temperature and relative humidity returns the dew point in Celsius as an integer multiplied with 100.

Syntax

bme680.dewpoint(H, T)

Parameters

  • H relative humidity in percent multiplied by 1000.
  • T temperate in Celsius multiplied by 100.

Returns

dew point in Celsius

bme680.qfe2qnh()

For given altitude converts the air pressure to sea level air pressure.

Syntax

bme680.qfe2qnh(P, altitude)

Parameters

  • P measured pressure
  • altitude altitude in meters of measurement point

Returns

sea level pressure

bme680.read()

Reads the sensor and returns the temperature, the air pressure, the air relative humidity and

Syntax

bme680.read([altitude])

Parameters

  • (optional) altitude- altitude in meters of measurement point. If provided also the air pressure converted to sea level air pressure is returned.

Returns

  • T temperature in Celsius as an integer multiplied with 100
  • P air pressure in hectopascals multiplied by 100
  • H relative humidity in percent multiplied by 1000
  • G gas resistance
  • QNH air pressure in hectopascals multiplied by 100 converted to sea level

Any of these variables is nil if the readout of given measure was not successful.

The measured values can be read only once. Following attempts to read values will return nil. A new startreadout() needs to be called first before next read().

bme680.startreadout()

Starts readout (turns the sensor into forced mode). After the readout the sensor turns to sleep mode.

Syntax

bme680.startreadout(delay, callback)

Parameters

  • delay sets sensor to forced mode and calls the callback (if provided) after given number of milliseconds. For 0 the default delay is calculated by the formula provided by Bosch. Apparently for certain combinations of oversamplings setup the the delay returned by the formula is not sufficient and the readout is not ready (make sure you are not reading the previous measurement). For default parameters (2x, 16x, 1x) the calculated delay is 121 ms while in reality 150 ms are needed to get the result.
  • callback if provided it will be invoked after given delay. The sensor reading should be finalized by then so.

Returns

nil

bme680.setup()

Initializes module. Initialization is mandatory before read values.

Syntax

bme680.setup([temp_oss, press_oss, humi_oss, heater_temp, heater_duration, IIR_filter, cold_start])

Parameters

  • (optional) temp_oss - Controls oversampling of temperature data. Default oversampling is 2x.
  • (optional) press_oss - Controls oversampling of pressure data. Default oversampling is 16x.
  • (optional) humi_oss - Controls oversampling of humidity data. Default oversampling is 1x
  • (optional) heater_temp -
  • (optional) heater_duration -
  • (optional) IIR_filter - Controls the time constant of the IIR filter. Default fitler coefficient is 31.
  • (optional) cold_start - If 0 then the bme680 chip is not initialised. Usefull in a battery operated setup when the ESP deep sleeps and on wakeup needs to initialise the driver (the module) but not the chip itself. The chip was kept powered (sleeping too) and is holding the latest reading that should be fetched quickly before another reading starts (bme680.startreadout()). By default the chip is initialised.
temp_oss, press_oss, humi_oss Data oversampling
0 Skipped (output set to 0x80000)
1 oversampling ×1
2 oversampling ×2
3 oversampling ×4
4 oversampling ×8
5 oversampling ×16
IIR_filter Filter coefficient
0 Filter off
1 1
2 3
3 7
4 15
5 31
6 63
7 127

Returns

nil if initialization has failed (no sensor connected?)

Example

alt=320 -- altitude of the measurement place

sda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once

bme680.setup()

-- delay calculated by formula provided by Bosch: 121 ms, minimum working (empirical): 150 ms
bme680.startreadout(150, function ()
    T, P, H, G, QNH = bme680.read(alt)
    if T then
        local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
        print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
        print(string.format("QFE=%d.%03d", P/100, P%100))
        print(string.format("QNH=%d.%03d", QNH/100, QNH%100))
        print(string.format("humidity=%d.%03d%%", H/1000, H%1000))
        print(string.format("gas resistance=%d", G))
        D = bme680.dewpoint(H, T)
        local Dsgn = (D < 0 and -1 or 1); D = Dsgn*D
        print(string.format("dew_point=%s%d.%02d", Dsgn<0 and "-" or "", D/100, D%100))
    end
end)