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:
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:
Typ: Multi-Select
Label: Batterie
Default: All
Verwendung in Queries:
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
- Öffne Dashboard
- Settings (⚙️) → JSON Model
- Kopiere JSON
- Speichere als
battery-storage-dashboard.json
Import
Option 1: Provisioning (empfohlen)
Speichere Dashboard in:
Option 2: Manuell
- Grafana → Dashboards → Import
- Upload JSON file
- Wähle Datasource:
SolarLog PostgreSQL - 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:
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