Get BME280 readings in openHABian with MQTT

Get BME280 readings in openHABian with MQTT

Bosch’s BME280 is a popular environmental sensor that can measure temperature, humidity and pressure. The purpose of this how-to is to explain how to configure a OpenHABian system running in a Paspberry Pi to get the sensor’s readings as [OpenHAB Items](Items | openHAB).

I got a general idea of what needed to be done from this discussion. I got help about the specific steps from Claude AI. My experience in Linux systems was useful. I thought it would be helpful to put it in straightforward how-to that anybody could follow.

The set-up used in this how-to is as follows:

  • Raspberry Pi 4b, 4Gbytes
  • Linux OpenHABian 6.12.25
  • OpenHAB 5.0.2
  • BME280 module board (Pimoroni’s)

Connect the BME280 to the Raspberry Pi

There are several tiny electronic boards that contain the sensor and allow direct connection to the Raspberry’s GPIO. It’s my understanding that most boards are compatible with either Adafruit’s or Pimoroni’s boards. These are the only two types that will be covered in this how-to. You will find which type you have in the process below.

The boards have at least four pins, labeled in different ways. You only need to connect four. You should find the specific connection mapping for your board. In my case, I connected it as follows:

BME280 board GPIO Pin GPIO Function
VCC 1 3v3 Power
GND 9 Ground
SCL 5 GPIO 3 (I2C1 SCL)
SDA 3 GPIO 2 (I2C1 SDA)

You can use other GPIO pins for 3v3 power and ground. For example, I have seen schemas connecting GND to pin 6. In my case, that pin is taken by the power supply of the touch display.

Enable I2C

Start the Rasbperry configuration:

sudo raspi-config

Navigate to Interface Options > I2C and answer Yes to enable the I2C interface.

Run this to check if the BME280 board is detected:

sudo i2cdetect -y 1

You should see a number “76” or “77”, depending on the type of you board:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --# 

“76” means that my board is Pimoroni-compatible. If you see “77”, yours is Adafruit-compatible.

Get readings with a Python script

The system’s default Python environment won’t let you install the modules needed to communicate with the card, so you need to create a virtual environment. Let’s create one in the $HOME directory, in a subdirectory named mypyenv. You may want to use a hidden directory (starting with a dot) like .mypyenv:

cd $HOME
python -m venv mypyenv

Now you need to install the modules. You have two options, install modules for Adafruit or Pimoroni. You can use either with any of the board types, but I suppose it makes more sense to use the one that matches your board. I’m going to show you examples for both, but you only need one of them.

Adafruit

Install the Python modules to communicate with an Adafruit BME280 board:

$HOME/mypyenv/bin/pip3 install adafruit-circuitpython-bme280

Write a script to check that you can get readings from the board. Let’s call it bme280_test.py and place it in the $HOME directory:

import time
import board
import adafruit_bme280.advanced as adafruit_bme280

# --- Initialize sensor ---
i2c = board.I2C()
bme = adafruit_bme280.Adafruit_BME280_I2C(i2c)

# --- Print readings ---
while True:
    temperature = bme.temperature
    humidity = bme.humidity
    pressure = bme.pressure / 100.0
    print(f"Temp: {temperature:.2f} °C | Humidity: {humidity:.2f} % | Pressure: {pressure:.2f} hPa")
    time.sleep(2)

Run the script:

 $HOME/mypyenv/bin/python3 $HOME/bme280_test.py

You should get something like:

Temp: 22.28 °C | Humidity: 45.26 % | Pressure: 10.18 hPa
Temp: 22.27 °C | Humidity: 45.07 % | Pressure: 10.18 hPa
Temp: 22.27 °C | Humidity: 45.04 % | Pressure: 10.18 hPa

I don’t know if all boards return the same units. If you don’t like them, you can convert them in the script. In the script above, the pressure reading is divided by 100 to convert Pascals to Hectopascals.

I actually get the following because my board is Pimoroni’s:

ValueError: No I2C device at address: 0x77

I just need to change line number 7 in the script to make it work:

bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76)

Pimoroni

Install the Python modules to communicate with a Pimoroni BME280 board:

$HOME/mypyenv/bin/pip3 install pimoroni-bme280

