Initiale Version: Stromverbrauch-Web-App (strom-next)

Next.js-App zur Visualisierung des Stromverbrauchs aus InfluxDB
(Bucket strom, measurement vzlogger, Feld arbeit = kumulativer
Zaehlerstand in Wh).

- 4 Balken-Diagramme: 24h (stuendlich), Woche (stuendlich),
  31 Tage (taeglich), Jahr (pro Monat, immer 12 Monate)
- Verbrauch via difference des Zaehlerstands, zeitzonen-korrekt
- 24h liest Rohdaten (aktuell), 7d/31d/365d den stuendlichen
  Downsampling-Rollup (arbeit_hourly) -> sub-sekunde
- Gesamtverbrauch je Zeitraum unter dem Chart
- Design/Layout angelehnt an Werte-Log "Verlauf"

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 14:05:27 +02:00
commit 3649bf4e22
19 changed files with 7659 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
# Stromverbrauch (strom-next)
Next.js-App zur Visualisierung des Stromverbrauchs aus einer InfluxDB.
Design/Layout angelehnt an das Projekt *Werte-Log* (Ansicht „Verlauf").
## Datenquelle
- InfluxDB Bucket `strom`, Measurement `vzlogger`, Feld `arbeit` (Zählerstand in **Wh**)
- Der Wert ist ein **kumulativer Zählerstand**; der Verbrauch je Intervall
ergibt sich aus der Differenz aufeinanderfolgender Zählerstände
(`difference` in Flux).
- Die Rohdaten haben 1-Sekunden-Auflösung. Für die langen Zeiträume wäre die
Live-Aggregation zu langsam (Jahr ≈ 70 s), daher gibt es einen **Downsampling-Task**.
## Downsampling-Task (InfluxDB)
Ein InfluxDB-Task `arbeit_hourly_rollup` (stündlich, in der InfluxDB unter
Tasks zu finden) schreibt fortlaufend den **letzten Zählerstand je Stunde** als
Measurement `arbeit_hourly` (Feld `arbeit`) zurück in den Bucket `strom`:
```flux
option task = {name: "arbeit_hourly_rollup", every: 1h, offset: 2m}
from(bucket: "strom")
|> range(start: -3h)
|> filter(fn: (r) => r._measurement == "vzlogger" and r._field == "arbeit")
|> aggregateWindow(every: 1h, fn: last, createEmpty: false)
|> set(key: "_measurement", value: "arbeit_hourly")
|> to(bucket: "strom")
```
- **24h**-Chart liest die **Rohdaten** (`vzlogger`) → immer top-aktuell.
- **7d/31d/365d** lesen den **Rollup** (`arbeit_hourly`) → sub-sekunden-schnell.
- Tages-/Stundenwerte: erst `difference` (stündlicher Verbrauch), dann
`aggregateWindow(sum)` pro Tag/Stunde (zeitzonen-korrekt via `Europe/Berlin`).
Liefert exakt dieselben Werte wie die Rohdaten-Aggregation.
### Backfill (einmalig, schon ausgeführt)
Die Historie ab 2022-10-09 wurde einmalig in `arbeit_hourly` geschrieben.
Falls erneut nötig (z. B. nach Datenlücke), jahresweise:
```flux
from(bucket:"strom")
|> range(start: 2025-01-01T00:00:00Z, stop: 2026-01-01T00:00:00Z)
|> filter(fn:(r)=>r._measurement=="vzlogger" and r._field=="arbeit")
|> aggregateWindow(every:1h, fn:last, createEmpty:false)
|> set(key:"_measurement", value:"arbeit_hourly")
|> to(bucket:"strom")
```
## Diagramme (alle als Balken-Diagramme)
| Zeitraum | Balken | Auswahl |
|-------------------|--------------|----------------------------------|
| Letzte 24 Stunden | 1 / Stunde | Tag (leer = letzte 24h ab jetzt) |
| Letzte 7 Tage | 1 / Stunde | Tag |
| Letzte 31 Tage | 1 / Tag | Monat |
| Letzte 365 Tage | 1 / Tag | Jahr |
X-Achse: Datum/Zeit · Y-Achse: kWh
## Setup
```bash
npm install
cp .env.local.example .env.local
# .env.local mit echtem INFLUX_TOKEN (und ggf. Feldname/Einheit) befüllen
```
### .env.local
```
INFLUX_URL=http://nuccy:8086
INFLUX_TOKEN=...
INFLUX_ORG=citysensor
INFLUX_BUCKET=strom
INFLUX_MEASUREMENT=vzlogger
INFLUX_FIELD=arbeit
INFLUX_UNIT_FACTOR=0.001 # Zählerstand liegt in Wh vor
```
Den Feldnamen und die Einheit ggf. einmalig prüfen:
```bash
curl -s -XPOST "http://nuccy:8086/api/v2/query?org=citysensor" \
-H "Authorization: Token $INFLUX_TOKEN" \
-H "Accept: application/csv" \
-H "Content-type: application/vnd.flux" \
-d 'import "influxdata/influxdb/schema"
schema.fieldKeys(bucket: "strom", predicate: (r) => r._measurement == "arbeit")'
```
## Starten
```bash
npm run dev # http://localhost:3000
npm run build # Produktionsbuild
npm start
```