Raspberry Pi: BME280 Temperature, Humidity and Pressure Sensor (Python)

Learn how to interface the BME280 sensor with the Raspberry Pi to get temperature, humidity, and pressure readings. You’ll learn how to connect the sensor to the Raspberry Pi board and write a Python script that gets sensor data and displays it on the terminal.

Raspberry Pi Getting Started BME280 Pressure Temperature Humidity Sensor Python

Table of Contents

Throughout this tutorial, we’ll cover the following topics:

Prerequisites

Before continuing with this tutorial, check the following prerequisites.

  1. Get familiar with the Raspberry Pi board—if you’re not familiar with the Raspberry Pi, you can read our Raspberry Pi Getting Started Guide here.
  2. You must know how to run and create Python files on your Raspberry Pi. We like to program our Raspberry Pi via SSH using an extension on VS Code. We have a detailed tutorial about that subject: Programming Raspberry Pi Remotely using VS Code (Remote-SSH).
  3. Know how to use the Raspberry Pi GPIOs so that you know how to wire the circuit properly. Read the following tutorial: Raspberry Pi Pinout Guide: How to use the Raspberry Pi GPIOs?

Introducing BME280 Sensor Module

The BME280 sensor module reads barometric pressure, temperature, and humidity. Because pressure changes with altitude, you can also estimate altitude. There are several versions of this sensor module. We’re using the module illustrated in the figure below.

BME280 Sensor I2C Module reads pressure, temperature, and humidity

This sensor communicates using I2C communication protocol, so the wiring is very simple. You can use the default Raspberry Pi I2C pins as shown in the following table:

BME280Raspberry Pi
Vin3.3V
GNDGND
SCLGPIO 3
SDAGPIO 2

Learn more about the Raspberry Pi GPIOs: Raspberry Pi Pinout Guide: How to use the Raspberry Pi GPIOs?

Parts Required

Raspberry Pi with BME280 Sensor

Here’s a list of parts you need to build the circuit:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Enable I2C on the Raspberry Pi

I2C communication is not enabled by default. You need to enable it manually. Open a terminal window on your Raspberry Pi and type the following command:

sudo raspi-config

The following menu will open. Select Interface Options.

Raspberry Pi Enable I2C communication

Then, select the I2C option.

Raspberry Pi Enable I2C communication

Finally, enable I2C by selecting Yes.

Raspberry Pi Enable I2C communication

I2C should be successfully enabled.

Raspberry Pi I2C communication enabled

After enabling I2C, reboot your Raspberry Pi by running the following command:

sudo reboot

Wiring the BME280 to the Raspberry Pi

Wire the BME280 to the Raspberry Pi default I2C pins.

Raspberry Pi Wiring BME280 Diagram
BME280Raspberry Pi
Vin3.3V
GNDGND
SCLGPIO 3
SDAGPIO 2

Getting the Sensor I2C Address

With the sensor connected to the Raspberry Pi, let’s check if the sensor is connected properly by searching for its I2C address.

Open a Terminal window on your Raspberry Pi and run the following command:

sudo i2cdetect -y 1

It should show your sensor I2C address:

BME280 Getting BME280 I2C Address

Install BME280 Library

There are several libraries compatible with the Raspberry Pi to read from the BME280 sensor. We’ll be using the RPi.BME280 library. This library is available to install through PIP (a package manager for Python packages).

First, install or upgrade pip by running the following command:

sudo pip install --upgrade pip

Then, run the following command to install the library using pip:

sudo pip install RPI.BME280

Python Code for Raspberry Pi BME280 (Temperature, Humidity, and Pressure)

The following script gets temperature, humidity, and pressure from the BME280 sensor and prints the readings on the Python shell. Create a new Python file with a name of your choice, for example, bme280_basic.py, and copy the following code.

import time
import smbus2
import bme280

# BME280 sensor address (default address)
address = 0x76

# Initialize I2C bus
bus = smbus2.SMBus(1)

# Load calibration parameters
calibration_params = bme280.load_calibration_params(bus, address)

def celsius_to_fahrenheit(celsius):
    return (celsius * 9/5) + 32

