No description
  • Python 43.8%
  • JavaScript 37.7%
  • HTML 11.8%
  • CSS 6.5%
  • Dockerfile 0.2%
Find a file
2026-06-28 12:07:19 +01:00
app Change update time 2026-06-28 12:07:19 +01:00
static Update Time change 2026-06-28 11:52:14 +01:00
tests fix: Null-Pointer, Solarladen-Phasenerkennung, Echtzeit-Verbesserung 2026-06-25 14:35:52 +00:00
.dockerignore feat: PostgreSQL-Migration, Plotly-Charts, OCPP-Server, API-Key-Rollen, Bugfixes 2026-06-25 09:25:01 +00:00
.env.example docs: README aktualisiert, .env.example erweitert 2026-06-25 09:41:12 +00:00
.gitignore feat: PostgreSQL-Migration, Plotly-Charts, OCPP-Server, API-Key-Rollen, Bugfixes 2026-06-25 09:25:01 +00:00
docker-compose.yml feat: PostgreSQL-Migration, Plotly-Charts, OCPP-Server, API-Key-Rollen, Bugfixes 2026-06-25 09:25:01 +00:00
Dockerfile feat: PostgreSQL-Migration, Plotly-Charts, OCPP-Server, API-Key-Rollen, Bugfixes 2026-06-25 09:25:01 +00:00
README.md docs: README aktualisiert – PostgreSQL, OCPP, Plotly, API-Rollen, Wallbox 2026-06-25 09:40:02 +00:00
requirements.txt feat: PostgreSQL-Migration, Plotly-Charts, OCPP-Server, API-Key-Rollen, Bugfixes 2026-06-25 09:25:01 +00:00

DEYE Solar Monitor

Vollständige Web-Applikation zur Überwachung und Steuerung eines DEYE-Wechselrichters (SUN SG05LP3-EU) über Modbus, mit OCPP-Wallbox-Integration für Go-e Gemini.

Features

  • Solar Monitor mit animiertem Energiefluss-Diagramm (Solar → WR → Batterie/Netz/Haus)
  • Live-Daten mit 1-Sekunden-Refresh: Spannung, Strom, Leistung, Temperatur für alle Komponenten
  • Verlaufs-Charts mit Plotly (interaktiv, Zoom, Pan, Hover-Tooltips)
  • Energie-Logging: Kumulative Zähler als Delta, Live-Werte als Mittelwert
  • Selbstbaubare Dashboards mit Widgets (Karte, Radial, Balken, Säule, Text)
  • Rohe Modbus-Daten in Echtzeit mit Register-Naming
  • OCPP 1.6 Server für Go-e Gemini Wallbox
  • Wallbox-Steuerung: Solarladen, Chip-basierte Regeln, Ladestrombegrenzung
  • API mit Rollen-basiertem Key-Schutz (Admin vs. Limited)
  • PostgreSQL als externe Datenbank
  • 5 GB Log-Limit mit automatischer Bereinigung
  • Passwortschutz nur bei externem Zugriff (Heimnetz = frei)

Architektur

┌────────────────────────────────────────────────────────┐
│  Browser (Heimnetz oder extern)                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Frontend (vanilla JS + Plotly, Single-Page)      │  │
│  │  • Solar Monitor (Flow-Diagramm + Detail-Karten)  │  │
│  │  • Dashboards (selbstbaubar)                      │  │
│  │  • Verlauf (Plotly-Charts)                        │  │
│  │  • Rohdaten (Modbus Register)                     │  │
│  │  • Wallbox (Status, Transaktionen, Regeln)        │  │
│  │  • Admin (Felder, Keys, Modbus, Logging)          │  │
│  │  • API-Dokumentation                              │  │
│  └──────────────────────────────────────────────────┘  │
└────────────────────────┬───────────────────────────────┘
                         │ HTTP / WebSocket
