FEAT-NETATMO-01: Netatmo Weather Station Plugin

OAuth2 Password-Grant + Refresh-Token on-the-fly. Holt sich automatisch
einen neuen Access-Token wenn der alte abläuft (3h Gültigkeit).

Module: NAMain (Indoor), NAModule1 (Outdoor), NAModule2 (Wind),
NAModule3 (Regen), NAModule4 (Extra Indoor).

Slot-responsive:
  1x1 — Outdoor-Temp prominent + Mini-Status
  4x1 — Indoor | Outdoor | Wind/Regen kompakt (3 Spalten)
  1x4 — Vertikale Liste aller Module
  2x2 — Indoor-Card (mit CO2-Bar) + Outdoor-Card + Wind/Regen-Bereich
  4x4 — Volle Ansicht mit Min/Max, Windrose, Timestamps

Config-Optionen:
  client_id/client_secret/username/password (secrets via Admin-UI)
  station_filter (substring-match für Multi-Setup)
  show_indoor/outdoor/wind/rain/compass/secondary (bools)
  co2_thresholds (ppm, default ok@600,warn@1000,alert@1500)
  temp_unit (C/F), wind_unit (kmh/ms)

Plus:
  - plugins/NETATMO.md: vollständige Doku (Setup, Optionen, Diagnose)
  - config.netatmo.example.json: copy-paste Beispiel-Config
  - layout.py: netatmo default-size = 4x4 (4 Sub-Cards brauchen Platz)
  - README.md: Plugin-Tabelle erweitert

