Remarks

Bme280
Status Status badge: working
Source code GitHub
Datasheet(s) GitHub
NuGet package NuGet Gallery for Meadow.Foundation.Sensors.Atmospheric.Bme280

The BME280 is a combined temperature, pressure and humidity sensor controlled via I2C.

Purchasing

The BME280 sensor is available as a breakout board from the following suppliers:

The BME280 can operating in polling and interrupt mode. By default, this sensor operates in interrupt mode.

Code Example

Bme280 sensor;

public override Task Initialize()
{
    Console.WriteLine("Initializing...");

    //CreateSpiSensor();
    CreateI2CSensor();

    var consumer = Bme280.CreateObserver(
        handler: result =>
        {
            Console.WriteLine($"Observer: Temp changed by threshold; new temp: {result.New.Temperature?.Celsius:N2}C, old: {result.Old?.Temperature?.Celsius:N2}C");
        },
        filter: result =>
        {
            //c# 8 pattern match syntax. checks for !null and assigns var.
            if (result.Old is { } old)
            {
                return (
                (result.New.Temperature.Value - old.Temperature.Value).Abs().Celsius > 0.5
                &&
                (result.New.Humidity.Value - old.Humidity.Value).Percent > 0.05
                );
            }
            return false;
        }
    );
    sensor.Subscribe(consumer);

    sensor.Updated += (sender, result) => {
        Console.WriteLine($"  Temperature: {result.New.Temperature?.Celsius:N2}C");
        Console.WriteLine($"  Relative Humidity: {result.New.Humidity:N2}%");
        Console.WriteLine($"  Pressure: {result.New.Pressure?.Millibar:N2}mbar ({result.New.Pressure?.Pascal:N2}Pa)");
    };

    return Task.CompletedTask;
}

public override async Task Run()
{
    var conditions = await sensor.Read();
    Console.WriteLine("Initial Readings:");
    Console.WriteLine($"  Temperature: {conditions.Temperature?.Celsius:N2}C");
    Console.WriteLine($"  Pressure: {conditions.Pressure?.Bar:N2}hPa");
    Console.WriteLine($"  Relative Humidity: {conditions.Humidity?.Percent:N2}%");

    sensor.StartUpdating(TimeSpan.FromSeconds(1));
}

void CreateSpiSensor()
{
    Console.WriteLine("Create BME280 sensor with SPI...");

    var spi = Device.CreateSpiBus();
    sensor = new Bme280(spi, Device.CreateDigitalOutputPort(Device.Pins.D00));
}

void CreateI2CSensor()
{
    Console.WriteLine("Create BME280 sensor with I2C...");

    var i2c = Device.CreateI2cBus();
    sensor = new Bme280(i2c, (byte)Bme280.Addresses.Default); // SDA pulled up

}

Sample project(s) available on GitHub

Interrupt Mode

When the driver is operating in interrupt mode, the driver will periodically check the sensor reading. An interrupt will be generated if the difference between the last reported reading and the current reading is greater than a threshold value.

The sensor operates in interrupt mode by default.

The following application will generate interrupts when changes to any one of the temperature, humidity or pressure readings exceed their threshold values:

public class MeadowApp : App<F7Micro, MeadowApp>
{
    Bme280 bme280;

    public MeadowApp()
    {
        Console.WriteLine("Initializing...");

        // configure our BME280 on the I2C Bus
        var i2c = Device.CreateI2cBus();
        bme280 = new Bme280 (
            i2c,
            Bme280.I2cAddress.Adddress0x77 //default
        );

        bme280.Subscribe(new FilterableObserver<AtmosphericConditionChangeResult, AtmosphericConditions>(
            h => {
                Console.WriteLine($"Temp and pressure changed by threshold; new temp: {h.New.Temperature}, old: {h.Old.Temperature}");
            },
            e => {
                return (
                    (Math.Abs(e.Delta.Temperature) > 1)
                    &&
                    (Math.Abs(e.Delta.Pressure) > 5)
                    );
            }
        ));

        // classical .NET events can also be used:
        bme280.Updated += (object sender, AtmosphericConditionChangeResult e) => 
        {
            Console.WriteLine($"  Temperature: {e.New.Temperature}ºC");
            Console.WriteLine($"  Pressure: {e.New.Pressure}hPa");
            Console.WriteLine($"  Relative Humidity: {e.New.Humidity}%");
        };

        // get chip id
        Console.WriteLine($"ChipID: {bme280.GetChipID():X2}");            

        // get an initial reading
        ReadConditions().Wait();

        // start updating continuously
        bme280.StartUpdating();
    }