┌────────────────────────▼───────────────────────────────┐
│  FastAPI Backend (Port 8000)                           │
│  ┌──────────┐ ┌──────────┐ ┌───────────────────────┐   │
│  │ Auth-MW  │ │ Modbus   │ │ Logger-Service        │   │
│  │ IP/Passw.│ │ Reader   │ │ (Background, 2s)      │   │
│  │ API-Keys │ │ real/mock│ │ Live→Mittelwert       │   │
│  │ Rollen   │ └──────────┘ │ Cumul→Delta/Running   │   │
│  └──────────┘               └───────────┬───────────┘   │
│  ┌──────────────────┐ ┌──────────────┐  │               │
│  │ OCPP 1.6 Server  │ │ Maintenance  │  │               │
│  │ (Port 9000, WS)  │ │ (5GB Limit)  │  │               │
│  └──────────────────┘ └──────────────┘  │               │
│                           ┌─────────────▼─────────────┐ │
│                           │  asyncpg Connection-Pool  │ │
│                           └─────────────┬─────────────┘ │
└─────────────────────────────────────────┼───────────────┘
                                          │
┌─────────────────────────────────────────▼───────────────┐
│  PostgreSQL 16 (externer Docker-Container)              │
│  • log_entries, readings, external_data                 │
│  • api_keys, dashboards, settings_kv                    │
│  • ocpp_transactions, ocpp_id_tags, ocpp_charging_rules │
│  • wallbox_state, register_names                        │
└─────────────────────────────────────────────────────────┘

Modbus-Mapping

Das Feld-Mapping basiert auf der V6.2-Konfiguration [1]. Es umfasst:

  • Batterie: SOC, Spannung, Strom, Leistung, Ladung/Entladung (Heute/Gesamt), Health, Temperatur
  • Netz: Spannung/Leistung L1-L3, Bezug/Einspeisung (Heute/Gesamt), Frequenz
  • Solar: Leistung/Spannung/Strom String 1+2, Erzeugung (Heute/Gesamt)
  • Haus: Verbrauch L1-L3, Gesamt, Frequenz (Heute/Gesamt)
  • Temperatur: Transformator, Kühlkörper, Batterie (Rohwert 100 °C)
  • Konfiguration: Lademodi, Mindestladung, Batteriekapazität, max. Lade-/Entladestrom
  • Status: Invertertyp, Status, On/Off, Battery Info

Faktor-Korrekturen

Einige Faktoren aus dem Mapping [1] wurden korrigiert, da sie in der Originaldatei nicht stimmten:

Feld Original-Faktor Korrigierter Faktor Bemerkung
Batterie Ausgangsleistung 10 10 DataType 5 (signed), bereits korrekt
Batterie Ausgangsstrom 0.01 0.01 DataType 5 (signed), bereits korrekt
Solarerzeugung String 1 Heute 0.01 0.01 Bereits korrekt
Einspeisung Gesamt 0.01 0.01 Bereits korrekt
Netzbezug aktuell L1-L3 0 1 Factor 0 → 1 (Watt.I Profil)
Hausverbrauch L1-L3 0 1 Factor 0 → 1 (Watt.I Profil)
Solarleistung String 1/2 0 1 Factor 0 → 1 (Watt.I Profil)

Virtuelle Felder

Temperaturen werden aus Rohregistern berechnet (Rohwert 100 °C), Zeitpunkte aus Integer HHMM zu "HH:MM" formatiert.

Logging-Logik

Der Logger liest alle 2 Sekunden (einstellbar) die Modbus-Werte:

  • Live-Felder (type: "live"): Werte werden über ein Intervall gepuffert und als Mittelwert gespeichert.
  • Kumulative Felder (type: "cumulative"): Werte werden als Delta zum letzten Lesevorgang gespeichert.
  • Total-Zähler (Felder mit "Total" im Namen): Deltas werden zu einem fortlaufenden Stand kumuliert. Das verhindert Spikes bei geringer Zählerauflösung (z. B. 0 → 1 → 0 → 1).

Reset-Erkennung: Wenn ein kumulativer Zähler zurückgesetzt wird (Tageswechsel), wird kein negativer Delta geloggt.

