Zum Inhalt

Grafana Battery Dashboard

Übersicht

Das Battery Storage Dashboard bietet eine umfassende Überwachung aller Batteriespeichersysteme mit 11 Panels für Echtzeit-Monitoring und historische Analysen.


Dashboard-Zugriff

URL: http://localhost:3001/d/battery-storage-dashboard/battery-storage-system

Credentials: - Username: admin - Password: admin (beim ersten Login ändern)


Dashboard-Panels

1. Total Battery Capacity (Stat)

Typ: Stat Panel
Metrik: Gesamtkapazität aller Batterien
Query:

SELECT SUM(capacity_kwh) as total_capacity
FROM batteries
WHERE enabled = true

Anzeige: - Einheit: kWh - Icon: Battery - Farbe: Blau

2. Average SOC (Gauge)

Typ: Gauge Panel
Metrik: Durchschnittlicher State of Charge
Query:

SELECT AVG(bd.state_of_charge) as avg_soc
FROM batteries b
LEFT JOIN LATERAL (
  SELECT state_of_charge
  FROM battery_data
  WHERE battery_id = b.id
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE b.enabled = true

Thresholds: - 🔴 Red: < 20% - 🟡 Yellow: 20-40% - 🟢 Green: > 40%

3. Current Total Power (Stat)

Typ: Stat Panel mit Sparkline
Metrik: Gesamtleistung (positiv=laden, negativ=entladen)
Query:

SELECT 
  COALESCE(SUM(bd.power), 0) as total_power
FROM batteries b
LEFT JOIN LATERAL (
  SELECT power
  FROM battery_data
  WHERE battery_id = b.id
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE b.enabled = true

Anzeige: - Einheit: kW - Sparkline: Verlauf der letzten Stunde - Farbe: Grün (laden) / Orange (entladen)

4. Battery Status Overview (Table)

Typ: Table Panel
Metrik: Übersicht aller Batterien mit aktuellen Werten
Query:

SELECT 
  b.name,
  b.manufacturer,
  b.model,
  b.capacity_kwh,
  COALESCE(bd.state_of_charge, 0) as soc,
  COALESCE(bd.power, 0) as power,
  COALESCE(bd.status, 'UNKNOWN') as status,
  COALESCE(bd.temperature_avg, 0) as temperature
FROM batteries b
LEFT JOIN LATERAL (
  SELECT *
  FROM battery_data
  WHERE battery_id = b.id
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE b.enabled = true
ORDER BY b.name

Spalten: - Name - Hersteller - Modell - Kapazität (kWh) - SOC (%) - Power (kW) - Status - Temperatur (°C)

Formatierung: - SOC: Gauge (0-100%) - Power: Positiv=Grün, Negativ=Orange - Status: Badge mit Farben - Temperatur: Warnung bei >40°C

5. SOC by Battery (Time Series)

Typ: Time Series Panel
Metrik: SOC-Verlauf pro Batterie
Query:

SELECT 
  bd.timestamp as time,
  b.name,
  bd.state_of_charge as soc
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '24 hours'
  AND b.enabled = true
ORDER BY bd.timestamp

Darstellung: - Y-Achse: 0-100% - Legende: Batteriename - Intervall: 5 Minuten - Interpolation: Linear

6. Power Flow (Time Series)

Typ: Time Series Panel (mit positiv/negativ Bereichen)
Metrik: Lade-/Entladeleistung pro Batterie
Query:

SELECT 
  bd.timestamp as time,
  b.name,
  bd.power
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '24 hours'
  AND b.enabled = true
ORDER BY bd.timestamp

Darstellung: - Positiv (laden): Grün, Bereich oberhalb X-Achse - Negativ (entladen): Orange, Bereich unterhalb X-Achse - Y-Achse: kW (automatisch skaliert) - Stacked: Ja (Gesamtleistung sichtbar)

7. Energy Today (Bar Gauge)

Typ: Bar Gauge (Horizontal)
Metrik: Geladene und entladene Energie heute
Query:

SELECT 
  b.name,
  COALESCE(SUM(bd.energy_charged_today), 0) as charged,
  COALESCE(SUM(bd.energy_discharged_today), 0) as discharged
FROM batteries b
LEFT JOIN LATERAL (
  SELECT *
  FROM battery_data
  WHERE battery_id = b.id
  AND DATE(timestamp) = CURRENT_DATE
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE b.enabled = true
GROUP BY b.id, b.name
ORDER BY b.name

Anzeige: - Zwei Bars pro Batterie (charged/discharged) - Einheit: kWh - Farbe: Grün (charged), Orange (discharged)

8. Temperature Monitoring (Time Series)

Typ: Time Series Panel
Metrik: Temperaturverlauf aller Batterien
Query:

SELECT 
  bd.timestamp as time,
  b.name,
  bd.temperature_avg as temperature
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '24 hours'
  AND b.enabled = true
ORDER BY bd.timestamp

Thresholds: - 🔵 Normal: < 35°C - 🟡 Warnung: 35-45°C - 🔴 Kritisch: > 45°C

9. Voltage & Current (Mixed Graph)

Typ: Time Series Panel (dual Y-axis)
Metrik: Spannung (links) und Strom (rechts)
Query:

SELECT 
  bd.timestamp as time,
  b.name || ' Voltage' as metric,
  bd.voltage as value
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '6 hours'
  AND b.enabled = true
UNION ALL
SELECT 
  bd.timestamp as time,
  b.name || ' Current' as metric,
  bd.current as value
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '6 hours'
  AND b.enabled = true
ORDER BY time

Darstellung: - Links: Voltage (V) - Linien - Rechts: Current (A) - Balken - Farben: Unterschiedlich pro Batterie

10. Battery Health (SOH) (Stat)

Typ: Stat Panel Grid
Metrik: State of Health pro Batterie
Query:

SELECT 
  b.name,
  COALESCE(bd.state_of_health, 100) as soh
FROM batteries b
LEFT JOIN LATERAL (
  SELECT state_of_health
  FROM battery_data
  WHERE battery_id = b.id
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE b.enabled = true
ORDER BY b.name

Thresholds: - 🟢 Gut: > 90% - 🟡 OK: 80-90% - 🔴 Kritisch: < 80%

11. Cycle Count (Last 30 Days)

Typ: Time Series Panel
Metrik: Zyklen-Entwicklung über 30 Tage
Query:

SELECT 
  DATE(bd.timestamp) as time,
  b.name,
  MAX(bd.cycles) as cycles
FROM battery_data bd
JOIN batteries b ON bd.battery_id = b.id
WHERE 
  bd.timestamp >= NOW() - INTERVAL '30 days'
  AND b.enabled = true
GROUP BY DATE(bd.timestamp), b.name, b.id
ORDER BY time

Anzeige: - Step-Line (Treppen-Darstellung) - Wert im Tooltip - Summe in Legende


Variables (Dashboard-Filter)

Battery Filter

Variable: $battery
Query:

SELECT name FROM batteries WHERE enabled = true ORDER BY name

Typ: Multi-Select
Label: Batterie
Default: All

Verwendung in Queries:

WHERE b.name IN ($battery)

Time Range

Standard: Last 24 hours
Custom Ranges: - Last 1 hour - Last 6 hours - Last 24 hours - Last 7 days - Last 30 days


Alerts

Konfigurierte Alerts

1. Low SOC Warning

Bedingung: SOC < 20% für > 5 Minuten
Severity: Warning
Query:

SELECT AVG(state_of_charge) as avg_soc
FROM battery_data
WHERE timestamp >= NOW() - INTERVAL '5 minutes'
GROUP BY battery_id
HAVING AVG(state_of_charge) < 20

2. High Temperature Alert

Bedingung: Temperatur > 45°C für > 2 Minuten
Severity: Critical
Query:

SELECT AVG(temperature_avg) as avg_temp
FROM battery_data
WHERE timestamp >= NOW() - INTERVAL '2 minutes'
GROUP BY battery_id
HAVING AVG(temperature_avg) > 45

3. Battery Offline

Bedingung: Keine Daten seit > 10 Minuten
Severity: Warning
Query:

SELECT b.name
FROM batteries b
LEFT JOIN LATERAL (
  SELECT timestamp
  FROM battery_data
  WHERE battery_id = b.id
  ORDER BY timestamp DESC
  LIMIT 1
) bd ON true
WHERE 
  b.enabled = true
  AND (bd.timestamp IS NULL OR bd.timestamp < NOW() - INTERVAL '10 minutes')


Dashboard-Export/Import

Export

  1. Öffne Dashboard
  2. Settings (⚙️) → JSON Model
  3. Kopiere JSON
  4. Speichere als battery-storage-dashboard.json

Import

Option 1: Provisioning (empfohlen)

Speichere Dashboard in:

deployment/grafana/dashboards/battery-storage-dashboard.json

Option 2: Manuell

  1. Grafana → Dashboards → Import
  2. Upload JSON file
  3. Wähle Datasource: SolarLog PostgreSQL
  4. Import

Datasource-Konfiguration

PostgreSQL Datasource

Name: SolarLog PostgreSQL
Host: postgres:5432
Database: solarlog_db
User: solarlog
Password: (aus .env)
SSL Mode: disable (internal network)

Provisioning-Datei:

apiVersion: 1

datasources:
  - name: SolarLog PostgreSQL
    type: postgres
    access: proxy
    url: postgres:5432
    database: solarlog_db
    user: solarlog
    secureJsonData:
      password: ${DB_PASSWORD}
    jsonData:
      sslmode: disable
      maxOpenConns: 10
      maxIdleConns: 5
      connMaxLifetime: 14400
    editable: true


Performance-Optimierung

Indexe

Wichtige Indexe für schnelle Queries:

-- Composite Index für LATERAL JOIN
CREATE INDEX idx_battery_data_battery_time 
ON battery_data(battery_id, timestamp DESC);

-- Index für Zeit-Filter
CREATE INDEX idx_battery_data_timestamp 
ON battery_data(timestamp DESC);

-- Index für Status-Filter
CREATE INDEX idx_batteries_enabled 
ON batteries(enabled) WHERE enabled = true;

Query-Caching

Einstellung in Grafana: - Cache Timeout: 60 Sekunden - Min Cache Duration: 30 Sekunden

docker-compose.yml:

environment:
  - GF_CACHING_ENABLED=true
  - GF_CACHING_TTL=60s

Daten-Retention

PostgreSQL Partition:

-- Partitionierung nach Monat
CREATE TABLE battery_data_2025_10 PARTITION OF battery_data
FOR VALUES FROM ('2025-10-01') TO ('2025-11-01');

-- Automatisches Cleanup alter Daten
DELETE FROM battery_data 
WHERE timestamp < NOW() - INTERVAL '90 days';


Troubleshooting

Dashboard lädt nicht

Problem: Weiße Seite oder Fehler

Lösung:

# Prüfe Grafana Logs
docker compose logs grafana | tail -50

# Prüfe Datasource
curl http://localhost:3001/api/datasources

# Prüfe PostgreSQL Connection
docker compose exec grafana nc -zv postgres 5432

Queries zu langsam

Problem: Panels laden > 5 Sekunden

Lösung: 1. Prüfe Indexe: EXPLAIN ANALYZE SELECT ... 2. Reduziere Zeitfenster (24h statt 7 Tage) 3. Erhöhe Aggregations-Intervall (5min statt 1min) 4. Aktiviere Query-Caching

Keine Daten sichtbar

Problem: Panels zeigen "No data"

Lösung:

# Prüfe ob Daten vorhanden
docker compose exec postgres psql -U solarlog -d solarlog_db \
  -c "SELECT COUNT(*) FROM battery_data;"

# Prüfe Demo-Daten
curl http://localhost:8080/api/v1/batteries/ | jq '.[] | {name, is_demo}'

# Generiere Demo-Daten
python3 scripts/create_demo_batteries.py


Siehe auch