feat(utils): adapt virtual battery and VGT interface
Tests / test (push) Successful in 46s

This commit is contained in:
dh
2026-09-27 12:28:32 +00:00
parent 92eec804a7
commit f11b1fbe61
22 changed files with 2445 additions and 104 deletions
+6 -7
View File
@@ -1,20 +1,19 @@
# Modulübersicht Enelix Utils
> Status: Verbrauchskostenreport, CC100 Hardware, Energiediagramm und Shelly
> Modul sind implementiert. Die übrigen Module sind als Diskussionsentwürfe dokumentiert.
> Status: Alle dokumentierten Enelix-Utils-Module sind implementiert.
| Modul | Herkunft | EMS-Abhängigkeit |
| --- | --- | --- |
| [Verbrauchskostenreport](Verbrauchskostenreport/README.md) | Kosten- und Verbrauchsauswertung | Keine |
| [Virtuelle Batterie](Virtuelle-Batterie/README.md) | Bat_EV_SDL_V4 | Optionaler Vertrag, keine Code-Abhängigkeit |
| [Virtuelle Batterie](Virtuelle-Batterie/README.md) | Bat_EV_SDL_V4 (implementiert) | Optionaler Vertrag, keine Code-Abhängigkeit |
| [CC100 Hardware](CC100-Hardware/README.md) | CC100_HW (implementiert) | Keine |
| [Energiediagramm](Energiediagramm/README.md) | Energy_Pie (implementiert) | Keine |
| [VGT-Schnittstelle](VGT-Schnittstelle/README.md) | MQTTPVSDL + MQTTBatterySDL | Optional konfigurierbar |
| [VGT-Schnittstelle](VGT-Schnittstelle/README.md) | MQTTPVSDL + MQTTBatterySDL (implementiert) | Optional konfigurierbar |
| [Shelly Modul](Shelly-Modul/README.md) | Shelly_Parser_MQTT | Keine |
Utils-Module beeinflussen sich nicht gegenseitig. Prognose, Lizenzierung und
Störüberwachung sind keine Module dieses Repositories.
`0*` bezeichnet einen noch nicht eingerichteten Anlagenwert. Erst nach der
Teamfreigabe erhält ein Modul `module.json`, `form.json`, `module.php` und
zugehörige Unit-Tests.
`0*` bezeichnet einen noch nicht eingerichteten Anlagenwert. Jedes Modul
besitzt `module.json`, `form.json`, `module.php`, Unit-Tests und einen
registrierten IP-Symcon-Laufzeittest.
+92 -31
View File
@@ -1,42 +1,103 @@
# VGT-Schnittstelle
> Status: Diskussionsentwurf. Führt `MQTTPVSDL` und die vorhandenen
> Batterie-Felder aus `MQTTBatterySDL` zusammen.
> Status: Implementiert fuer IP-Symcon 8.0. Fuehrt `MQTTPVSDL` und
> `MQTTBatterySDL` zusammen.
Die bestehende MQTT-Arbeitsweise und technische Alt-Idents bleiben erhalten.
Die Geräteart PV oder Batterie steuert nur die sichtbaren Felder.
Die bestehende MQTT-Schnittstelle wurde unveraendert uebernommen. Weder
Topic-Namen noch Request- und Response-Felder wurden erweitert oder
umbenannt. Die Geraeteart bestimmt nur Regelverhalten und sichtbare Messwerte.
## Variablen
## Feste MQTT-Schnittstelle
| Technischer Ident | Typ / Zugriff | Beschreibung |
| Richtung | Topic |
| --- | --- |
| Lesen | `feedback-request/{TopicSuffix}` |
| Leseantwort | `feedback-response/{TopicSuffix}` |
| Steuern | `remote-control-request/{TopicSuffix}` |
| Steuerantwort | `remote-control-response/{TopicSuffix}` |
Ein Steuerauftrag verwendet weiterhin:
```json
{
"power_setpoint": 3500,
"strategy": "activate"
}
```
Die Steuerantwort enthaelt weiterhin ausschliesslich
`power_setpoint` und `strategy`.
Die Leseantwort enthaelt fuer PV:
- `power_production`
- `is_ready`
- `is_running`
Bei der Geraeteart Batterie kommen unveraendert hinzu:
- `state_of_charge`
- `min_soc`
- `max_soc`
MQTT wird weiterhin mit Pakettyp 3, QoS 0 und `Retain=false` ueber den
IP-Symcon-MQTT-Parent verwendet.
## Batterie und virtuelle Batterie
Im Batteriemodus wird `ReqActionID` auf die Variable `SDLSollleistung`
der virtuellen Batterie gelegt. `PowerProductionID` verweist auf
`SDLIstleistung`, `SoCID` auf `SDLLadezustand`.
Die VGT-Schnittstelle schreibt niemals physische Batterieregister. Die
virtuelle Batterie priorisiert den SDL-Auftrag und verteilt den gemeinsamen
Nettosollwert.
Die Vorzeichenumkehr von Enelix 1 bleibt erhalten: Bei `activate` wird der
empfangene Batterie-`power_setpoint` mit umgekehrtem Vorzeichen an die
Zielvariable uebergeben.
## Strategien
| Strategie | PV | Batterie |
| --- | --- | --- |
| `IsReady` | Boolean / Anzeige | Bestehender Bereitschaftsstatus. |
| `IsRunning` | Boolean / Anzeige | Bestehender Bearbeitungsstatus. |
| `MinSoC` | Float / Anzeige | Nur Batterie; untere Ladezustandsgrenze. |
| `MaxSoC` | Float / Anzeige | Nur Batterie; obere Ladezustandsgrenze. |
| `PowerSetpoint` | Integer / bedienbar | Bestehende Leistungsvorgabe und Testaktion. |
| `Strategy` | String / bedienbar | Bestehende Strategie und Testaktion. |
| `LastReadResponse` | String / Anzeige | Letzte Lese-Antwort. |
| `LastWriteResponse` | String / Anzeige | Letzte Steuer-Antwort. |
| `activate` | Setpoint zwischen 0 und Maximum | invertierter Setpoint |
| `stop` | Freigabe auf konfiguriertes Maximum | 0 W |
| `restore` | keine aktive Fernbegrenzung | Regelung auf `TargetSoC` |
Im Batteriemodus verhindern `MinSoC` und `MaxSoC` eine Vorgabe in die
falsche Richtung an der jeweiligen Ladezustandsgrenze.
## Properties
| Technischer Ident | Typ | Standard / Beschreibung |
| --- | --- | --- |
| `Geraeteart` | Auswahl | `PV`; alternativ `Batterie`. |
| `TopicSuffix` | String | leer; bestehender MQTT-Suffix. |
| `ReqActionID` | Integer | `0`; bestehende Ausgabevariable/Nennleistung. |
| `PowerProductionID` | Integer | `0`; aktuelle SDL-Leistung. |
| `SoCID` | Integer | `0`; nur bei Batterie. |
| `TargetSoC` | Float | `50` %; nur bei Batterie. |
| `ChargePower` | Integer | `2500` W; nur bei Batterie. |
| `DischargePower` | Integer | `2500` W; nur bei Batterie. |
| `MaxPowerSetpoint` | Integer | `10000` W. |
| Property | Standard | Beschreibung |
| --- | ---: | --- |
| `Geraeteart` | PV | PV oder Batterie |
| `TopicSuffix` | leer | Unveraenderter MQTT-Suffix |
| `ReqActionID` | 0 | Bedienbare Zielvariable |
| `PowerProductionID` | 0 | Aktuelle SDL-/PV-Leistung |
| `SoCID` | 0 | Ladezustand im Batteriemodus |
| `TargetSoC` | 50 % | Zielwert fuer `restore` |
| `ChargePower` | 2500 W | Ladeleistung fuer `restore` |
| `DischargePower` | 2500 W | Entladeleistung fuer `restore` |
| `MaxPowerSetpoint` | 10000 W | Begrenzung eingehender Setpoints |
| `LoggingEin` | false | Debug-Ausgaben |
## Verhalten und offene Punkte
## Robustheit
- MQTT-Parent, Auftragsauswertung, Timer, Aktionen und vorhandener Testknopf
bleiben fachlicher Ausgangspunkt.
- Passende MQTT-Verbindung zuordnen oder bei der Instanziierung anlegen.
- Keine neuen Zieladapter, Protokolle oder Datenqualitätsfelder in diesem Schritt.
- Optionale EMS-Anbindung darf keine feste Repository-Abhängigkeit erzeugen.
- Zielvariablen muessen numerisch und bedienbar sein.
- MQTT-Antworten werden in einer FIFO-Warteschlange verarbeitet; schnelle
parallele Anfragen ueberschreiben sich nicht mehr.
- Fehler der Zielaktion werden als Instanzstatus und Stoertext angezeigt.
- Ungueltige JSON-Nutzdaten werden ohne Hardwareaktion verworfen.
- MQTT-Payload und Topic-Vertrag bleiben dabei vollstaendig kompatibel.
## Inbetriebnahme
1. Vorhandenen MQTT-Parent zuordnen.
2. Geraeteart und bisherigen `TopicSuffix` uebernehmen.
3. Ziel- und Messvariablen konfigurieren.
4. Im Batteriemodus die Variablen der virtuellen Batterie verwenden.
5. `MinSoC`, `MaxSoC` und `TargetSoC` pruefen.
6. Zuerst `feedback-request`, danach `stop`, `activate` und
gegebenenfalls `restore` testen.
+105 -58
View File
@@ -1,68 +1,115 @@
# Virtuelle Batterie
> Status: Diskussionsentwurf. Übernimmt `Bat_EV_SDL_V4` für die Bereiche
> Eigenverbrauch und SDL.
> Status: Implementiert fuer IP-Symcon 8.0. Adaptiert das Grundkonzept aus
> `Bat_EV_SDL_V4`, ohne dessen herstellerspezifische Typnamen zu uebernehmen.
Batterien und VGT-Kommunikation werden ausgewählt. Das Modul bleibt ohne EMS
nutzbar; eine EMS-Anbindung verwendet optional denselben Nachrichtenvertrag,
ohne Code-Abhängigkeit zwischen den Repositories.
Das Modul fasst mehrere physische Batterien zu genau einer grossen virtuellen
Batterie zusammen. Diese Gesamtbatterie wird in einen Eigenverbrauchs- und
einen SDL-Anteil aufgeteilt. SDL hat bei der Leistungsverteilung Vorrang.
## Variablen
## Verantwortlichkeiten
| Ident | Typ / Zugriff | Beschreibung |
| --- | --- | --- |
| `Aktiv` | Boolean / bedienbar | Koordination aktivieren. |
| `EigenverbrauchSollleistung` | Float / bedingt bedienbar | W; nur bei lokaler Quelle schreiben. |
| `SDLSollleistung` | Float / Anzeige | W; nur aus gültigem zeitlichem Auftrag. |
| `EigenverbrauchIstleistung` | Float / Anzeige | W; zugeordneter Anteil. |
| `SDLIstleistung` | Float / Anzeige | W; zugeordneter Anteil. |
| `GesamtIstleistung` | Float / Anzeige | W; Summe gültiger physischer Messwerte. |
| `Leistungsquelle` | Integer / Anzeige | `0` fehlt, `1` berechnet, `2` gemessen. |
| `EigenverbrauchLadezustand` | Float / Anzeige | Virtueller Füllstand in %. |
| `SDLLadezustand` | Float / Anzeige | Virtueller Füllstand in %. |
| `EigenverbrauchMaxLaden` | Float / Anzeige | Verfügbare Ladeleistung in W. |
| `EigenverbrauchMaxEntladen` | Float / Anzeige | Verfügbare Entladeleistung in W. |
| `SDLMaxLaden` | Float / Anzeige | Verfügbare Ladeleistung in W. |
| `SDLMaxEntladen` | Float / Anzeige | Verfügbare Entladeleistung in W. |
| `EigenverbrauchStart` | Float / bedienbar | Startwert 0–100 % für explizites Rücksetzen. |
| `SDLStart` | Float / bedienbar | Startwert 0–100 % für explizites Rücksetzen. |
| `VirtuelleKontenRuecksetzen` | Boolean / Impuls | `true` löst aus und wird wieder zurückgesetzt. |
| `Managerstatus` | Integer / Anzeige | Nur bei Managerquelle. |
| `VGTStatus` | Integer / Anzeige | Nur bei VGT-Quelle. |
| `Stoerung` | Boolean / Anzeige | Eigene oder zugeordnete Fehler. |
| `Stoertext` | String / Anzeige | Diagnose. |
```text
Enelix Batterie-Modul -> EV-Proxyregister --+
+-> Virtuelle Batterie -> physische Sollwerte
VGT-Schnittstelle ----> SDLSollleistung ----+
```
Die virtuelle Batterie ist die einzige Instanz, die die konfigurierten
physischen Sollleistungsvariablen beschreibt. Das bestehende EMS-Batteriemodul
regelt den Eigenverbrauchsanteil. Die VGT-Schnittstelle regelt ausschliesslich
den SDL-Anteil.
Positive Leistung bedeutet Laden, negative Leistung bedeutet Entladen.
## Physische Batterien
Die Property `Batterieliste` enthaelt pro Batterie:
| Feld | Bedeutung |
| --- | --- |
| `Name` | Lesbare Kennung |
| `Kapazitaet_kWh` | Nutzbare Kapazitaet |
| `MaxLaden_W` | Maximale Ladeleistung |
| `MaxEntladen_W` | Maximale Entladeleistung |
| `LadezustandVariableID` | Aktueller Ladezustand in Prozent |
| `IstleistungVariableID` | Gemessene Leistung in W |
| `SollleistungVariableID` | Bedienbare Zielvariable mit Vorzeichen |
Der Gesamtladezustand ist kapazitaetsgewichtet. Beim Laden werden Batterien mit
tieferem Ladezustand zuerst verwendet, beim Entladen Batterien mit hoeherem
Ladezustand.
## Anschluss des bestehenden Batteriemoduls
Eine Enelix-EMS-Instanz **Batterie** wird als herstellerunabhaengige, von Enelix
gesteuerte Batterie eingerichtet. Ihre Messwerte und Register werden auf die
Variablen der virtuellen Batterie gelegt:
| Property im EMS-Batteriemodul | Variable der virtuellen Batterie |
| --- | --- |
| `MaxLadeleistungVariableID` | `EigenverbrauchMaxLaden` |
| `MaxEntladeleistungVariableID` | `EigenverbrauchMaxEntladen` |
| `LadezustandVariableID` | `EigenverbrauchLadezustand` |
| `IstleistungVariableID` | `EigenverbrauchIstleistung` |
| `ManagementRegisterVariableID` | `EVManagement` |
| `ModusRegisterVariableID` | `EVModus` |
| `LadeleistungRegisterVariableID` | `EVLadeleistung` |
| `EntladeleistungRegisterVariableID` | `EVEntladeleistung` |
Die Netzleistungsvariable bleibt die reale Messung des Anlagenanschlusspunktes.
Das Batteriemodul schreibt die vier Proxyregister atomar in seiner bestehenden
Reihenfolge. Erst das Managementregister uebernimmt den vollstaendigen
Eigenverbrauchsauftrag.
## Anschluss der VGT-Schnittstelle
| Property der VGT-Schnittstelle | Variable der virtuellen Batterie |
| --- | --- |
| `ReqActionID` | `SDLSollleistung` |
| `PowerProductionID` | `SDLIstleistung` |
| `SoCID` | `SDLLadezustand` |
Damit erreicht kein MQTT-Befehl direkt eine physische Batterie.
## Properties
| Ident | Typ | Standard / Beschreibung |
| --- | --- | --- |
| `Batterieliste` | String/JSON | `[]`; Zielstelle, Kapazität, Grenzen und Messquellen je Batterie. |
| `Eigenverbrauchsquelle` | Integer | `0` lokal, `1` externe Variable, `2` Managervertrag. |
| `EigenverbrauchSollVariableID` | Integer | `0`; Pflicht bei Quelle 1. |
| `SDLQuelle` | Integer | `0` keine, `1` VGT-Instanz, `2` externer Auftragsdatensatz. |
| `VGTInstanzID` | Integer | `0`; Pflicht bei SDLQuelle 1. |
| `SDLAuftragVariableID` | Integer | `0`; Pflicht bei Quelle 2, inklusive Gültigkeit. |
| `SDLReserveLaden` | Float | `0` W. |
| `SDLReserveEntladen` | Float | `0` W. |
| `Reservezeit` | Float | `0.5` h; Bereich 0–24. |
| `Aktualisierungsintervall` | Integer | `2` s. |
| `MesswertMaxAlter` | Integer | `30` s. |
| `Meldeintervall` | Integer | `10` s; bei Vertragsanbindung. |
| `VorgabeTimeout` | Integer | `30` s; bei weitergeleiteten Vorgaben. |
| `AusfallEigenverbrauch` | Integer | `0` auf 0 begrenzen, `1` lokale begrenzte Vorgabe. |
| `AusfallEigenverbrauchLeistung` | Float | `0` W; nur bei Ausfallmodus 1. |
| `FilterAktiv` | Boolean | `true`. |
| `FilterToleranz` | Float | `15` %. |
| `FilterRampe` | Float | `2000` W/s. |
| `FilterTreffer` | Integer | `1`. |
| `Abgleichintervall` | Float | `6` h. |
| `Abgleichtoleranz` | Float | `2` %. |
| `DiagnoseAnzeigen` | Boolean | `false`. |
| `PrioritaetPV` | Integer | `0`; nur bei Manageranbindung. |
| `PrioritaetPeak` | Integer | `0`; nur bei Manageranbindung. |
| Property | Standard | Beschreibung |
| --- | ---: | --- |
| `Batterieliste` | `[]` | Physische Batterien und Zielvariablen |
| `SDLReserveLaden` | 0 W | Fuer SDL reservierte Ladeleistung |
| `SDLReserveEntladen` | 0 W | Fuer SDL reservierte Entladeleistung |
| `Reservezeit` | 0.5 h | Energetische Reserve je Richtung |
| `Aktualisierungsintervall` | 2 s | Zyklische Sicherheitsaktualisierung |
| `MesswertMaxAlter` | 30 s | Zulaessiges Alter physischer Messwerte |
| `VorgabeTimeout` | 30 s | Gueltigkeit der EV- und SDL-Vorgaben |
| `EigenverbrauchStart` | 50 % | Startwert des EV-Kontos |
| `SDLStart` | 50 % | Startwert des SDL-Kontos |
| `LoggingEin` | false | Debug-Ausgaben |
## Verhalten und offene Punkte
## Verhalten und Sicherheit
Eigenverbrauch und SDL ergeben zusammen genau einen begrenzten Batteriesollwert.
Pro physischer Batterie darf nur eine Stelle führen. Messgrundlage und
Aufteilung der berechneten Leistungsanteile sind im Test eindeutig zu belegen.
- SDL wird vor dem Eigenverbrauch auf die reservierte Leistung begrenzt.
- Gleichgerichtete Eigenverbrauchsleistung erhaelt nur die verbleibende
physische Leistung.
- Gegenlaeufige Auftraege werden bilanziell getrennt und physisch als
Nettosollwert verteilt.
- Fehlende oder veraltete Batterien werden aus der aktuellen Aggregation
entfernt und auf 0 W gesetzt.
- Bei Deaktivierung, ungueltiger Konfiguration oder ohne gueltige Batterie
werden alle physischen Sollleistungsvariablen auf 0 W gesetzt.
- Eine erkannte Integrationsluecke wird gemeldet und nicht still auf eine
kuerzere Dauer begrenzt.
- Physische Zielvariablen werden ausschliesslich mit `RequestAction`
geschrieben.
## Inbetriebnahme
1. Mess- und Sollleistungsvariablen aller physischen Batterien festlegen.
2. Batterieliste konfigurieren und Messwertalter kontrollieren.
3. SDL-Leistungsreserve und Reservezeit eintragen.
4. Das vorhandene EMS-Batteriemodul auf die EV-Proxyregister konfigurieren.
5. Die VGT-Schnittstelle auf die drei SDL-Variablen konfigurieren.
6. Zuerst mit deaktivierter virtueller Batterie alle Vorzeichen pruefen.
7. Danach Eigenverbrauch und SDL einzeln testen.
8. Erst abschliessend gleich- und gegenlaeufige Auftraege pruefen.