Docker-Deployment

Mit docker-compose (empfohlen)

cd deye
docker compose up --build -d

Das startet automatisch:

  • PostgreSQL (Port 5432, persistentes Volume)
  • DEYE App (Port 8002, Modbus + OCPP)
  • OCPP-Server (Port 9000, WebSocket)

Konfiguration

Alle Einstellungen über Umgebungsvariablen (Prefix DEYE_):

Variable Standard Beschreibung
DEYE_MODBUS_MODE mock real oder mock (Test)
DEYE_ADMIN_PASSWORD admin Passwort für externen Zugriff
DEYE_MODBUS_PORT /dev/ttyUSB0 Serial-Port
DEYE_MODBUS_BAUDRATE 9600 Baudrate
DEYE_MODBUS_DEVICE_ID 1 Modbus Geräte-ID
DEYE_LOG_INTERVAL 2 Logging-Intervall (Sekunden)
DEYE_DB_HOST localhost PostgreSQL Host
DEYE_DB_PORT 5432 PostgreSQL Port
DEYE_DB_NAME deye Datenbankname
DEYE_DB_USER deye DB-Benutzer
DEYE_DB_PASSWORD deye DB-Passwort
DEYE_OCPP_ENABLED true OCPP-Server aktivieren
DEYE_OCPP_PORT 9000 OCPP WebSocket-Port
DEYE_WALLBOX_CP_ID goe ChargePoint ID der Wallbox

Zugriff

  • Web-UI: http://<raspberry-pi-ip>:8002 im Heimnetz ohne Passwort
  • OCPP: ws://<raspberry-pi-ip>:9000/goe in der Go-e Gemini als OCPP-URL eintragen
  • API-Doku: http://<raspberry-pi-ip>:8002/docs (Swagger)

Go-e Gemini einrichten

  1. In der Go-e App unter Experte → OCPP aktivieren
  2. OCPP-URL eintragen: ws://<raspberry-pi-ip>:9000/goe
  3. Protokoll: OCPP 1.6
  4. Die Wallbox verbindet sich automatisch und erscheint im Wallbox-Tab

API-Endpunkte

Interne API (Browser-Session oder lokal)

Route Methode Beschreibung
/api/live GET Live-Daten aller Felder
/api/live/{field} GET Ein einzelnes Feld
/api/raw GET Rohe Modbus-Register (mit Namen)
/api/log GET Log-Einträge (filterbar)
/api/log/batch GET Log-Daten für mehrere Felder in einem Request
/api/log DELETE Log-Einträge löschen (optional pro Feld)
/api/admin/fields GET/PUT/POST/DELETE Felder verwalten
/api/admin/modbus GET/PUT Modbus-Settings
/api/admin/modbus/write POST Modbus-Register schreiben
/api/admin/interval GET/PUT Log-Intervall
/api/admin/apikeys GET/POST/DELETE API-Keys verwalten (mit Rollen)
/api/admin/dashboards GET/POST/DELETE Dashboards verwalten
/api/admin/db/size GET Datenbankgröße
/api/admin/db/cleanup POST Log-Bereinigung auslösen

Wallbox-API

Route Methode Beschreibung
/api/wallbox/status GET Wallbox-Status (Leistung, Strom, Energie)
/api/wallbox/transactions GET Ladehistorie
/api/wallbox/id-tags GET/POST/DELETE RFID-Chips verwalten
/api/wallbox/rules GET/POST/DELETE Laderegeln verwalten
/api/wallbox/control POST Wallbox steuern (Start/Stop/Strom setzen)

Externe API (API-Key nötig, Header: X-API-Key)

Route Methode Beschreibung
/api/external/live GET Live-Daten (gefiltert nach Key-Rechten)
/api/external/log GET Log-Daten (gefiltert nach Key-Rechten)
/api/external/raw GET Rohdaten (nur Admin-Keys)
/api/external/write POST Modbus schreiben (nur Admin-Keys)

