Getting Started with BME680 Breakout

This tutorial will show you how to solder your BME680 breakout, install and use the Python library, and suggest some uses for it. We'll go through the functions of the Python library, including how to read all of the various sensor values.

Note that the size and shape of our BME680 breakout has changed slightly as of June 2018. This has no effect on the way the breakout works whatsoever. Old and new versions will work interchangeably.

Soldering your BME680 breakout

There are a couple of options when it comes to soldering your BME680 breakout.

We've included a piece of right-angle socket header that you can solder on and then pop the breakout right onto pins 1, 3, 5, 7, and 9 of your Raspberry Pi (the bottom left 5 pins on the GPIO header, as shown above and below).

Note that it's important that you don't mount the sensor on your Pi's pins back to front, or it will cause damage to the sensor! The side of the board with the components on should be closest to the top edge of your Pi if you're using the right-angle header.

BME680 with right-angle female header

There's a piece of pin header that you can use if you plan to use socket-to-socket jumper wires or a breadboard with your breakout.

BME680 with standard male header

BME680 in breadboard, connected to Arduino

Or you can solder wires straight to the breakout if you plan to use the breakout in a more permanent, embedded setup.

If you're not a confident solderer, then you can check out our Ultimate Guide to Soldering for a bunch of tips on how to get started and how to improve your soldering.

Changing the default I2C address

The breakout has a default I2C address of 0x76, but this can be changed so that you can use up to two breakouts on the same Raspberry Pi or Arduino. To change the I2C address to 0x77, simply flow a small blob of solder across the two solder pads so that it bridges the pads. If you decide to change it back at a later date, then you can use a solder sucker or some solder braid to remove the solder and un-bridge the pads.

Close-up of mounted BME680 and solder pads

⚠ Note that on newer versions of this breakout, the I2C address is changed using a cuttable trace, so no soldering is required. Slice carefully through the narrow part of the trace using a craft knife or similar (watch your fingers!) to change the address to 0x77.

Installing the software

We always recommend using the most up-to-date version of Raspberry Pi OS, as this is what we test our boards and software against, and it often helps to start with a completely fresh install of Raspberry Pi OS, although this isn't necessary.

You'll need to have I2C enabled on your Raspberry Pi. You can do this using the Raspberry Pi Configuration menu or by typing sudo raspi-config in the terminal. The option to enable I2C is under 'Interface Options'.

Next, in the terminal, type the following to clone the repository and install it:

git clone https://github.com/pimoroni/bme680-python
cd bme680-python
sudo ./install.sh

The library should now be installed. You'll find the examples in bme680-python/examples (the installer will also give you an option to copy them to /home/pi/Pimoroni/bme680/examples).

You can also use pip to install the BME680 library, as follows, although you'll have to download the examples separately:

sudo pip install bme680

Or you can use our one-line-installer, which should set up and install everything in one go, and download the examples into the /home/pi/Pimoroni/bme680/examples folder:

curl https://get.pimoroni.com/bme680 | bash

Running the built-in example and burning in the sensor

We've included an example that prints out all of the sensor readings - the temperature, pressure, humidity, and gas resistance value - continuously.

In our testing, we've found that it helps to run the sensor for at least 20 minutes the first time that you use it, to "burn in" the sensor. The sensor's readings, especially the gas resistance readings, will drift gradually and then stabilise after a while. This drift will happen every time you start taking readings but, after the initial burn-in, the readings should stabilise fairly quickly each time, usually after a couple of minutes.

To run the example, type the following:

cd /home/pi/Pimoroni/bme680/examples
python read-all.py

Leave the example running for a couple of minutes, or for at least 20 minutes if you haven't run it before (watch for the gas resistance readings stabilising). You can press control-c to stop the example running.

If you want to log the sensor values to a text file, then it's simple to do that by redirecting the output of the program to a text file in the terminal, as follows:

python read-all.py > bme680-data.txt

Note that the values are comma-separated, so you should be able to import them into a spreadsheet to plot them fairly easily.

Imports and configuring the sensor

Reading the sensor values on the BME680 is fairly straightforward, but requires quite a few configuration values to be set initially. You can also run the sensor in two different "modes" - with or without gas readings being taken - and if gas readings aren't taken and just temperature, pressure, and humidity readings are taken, then you can sample data much more quickly.

When gas readings are being taken, because the gas measurement requires the hot plate inside the sensor to be heated, the temperature, pressure, and humidity readings will be taken first to minimise the effect of the hot plate on the temperature reading.

We'll look first at the library import and the configuration settings. Open a terminal window, type python to open a Python prompt, and then type the following:

import bme680
import time

sensor = bme680.BME680()

sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)

sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
sensor.set_gas_heater_temperature(320)
sensor.set_gas_heater_duration(150)
sensor.select_gas_heater_profile(0)