Verifiziert: /api/plugins.json listet netatmo, Auto-Loader erkennt es,
Admin-UI zeigt das Config-Form.
This commit is contained in:
hermes
2026-08-29 18:35:29 +04:00
parent 8f3480ee2e
commit 25b0432757
5 changed files with 1116 additions and 0 deletions
+201
View File
@@ -0,0 +1,201 @@
# Netatmo Weather Station Plugin
Zeigt die Live-Daten deiner heimischen [Netatmo Wetterstation](https://www.netatmo.com/de-de/weather/weatherstation)
auf dem 7.3″ ACeP Dashboard: Indoor-Temperatur, CO₂, Luftfeuchte, Luftdruck,
Outdoor-Werte, Wind (Stärke + Böen + Richtung mit Windrose) und Regenmengen.
Funktioniert mit **jeder** Netatmo-Konfiguration (Hauptmodul + beliebige
Zusatzmodule). Module, die du nicht hast, werden automatisch weggelassen.
![Netatmo 4×4](docs/netatmo_4x4.png)
---
## 1. Netatmo-App registrieren
Damit das Plugin Daten abrufen darf, brauchst du eine App-Registrierung
bei Netatmo. Das ist einmalig und kostenlos.
1. Gehe zu <https://dev.netatmo.com/apps/> und logge dich mit deinem
Netatmo-Account ein.
2. Klicke **Create an App**.
3. Fülle das Formular aus:
- **Name**: z. B. „epaper-dashboard"
- **Description**: z. B. „Wetterdaten auf meinem ePaper-Display"
- **Data Protection Officer**: nicht erforderlich für eine persönliche App
4. Bei den **Scopes** wähle mindestens **`read_station`** aus
(Standard-Scope der Weather API). Mehr brauchst du für dieses Plugin nicht.
5. Speichern. Du bekommst **Client-ID** und **Client-Secret** angezeigt —
die brauchst du gleich.
> Hinweis: Netatmo verwendet **OAuth2 mit Password-Grant** für die
> Weather API (kein Browser-Redirect nötig). Dein Passwort wird nur
> lokal für den initialen Token verwendet — es wird **nie** auf der
> Festplatte persistiert, sondern liegt nur im RAM des laufenden
> Dashboard-Prozesses.
---
## 2. Plugin konfigurieren
### Option A — über die Admin-Weboberfläche (empfohlen)
`http://<pi>:8080/` öffnen, in der Sidebar das Widget **Netatmo**
auswählen und die Werte eintragen:
| Feld | Wert |
|---|---|
| Client-ID | von dev.netatmo.com/apps |
| Client-Secret | von dev.netatmo.com/apps |
| Username | deine Netatmo-Login-E-Mail |
| Password | dein Netatmo-Passwort |
| Station (Filter) | leer lassen, wenn du nur eine Station hast |
Speichern. Klicke **Refresh Now** — wenn alles passt, sollten nach
~30s die ersten Daten erscheinen.
### Option B — direkt in `config.json`
Unter `plugin_configs.netatmo` eintragen (Beispiel siehe
[`config.netatmo.example.json`](config.netatmo.example.json)):
```json
{
"plugin_configs": {
"netatmo": {
"client_id": "abc123...",
"client_secret": "def456...",
"username": "du@example.com",
"password": "GEHEIM",
"station_filter": "",
"show_indoor": true,
"show_outdoor": true,
"show_wind": true,
"show_rain": true,
"show_compass": true,
"show_secondary": true,
"co2_thresholds": "ok@600,warn@1000,alert@1500",
"bar_gradient": true,
"temp_unit": "C",
"wind_unit": "kmh"
}
}
}
```
> ⚠️ Secrets in `config.json` sind auf dem Pi persistent (lokal in
> `/home/<user>/.hermes/projects/pi/config.json`). Wenn du das
> vermeiden willst, nimm die Admin-UI — die legt sie genauso ab, aber
> du siehst die Werte nie im Klartext-Editor.
---
## 3. Layout zuweisen
In der Admin-UI ein Netatmo-Widget auf das Grid ziehen. Das Plugin ist
**responsive**: dieselbe Konfiguration sieht auf jedem Slot gut aus.
| Slot | Was du siehst |
|---|---|
| **1×1** | Große Außen-Temperatur, Mini-CO₂/Feuchte-Status |
| **2×1** | Outdoor-Temperatur + Wind-Geschwindigkeit kompakt |
| **4×1** | Indoor · Outdoor · Wind/Regen — drei Spalten |
| **1×4** | Vertikale Liste aller Module |
| **2×2** | Indoor-Card (mit CO₂-Bar) + Outdoor-Card + Wind/Regen-Bereich |
| **4×4** | Volle Ansicht mit allen Modulen, Min/Max, Windrose |
Das Plugin priorisiert bei der Layout-Wahl **wide/tall** vor `small`,
damit 4×1- und 1×4-Slots nicht in die Mini-Ansicht fallen.
---
## 4. Optionen im Detail
| Option | Typ | Default | Bedeutung |
|---|---|---|---|
| `client_id` | secret | — | Netatmo App Client-ID |
| `client_secret` | secret | — | Netatmo App Client-Secret |
| `username` | secret | — | Netatmo Login (E-Mail) |
| `password` | secret | — | Netatmo Passwort (nur RAM) |
| `station_filter` | string | `""` | Substring-Filter auf Stations-/Modulname |
| `show_indoor` | bool | `true` | Hauptmodul + zusätzliche Indoor-Sensoren anzeigen |
| `show_outdoor` | bool | `true` | NAModule1 (Außen) anzeigen |
| `show_wind` | bool | `true` | NAModule2 (Wind) anzeigen |
| `show_rain` | bool | `true` | NAModule3 (Regen) anzeigen |
| `show_compass` | bool | `true` | Windrose in der Wind-Card zeichnen |
| `show_secondary` | bool | `true` | Min/Max + letzte Aktualisierung |
| `co2_thresholds` | string | `ok@600,warn@1000,alert@1500` | CO₂-Bar Schwellen (ppm) |
| `bar_gradient` | bool | `true` | Verlaufsmodus der Bar |
| `temp_unit` | select | `C` | `C` oder `F` |
| `wind_unit` | select | `kmh` | `kmh` oder `ms` |
### CO₂-Schwellen anpassen
`co2_thresholds` ist ein String im Format `farbe@ppm_in_ppm`.
Mehrere Stufen durch Komma trennen:
- `ok@600,warn@1000,alert@1500` — Netatmo-Default-Empfehlungen
- `ok@800,warn@1200` — nur 2 Stufen (kompakt)
- `ok@1000,warn@1500,alert@2000` — strenger (z. B. für Schlafzimmer)
### Station-Filter
Wenn du mehrere Stationen hast (z. B. „Home" und „Office"), kannst du
über `station_filter` einen Substring matchen. Erst wird der
Stationsname geprüft, dann die Modulnamen. Leer = erste Station.
---
## 5. Fehlerdiagnose
### Auth-Fehler (HTTP 401)
- Stimmen Client-ID/Secret mit dem Eintrag auf dev.netatmo.com/apps überein?
- Stimmt das Passwort (case-sensitive)?
- Wurde deine App bei Netatmo evtl. deaktiviert?
→ Plugin setzt den Token-Cache automatisch zurück, beim nächsten Render
wird ein neuer Token geholt.
### "Keine Station gefunden"
- Hat deine Station in den letzten 4h Daten an Netatmo geschickt?
(Netatmo markiert sie sonst als offline.)
- Stimmt der `station_filter`? Wenn du dort z. B. „Home" eingibst, aber
die Station heißt „Home Office", passt es trotzdem (Substring-Match).
Leer = erste Station.
### "API nicht erreichbar"
- Pi hat Internet? (`ping api.netatmo.net`)
- DNS? (`nslookup api.netatmo.net`)
### Werte fehlen / sind 0
- Manche Datenpunkte sind nur in der **Paid**-Subscription verfügbar
(z. B. Historische Daten > 1h). Aktuelle Werte sind immer frei.
---
## 6. Technische Details
| Aspekt | Wert |
|---|---|
| API-Version | Netatmo Connect OAuth2 |
| Endpoints | `POST /oauth2/token`, `GET /api/getstationsdata` |
| Token-Lebensdauer | 10800s (3h), Refresh on the fly |
| Cache | In-Memory, kein Disk-IO pro Render |
| Datenquelle | Netatmo Cloud (Update alle ~10 Min) |
| Modul-Typen | NAMain, NAModule1..4 |
| `reachable`-Feld | „true" wenn das Modul in den letzten 4h gesehen wurde |
### Was wird pro Refresh gemacht?
1. Prüfe Token-Cache (RAM). Wenn abgelaufen oder fehlend → hole neuen
Token via Password-Grant (initial) oder Refresh-Grant.
2. `GET /api/getstationsdata?get_favorites=false` mit Bearer-Token.
3. Parse Antwort, filtere nach `station_filter` und sichtbaren Modulen.
4. Rendere je nach Slot-Größe (`small` / `wide` / `tall` / `standard`).
Bei 401 wird der Token-Cache geleert und **einmal** neu authentifiziert.
Wenn das auch fehlschlägt → roter Error-Banner mit der genauen HTTP-Meldung.