2026-08-30 11:01:19 +02:00
|
|
|
|
# GetNetatmoData v2
|
2026-08-30 07:50:24 +02:00
|
|
|
|
|
2026-08-30 11:01:19 +02:00
|
|
|
|
A small Flask service that polls Netatmo's Weather API every ten minutes, stores
|
|
|
|
|
|
the readings in RRDtool databases, and serves a responsive graph dashboard.
|
|
|
|
|
|
|
|
|
|
|
|
## What it stores
|
|
|
|
|
|
|
2026-09-03 22:26:40 +02:00
|
|
|
|
The service creates `netatmo_outdoor.rrd`, `netatmo_pressure.rrd`,
|
|
|
|
|
|
`netatmo_wind.rrd`, `netatmo_rain.rrd`,
|
2026-08-30 12:30:07 +02:00
|
|
|
|
`netatmo_bedroom.rrd`, `netatmo_study.rrd`, and `netatmo_living.rrd`. Each has
|
|
|
|
|
|
ten-minute archives for the last two weeks and six-hour archives covering a
|
|
|
|
|
|
year. Day, two-week, and year PNG graphs are rendered on demand. The wind graph
|
|
|
|
|
|
splits average wind into 12 colored direction bands and draws gusts as a line.
|
2026-09-06 12:25:34 +02:00
|
|
|
|
The rain database stores Netatmo's `sum_rain_1` and cumulative `sum_rain_24`
|
|
|
|
|
|
readings. Day and two-week graphs show rain accumulated per hour; the year graph
|
|
|
|
|
|
shows rain accumulated per day. The midnight reset of `sum_rain_24` is preserved,
|
|
|
|
|
|
and MAX consolidation retains daily totals in the longer-term archive.
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
2026-09-03 22:26:40 +02:00
|
|
|
|
The Outdoor module does not contain a pressure sensor, so the dedicated pressure
|
|
|
|
|
|
graph reads it from the main station. Its Y axis is fixed at 900–1100 mbar. A
|
|
|
|
|
|
module without `dashboard_data` is skipped until it becomes reachable again.
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
|
|
|
|
|
## Prerequisites and setup
|
|
|
|
|
|
|
|
|
|
|
|
Install the RRDtool Python binding and native library using your operating
|
|
|
|
|
|
system package manager (for example `apt install python3-rrdtool` on Debian or
|
|
|
|
|
|
Ubuntu), then set up the Python application. If your distribution does not
|
|
|
|
|
|
provide the binding, `pip install -r requirements.txt` installs its PyPI package
|
|
|
|
|
|
but may require the RRDtool development headers and a C compiler.
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
python3 -m venv .venv
|
|
|
|
|
|
.venv/bin/pip install -r requirements.txt
|
2026-08-30 12:25:57 +02:00
|
|
|
|
cp config.example.yaml config.yaml
|
2026-08-30 11:01:19 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Add the client ID and secret for the Netatmo application **GetNetatmoData v2**
|
2026-08-30 12:25:57 +02:00
|
|
|
|
to the private `config.yaml`. Ensure `netatmo.redirect_uri` exactly matches a
|
|
|
|
|
|
redirect URI configured for that application, then perform the initial
|
|
|
|
|
|
`read_station` authorization:
|
2026-08-30 11:33:13 +02:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
.venv/bin/python scripts/get_netatmo_token.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The helper opens Netatmo's consent page. After approval, paste the complete URL
|
|
|
|
|
|
from the browser's address bar back into the prompt. This works even if the local
|
|
|
|
|
|
callback page itself cannot be reached. The script exchanges the authorization
|
|
|
|
|
|
code and writes the token file with mode `0600`.
|
|
|
|
|
|
|
2026-08-30 12:25:57 +02:00
|
|
|
|
The service loads `netatmo.token_file` at startup. Before an access token expires,
|
2026-08-30 11:33:13 +02:00
|
|
|
|
it refreshes it and atomically saves both the new access token and any rotated
|
|
|
|
|
|
refresh token. Values in the token file take precedence over initial token values
|
2026-08-30 12:25:57 +02:00
|
|
|
|
in YAML. Client credentials remain in the private configuration and are never written to
|
2026-08-30 11:33:13 +02:00
|
|
|
|
the token file or an RRD.
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
2026-08-30 12:25:57 +02:00
|
|
|
|
Run the service; host, port, and URL prefix all come from `config.yaml`:
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-30 12:25:57 +02:00
|
|
|
|
.venv/bin/python wsgi.py
|
2026-08-30 11:01:19 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-30 12:41:40 +02:00
|
|
|
|
For production, use the Waitress entry point. It reads host, port, thread count,
|
|
|
|
|
|
and all application settings from `config.yaml`:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
.venv/bin/python serve.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-30 12:25:57 +02:00
|
|
|
|
With the example settings, open <http://localhost:30225/w/>. Keep one application worker because the polling
|
2026-08-30 11:01:19 +02:00
|
|
|
|
scheduler runs inside the service process. Alternatively set
|
2026-08-30 12:25:57 +02:00
|
|
|
|
`collector.enabled: false` in web workers and invoke this from a system timer:
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
.venv/bin/flask --app wsgi collect-now
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-30 12:25:57 +02:00
|
|
|
|
`storage.rrd_folder` configures the database directory (default `./rrd`). The
|
2026-09-03 22:26:40 +02:00
|
|
|
|
`modules` section allows the Netatmo display names to be changed.
|
2026-08-30 12:25:57 +02:00
|
|
|
|
Set `server.url_prefix: /w` to mount the dashboard, static assets, and every API endpoint
|
2026-08-30 11:33:13 +02:00
|
|
|
|
below `/w`; leave it empty to serve from the site root. When a prefix is set,
|
|
|
|
|
|
open <http://localhost:5000/w/> instead.
|
2026-08-30 11:01:19 +02:00
|
|
|
|
|
2026-08-30 12:25:57 +02:00
|
|
|
|
`logging.file` selects a rotating application log (by default
|
2026-08-30 12:01:46 +02:00
|
|
|
|
`RRD_FOLDER/netatmo_service.log`). Every Netatmo HTTP attempt records success or
|
|
|
|
|
|
failure, HTTP status, endpoint, and duration without credentials. Collector,
|
|
|
|
|
|
Flask, uncaught main-thread, and uncaught worker-thread exceptions are written to
|
2026-08-30 12:25:57 +02:00
|
|
|
|
the same log. `logging.max_bytes` defaults to 5 MiB and `backup_count` to five.
|
2026-08-30 12:11:57 +02:00
|
|
|
|
The service account must have write permission on the log directory. Console
|
|
|
|
|
|
logging remains enabled by default so `python wsgi.py` displays its listening
|
2026-08-30 12:25:57 +02:00
|
|
|
|
address; set `logging.console: false` to use only the logfile.
|
2026-08-30 12:01:46 +02:00
|
|
|
|
|
2026-08-30 12:41:40 +02:00
|
|
|
|
## systemd installation
|
|
|
|
|
|
|
|
|
|
|
|
The included `deploy/netatmo.service` runs Waitress from `/srv/service_netatmo`
|
|
|
|
|
|
under a dedicated, non-login `netatmo` account. As root, create the account and
|
|
|
|
|
|
writable data directory:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
useradd --system --home-dir /srv/service_netatmo --shell /usr/sbin/nologin netatmo
|
|
|
|
|
|
install -d -o netatmo -g netatmo -m 0750 /var/lib/rrd
|
|
|
|
|
|
chown netatmo:netatmo /srv/service_netatmo/config.yaml
|
|
|
|
|
|
chmod 0600 /srv/service_netatmo/config.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Create the virtual environment and install dependencies as that account:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
sudo -u netatmo python3 -m venv /srv/service_netatmo/.venv
|
|
|
|
|
|
sudo -u netatmo /srv/service_netatmo/.venv/bin/pip install -r /srv/service_netatmo/requirements.txt
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Install and start the unit:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
install -o root -g root -m 0644 /srv/service_netatmo/deploy/netatmo.service /etc/systemd/system/netatmo.service
|
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
|
systemctl enable --now netatmo.service
|
|
|
|
|
|
systemctl status netatmo.service
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Follow service output and the rotating application log with:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
journalctl -u netatmo.service -f
|
|
|
|
|
|
tail -f /var/lib/rrd/netatmo_service.log
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-30 11:01:19 +02:00
|
|
|
|
## HTTP API
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
GET /last/<rrd-name>/<data-point>
|
|
|
|
|
|
GET /graph/<rrd-name>/<period>
|
|
|
|
|
|
GET /graph/<rrd-name><period> # compact compatibility form
|
|
|
|
|
|
GET /health
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Periods are `day`, `2weeks`, and `year`. Examples:
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
curl http://localhost:5000/last/outdoor/humidity
|
|
|
|
|
|
curl --output wind.png http://localhost:5000/graph/wind/2weeks
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Data points are:
|
|
|
|
|
|
|
2026-09-06 12:25:34 +02:00
|
|
|
|
- `outdoor`: `temperature`, `min_temp`, `max_temp`, `humidity`, `pressure`
|
2026-09-03 22:26:40 +02:00
|
|
|
|
- `pressure`: `pressure`
|
2026-08-30 11:01:19 +02:00
|
|
|
|
- `wind`: `gust`, `average`, `angle`
|
2026-09-06 12:25:34 +02:00
|
|
|
|
- `rain`: `sum_rain_24`, `sum_rain_1`
|
2026-08-30 11:01:19 +02:00
|
|
|
|
- `bedroom`, `study`, `living`: `temperature`, `co2`, `humidity`
|
|
|
|
|
|
|
|
|
|
|
|
The service creates missing RRDs at startup but deliberately does not alter an
|
|
|
|
|
|
existing RRD schema. If a schema is changed in code, migrate or archive the old
|
|
|
|
|
|
files before restarting.
|