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
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
.
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
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
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 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
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