    protected async Task ReadConditions()
    {
        var conditions = await bme280.Read();
        Console.WriteLine("Initial Readings:");
        Console.WriteLine($"  Temperature: {conditions.Temperature}ºC");
        Console.WriteLine($"  Pressure: {conditions.Pressure}hPa");
        Console.WriteLine($"  Relative Humidity: {conditions.Humidity}%");
    }
}

Sample projects available on GitHub

Polling Mode

In polling mode, it is the responsibility of the main application to check the sensor readings ona periodic basis. The following application creates an instance of the BME280 class using the I2C interface. The temperature, pressure and humidity are read every second and the readings displayed using the debugger.

The sensor is put into polling mode by setting the updateInterval to 0 in the constructor.

public class MeadowApp : App<F7Micro, MeadowApp>
{
    public MeadowApp()
    {
        // Create a new BME280 object and put the sensor into polling
        // mode (update interval set to 0ms).
        Bme280 sensor = new Bme280(updateInterval: 0);

        string message;
        while (true)
        {
            // Make the sensor take new readings.
            sensor.Update();

            // Prepare a message for the user and output to the debug console.
            message = "Temperature: " + sensor.Temperature.ToString("F1") + " C\n";
            message += "Humidity: " + sensor.Humidity.ToString("F1") + " %\n";
            message += "Pressure: " + (sensor.Pressure / 100).ToString("F0") + " hPa\n\n";
            Console.WriteLine(message);

            // Sleep for 1000ms before repeating the process.
            Thread.Sleep(1000);
        }
    }
}

Wiring Example

The BME280 can be connected using I2C or SPI. Only 4 wires are required when using I2C:

  • 3.3V
  • Ground
  • SDA
  • SCL

It should be noted that the Sparkfun board is supplied with pull-up resistors enabled by default. The Adafruit board does not have any pull-up resistors onboard. It is therefore necessary to add two pull-up resistors (4.7 K should be adequate for a single device) between 3.3V and SDA and 3.3V and SCL.

Characteristic Locus
Inheritance System.Object ObservableBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>> SensorBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>> SamplingSensorBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>> > Bme280
Implements ITemperatureSensor IHumiditySensor IBarometricPressureSensor
Inherited Members SamplingSensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.StartUpdating(Nullable<TimeSpan>) SamplingSensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.StopUpdating() SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.Updated SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.samplingLock SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.SamplingTokenSource SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.Conditions SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.IsSampling SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.UpdateInterval SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.ReadSensor() SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.RaiseEventsAndNotify(IChangeResult<>) SensorBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.Read() ObservableBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.observers ObservableBase<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>.NotifyObservers(IChangeResult<>) Meadow.Foundation.ObservableBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>>.Subscribe(IObserver<>) Meadow.Foundation.ObservableBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>>.CreateObserver(Action<>, System.Nullable<Predicate<IChangeResult<UNIT>>>)
Namespace Meadow.Foundation.Sensors.Atmospheric
Assembly Bme280.dll

Syntax

public class Bme280 : SamplingSensorBase<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)>, ITemperatureSensor, IHumiditySensor, IBarometricPressureSensor

Constructors

Bme280(II2cBus, Byte)

Initializes a new instance of the BME280 class

Declaration
public Bme280(II2cBus i2cBus, byte address = null)

Parameters

Type Name Description
II2cBus i2cBus

I2C Bus to use for communicating with the sensor

System.Byte address

I2C address of the sensor (default = 0x77)

Bme280(IMeadowDevice, ISpiBus, IPin)

Initializes a new instance of the BME280 class

Declaration
public Bme280(IMeadowDevice device, ISpiBus spiBus, IPin chipSelectPin)

Parameters

Type Name Description
IMeadowDevice device

The meadow device used to create the chip select port

ISpiBus spiBus

The SPI bus connected to the BME280

IPin chipSelectPin

The chip select pin

Bme280(ISpiBus, IDigitalOutputPort)

Declaration
public Bme280(ISpiBus spiBus, IDigitalOutputPort chipSelect)

Parameters

Type Name Description
ISpiBus spiBus
IDigitalOutputPort chipSelect

Fields

compensationData

Compensation data from the sensor.

Declaration
protected Bme280.CompensationData compensationData

Field Value

Type Description
Bme280.CompensationData

configuration

Declaration
protected Bme280.Configuration configuration

Field Value

Type Description
Bme280.Configuration

readBuffer

Declaration
protected Memory<byte> readBuffer

Field Value

Type Description
Memory<System.Byte>

writeBuffer