API-Key-Rollen

  • Admin: Voller Zugriff inkl. Schreibrechte, Rohdaten, Wallbox-Steuerung
  • Limited: Nur Lesen, auf ausgewählte Felder beschränkt

Beispiel

# Live-Daten mit API-Key
curl -H "X-API-Key: <key>" http://pi:8002/api/external/live

# Log-Daten für mehrere Felder (Batch)
curl "http://pi:8002/api/log/batch?fields=BatSOC,PV1_P&limit=5000"

# Wallbox Ladestrom setzen
curl -X POST -H "Content-Type: application/json" \
  -d '{"action":"set_current","current_a":10}' \
  http://pi:8002/api/wallbox/control

Wallbox-Regeln

Drei Regel-Typen stehen zur Verfügung:

  • Solarladen: Nutzt PV-Überschuss (PV-Leistung Hausverbrauch) zum Laden. Bei ausreichendem Überschuss wird der Ladestrom automatisch berechnet (230V × 3-phasig).
  • Solarladen (Chip-basiert): Wie Solarladen, aber nur für bestimmte RFID-Tags aktivierbar.
  • Ladestrombegrenzung: Setzt einen festen Maximalstrom unabhängig vom PV-Überschuss.

Regeln werden im Wallbox-Tab erstellt und angewendet, sobald die Wallbox lädt.

Felder-Definition

Jedes Feld hat folgende Eigenschaften:

Feld Typ Beschreibung
name string Eindeutiger Name (z.B. BatV)
realname string Anzeigename (z.B. Batterie Spannung)
address int Absolute Modbus-Register-Adresse
factor float Skalierungsfaktor (Wert × factor)
unit string Einheit (z.B. V, W, %, kWh)
signed bool Vorzeichenbehaftet (für negative Werte)
type string live (Mittelwert) oder cumulative (Delta)
log bool Soll dieses Feld geloggt werden?

Entwicklung / Test

Für Tests ohne echten Modbus-Adapter: DEYE_MODBUS_MODE=mock setzen. Der Mock generiert realistische sinusförmige Werte.

# PostgreSQL starten (oder extern nutzen)
docker run -d --name deye-pg -e POSTGRES_DB=deye -e POSTGRES_USER=deye \
  -e POSTGRES_PASSWORD=deye -p 5432:5432 postgres:16-alpine

# Lokal starten (Testmodus)
DEYE_MODBUS_MODE=mock DEYE_DB_HOST=localhost uvicorn app.main:app --port 8080

Dateistruktur

deye/
├── app/
│   ├── __init__.py
│   ├── config.py           # Konfiguration (Modbus, DB, OCPP)
│   ├── database.py         # PostgreSQL-Schema & Queries (asyncpg)
│   ├── modbus_reader.py    # Modbus-Reader (real + mock, V6.2-Mapping)
│   ├── logger_service.py   # Logger-Background-Service
│   ├── ocpp_server.py      # OCPP 1.6 WebSocket-Server
│   ├── auth.py             # Auth-Middleware & API-Key-Rollen
│   └── main.py             # FastAPI-Routen
├── static/
│   ├── index.html          # Haupt-App (Single-Page)
│   ├── login.html          # Login-Seite
│   └── js/
│       ├── api.js          # API-Wrapper mit Deduplication
│       ├── app.js          # Haupt-App, Navigation, Live-Polling
│       ├── widgets.js      # Widget-Engine (Card, Radial, Balken, Säule)
│       ├── view-solar.js   # Solar Monitor (Flow-Diagramm)
│       ├── view-dashboard.js # Dashboard Builder
│       ├── view-log.js     # Verlauf (Plotly-Charts)
│       ├── view-raw.js     # Rohdaten (Modbus Register)
│       ├── view-wallbox.js # Wallbox (Status, Regeln, Transaktionen)
│       ├── view-admin.js   # Admin (Modbus, Felder, Keys, Logging)
│       └── view-api-docs.js # API-Dokumentation
├── Dockerfile
├── docker-compose.yml      # PostgreSQL + DEYE App
├── requirements.txt
└── .env.example