while True:
    try:
        # Read sensor data
        data = bme280.sample(bus, address, calibration_params)

        # Extract temperature, pressure, and humidity
        temperature_celsius = data.temperature
        pressure = data.pressure
        humidity = data.humidity

        # Convert temperature to Fahrenheit
        temperature_fahrenheit = celsius_to_fahrenheit(temperature_celsius)

        # Print the readings
        print("Temperature: {:.2f} °C, {:.2f} °F".format(temperature_celsius, temperature_fahrenheit))
        print("Pressure: {:.2f} hPa".format(pressure))
        print("Humidity: {:.2f} %".format(humidity))

        # Wait for a few seconds before the next reading
        time.sleep(2)

    except KeyboardInterrupt:
        print('Program stopped')
        break
    except Exception as e:
        print('An unexpected error occurred:', str(e))
        break

View raw code

How the Code Works

Continue reading to learn how the code works, or skip to the Demonstration section.

Import Required Libraries

First, we import the required libraries: time, smbus2, and bme280. The time module lets us add delays in our code, smbus2 helps us communicate with I2C devices like the BME280 sensor, and bme280 provides functions to easily interact with the sensor.

import time
import smbus2
import bme280

Initialize the BME280 Sensor

We set the default address of the BME280 sensor to 0x76. This is the address that the sensor communicates with over the I2C bus (check this previous section).

# BME280 sensor address (default address)
address = 0x76

We then initialize the I2C bus using the smbus2.SMBus(1) command.

# Initialize I2C bus
bus = smbus2.SMBus(1)

Then, we initialize the sensor by setting the I2C bus and its I2C address.

# Load calibration parameters
calibration_params = bme280.load_calibration_params(bus, address)

Convert Celsius to Fahrenheit

We define a function called celsius_to_fahrenheit(celsius) which converts temperature from Celsius to Fahrenheit. Then, we can call this function later on in our code to convert the temperature.

def celsius_to_fahrenheit(celsius):
    return (celsius * 9/5) + 32

Getting Sensor Readings

We enter an infinite loop using while True to repeatedly read and display sensor data.

while True:

We use the bme280.sample(bus, address, calibration_params) function to read sensor data.

data = bme280.sample(bus, address, calibration_params)

We extract the temperature, pressure, and humidity from the data returned by the sensor and save each reading on a variable: temperature_celsius, pressure, and humidity.

# Extract temperature, pressure, and humidity
temperature_celsius = data.temperature
pressure = data.pressure
humidity = data.humidity

We convert the temperature from Celsius to Fahrenheit using the function we created previously and save it in the temperature_fahrenheit variable.

# Convert temperature to Fahrenheit
temperature_fahrenheit = celsius_to_fahrenheit(temperature_celsius)

Finally, we print the readings formatted with two decimal places:

# Print the readings
print("Temperature: {:.2f} °C, {:.2f} °F".format(temperature_celsius, temperature_fahrenheit))
print("Pressure: {:.2f} hPa".format(pressure))
print("Humidity: {:.2f} %".format(humidity))

New readings are printed every two seconds. You can adjust the time between each sample by adding a different number to the sleep() method.

time.sleep(2)

Handle Interruptions and Exceptions

We use exception handling to catch keyboard interrupts (when the user presses Ctrl+C) and other exceptions. If this happens, we print an error message and use the break command to get out of the loop.

except KeyboardInterrupt:
    print('Program stopped')
    break
except Exception as e:
    print('An unexpected error occurred:', str(e))
    break

Demonstration

Save your Python file. Then run it on your Raspberry Pi. Run the following command on the directory of your Python file:

python bme280_basic.py

You should get new temperature, humidity, and pressure readings on the Python Shell or on the Raspberry Pi Terminal every three seconds.

Raspberry Pi BME280 Readings Python Terminal

You can stop the execution of the program by pressing CTRL+C.

Wrapping Up

In this tutorial, you learned how to interface the BME280 temperature, humidity, and pressure sensor with the Raspberry Pi and how to write a Python program to get and display readings. This is one of the simplest examples to get you started using the BME280 sensor.

We hope you found this tutorial useful. If you’re a beginner to the Raspberry Pi, you can get started with the following tutorials:

You can check all our Raspberry Pi projects on the following link:

Finally, if you would like to interface the BME280 with other microcontrollers, we have tutorials for ESP32, ESP8266, and Arduino:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

