monitoring: Wetter-Tagesberichte in Grafana auffindbar machen

- weather-report-history.json (ha-weather-report-history): Finder-Tabelle,
  eine Zeile pro Tag (Datum, Kurzbewertung, T min/max/Mittel, Regen, UV, Boee)
  mit Drilldown-Data-Link aufs Tagesbericht-Dashboard
- weather-day-report.json: Zeitzone Europe/Berlin, Info-Panel zur Tagesauswahl,
  Nav-Dropdown zu den Wetter-Dashboards
- monitoring/README: Abschnitt Wetter-Tagesberichte (finden, Datum waehlen,
  Quelle InfluxDB-SQL statt Markdown-Index, Deploy, Explore-Test)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 09:27:26 +02:00
parent dee9b102bd
commit 536a6fd0cd
3 changed files with 121 additions and 3 deletions
+50
View File
@@ -74,6 +74,56 @@ INFLUXDB_BIND_IP=192.168.178.58
- Uptime Kuma ist entfernt; `Homelab / Availability`, Blackbox Exporter und Prometheus-Alerts sind der Zielzustand fuer HTTP-Verfuegbarkeit.
- Dashboard-Zielbestand: `Homelab / Availability`, `Homelab / Containers + Logs`, `Homelab / Host Overview`, `Homelab / Family Status`, `Traefik Official Standalone Dashboard`.
## Wetter-Tagesberichte
Die Ecowitt-/HA-Wetterdaten (DB `homeassistant`, Datasource `ha-weather-influx`)
werden in drei Grafana-Dashboards sichtbar (Ordner `Homelab`, Tag `weather`):
- `Wetterarchiv KalliHome` (`ha-weather-archive`): Verlaeufe und Gauges ueber einen Zeitbereich.
- `Wetterbericht KalliHome` (`ha-weather-day-report`): ausfuehrlicher Tagesbericht (Markdown-Tabelle) fuer **einen** Tag.
- `Wetter-Tagesberichte KalliHome` (`ha-weather-report-history`): Index/Finder, **eine Zeile pro Tag** mit Kurzbewertung, T min/max/Mittel, Regen, UV und Boee.
### Alte Tagesberichte finden und ein Datum waehlen
1. Dashboard **`Wetter-Tagesberichte`** oeffnen (Standard: letzte 30 Tage, Europe/Berlin).
In der Tabelle **auf das Datum klicken** -> der ausfuehrliche Tagesbericht oeffnet
sich fuer genau diesen Tag. Weiter zurueck: Zeitbereich oben rechts vergroessern.
2. Alternativ im Dashboard **`Wetterbericht KalliHome`** direkt einen Tag waehlen:
Zeitbereich oben rechts -> *Absolute time range* -> z. B. From `2026-06-15 00:00:00`,
To `2026-06-16 00:00:00` -> **Apply**. Beide Dashboards haben Zeitzone
`Europe/Berlin`, die Eingaben gelten also in Berliner Lokalzeit; Standard ist
`gestern` (`now-1d/d` bis `now/d`).
Grafana hat **keine echte Datepicker-Variable**: eine Textbox-Variable kann den
Zeitbereich nicht setzen, und ein `report_date`-Ansatz braeuchte zeitzonen-genaues
Tages-Bounding in InfluxDB-3-SQL. Deshalb ist der **Timepicker bei Dashboard-Zeitzone
`Europe/Berlin`** der exakte Weg fuer einen vollstaendigen Lokaltag, und die
Index-Tabelle der bequeme Klick-Selektor fuer alte Tage. Die Tabellen-Buckets liegen
auf UTC-Mitternacht (~01:00/02:00 Berlin); der verlinkte Tagesbericht zeigt das
gewaehlte Fenster vollstaendig.
### Quelle: InfluxDB statt Markdown-Index
Die Dashboards rendern direkt per SQL aus InfluxDB 3 Core - gleiche Quelle wie der
Markdown-Generator `services/posture-check/weather-day-report.py`. Damit ist jeder
zurueckliegende Tag reproduzierbar, solange die Rohdaten vorgehalten werden; ein
separater Markdown-Index ist bewusst nicht noetig. Die erzeugten Tagesberichte als
Datei (E-Mail/Offline-Archiv) liegen weiterhin unter
`/mnt/user/services/posture-check/daily-reports/homelab-day-YYYY-MM-DD.md`.
### Deploy und Test
Dashboards werden aus `monitoring/grafana/dashboards/` provisioniert (Verzeichnis-
Mount, Reload alle 5 Minuten, Ordner `Homelab`). Nach Push nach Gitea deployt Komodo
den `monitoring`-Stack; Grafana laedt die JSON-Dateien automatisch nach. Kein
Bootstrap-Importer noetig (der gilt nur fuer grafana.com-Dashboard-ID 17346).
SQL der Index-Tabelle vor dem Verlassen einmal pruefen: Grafana -> *Explore* ->
Datasource `ha-weather-influx` -> die `rawSql` aus `weather-report-history.json`
einfuegen und einen Zeitbereich (z. B. letzte 7 Tage) waehlen. Erwartet: eine Zeile
pro Tag mit gefuellten Spalten. Falls `extract(epoch FROM ...)` auf dem InfluxDB-3-
Build nicht unterstuetzt wird, stattdessen `to_unixtime(...)` verwenden.
## Alerting
Prometheus wertet `monitoring/prometheus/alerts.yml` aus und sendet an `monitoring-alertmanager`.
@@ -2,19 +2,32 @@
"uid": "ha-weather-day-report",
"title": "Wetterbericht KalliHome",
"tags": ["weather", "ecowitt", "homeassistant", "report"],
"timezone": "browser",
"timezone": "Europe/Berlin",
"schemaVersion": 39,
"version": 1,
"version": 2,
"refresh": "",
"time": { "from": "now-1d/d", "to": "now/d" },
"templating": { "list": [] },
"annotations": { "list": [] },
"links": [
{ "asDropdown": true, "icon": "external link", "includeVars": false, "keepTime": false, "tags": ["weather"], "targetBlank": false, "title": "Wetter-Dashboards", "tooltip": "", "type": "dashboards", "url": "" }
],
"panels": [
{
"id": 2,
"title": "",
"type": "text",
"gridPos": { "h": 4, "w": 24, "x": 0, "y": 0 },
"options": {
"mode": "markdown",
"content": "## Tag auswählen\n\n**Standard:** gestern (ganzer Tag, Europe/Berlin).\n\n**Anderen Tag:** Zeitbereich oben rechts → *Absolute time range* → z. B. From `2026-06-15 00:00:00`, To `2026-06-16 00:00:00` → **Apply** (Zeiten gelten in Europe/Berlin).\n\n**Alle Tage als Liste:** [Wetter-Tagesberichte](/d/ha-weather-report-history) dort jeden Tag per Klick öffnen."
}
},
{
"id": 1,
"title": "Tagesbericht",
"type": "table",
"gridPos": { "h": 16, "w": 24, "x": 0, "y": 0 },
"gridPos": { "h": 16, "w": 24, "x": 0, "y": 4 },
"datasource": { "type": "influxdb", "uid": "ha-weather-influx" },
"fieldConfig": {
"defaults": {
@@ -0,0 +1,55 @@
{
"uid": "ha-weather-report-history",
"title": "Wetter-Tagesberichte KalliHome",
"tags": ["weather", "ecowitt", "homeassistant", "report"],
"timezone": "Europe/Berlin",
"schemaVersion": 39,
"version": 1,
"refresh": "",
"time": { "from": "now-30d/d", "to": "now/d" },
"templating": { "list": [] },
"annotations": { "list": [] },
"links": [
{ "asDropdown": true, "icon": "external link", "includeVars": false, "keepTime": false, "tags": ["weather"], "targetBlank": false, "title": "Wetter-Dashboards", "tooltip": "", "type": "dashboards", "url": "" }
],
"panels": [
{
"id": 2,
"title": "",
"type": "text",
"gridPos": { "h": 4, "w": 24, "x": 0, "y": 0 },
"options": {
"mode": "markdown",
"content": "## Wetter-Tagesberichte\n\nEine Zeile pro Tag im gewählten Zeitbereich (Standard: letzte 30 Tage, Europe/Berlin). **Auf das Datum klicken** öffnet den ausführlichen [Tagesbericht](/d/ha-weather-day-report) für genau diesen Tag. Zeitbereich oben rechts ändern, um weiter zurückzublättern.\n\nHinweis: Die Tagesgrenzen dieser Übersicht liegen auf UTC-Mitternacht (~01:00/02:00 Europe/Berlin); der verlinkte Tagesbericht zeigt das gewählte Tagesfenster vollständig an. Regen ist der Tages-Maximalwert von `gw3000a_daily_rain`."
}
},
{
"id": 1,
"title": "Tagesübersicht",
"type": "table",
"gridPos": { "h": 20, "w": 24, "x": 0, "y": 4 },
"datasource": { "type": "influxdb", "uid": "ha-weather-influx" },
"fieldConfig": {
"defaults": {
"custom": { "align": "left", "cellOptions": { "type": "auto" }, "filterable": true, "inspect": false }
},
"overrides": [
{ "matcher": { "id": "byName", "options": "from_ms" }, "properties": [ { "id": "custom.hidden", "value": true } ] },
{ "matcher": { "id": "byName", "options": "to_ms" }, "properties": [ { "id": "custom.hidden", "value": true } ] },
{ "matcher": { "id": "byName", "options": "Datum" }, "properties": [ { "id": "links", "value": [ { "title": "Tagesbericht öffnen", "url": "/d/ha-weather-day-report?from=${__data.fields.from_ms}&to=${__data.fields.to_ms}&timezone=Europe/Berlin", "targetBlank": true } ] } ] },
{ "matcher": { "id": "byName", "options": "Bewertung" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "color-text" } }, { "id": "mappings", "value": [ { "type": "value", "options": { "Sonnig, warm": { "color": "#ffa94d", "index": 0 }, "Warm": { "color": "#ffd43b", "index": 1 }, "Regnerisch": { "color": "#4dabf7", "index": 2 }, "Kalt": { "color": "#74c0fc", "index": 3 }, "Unauffaellig": { "color": "#adb5bd", "index": 4 } } } ] } ] }
]
},
"options": { "showHeader": true, "cellHeight": "sm", "footer": { "show": false, "reducer": ["sum"], "countRows": false }, "sortBy": [ { "displayName": "Datum", "desc": true } ] },
"targets": [
{
"refId": "A",
"datasource": { "type": "influxdb", "uid": "ha-weather-influx" },
"rawQuery": true,
"format": "table",
"rawSql": "WITH t AS (SELECT date_bin(INTERVAL '1 day', time) AS d, min(value) AS tmin, max(value) AS tmax, avg(value) AS tavg FROM \"°C\" WHERE entity_id = 'gw3000a_outdoor_temperature' AND $__timeFilter(time) GROUP BY 1), r AS (SELECT date_bin(INTERVAL '1 day', time) AS d, max(value) AS rain FROM \"mm\" WHERE entity_id = 'gw3000a_daily_rain' AND $__timeFilter(time) GROUP BY 1), u AS (SELECT date_bin(INTERVAL '1 day', time) AS d, max(value) AS uvmax FROM \"UV index\" WHERE entity_id = 'gw3000a_uv_index' AND $__timeFilter(time) GROUP BY 1), s AS (SELECT date_bin(INTERVAL '1 day', time) AS d, max(value) AS smax FROM \"W/m²\" WHERE entity_id = 'gw3000a_solar_radiation' AND $__timeFilter(time) GROUP BY 1), wg AS (SELECT date_bin(INTERVAL '1 day', time) AS d, max(value) AS wmax FROM \"km/h\" WHERE entity_id = 'gw3000a_wind_gust' AND $__timeFilter(time) GROUP BY 1) SELECT cast(cast(t.d AS date) AS varchar) AS \"Datum\", CASE WHEN s.smax >= 700 AND u.uvmax >= 6 THEN 'Sonnig, warm' WHEN t.tmax >= 25 THEN 'Warm' WHEN coalesce(r.rain, 0) >= 5 THEN 'Regnerisch' WHEN t.tmax <= 5 THEN 'Kalt' ELSE 'Unauffaellig' END AS \"Bewertung\", round(t.tmin, 1) AS \"T min °C\", round(t.tmax, 1) AS \"T max °C\", round(t.tavg, 1) AS \"T Mittel °C\", round(coalesce(r.rain, 0), 1) AS \"Regen mm\", round(u.uvmax, 1) AS \"UV max\", round(wg.wmax, 1) AS \"Böe max km/h\", cast(extract(epoch FROM t.d) AS bigint) * 1000 AS from_ms, cast(extract(epoch FROM t.d + INTERVAL '1 day') AS bigint) * 1000 AS to_ms FROM t LEFT JOIN r ON r.d = t.d LEFT JOIN u ON u.d = t.d LEFT JOIN s ON s.d = t.d LEFT JOIN wg ON wg.d = t.d ORDER BY t.d DESC"
}
]
}
]
}