From c1a77b0dbcd8d291cc5d9dd37874586efcdd166d Mon Sep 17 00:00:00 2001 From: DanielHaefliger Date: Tue, 12 May 2026 14:24:37 +0200 Subject: [PATCH] =?UTF-8?q?Batteriemodul=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Batterie/README.md | 122 ++++++++++ Batterie/form.json | 103 +++++++++ Batterie/module.json | 12 + Batterie/module.php | 527 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 764 insertions(+) create mode 100644 Batterie/README.md create mode 100644 Batterie/form.json create mode 100644 Batterie/module.json create mode 100644 Batterie/module.php diff --git a/Batterie/README.md b/Batterie/README.md new file mode 100644 index 0000000..8e1f19b --- /dev/null +++ b/Batterie/README.md @@ -0,0 +1,122 @@ +# Enelix-Verbrauchermodul Batterie + +Dieses Modul integriert Batteriespeicher als steuerbare Verbraucher/Erzeuger in das Belevo Energiemanagement-System (Enelix). Es berechnet dynamisch Lade- und Entladevorgaben, kommuniziert mit dem übergeordneten Manager und steuert native Wechselrichter-Schnittstellen. + +--- + +## Inhaltsverzeichnis + +1. [Funktionsumfang](#1-funktionsumfang) +2. [Voraussetzungen](#2-voraussetzungen) +3. [Installation](#3-installation) +4. [Instanz anlegen & Konfiguration](#4-instanz-anlegen--konfiguration) +5. [Statusvariablen & Profile](#5-statusvariablen--profile) +6. [WebFront / Bedienung](#6-webfront--bedienung) +7. [Mapping auf Code-Komponenten](#7-mapping-auf-code-komponenten) +8. [Zukünftige Erweiterungen](#8-zukünftige-erweiterungen) + +--- + +## 1. Funktionsumfang + +- **Zyklische Steuerung:** In konfigurierbaren Intervallen (`Interval`) berechnet das Modul die aktuell verfügbaren Leistungsschritte und aktualisiert den Status. +- **Hersteller-Integration:** Native Steuerlogik für spezifische Wechselrichter (Goodwe, Solaredge, Sig Energy). Die Modus-Umschaltung (Laden/Entladen/Standby) erfolgt automatisch durch setzen der passenden Hersteller-Codes. +- **PowerSteps-Generierung:** Das Modul meldet dem Enelix-Manager ein Array an möglichen Leistungsschritten (`PowerSteps`), berechnet aus der maximalen Lade- (`MaxBatterieleistung`) und Entladeleistung (`MaxNachladen`). Dies geschieht in 250 Watt schritten, wobei zur feineren Regelung um den aktuellen Sollwert noch 50W-Schritte verteilt werden. +- **Peak-Shaving vs. PV-Überschuss:** Automatische Anpassung der angebotenen `PowerSteps` basierend auf dem vom Manager vorgegebenen Modus (`Is_Peak_Shaving`). Im Peak-Shaving-Modus arbeitet die Batterie im unteren SoC-Bereich um lastspitzen zu brechen, im Solarmodus im oberen Bereich um den Eigenverbruach zu optimieren. +- **Peak-Shaving-Reserve:** Berücksichtigung des Ladezustands (SoC). Eine einstellbare Reserve (`AufdasNachladen`) wird für das Peak-Shaving vorgehalten. Bei Unterschreitung der Minimalkapazität (`MinimumEntladen`) wird die Entladung blockiert. + +--- + +## 2. Voraussetzungen + +- IP-Symcon **≥ 8.0** +- Modul-URL: `https://git.belevo.ch/dh/enelix.git` +- Vorhandener und eingerichteter Enelix Manager. +- Anbindung der Wechselrichter-Variablen (Netzbezug, SoC, Batterieleistung) in IP-Symcon. + +--- + +## 3. Installation + +1. In IP-Symcon **Module Control** öffnen. +2. **Hinzufügen → Git-Repository**. +3. URL eingeben und **Installieren**. +4. IP-Symcon neu starten. + +--- + +## 4. Instanz anlegen & Konfiguration + +### 4.1 Instanz anlegen + +- Rechtsklick **Instanzen** → **Instanz hinzufügen** +- Filter: **Belevo** +- Auswahl: **Batterie (Verbraucher)** + +### 4.2 Properties + +| Name | Typ | Beschreibung | +|---|---|---| +| **IdleCounterMax** | NumberSpinner | Anzahl der Intervall-Zyklen zwischen zwei Leistungsänderungen. | +| **Interval** | NumberSpinner | Berechnungsintervall in Sekunden. | +| **Batterietyp** | Select | Wechselrichter-Typ (0: Unabhängig, 1: Goodwe, 2: Solaredge, 3: Sig Energy). | +| **MaxBatterieleistung** | SelectVariable | Maximale Ladeleistung der Batterie (Watt). | +| **MaxNachladen** | SelectVariable | Maximalen Entladeleistung der Batterie (Watt). | +| **AufdasNachladen** | NumberSpinner | Nachladekapazität (Reserve für Peak-Shaving in %). | +| **MinimumEntladen** | NumberSpinner | Minimale Kapazität (Tiefenentladeschutz in %). | +| **Batteriemanagement** | Select | Steuerung der Batterie durch (1: Wechselrichter, 2: Manager Enelix). | +| **Batterieladezustand**| SelectVariable | Variable mit dem aktuellen Batterieladestand (SoC in %). | +| **Netzbezug** | SelectVariable | Variable mit dem zu regelnden Netzbezug (identisch mit Manager). | +| **AktuelleBatterieleistung**| SelectVariable| Variable mit der aktuellen Ist-Leistung der Batterie. | + +--- + +## 5. Statusvariablen & Profile + +| Ident | Typ | Beschreibung | +|---|---|---| +| **PowerSteps** | String | JSON-Array der dem Manager angebotenen Leistungsschritte. | +| **Aktuelle_Leistung** | Integer | Die aktuell von der Batterie erbrachte Leistung. | +| **Power** | Integer | Interner | Die aktuell vom Manager zugewiesene Soll-Leistung. | +| **Laden_Entladen** | Integer | Herstellerspezifischer Code zum Einstellen des Lademodi (z.B. Goodwe: 11=Laden, 12=Entladen). | +| **Idle** | Boolean | Status der Sperrzeit (`true` = bereit für neue Werte, `false` = gesperrt). | +| **Hysterese** | Boolean | Zeigt an, ob die Batterie aktuell in Hystere nachregelt. | +| **Bezogene_Energie** | Float | Rechnerisch aufsummierte Energie (Leistung × Zeit). | +| **PV_Prio** | Integer | Priorität des Verbrauchers für PV-Optimierung, Tiefe Nummer = Hohe Priorität | +| **Sperre_Prio** | Integer | Priorität des Verbrauchers für Peak-Optimierung, Tiefe Nummer = Hohe Priorität | +| **Bezogene_Energie** | Float | Rechnerisch aufsummierte Energie (Leistung × Zeit). | +| **Is_Peak_Shaving** | Boolean | Vom Manager übermittelter aktueller Betriebsmodus. | +| **Goodwe_EntLadeleistung** | Interner | Zusatzvariable für Steuerung der Sollleistung bei Goodwespeichern | +| **Ladeleistung** | Interner | Sollladelesistung Speicher | +| **Entladeleistung** | Interner | Sollentladeleistung Speicher | + +*(Die Variabeln `Goodwe_EntLadeleistung`, `Ladeleistung` oder `Entladeleistung` werden in abhängigkeit von `Batterietyp` angelegt).* + +--- + +## 6. WebFront / Bedienung + +Die Anbindung der Batterie sowie die regelung der Prioritäten wird über folgende Variabeln eingestellt: +`Laden_Entladen`- Signalisation ob Speicher laden soll oder entladen (Herstellerunabhängig 0 = Laden, 1 = Entladen, ansonsten Herstellerabhängige Werte) +`Ladeleistung` - Soll Ladeleistung Speicher +`Entladeleistung` - Soll Entladeleistung Speicher +`Goodwe_EntLadeleistung`- Zusatzvariable Entladeleistung für Goodwe-Speicher + +`PV_Prio` - Priorität des Verbrauchers für PV-Optimierung, Tiefe Nummer = Hohe Priorität +`Sperre_Prio` - Priorität des Verbrauchers für Peak-Optimierung, Tiefe Nummer = Hohe Priorität + +## 7. Mapping auf Code-Komponenten + +| Komponente | Funktion im Code (`module.php`) | +|---|---| +| **Timer-Registrierung** | `ApplyChanges()` setzt `Timer_Do_UserCalc_Battery` basierend auf `Interval`. Erstellt die passenden Variabeln auf basis des Batterietyps | +| **PowerSteps Generierung**| `GeneratePowerSteps()` baut das Raster aus zulässigen Werten basierend auf MaxLaden/Entladen in 250er/50er Schritten auf. | +| **Betriebslogik & Limits**| `GetCurrentData($Peak)` filtert die `PowerSteps` je nach SoC, Hysterese und Peak-Modus. | +| **Leistungszuteilung** | `SetAktuelle_Leistung($power)` übersetzt die vom Manager geforderte Leistung in herstellerspezifische Variablen und Steuercodes. | + + +--- + +## 8. Zukünftige Erweiterungen + +- **Wetter- und Prognosedaten:** Dynamische Anpassung des Parameters `AufdasNachladen` basierend auf dem zu erwartenden Solarertrag, Anpassung des Parameters auf Monate umd Peak auf Monatsende zu optimieren. diff --git a/Batterie/form.json b/Batterie/form.json new file mode 100644 index 0000000..563125c --- /dev/null +++ b/Batterie/form.json @@ -0,0 +1,103 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Konfiguration Enelix-Verbrauchermodul Batterie" + }, + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Anzahl Interval-Zyklen zwischen zwei Leistungsänderungen", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte", + "suffix": "Sekunden" + }, + { + "type":"Select", + "name":"Batterietyp", + "caption":"Batterietyp", + "options":[ + { + "caption":"Herstellerunabhängig", + "value":0 + }, + { + "caption":"Goodwe", + "value":1 + }, + { + "caption":"Solaredge", + "value":2 + }, + { + "caption":"Sig Energy", + "value":3 + } + ] + }, + { + "type": "SelectVariable", + "name": "MaxBatterieleistung", + "caption": "Maximale Ladeleistung Batterie", + "suffix": "" + }, + { + "type": "SelectVariable", + "name": "MaxNachladen", + "caption": "Maximum Nachladeleistung Batterie", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "AufdasNachladen", + "caption": "Nachladekapazität für Peakshavingreserve", + "suffix": "" + + }, + { + "type": "NumberSpinner", + "name": "MinimumEntladen", + "caption": "Maximale Entladetiefe", + "suffix": "" + }, + { + "type":"Select", + "name":"Batteriemanagement", + "caption":"Steuerung der Batterie durch -", + "options":[ + { + "caption":"Wechselrichter (Verbraucher deaktiviert sich am Manager)", + "value":1 + }, + { + "caption":"Manager Enelix", + "value":2 + } + ] + }, + { + "type": "SelectVariable", + "name": "Batterieladezustand", + "caption": "Batterieladestand", + "test": true + }, + { + "type": "SelectVariable", + "name": "Netzbezug", + "caption": "Variable mit dem zu regelnden Netzbezug (= Netzbezug im Manager)" + }, + { + "type": "SelectVariable", + "name": "AktuelleBatterieleistung", + "caption": "Variable mit der aktueller Batterieleistung" + }, + { + "type": "Label", + "caption": "Je nach Wr-Type bekommt Laden_Entlade andere Werte.\nGoodwe: Laden=11, Entladen=12,\nSolaredge: Laden=3, Entladen=4,\nSig Energy: Laden=3, Entladen=6, P in kW" + } + ] +} diff --git a/Batterie/module.json b/Batterie/module.json new file mode 100644 index 0000000..1edd4f1 --- /dev/null +++ b/Batterie/module.json @@ -0,0 +1,12 @@ +{ + "id": "{166B9E49-882B-ADED-F256-4DD4CC24DF6C}", + "name": "Batterie", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "https://git.belevo.ch/dh/Enelix/src/branch/main/Batterie" +} \ No newline at end of file diff --git a/Batterie/module.php b/Batterie/module.php new file mode 100644 index 0000000..4c385f2 --- /dev/null +++ b/Batterie/module.php @@ -0,0 +1,527 @@ +RegisterPropertyInteger("MaxBatterieleistung", 0); + $this->RegisterPropertyInteger("Batteriespannung", 50); + $this->RegisterPropertyInteger("AufdasNachladen",0); + $this->RegisterPropertyInteger("MinimumEntladen",0); + $this->RegisterPropertyInteger("Batterieladezustand",0); + $this->RegisterPropertyInteger("Batteriemanagement", 1); + $this->RegisterPropertyInteger("Batterietyp", 1); + $this->RegisterPropertyInteger("MaxNachladen",0); + $this->RegisterPropertyInteger("Netzbezug", 0); + $this->RegisterPropertyInteger("AktuelleBatterieleistung", 0);// Initialisierung mit 0 + $this->RegisterPropertyInteger("Interval", 2); // Recheninterval + $this->RegisterVariableInteger("Batteriemanagement_Variabel","Batteriemanagement_Variabel", "",0); + $this->RegisterVariableInteger("Laden_Entladen","Laden_Entladen", "",3); + $this->RegisterVariableBoolean("Hysterese", "Hysterese","",false); + + + + // Variabeln für Kommunkation mit Manager + $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle zugeteilte Leistung", "", 0); + $this->RegisterVariableString("PowerSteps", "Leistungsschritte"); + $this->RegisterVariableBoolean("Idle", "Idle", "", 0); + $this->RegisterVariableInteger("Sperre_Prio", "Priorität Peakshaving"); + $this->RegisterVariableInteger("PV_Prio", "Priorität PV"); + $this->RegisterVariableInteger("Power", "Leistung Batterie"); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Peakshavingmodus"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung Delta", "", 0); + $this->RegisterVariableFloat("Bezogene_Energie", "Bezogene Energie", "", 0); + + // Hilfsvariabeln für Idle zustand + $this->RegisterPropertyInteger("IdleCounterMax", 2); + $this->RegisterVariableInteger("IdleCounter", "IdleCounter", "", 0); + $this->SetValue("IdleCounter", 0); + + // Initialisiere Idle + + $this->RegisterTimer("Timer_Do_UserCalc_Battery",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + + $batterieManagement = $this->ReadPropertyInteger("Batteriemanagement"); + $this->SetValue("Batteriemanagement_Variabel", $batterieManagement); + $this->SetTimerInterval("Timer_Do_UserCalc_Battery",$this->ReadPropertyInteger("Interval")*1000); + + $batterietyp = $this->ReadPropertyInteger("Batterietyp"); + + // Batterietypabhängige Variabeln Initialisieren + switch ($batterietyp) { + case 0: // Herstellerunabhängig + + $this->MaintainVariable("Goodwe_EntLadeleistung", "Goodwe_EntLadeleistung", VARIABLETYPE_FLOAT, "", 10, false); + $this->MaintainVariable("Ladeleistung", "Ladeleistung", VARIABLETYPE_FLOAT, "", 11, false); + $this->MaintainVariable("Entladeleistung", "Entladeleistung", VARIABLETYPE_FLOAT, "", 13, false); + break; + + case 1: // Goodwe + $this->MaintainVariable("Goodwe_EntLadeleistung", "Goodwe_EntLadeleistung", VARIABLETYPE_FLOAT, "", 10, true); + $this->MaintainVariable("Ladeleistung", "Ladeleistung", VARIABLETYPE_FLOAT, "", 11, false); + $this->MaintainVariable("Entladeleistung", "Entladeleistung", VARIABLETYPE_FLOAT, "", 13, false); + break; + + case 2: // Solaredge + $this->MaintainVariable("Goodwe_EntLadeleistung", "Goodwe_EntLadeleistung", VARIABLETYPE_FLOAT, "", 10, false); + $this->MaintainVariable("Ladeleistung", "Ladeleistung", VARIABLETYPE_FLOAT, "", 11, true); + $this->MaintainVariable("Entladeleistung", "Entladeleistung", VARIABLETYPE_FLOAT, "", 13, true); + break; + + case 3: // SiG Energy + $this->MaintainVariable("Goodwe_EntLadeleistung", "Goodwe_EntLadeleistung", VARIABLETYPE_FLOAT, "", 10, false); + $this->MaintainVariable("Ladeleistung", "Ladeleistung", VARIABLETYPE_FLOAT, "", 11, true); + $this->MaintainVariable("Entladeleistung", "Entladeleistung", VARIABLETYPE_FLOAT, "", 13, true); + break; + + default: + // Default, werden alle ausgeschaltet + $this->MaintainVariable("Goodwe_EntLadeleistung", "Goodwe_EntLadeleistung", VARIABLETYPE_FLOAT, "", 10, false); + $this->MaintainVariable("Ladeleistung", "Ladeleistung", VARIABLETYPE_FLOAT, "", 11, false); + $this->MaintainVariable("Entladeleistung", "Entladeleistung", VARIABLETYPE_FLOAT, "", 13, false); + break; + } + + // + $maxBatVar = $this->ReadPropertyInteger("MaxBatterieleistung"); + $maxNachVar = $this->ReadPropertyInteger("MaxNachladen"); + + if ($maxBatVar > 0) { + $this->RegisterMessage($maxBatVar, VM_UPDATE); + } + if ($maxNachVar > 0) { + $this->RegisterMessage($maxNachVar, VM_UPDATE); + } + + + } + + +public function RequestAction($Ident, $Value) +{ + switch ($Ident) { + + case "SetAktuelle_Leistung": + $this->SetValue("Power", (int)$Value); + break; + + case "GetCurrentData": + $this->SetValue("Is_Peak_Shaving", (bool)$Value); + break; + + + case "Do_UserCalc": + + $this->SetAktuelle_Leistung($this->GetValue("Power")); + $this->GetCurrentData($this->GetValue("Is_Peak_Shaving")); + break; + + default: + break; + + } +} + + // Nach aufruf bei anpassung Batteriewerte, sofort Getcurrentdata aufrufen. + public function MessageSink($TimeStamp, $SenderID, $Message, $Data) +{ + if ($Message !== VM_UPDATE) { + return; + } + + $maxBatVar = $this->ReadPropertyInteger("MaxBatterieleistung"); + $maxNachVar = $this->ReadPropertyInteger("MaxNachladen"); + + if ($SenderID === $maxBatVar || $SenderID === $maxNachVar) { + // PowerSteps sofort neu berechnen (mit aktuellem Peak-Status) + $this->GetCurrentData($this->GetValue("Is_Peak_Shaving")); + } +} + + + + // Aktuelle Leistung setzen lassen, der Manager vorgibt + public function SetAktuelle_Leistung(int $power) + { + + $batterietyp = $this->ReadPropertyInteger("Batterietyp"); + $batterieManagement = $this->ReadPropertyInteger("Batteriemanagement"); + + //Fallunterscheidung, soll Enelix überhaupt steuern? + + // Wechselrichter steuert + // Goodwe, Solaredge WR Modus + if ($batterieManagement == 1 && ($batterietyp == 1 || $batterietyp == 2)) { + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Batteriemanagement_Variabel", 1); + return; + //Sig Energy, Herstellerunabhänig im WR Modus + } elseif ($batterieManagement == 1 && ($batterietyp == 0 || $batterietyp == 3)) { + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Batteriemanagement_Variabel", 0); + return; + + // Enelix Steuert + // Sig Energy Symcon Modus + } elseif ($batterieManagement == 2 && ($batterietyp == 0 || $batterietyp == 3)) { + $this->SetValue("Batteriemanagement_Variabel", 1); + + //Solaredge Symcon Modus + }elseif ($batterieManagement == 2 && $batterietyp == 2) { + $this->SetValue("Batteriemanagement_Variabel", 4); + } + + // Variabeln entsprechend gewältem Batterietyp setzen + $batterietyp = $this->ReadPropertyInteger("Batterietyp"); + if ($batterietyp == 0) {//Herstellerunabhängig + + if($this->GetValue("Is_Peak_Shaving")==true){ + + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 0); + } else { + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 1); + } + + }else{ + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 0); + } else { + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 1); + } + } + } + elseif ($batterietyp == 1) {//Goodwe + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Ladeleistung", 0); + if($this->GetValue("Is_Peak_Shaving")==true){ + + if ($power >= 0) { + $this->SetValue("Goodwe_EntLadeleistung", abs($power)); + $this->SetValue("Laden_Entladen", 11); + } else { + $this->SetValue("Goodwe_EntLadeleistung", abs($power)); + $this->SetValue("Laden_Entladen", 12); + } + + }else{ + + if ($power >= 0) { + $this->SetValue("Goodwe_EntLadeleistung", abs($power)); + $this->SetValue("Laden_Entladen", 11); + } else { + $this->SetValue("Goodwe_EntLadeleistung", abs($power)); + $this->SetValue("Laden_Entladen", 12); + } + + } + + }elseif ($batterietyp == 2) {//Solaredge + + if($this->GetValue("Is_Peak_Shaving")==true){ + + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 3); + } else { + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 4); + } + + }else{ + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 3); + } else { + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 4); + } + } + } elseif ($batterietyp == 3) {//Sig Energy + + if($this->GetValue("Is_Peak_Shaving")==true){ + + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power/1000); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 3); + } else { + $this->SetValue("Entladeleistung", abs($power)/1000); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 6); + } + + }else{ + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power/1000); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden_Entladen", 3); + } else { + $this->SetValue("Entladeleistung", abs($power)/1000); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden_Entladen", 6); + } + } + } + + + + + // Prüfe auf Änderung der Leistung im Vergleich zur letzten Einstellung + $lastPower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); + if ($power != $lastPower) { + $this->SetValue("Idle", false); + $this->SetValue( + "IdleCounter", + $this->ReadPropertyInteger("IdleCounterMax") + ); + } + + // Setze die neue aktuelle Leistung + $this->SetValue("Aktuelle_Leistung", $power); + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + + // IdleCounter verarbeiten + $this->ProcessIdleCounter(); + + + } + + + public function GetCurrentData(bool $Peak) + { + // Aktuelle Daten ausarbeiten und Berechnen + $array_powersteps = $this->GeneratePowerSteps(); + $aufdasnachladen = $this->ReadPropertyInteger("AufdasNachladen"); + $minimumentladen = $this->ReadPropertyInteger("MinimumEntladen"); + $maxleistung = GetValue($this->ReadPropertyInteger("MaxBatterieleistung"));//Ladeleistung + $maxentladeleistung = GetValue($this->ReadPropertyInteger("MaxNachladen"));//Entladeleistung + $dummy_array = []; + $batterieladezustand = GetValue($this->ReadPropertyInteger("Batterieladezustand")); + $filtered_powersteps_entladen = []; + if ($this->ReadPropertyInteger("Batteriemanagement") == 1) { + $dummy_array[] = 0; + return $this->SetValue("PowerSteps", json_encode($dummy_array)); + } + + + $netzbezug = GetValue($this->ReadPropertyInteger("Netzbezug")); + $bat_leistung = GetValue($this->ReadPropertyInteger("AktuelleBatterieleistung")); + + + if ($Peak && $netzbezug > 0) { + $netzbezug = -min($netzbezug, $maxentladeleistung) + $bat_leistung; + } + + if($batterieladezustand>(5+$aufdasnachladen)){ + + $this->SetValue("Hysterese", false); + + }elseif($batterieladezustand<=$aufdasnachladen){ + $this->SetValue("Hysterese", true); + } + + $hyst = $this->GetValue("Hysterese"); + + if($Peak){ + + if($batterieladezustand>$aufdasnachladen && $hyst==false){ + + $dummy_array[] = $netzbezug; + $this->SetValue("PowerSteps", json_encode($dummy_array)); + + }elseif($batterieladezustand>$aufdasnachladen && $hyst==true){ + + + $filtered_powersteps = array_filter($array_powersteps, function ($value) { + return $value <= 0; + }); + $filtered_powersteps_laden = array_values($filtered_powersteps); + $this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden)); + + }elseif($batterieladezustand>$minimumentladen){ + + $this->SetValue("PowerSteps", json_encode($array_powersteps)); + } + else{ + + $filtered_powersteps = array_filter($array_powersteps, function ($value) { + return $value >= 0; + }); + $filtered_powersteps_laden = array_values($filtered_powersteps); + $this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden)); + } + + }else{ + + + if($batterieladezustand>99){ + + $filtered_powersteps = array_filter($array_powersteps, function ($value) { + return $value <= 0; + }); + $filtered_powersteps_laden = array_values($filtered_powersteps); + $this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden)); + + }elseif($batterieladezustand>$aufdasnachladen && $hyst==false){ + + $this->SetValue("PowerSteps", json_encode($array_powersteps)); + + + }elseif($batterieladezustand>=$aufdasnachladen && $hyst==true){ + + $filtered_powersteps = array_filter($array_powersteps, function ($value) { + return $value >= 0; + }); + $filtered_powersteps_laden = array_values($filtered_powersteps); + $this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden)); + + + }elseif($batterieladezustand<$aufdasnachladen){ + + //$dummy_array[] = GetValue($this->ReadPropertyInteger("MaxNachladen")); + $dummy_array[] = GetValue($this->ReadPropertyInteger("MaxBatterieleistung")); + $this->SetValue("PowerSteps", json_encode($dummy_array)); + + } + + } + + } + + + // Ab hier Hilfsfunktionen + +private function GeneratePowerSteps() +{ + // Hilfsfunktion um die Möglichen Powersteps zu generieren + $maxleistung_raw = GetValue($this->ReadPropertyInteger("MaxBatterieleistung")); + $nachladen_raw = GetValue($this->ReadPropertyInteger("MaxNachladen")); + + $stepSize = 250; // Grobe Schrittgröße + $stepSizeSmall = 50; // Feine Schrittgröße + + // Grenzen auf 50er abrunden (floor) + $maxleistung = (int)(floor($maxleistung_raw / $stepSizeSmall) * $stepSizeSmall); + $minleistung = (int)(-floor($nachladen_raw / $stepSizeSmall) * $stepSizeSmall); // negativ! + + // Sicherheitscheck: falls Werte komisch sind + if ($maxleistung < 0) $maxleistung = 0; + if ($minleistung > 0) $minleistung = 0; + + // Grundarray: von min bis max in 250er Schritten + $neg = ($minleistung < 0) ? range($minleistung, 0, $stepSize) : [0]; + $pos = range(0, $maxleistung, $stepSize); + + $array_powersteps = array_values(array_unique(array_merge($neg, $pos))); + sort($array_powersteps, SORT_NUMERIC); + + // Zusätzlichen Wert auf 50er abrunden + $closestValue = (int)(floor($additionalValue / $stepSizeSmall) * $stepSizeSmall); + + // Clamp in den Bereich + if ($closestValue < $minleistung) $closestValue = $minleistung; + if ($closestValue > $maxleistung) $closestValue = $maxleistung; + + // Prüfen ob der Wert im Array existiert (bei 250er Raster oft NICHT) + $index = array_search($closestValue, $array_powersteps, true); + + // Wenn nicht vorhanden: an der richtigen Stelle einsortieren + if ($index === false) { + $index = 0; + $count = count($array_powersteps); + while ($index < $count && $array_powersteps[$index] < $closestValue) { + $index++; + } + } + + // Feine Werte um closestValue herum (±4 * 50) + $newValues = []; + for ($i = -4; $i <= 4; $i++) { + $v = $closestValue + ($i * $stepSizeSmall); + if ($v >= $minleistung && $v <= $maxleistung) { + $newValues[] = $v; + } + } + + // Duplikate vermeiden (falls schon Werte vorhanden sind) + $newValues = array_values(array_unique($newValues)); + + // Wenn closestValue exakt im Grundarray war: diesen einen ersetzen + // sonst: feinwerte einfach an der Einfügestelle einfügen + if (array_search($closestValue, $array_powersteps, true) !== false) { + $existingIndex = array_search($closestValue, $array_powersteps, true); + array_splice($array_powersteps, $existingIndex, 1, $newValues); + } else { + array_splice($array_powersteps, $index, 0, $newValues); + } + + // Am Ende sortieren + $array_powersteps = array_values(array_unique($array_powersteps)); + sort($array_powersteps, SORT_NUMERIC); + + return $array_powersteps; +} + + + + + private function CheckIdle($power) + { // Hilfsfunktion zum Prüfen ob die Batterie schon wieder Leistung verändern kann + $lastpower = GetValue("Aktuelle_Leistung"); + if ($lastpower != GetValue("Aktuelle_Leistung")) { + $this->SetValue("Idle", false); + $this->SetValue( + "IdleCounter", + $this->ReadPropertyInteger("IdleCounterMax") + ); + } + // IdleCounter auslesen und verarbeiten + $idleCounter = $this->GetValue("IdleCounter"); + if ($idleCounter > 0) { + $this->SetValue("Idle", false); + $this->SetValue("IdleCounter", $idleCounter - 1); + } else { + $this->SetValue("Idle", true); + } + } + + + private function ProcessIdleCounter() + { + // IdleCounter auslesen und verarbeiten + $idleCounter = $this->GetValue("IdleCounter"); + if ($idleCounter > 0) { + $this->SetValue("Idle", false); + $this->SetValue("IdleCounter", $idleCounter - 1); + } else { + $this->SetValue("Idle", true); + } + } + +} +?>