15 thoughts on “Raspberry Pi: BME280 Temperature, Humidity and Pressure Sensor (Python)”

  1. Hi Sara.
    Nice tutorial, it’s great that there are more raspberry pi on the market again,
    and the prices of the bme280 modules have also dropped again.

    Reply
  2. Good luck getting one that isn’t a copy. I had a batch at only one even came close. Seems to be a huge range of knock offs in this sector.

    Reply
      • Oh dear, that’s on me Sara.

        I was referring to the entire line of these MEMS pressure/humidity & temperature sensors. To the best of my knowledge, the Picos are all OEM parts.

        I think there’s a brisk trade in the (fake) sensors because they are in most modern cars these days (and lots of other places) because they form part of the A/C.

        Reply
          • This extends even to the 680s which are also sold on the “black” market.

            They identify themselves over IIC as the correct part but give out readings that are clearly not even close to what they should be. I got about 20 of the BME280s and not a single one worked as it should. Took me a couple of goes with the (more expensive) 680 to find on that was the real deal.

            It’s not surprising really – considering that these Chinese fake manufacturers have even cloned relative cheap ICs like the XR2206 – and that goes back years. You can tell you have a fake as the real one operates all the way to its specified maximum voltage whereas the fakes work up to around 12V (far more than most stuff works at these days) but above that they go wonky.

            I suspect the others are just whatever they can get cheap and then they remove the marking and replace it with markings from the more expensive chip. That’ll teach me to use DigiKey or Mouser rather than some fly-by-night seller on eBay based in China. 😉

  3. on the new raspberry os bookworm you have to use

    sudo pip install –upgrade pip –break-system-packages
    sudo pip install RPI.BME280 –break-system-packages

    otherwise you will get this message
    error: externally-managed-environment

    × This environment is externally managed
    ╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install

    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Spouse
    make sure you have python3-full installed.

    For more information visit http://rptl.io/venv

    note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing –break-system-packages.

    Reply
  4. The way to set up a static ip address has also changed,
    but this should work.
    sudo nmcli con mod “your ssid” ipv4.addresses “192.168.0.250/24” ipv4.gateway “192.168.0.1” ipv4.dns “8.8.8.8” ipv4.method manual
    sudo systemctl restart NetworkManager

    Does anyone here know how to
    Create wireless access point on the new bookworm,
    unfortunately that has also changed

    Reply
    • I got my raspberrypi set up as an access point with this.
      Just find the mac address of your pi with ifconfig, under wlan0 ether and change this to yours.
      sudo nmcli con modify TEST-AP wifi.cloned-mac-address d8:3a:dd:32:7b:cb

      #sudo nmcli con delete TEST-AP
      sudo nmcli con add type wifi ifname wlan0 mode ap con-name TEST-AP ssid TEST autoconnect true
      sudo nmcli con modify TEST-AP wifi.band bg
      sudo nmcli con modify TEST-AP wifi.channel 7
      sudo nmcli con modify TEST-AP wifi.cloned-mac-address d8:3a:dd:32:7b:cb
      sudo nmcli con modify TEST-AP wifi-sec.key-mgmt wpa-psk
      sudo nmcli con modify TEST-AP wifi-sec.proto rsn
      sudo nmcli con modify TEST-AP wifi-sec.group ccmp
      sudo nmcli con modify TEST-AP wifi-sec.pairwise ccmp
      sudo nmcli con modify TEST-AP wifi-sec.psk “yourpassword”
      sudo nmcli con modify TEST-AP ipv4.method shared ipv4.address 192.168.4.1/24
      sudo nmcli con modify TEST-AP ipv6.method disabled
      sudo nmcli con up TEST-AP

      Reply
  5. Hi.
    Remember to change the Quotation mark,
    as they are not shown correctly here.
    by the way raspberry pi zero 2w runs fine on raspberry os bookworm 64 bit.

    Reply
  6. Hi.
    adafruit drivers work pretty well too
    with this
    sudo pip3 install adafruit-circuitpython-bme280

    #!/usr/bin/python3

    import board
    import time

    import adafruit_bme280.advanced as adafruit_bme280

    Create sensor object, using the board’s default I2C bus.

    i2c = board.I2C() # uses board.SCL and board.SDA
    #bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
    bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76)

    bme280.mode = adafruit_bme280.MODE_NORMAL
    bme280.standby_period = adafruit_bme280.STANDBY_TC_500
    bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16
    bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
    bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1
    bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2
    time.sleep(35/1000)

    print(bme280.temperature)
    print(bme280.relative_humidity)
    print(bme280.pressure)

    Reply
  7. Hi Sara,
    I can get the BME280 to work fine on ESP32, but when I try to run it on my Pi3 I get the error
    “Traceback (most recent call last):
    File “”, line 12, in
    AttributeError: module ‘bme280’ has no attribute ‘populate_calibration_data’
    I hoping you can offer some insight as to why.

    Tom

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.