The bme280_test.py script should be as follows:

import time
from smbus2 import SMBus
from bme280 import BME280

# Initialize sensor
bus = SMBus(1)
bme = BME280(i2c_dev=bus)

# Print readings
while True:
    temperature = bme.get_temperature()
    humidity = bme.get_humidity()
    pressure = bme.get_pressure() / 100.0
    print(f"Temp: {temperature:.2f} °C | Humidity: {humidity:.2f} % | Pressure:
{pressure:.2f} hPa")
    time.sleep(2)

I don’t have an Adafruit board, so I cannot test how to make Pimoroni’s modules work with such board.

The rest of this how-to will be based on Pimoroni’s modules. Change the imports and the sensor initialization if you want to use Adafruit’s.

Send the readings through the MQTT broker

The expected way to send these readings to OpenHAB is through a MQTT broker, so let’s do that. Run the following command to install Mosquitto:

sudo openhabian-config

Navigate to Optional Components > Mosquitto and select Continue. It will ask you for a MQTT-User and password. We will later need to write these in a file in plain text, so don’t use any of your secret passwords. Create a dedicated user and password for this purpose.

You may not need to do this the first time; but just in case, restart the Mosquitto service to apply the changes:

sudo systemctl restart mosquitto

You need to install the [Paho MQTT Client](client module — Eclipse paho-mqtt documentation) to be able to connect to the MQTT broker in Python:

 $HOME/mypyenv/bin/pip3 install paho-mqtt

Let’s write the final Python script to read the BME280 sensor and publish the readings in the MQTT broker in intervals of time.

In the example below, all the configuration parameters are defined as variables at the beginning of the script. You don’t have to bother with the rest of the script. Here is where you have put the MQTT user and password you entered before. You may choose any MQTT topics and time interval you like.

You probably want to have this script running in the background all the time, so I recommend you to put it in a hidden directory to avoid accidental deletion. For the sake of simplicity of this tutorial, we will put the script in a file named bme280_mqtt.py in the $HOME directory:

import time
import signal
import sys
from smbus2 import SMBus
from bme280 import BME280
import paho.mqtt.client as mqtt

# --- Configuration ---
MQTT_HOST = "localhost"
MQTT_PORT = 1883
MQTT_USER = "YOUR_MQTT_USER"
MQTT_PASSWORD = "YOUR_MQTT_PASSWORD"
MQTT_TOPIC_TEMP = "bme280/temperature"
MQTT_TOPIC_HUM = "bme280/humidity"
MQTT_TOPIC_PRESS = "bme280/pressure"
INTERVAL = 10  # seconds

# --- Handle graceful termination
running = True

def handle_signal(sig, frame):
    global running
    running = False

signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGINT, handle_signal)

# --- Initialize sensor ---
bus = SMBus(1)
bme = BME280(i2c_dev=bus)

# --- Initialize MQTT client ---
client = mqtt.Client(
    protocol=mqtt.MQTTv311,
    callback_api_version=mqtt.CallbackAPIVersion.VERSION2
)
client.username_pw_set(MQTT_USER, MQTT_PASSWORD)
client.connect(MQTT_HOST, MQTT_PORT, 60)
client.loop_start()

# --- Publish loop ---
try:
    while running:
        temperature = bme.get_temperature()
        humidity = bme.get_humidity()
        pressure = bme.get_pressure() / 100.0

        client.publish(MQTT_TOPIC_TEMP, f"{temperature:.2f}")
        client.publish(MQTT_TOPIC_HUM, f"{humidity:.2f}")
        client.publish(MQTT_TOPIC_PRESS, f"{pressure:.2f}")

        time.sleep(INTERVAL)

# --- Termination
finally:
    client.loop_stop()
    client.disconnect()
    bus.close()

Run the script:

$HOME/mypyenv/bin/python3 $HOME/bme280_mqtt.py

The script runs in an infinite loop until you interrupt it with CTRL+C. When you do, it will take a few seconds to close the connections before stopping.

Keep the script running and open another terminal window to test it. In the new terminal, run the following command to print the readings published in the MQTT topics:

mosquitto_sub -h localhost -t "bme280/#" -v -u YOUR_MQTT_USER -P YOUR_MQTT_PASSWORD