We'll go through quickly what the above means, but most of it can be left unmeddled with in the majority of cases.

First, we import the bme680 and time libraries. We'll be using the time library to introduce a small delay between each reading of the sensor.

sensor = bme680.BME680() creates an instance of the sensor, that we'll use to set the settings and take the readings from.

The _oversample settings that are set for the humidity, pressure, and temperature set a balance between accuracy of reading and amount of noise. The higher the oversampling, the greater the reduction in noise, albeit with a loss of accuracy.

The filter protects sensor readings against transient changes in conditions, e.g. a door slamming will cause the pressure to change momentarily, and the IIR filter will filter out these transient spiky values.

The gas measurement has a few settings that can be tweaked. It can be enabled or disabled with set_gas_status. Disabling it allows the other readings to be taken more rapidly, as mentioned above. The temperature and duration that the hot plate is held at that temperature can be altered, although we'd recommend not altering these settings if your gas resistance readings look sensible.

BME680 Not Found? If you're using a breakout that's been modified to use the alternate I2C address you'll need to specify the address when you create a sensor instance, you can do this using the constants stored in the library like this:

sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)

(the Github examples will try both addresses automatically).

Reading data from the sensor

Data can be read from the sensor as follows:

while True:
    if sensor.get_sensor_data():
        output = "{0:.2f} C,{1:.2f} hPa,{2:.2f} %RH".format(sensor.data.temperature, sensor.data.pressure, sensor.data.humidity)

        if sensor.data.heat_stable:
            print("{0},{1} Ohms".format(output, sensor.data.gas_resistance))

        else:
            print(output)

    time.sleep(1)

You'll see that the temperature, pressure, and humidity can be read with sensor.data.temperature, sensor.data.pressure, and sensor.data.humidity respectively (the units are degrees Celsius, hectoPascals, and % relative humidity).

The gas is read with sensor.data.gas_resistance and will return a resistance reading in Ohms, up to several hundred thousand Ohms (there's more on how to interpret these readings in the section below).

There are a couple of extra lines - if sensor.get_sensor_data(): and if sensor.data.heat_stable: - that ensure that readings are ready to be taken. They both return Boolean values, True or False.

The lines that format the output look a little scary, but they're just placeholders that let you format the values nicely. We'll go through how it works.

output = "{0:.2f} C,{1:.2f} hPa,{2:.2f} %RH".format(sensor.data.temperature, sensor.data.pressure, sensor.data.humidity)

The parts in the curly brackets - {0:.2f} - are placeholders. The first 0 is the index of the placeholder (you'll see the others are 1 and 2). The remaining bit - :.2f - tells it that the number is a floating point number (f), and to use two decimal places after the decimal point (.2). Then in the round brackets, after .format, we pass it the three values that we want to replace the placeholders with - sensor.data.temperature, sensor.data.pressure, sensor.data.humidity.

There's a great explanation of all of the different string formatting options at the PyFormat site.

After checking that the gas heater is stable, we also place the gas resistance reading into our formatted output string - "{0},{1} Ohms".format(output, sensor.data.gas_resistance).

Finally, a time.sleep(1) introduces a small pause between readings.

Interpreting the gas resistance readings

The sensor produces gas resistance readings in Ohms. These will range from the low thousands up to several hundred thousand Ohms. Every time that you use the sensor, it will take a few minutes (or more if it's the first time you've used it) to stabilise; you'll see the readings creeping upwards. When the readings stabilise, this will be your background reference reading.

If the air quality increases, then the gas resistance reading will increase, and if the air quality decreases, then the gas resistance reading will decrease also. You can test it out by holding something like a permanent marker, or spraying a little perfume on a piece of tissue and holding it near the sensor (always take care when using solvents, don't let children do this part, and make sure that your room is well-ventilated).

In our example of how to convert the BME680's gas resistance readings into a percentage indoor air quality (IAQ), we took a background reading for 5 minutes, then set this as the optimal gas resistance reading (100%), and also factored in humidity with a weighting of 75:25 for gas:humidity, as humidity also has an effect on IAQ (a relative humidity of 40% is optimal).

Taking it further

Why not visualise the gas resistance readings with one of our LED boards? There's an example in the BME680 Python library of how you might translate the gas resistance readings into a friendlier percentage air quality, which you could then map to a colour.

The gas reading in the BME680 should be sensitive to a wide range of different gases, like methane and other volatile organic compounds (VOCs), carbon monoxide, ethanol, human breath and sweat, and more, so you can really have some fun creating fart detectors or even a crude breathalyser!

That's all folks!

Search above to find more great tutorials and guides.

Plasma 2040

Swathe everything in rainbows with this all-in-one, USB-C powered controller for WS2812/Neopixel and APA102/Dotstar addressable LED strip.