All Articles

Raspberry pi temperature monitor using bme280, prometheus and grafana

Grafana

What we’ll do

Short walk-through for building a home temperature, humidy and pressure sensor by attaching a BME280 sensor to a raspberry pi, using prometheus to build a timeseries for temperature, humidy and pressure and grafana to visualize it in a nice dashboard.

All the services are running as docker containers using docker-compose.

Running project: on github

Dashboard snapshot: snapshot

The sensor

I’ve used this sensor but you can use anything you have.

First of all, depending on what you’re using you have to make sure the i2c interface is enabled. For me it was just running apt install i2c-tools.

To connect the sensors and be able to use it on the raspberry pi I’ve followed this tutorial. The script I’m using is different though, we’ll get to that later.

After connecting the sensor check that it’s connected using sudo i2cdetect -y 1.

The script

After the sensor is there it’s time to read the temperature in a proper way. We plan on using prometheus so the readings have to be in a format which can be understood by prometheus.

In the script I’m using the bme280 library to easily read the sensor output and then manually format it for prometheus.

Embedded from https://github.com/ecyshor/pi-temperature-monitor/blob/main/read-temp.py

import smbus2
import bme280

port = 1
address = 0x76
bus = smbus2.SMBus(port)

calibration_params = bme280.load_calibration_params(bus, address)

# the sample method will take a single reading and return a
# compensated_reading object
data = bme280.sample(bus, address, calibration_params)


def print_gauge(name, value, text):
    print(f'# HELP {name} {text}')
    print(f'# TYPE {name} gauge')
    print(f'{name} {value}')


# the compensated_reading class has the following attributes
print_gauge("temperature", data.temperature, "Temperature in celsius")
print_gauge("pressure", data.pressure, "Pressure")
print_gauge("humidity", data.humidity, "Humidity percentage")

Check the original code here

HTTP output from script

For that I’ve written a simple http service, scaap which can be configured to run a script and return the output for each http request. This means each time prometheus scrapes our service it will execute the python script to read the temperature.

The scaap configuration:

Embedded from https://github.com/ecyshor/pi-temperature-monitor/blob/main/scaap.toml

[[script]]
name = "temperature"
command = "python3"
arguments = ["/etc/scaap/read-temp.py"] 

Check the original code here

Required dependencies for the script are installed in the scaap runtime init script:

Embedded from https://github.com/ecyshor/pi-temperature-monitor/blob/main/init-runtime.sh

#!/bin/sh
set -ex
apt-get update && apt-get -y install python3 python3-pip
pip3 install smbus2 RPi.bme280

Check the original code here

The scripts runs inside the container so this means that the i2c device has to be mapped into the docker container. For my usecase this is where I map the device

Docker setup

This is all we need to be able to configure the docker-compose file

Embedded from https://github.com/ecyshor/pi-temperature-monitor/blob/main/docker-compose.yml

version: "3"
services:
  prometheus:
    image: prom/prometheus:latest
    user: "1000:1000"
    container_name: prometheus
    restart: unless-stopped
    ports:
      - 9090:9090
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --storage.tsdb.retention.time=2y
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./prometheus/data:/prometheus
    depends_on:
      - scaap
  grafana:  
    image: grafana/grafana
    restart: unless-stopped
    user: "1000:1000"
    depends_on:
      - prometheus
    ports:
      - 3000:3000
    volumes:
      - ./grafana/data:/var/lib/grafana #grafana data storage
  scaap:
    image: ghcr.io/ecyshor/scaap:latest
    ports:
      - "3030:3030"
    volumes:
      - .:/etc/scaap/:ro # map the config and scripts
    restart: unless-stopped
    devices:
      - "/dev/i2c-1:/dev/i2c-1" #map the sensor inside the container so we can access it

Check the original code here

Prometheus config

Prometheus is configured automatically to call the scrip through the http service every 15s:

Embedded from https://github.com/ecyshor/pi-temperature-monitor/blob/main/prometheus/prometheus.yml

scrape_configs:
- job_name: temperature 
  scrape_interval: 5s
  metrics_path: /script/temperature
  static_configs:
  - targets:
    - scaap:3030

Check the original code here

Access

Once you start everything using docker-compose up you can access grafana using localhost:3000

The dashboard is not automatically provisioned but you can easily import it using following json

Go to dashboard json

Published Dec 5, 2020

Software engineer.