If you get lines like this every ten seconds, everything is working as expected:

bme280/temperature 21.39
bme280/humidity 46.16
bme280/pressure 10.25

Run the script in a systemd service

You probably want to have the script running in the background from the moment the system starts. For that, you need to create a systemd service. You need to put a new service file in the /etc/systemd/system. Let’s name it bme280mqtt.service:

[Unit]
Description=BME280 MQTT Publisher
After=mosquitto.service

[Service]
User=openhabian
WorkingDirectory=/home/openhabian
ExecStart=/home/openhabian/mypyenv/bin/python3 /home/openhabian/bme280_mqtt.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Here we cannot use environment variables like $HOME, so you need to make all the values explicit. This service file assumes the following:

  • The Python virtual environment is in /home/openhabian/mypyenv.

  • The script is in /home/openhabian/bme280_mqtt.py.

Otherwise, change the values accordingly.

You need to let the system know about the new service:

sudo systemctl daemon-reload

Enable the service:

sudo systemctl enable bme280mqtt.service

And start it:

sudo systemctl start bme280mqtt.service

Make sure you are not running the script with the python3 command. You should still get the readings with the same mosquitto_sub command you used before. For the final test, restart the system:

sudo reboot

If you still get the readings with mosquitto_sub command without doing anything else, you have achieved the goal of this section and the trickiest part of this how-to.

Get BME280’s readings as Items in OpenHAB

The rest of this how-to concerts OpenHAB configuration. I’m going to assume you are experienced with it and there is plenty of documentation in the website, so I will be brief. I’m a newbie in this area, so it’s likely that something in the configuration below is wrong or not optimal. Let me know and I will fix it.

First you need to install the MQTT Binding add-on. With it, create a Thing with three Channels. This is an example of a working configuration for what we have done so far:

UID: mqtt:broker:debc5cb380
label: Local MQTT
thingTypeUID: mqtt:broker
configuration:
  lwtQos: 0
  publickeypin: true
  clientid: a7b3289f-187f-455e-8179-eb81f5e79e4e
  keepAlive: 60
  hostnameValidated: true
  birthRetain: true
  secure: false
  certificatepin: true
  shutdownRetain: true
  password: YOUR_MQTT_PASSWORD
  protocol: TCP
  qos: 0
  reconnectTime: 60000
  port: 1883
  mqttVersion: V3
  host: localhost
  lwtRetain: true
  enableDiscovery: true
  username: YOUR_MQTT_USER
channels:
  - id: BME280Temperature
    channelTypeUID: mqtt:publishTrigger
    label: Temperature
    description: ""
    configuration:
      stateTopic: bme280/temperature
  - id: BME280Humidity
    channelTypeUID: mqtt:publishTrigger
    label: Room humidity
    description: ""
    configuration:
      stateTopic: bme280/humidity
  - id: BME280Pressure
    channelTypeUID: mqtt:publishTrigger
    label: Room pressure
    description: ""
    configuration:
      stateTopic: bme280/pressure

And finally, create an Item for each of the Channels. My pitfall here was to figure out that the type must be String, not Number. For example, for temperature:

label: Room temperature
type: String
icon: temperature
groupNames: []
tags:
  - Measurement
  - Temperature

That’s it. I hope this is useful. Let me know how I can improve this how-to, I appreciate your feedback.

1 Like

Personally I‘d take the ESP32/Tasmota route. Probably cheaper and smaller / easier to hide it somewhere. I once retrofitted an INEA Vindrikting: IKEA Vindriktning Air Quality Sensor - #418 by Goram - Share your Projects! - Home Assistant Community

Thanks for your feedback. I chose the RPi for its hardware and software ecosystem, besides being the system I’m familiar with. I plan to install it in a wall with a touch display and a KNX interface, to replace my current home automation panel. In any case, the choice of hardware is not within the scope of this how-to. I’m just describing the environment this how-to applies to, not advocating for it.

By the way, getting the OpenHAB UI in the RPi Touch Display is the how-to I’m currently working on, but I’m still figuring it out.

I ammended the last part of the tutorial as I learnt more things about OpenHAB configuration. As mentioned, I don’t have much experience in that area.