# BME280 module
| Since  | Origin / Contributor  | Maintainer  | Source  |
| :----- | :-------------------- | :---------- | :------ |
| 2020-10-04 | [vsky279](https://github.com/vsky279) | [vsky279](https://github.com/vsky279) | [bme280.lua](../../lua_modules/bme280/bme280.lua)|

This module communicates with [BME280/BMP280 temperature/air presssure/humidity sensors](http://www.bosch-sensortec.com/bst/products/all_products/bme280) (Bosch Sensortec) through [I2C](../modules/i2c.md) interface. 

Note: the module works only with the [bme280_math](../modules/bme280_math) module.

## bme280.setup()

Creates bme280sensor object and initializes module. Initialization is mandatory before read values. Note that there has to be a delay between some tens to hundreds of milliseconds between calling `setup()` and reading measurements.

Functions supported by bme280sensor object:
- [setup()](#sobjsetup)
- [read()](#sobjread)
- [startreadout()](#sobjstartreadout)
- [qfe2qnh](#sobjqfe2qnh)
- [altitude](#sobjaltitude)
- [dewpoint](#sobjdewpoint)

#### Syntax

`bme280.setup(id, [address, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])`

#### Parameters
- `id` - I2C bus number
- (optional)`address` - BME280 sensor address. `1` for `BME280_I2C_ADDRESS1 = 0x76`, `2` for  `BME280_I2C_ADDRESS2 = 0x77`. Default sensor address is `BME280_I2C_ADDRESS1`.
- (optional) `temp_oss` - Controls oversampling of temperature data. Default oversampling is 16x.
- (optional) `press_oss` - Controls oversampling of pressure data. Default oversampling is 16x.
- (optional) `humi_oss` - Controls oversampling of humidity data. Default oversampling is 16x
- (optional) `sensor_mode` - Controls the sensor mode of the device. Default sensor more is normal.
- (optional) `inactive_duration` - Controls inactive duration in normal mode. Default inactive duration is 20ms.
- (optional) `IIR_filter` - Controls the time constant of the IIR filter. Default filter coefficient is 16.
- (optional) `cold_start` - If 0 then the BME280 chip is not initialised. Useful 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 (`bme280sensor: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**|

|`sensor_mode`|Sensor mode|
|-----|-----------------|
|0|Sleep mode|
|1 and 2|Forced mode|
|**3**|**Normal mode**|

Using forced mode is recommended for applications which require low sampling rate or hostbased synchronization. The sensor enters into sleep mode after a forced readout. Please refer to BME280 Final Datasheet for more details.

|`inactive_duration`|t standby (ms)|
|-----|-----------------|
|0|0.5|
|1|62.5|
|2|125|
|3|250|
|4|500|
|5|1000|
|6|10|
|**7**|**20**|

|`IIR_filter`|Filter coefficient |
|-----|-----------------|
|0|Filter off|
|1|2|
|2|4|
|3|8|
|**4**|**16**|

#### Returns
`sobj` - BME280 Sensor Object (`nil` if initialization has failed)

## BME280 Sensor Object Methods

### sobj:setup()

Re-initializes the sensor.

### Parameters

Parameters are the same as for the [bme280.setup](#bme280setup) function.

### Return

Returned values are the same as for the [bme280.setup](#bme280setup) function.

### sobj:altitude()

For given air pressure (called QFE in aviation - see [wiki QNH article](https://en.wikipedia.org/wiki/QNH)) and sea level air pressure returns the altitude in meters, i.e. altimeter function.

#### Syntax
`sobj:altitude(P, QNH)`

#### Parameters
- `P` measured pressure
- `QNH` current sea level pressure

#### Returns
altitude in meters of measurement point

## sobj:dewpoint()

For given temperature and relative humidity returns the dew point in celsius.

#### Syntax
`sobj:dewpoint(H, T)`

#### Parameters
- `H` relative humidity in percent (100 means 100%)
- `T` temperate in celsius

#### Returns
dew point in celsisus

## sobj:qfe2qnh()

For given altitude converts the air pressure to sea level air pressure ([QNH](https://en.wikipedia.org/wiki/QNH)).

#### Syntax
`sobj:qfe2qnh(P, altitude)`

#### Parameters
- `P` measured pressure
- `altitude` altitude in meters of measurement point

#### Returns
sea level pressure


## sobj:read()

Reads the sensor and returns the temperature, the air pressure, the air relative humidity and see level pressure when `altitude` is specified.

#### Syntax
`sobj: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
- `P` air pressure in hectopascals
- `H` relative humidity in percent
- (optional) `QNH` air pressure in hectopascals (when `altitude` is specified)

Returns `nil` if the readout is not successful.

## sobj:startreadout()
Starts readout (turns the sensor into forced mode). After the readout the sensor turns to sleep mode. Callback function is called with  readout results.

#### Syntax
`sobj:startreadout(delay, callback)`

#### Parameters
- `callback` if provided it will be invoked after given `delay`. Callback parameters are identical to `sobj:read` results.
- `altitude` in meters of measurement point (QNH is returned when specified)
- `delay` sets sensor to forced mode and calls the `callback` (if provided) after given number of milliseconds. For 0 the default delay is set to 113ms (sufficient time to perform reading for oversampling settings 16x). For different oversampling setting please refer to [BME280 Final Datasheet - Appendix B: Measurement time and current calculation](https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280-DS002.pdf#page=51).

#### Returns
`nil`

#### Example
```lua
alt=320 -- altitude of the measurement place

sda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0)

tmr.create():alarm(500, tmr.ALARM_AUTO, function()
    local T, P, H, QNH = s:read(alt)
    local D = s:dewpoint(H, T)
    print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)
```

Example with sensor in sleep mode between readouts (asynchronous readouts)
```lua
alt=320 -- altitude of the measurement place

sda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0, nil, nil, nil, nil, 0) -- initialize to sleep mode

tmr.create():alarm(1000, tmr.ALARM_AUTO, function()
    s:startreadout(function(T, P, H, QNH)
        local D = s:dewpoint(H, T)
        print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
    end, alt)
end)
```

Altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
```lua
alt = 0 -- initial altitude

sda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0)

tmr.create():alarm(100, tmr.ALARM_AUTO, function()
    local _, P, _, lQNH = s:read(alt)
    if not QNH then QNH = lQNH end
    local altitude = s:altitude(P, QNH)
    
    print(("altitude=%.3f m"):format(altitude))
end)
```