Declaration
protected Memory<byte> writeBuffer

Field Value

Type Description
Memory<System.Byte>

Properties

Humidity

The humidity, in percent relative humidity, from the last reading..

Declaration
public RelativeHumidity? Humidity { get; }

Property Value

Type Description
System.Nullable<RelativeHumidity>

HumiditySampleCount

Declaration
public Bme280.Oversample HumiditySampleCount { get; set; }

Property Value

Type Description
Bme280.Oversample

Pressure

The pressure, in hectopascals (hPa), from the last reading. 1 hPa is equal to one millibar, or 1/10th of a kilopascal (kPa)/centibar.

Declaration
public Pressure? Pressure { get; }

Property Value

Type Description
System.Nullable<Pressure>

PressureSampleCount

Declaration
public Bme280.Oversample PressureSampleCount { get; set; }

Property Value

Type Description
Bme280.Oversample

Temperature

The temperature, in degrees celsius (°C), from the last reading.

Declaration
public Units.Temperature? Temperature { get; }

Property Value

Type Description
System.Nullable<Units.Temperature>

TemperatureSampleCount

Declaration
public Bme280.Oversample TemperatureSampleCount { get; set; }

Property Value

Type Description
Bme280.Oversample

Methods

GetChipID()

Declaration
public byte GetChipID()

Returns

Type Description
System.Byte

Initialize()

Declaration
protected void Initialize()

RaiseEventsAndNotify(IChangeResult<(Nullable<Units.Temperature> Temperature, Nullable<RelativeHumidity> Humidity, Nullable<Pressure> Pressure)>)

Declaration
protected override void RaiseEventsAndNotify(IChangeResult<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)> changeResult)

Parameters

Type Name Description
IChangeResult<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>> changeResult

ReadCompensationData()

Reads the compensation data.

Declaration
protected void ReadCompensationData()

Remarks

The compensation data is written to the chip at the time of manufacture and cannot be changed. This information is used to convert the readings from the sensor into actual temperature, pressure and humidity readings. From the data sheet, the register addresses and length are: Temperature and pressure: start address 0x88, end address 0x9F (length = 24) Humidity 1: 0xa1, length = 1 Humidity 2 and 3: start address 0xe1, end address 0xe7, (length = 8)

ReadSensor()

Update the sensor information from the BME280.

Declaration
protected override Task<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)> ReadSensor()

Returns

Type Description
Task<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>>

Overrides

Meadow.Foundation.SensorBase<System.ValueTuple<System.Nullable<Units.Temperature>, System.Nullable<RelativeHumidity>, System.Nullable<Pressure>>>.ReadSensor()

Remarks

Reads the raw temperature, pressure and humidity data from the BME280 and applies the compensation data to get the actual readings. These are made available through the Temperature, Pressure and Humidity properties. All three readings are taken at once to ensure that the three readings are consistent. Register locations and formulas taken from the Bosch BME280 datasheet revision 1.1, May 2015. Register locations - section 5.3 Memory Map Formulas - section 4.2.3 Compensation Formulas The integer formulas have been used to try and keep the calculations performant.

Reset()

Reset the sensor.

Declaration
public void Reset()

Remarks

Perform a full power-on-reset of the sensor and reset the configuration of the sensor.

StartUpdating(Nullable<TimeSpan>)

Declaration
public override void StartUpdating(TimeSpan? updateInterval = null)

Parameters

Type Name Description
System.Nullable<TimeSpan> updateInterval

UpdateConfiguration(Bme280.Configuration)

Update the configuration for the BME280.

Declaration
protected void UpdateConfiguration(Bme280.Configuration configuration)

Parameters

Type Name Description
Bme280.Configuration configuration

Remarks

This method uses the data in the configuration properties in order to set up the BME280. Ensure that the following are set correctly before calling this method:

  • Standby
  • Filter
  • HumidityOverSampling
  • TemperatureOverSampling
  • PressureOverSampling
  • Mode

Events

HumidityUpdated

Humidity changed event

Declaration
public event EventHandler<IChangeResult<RelativeHumidity>> HumidityUpdated

Event Type

Type Description
EventHandler<IChangeResult<RelativeHumidity>>

PressureUpdated

Pressure changed event

Declaration
public event EventHandler<IChangeResult<Pressure>> PressureUpdated

Event Type

Type Description
EventHandler<IChangeResult<Pressure>>

TemperatureUpdated

Temperature changed event

Declaration
public event EventHandler<IChangeResult<Units.Temperature>> TemperatureUpdated

Event Type

Type Description
EventHandler<IChangeResult<Units.Temperature>>