Read CO2, temperature, humidity, pressure, and battery from an Aranet4 sensor over Bluetooth LE and log to a local SQLite database. Visualise with Grafana.
Designed to run on a Raspberry Pi via crontab.
- Raspberry Pi (tested on Pi 4 / Pi 5) with Bluetooth
- Raspberry Pi OS (Bookworm or later)
- Bluetooth enabled and running (
sudo systemctl status bluetooth) - Python 3.9+ (pre-installed on Bookworm)
- uv (
curl -LsSf https://astral.sh/uv/install.sh | sh) - Grafana + SQLite datasource plugin (installed in steps 8-9 below)
- An Aranet4 sensor within Bluetooth range
- Smart Home integrations enabled in the Aranet Home phone app (device settings) — required for BLE data access
All shell commands below work in both bash and fish.
git clone https://github.com/12ian34/aranet4-dash.git
cd aranet4-dash
uv syncThat's it — uv sync creates the venv and installs dependencies from pyproject.toml.
Make sure the Aranet4 is nearby.
uv run aranetctl --scanLook for your device in the output:
=======================================
Name: Aranet4 0A3D9
Address: AA:BB:CC:DD:EE:FF
RSSI: -83 dBm
---------------------------------------
CO2: 593 ppm
Temperature: 19.0 °C
...
Note the MAC address. If no readings appear, make sure Smart Home integrations is enabled in the Aranet Home app.
sudo mkdir -p /var/lib/aranet4-dash
sudo chown $USER:grafana /var/lib/aranet4-dash
chmod 750 /var/lib/aranet4-dashThis keeps the DB outside your home directory so Grafana (grafana user) can read it via group permissions without exposing anything else.
Copy the example and fill in your values:
cp .env.example .env
nano .envARANET_MAC=AA:BB:CC:DD:EE:FF
DB_PATH=/var/lib/aranet4-dash/aranet.db
POLL_INTERVAL=60ARANET_MAC— the MAC address from step 2DB_PATH— where to store the SQLite databasePOLL_INTERVAL— seconds between readings in daemon mode (default 60, not used by crontab)
cd ~/dev/aranet4-dash # or wherever you cloned the repo
uv run aranet_logger.py --singleYou should see output like:
2026-02-09 12:00:00 INFO Scanning for Aranet4 (AA:BB:CC:DD:EE:FF)...
2026-02-09 12:00:10 INFO CO2=593 ppm Temp=19.0°C Humidity=56% Pressure=998.2 hPa Battery=96%
2026-02-09 12:00:10 INFO Reading saved to database
sqlite3 /var/lib/aranet4-dash/aranet.dbSELECT * FROM aranet_readings ORDER BY timestamp DESC LIMIT 5;
.quitCron always uses /bin/sh, so fish vs bash doesn't matter here.
crontab -eAdd these lines to poll every minute:
PATH=$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin
* * * * * cd $HOME/dev/aranet4-dash && uv run aranet_logger.py --single >> $HOME/dev/aranet4-dash/cron.log 2>&1The PATH line ensures cron can find uv. Save and exit, then verify:
crontab -lCheck it's working after a few minutes:
tail -f ~/dev/aranet4-dash/cron.logsudo apt-get install -y apt-transport-https software-properties-common
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y grafanaStart and enable:
sudo systemctl daemon-reload
sudo systemctl enable --now grafana-serverGrafana is now running at http://<pi-ip>:3000. Default login is admin / admin.
sudo grafana-cli plugins install frser-sqlite-datasource
sudo systemctl restart grafana-server- Open Grafana at
http://<pi-ip>:3000 - Go to Connections > Data sources > Add data source
- Search for SQLite
- Set the path to:
/var/lib/aranet4-dash/aranet.db - Click Save & test — should say "Data source is working"
A pre-built dashboard JSON is included in the repo at grafana/dashboard.json.
- In Grafana, go to Dashboards > New > Import
- Click Upload JSON file and select
grafana/dashboard.jsonfrom the repo - Click Import
The dashboard includes:
- Bar gauge — latest reading for CO2, Temperature, Humidity, Pressure, Battery with colour-coded thresholds, plus a "Last Updated" relative timestamp
- CO2 time series — with green/yellow/red threshold bands at 800/1000 ppm
- Temperature time series — blue line with comfort-zone threshold bands, 10-35 C range
- Humidity time series — blue line with threshold bands, 0-100% range
- Pressure time series — blue line, 950-1050 hPa range
Note: The
timestampcolumn stores SQLite datetime strings, but the SQLite datasource plugin needs numeric Unix epoch values. Time series queries convert withCAST(strftime('%s', timestamp) AS INTEGER)(seconds). The bar gauge "Last Updated" field uses* 1000(milliseconds) so Grafana'sdateTimeFromNowunit can display relative time like "5 min ago".
CREATE TABLE IF NOT EXISTS aranet_readings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
co2_ppm INTEGER,
temperature_c REAL,
humidity_percent REAL,
pressure_hpa REAL,
battery_percent INTEGER
);
CREATE INDEX IF NOT EXISTS idx_timestamp ON aranet_readings(timestamp);The database grows at roughly 1 row per reading (~100 bytes). At 1-minute intervals that's about 15 MB/year.
To manually compact:
sqlite3 /var/lib/aranet4-dash/aranet.db "VACUUM;"To delete old data (e.g. older than 1 year):
sqlite3 /var/lib/aranet4-dash/aranet.db "DELETE FROM aranet_readings WHERE timestamp < datetime('now', '-1 year');"
sqlite3 /var/lib/aranet4-dash/aranet.db "VACUUM;"- Make sure the Aranet4 is within Bluetooth range
- Check Bluetooth is up:
sudo systemctl status bluetooth - Restart Bluetooth:
sudo systemctl restart bluetooth - Make sure the MAC address in
.envis correct - Try
uv run aranetctl --scanto verify the device is visible
- Smart Home integrations must be enabled in the Aranet Home phone app — without it the device won't broadcast readings in BLE advertisements
# Check cron is running
sudo systemctl status cron
# Check the log
tail -20 ~/dev/aranet4-dash/cron.log
# Make sure uv is on PATH
which uvThe DB lives in /var/lib/aranet4-dash/ which should be owned by <your-user>:grafana. Check permissions:
ls -la /var/lib/aranet4-dash/
# Should show: drwxr-x--- <user> grafana (directory)
# and: -rw-r----- <user> grafana (aranet.db)Fix if needed:
sudo chown $USER:grafana /var/lib/aranet4-dash /var/lib/aranet4-dash/aranet.db
chmod 750 /var/lib/aranet4-dash
chmod 640 /var/lib/aranet4-dash/aranet.db