diff --git a/Batterie_Deye/README.md b/Batterie_Deye/README.md new file mode 100644 index 0000000..e69de29 diff --git a/Batterie_Deye/form.json b/Batterie_Deye/form.json new file mode 100644 index 0000000..86404ed --- /dev/null +++ b/Batterie_Deye/form.json @@ -0,0 +1,91 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Konfiguration der Batterie für Peakshaving" + }, + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte", + "suffix": "Sekunden" + }, + { + "type": "NumberSpinner", + "name": "MaxBatterieleistung", + "caption": "Maximale Batterieleistung", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "MaxNachladen", + "caption": "Maximum Nachladen", + "suffix": "" + }, + { + "type": "Label", + "caption": "Bei Deye wird vorerst der Ladezustand in V angegeben." + }, + { + "type": "NumberSpinner", + "name": "AufdasNachladen", + "caption": "Auf so viel Spannung nachladen", + "suffix": "V", + "minimum": 49, + "maximum": 56, + "step": 0.1 + + }, + { + "type": "NumberSpinner", + "name": "MinimumEntladen", + "caption": "Minimumspannung des Batterieladezustand", + "suffix": "V", + "minimum": 49, + "maximum": 56, + "step": 0.1 + }, + { + "type":"Select", + "name":"Batteriemanagement", + "caption":"Batteriemanagement", + "options":[ + { + "caption":"Durch Wechselrichter", + "value":2 + }, + { + "caption":"Durch EMS Symcon", + "value":0 + } + ] + }, + { + "type": "SelectVariable", + "name": "Batterieladezustand", + "caption": "Batterieladezustand", + "test": true + }, + { + "type": "SelectVariable", + "name": "Netzbezug", + "caption": "Variable mit dem zu regelnden Netzbezug" + }, + { + "type": "SelectVariable", + "name": "Kotnrolle_TOU_Spannung", + "caption": "Kontrollvariabel Spannung TOU1" + }, + { + "type": "SelectVariable", + "name": "Kotnrolle_Selling_CT", + "caption": "Kontrollvariabel Selling First/Zero Export to CT" + } + ] +} diff --git a/Batterie_Deye/module.json b/Batterie_Deye/module.json new file mode 100644 index 0000000..cc6c8e6 --- /dev/null +++ b/Batterie_Deye/module.json @@ -0,0 +1,12 @@ +{ + "id": "{76529CAE-191C-41BF-5FDE-EF4A4FE25651}", + "name": "Batterie_Deye", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Batterie_Deye/module.php b/Batterie_Deye/module.php new file mode 100644 index 0000000..7ee6809 --- /dev/null +++ b/Batterie_Deye/module.php @@ -0,0 +1,370 @@ +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("Kotnrolle_TOU_Spannung", 0); + $this->RegisterPropertyInteger("Kotnrolle_Selling_CT", 0); + $this->RegisterPropertyInteger("MaxNachladen",0); + $this->RegisterPropertyInteger("Netzbezug", 0); // Initialisierung mit 0 + $this->RegisterPropertyInteger("Interval", 2); // Recheninterval + + // Variabeln für Kommunkation mit Manager + $this->RegisterVariableFloat("Entladeleistung","Entladeleistung", "",0); + $this->RegisterVariableInteger("Laden3_Entladen4","Laden3_Entladen4", "",3); + $this->RegisterVariableFloat("Ladeleistung","Ladeleistung", "",0); + + $this->RegisterVariableInteger("Batteriemanagement_Variabel","Batteriemanagement_Variabel", "",0); + $this->RegisterVariableFloat("Ladestrom","Ladestrom", "",0); + $this->RegisterVariableFloat("Entladestrom","Entladestrom", "",0); + $this->RegisterVariableFloat("Batteriespannung_laden_entladen",0); + + $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0); + $this->RegisterVariableString("PowerSteps", "PowerSteps"); + $this->RegisterVariableBoolean("Idle", "Idle", "", 0); + $this->RegisterVariableInteger("Sperre_Prio", "Sperre_Prio"); + $this->RegisterVariableInteger("PV_Prio", "PV_Prio"); + $this->RegisterVariableInteger("Power", "Power"); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); + + $this->RegisterVariableBoolean("Hysterese", "Hysterese","",false); + $this->RegisterVariableBoolean("Schreibkontrolle", "Schreibkontrolle","",false); + + + $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->SetValue("Idle", true); + + $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); + } + + + private function GeneratePowerSteps($additionalValue) + { + $maxleistung = $this->ReadPropertyInteger("MaxBatterieleistung"); + $stepSize = 250; // Schrittgröße + $stepSizeSmall = 50; // Kleine Schrittgröße + + // Array direkt als Range erzeugen (schneller als Schleife) + $array_powersteps = range(-$maxleistung, $maxleistung, $stepSize); + + // Nächstgelegenen Wert direkt bestimmen (rundet auf den nächsten Step) + $closestValue = round($additionalValue / $stepSize) * $stepSize; + + // Falls der Wert nicht im Bereich liegt, abbrechen + if (!in_array($closestValue, $array_powersteps)) { + return $array_powersteps; + } + + // Index des gefundenen Werts suchen + $index = array_search($closestValue, $array_powersteps); + + // Zusätzliche Werte berechnen und auf MaxLeistung begrenzen + $newValues = array_filter([ + $closestValue - 4 * $stepSizeSmall, + $closestValue - 3 * $stepSizeSmall, + $closestValue - 2 * $stepSizeSmall, + $closestValue - $stepSizeSmall, + $closestValue, + $closestValue + $stepSizeSmall, + $closestValue + 2 * $stepSizeSmall, + $closestValue + 3 * $stepSizeSmall, + $closestValue + 4 * $stepSizeSmall, + ], function ($value) use ($maxleistung) { + return $value >= -$maxleistung && $value <= $maxleistung; + }); + + // Effizienteres Einfügen der Werte (direkt an der Stelle) + array_splice($array_powersteps, $index, 1, $newValues); + + return $array_powersteps; + } + + + + +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: + throw new Exception("Invalid Ident"); + } +} + + public function SetAktuelle_Leistung(int $power) + { + + if ($power < 0) { + + // Laden + $lade_strom = abs($power) / GetValue($this->ReadPropertyInteger("Batteriespannung")); + $this->SetValue("Ladestrom", $lade_strom); + $this->SetValue("Entladestrom", 0); + $this->SetValue("Batteriespannung_laden_entladen", 56); + + } elseif ($power > 0) { + + // Entladen + $entlade_strom = $power / GetValue($this->ReadPropertyInteger("Batteriespannung")); + $this->SetValue("Entladestrom", $entlade_strom); + $this->SetValue("Ladestrom", 0); + $this->SetValue("Batteriespannung_laden_entladen", 49); + + } else { + + // Kein Stromfluss (Leistung = 0) + $this->SetValue("Ladestrom", 0); + $this->SetValue("Entladestrom", 0); + // Optional: Spannung neutral setzen, falls gewünscht + $this->SetValue("Batteriespannung_laden_entladen", 52); + } + + + $batterieManagement = $this->ReadPropertyInteger("Batteriemanagement"); + // Wechselrichter steuert das Laden/Entladen der Batterie + if ($batterieManagement == 2) { + $this->SetValue("Ladestrom", 0); + $this->SetValue("Entladedestrom", 0); + return; + } + + + // 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) + { + + + $ct = GetValue($this->ReadPropertyInteger("Kotnrolle_Selling_CT")); + $sell_Ct = $this->GetValue("Batteriemanagement_Variabel"); + + + $V_Tou = GetValue($this->ReadPropertyInteger("Kotnrolle_TOU_Spannung")); + $V_lad_ent = $this->GetValue("Batteriespannung_laden_entladen"); + + if ($ct != $sell_Ct || $V_Tou != $V_lad_ent) { + $this->SetValue("Schreibkontrolle", false); + } else { + $this->SetValue("Schreibkontrolle", true); + } + + + + //$a = 2.54 * pow($V, 2) - 252 * $V + 6255.4; + + if ($this->GetValue("Ladestrom") > 0 ) { + $V = GetValue($this->ReadPropertyInteger("Batteriespannung")) + 1; + }elseif ($this->GetValue("Entladedestrom") > 0) { + $V = GetValue($this->ReadPropertyInteger("Batteriespannung")) - 1; + } else { + + $V = GetValue($this->ReadPropertyInteger("Batteriespannung")); + } + + IPS_LogMessage("Batterie", "Currentdata"); + + $array_powersteps = $this->GeneratePowerSteps($this->GetValue("Aktuelle_Leistung")); + $aufdasnachladen = $this->ReadPropertyInteger("AufdasNachladen"); + $minimumentladen = $this->ReadPropertyInteger("MinimumEntladen"); + $maxleistung = $this->ReadPropertyInteger("MaxBatterieleistung"); + $dummy_array = []; + + + $batterieladezustand = $V; + + + + $filtered_powersteps_entladen = []; + if ($this->ReadPropertyInteger("Batteriemanagement") == 2) { + $dummy_array[] = 0; + return $this->SetValue("PowerSteps", json_encode($dummy_array)); + } + + $netzbezug = GetValue($this->ReadPropertyInteger("Netzbezug")); + if (abs($netzbezug) > $maxleistung) { + $netzbezug = $maxleistung * (-1); + } + + if($batterieladezustand>(5+$aufdasnachladen)){ + + $this->SetValue("Hysterese", false); + + }elseif($batterieladezustand<=$aufdasnachladen){ + $this->SetValue("Hysterese", true); + } + + $hyst = $this->GetValue("Hysterese"); + + if($Peak){ + IPS_LogMessage("Batterie", "Im if teil"); + + 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{ + IPS_LogMessage("Batterie", "Im else teil"); + + + if($batterieladezustand>99){ + IPS_LogMessage("Batterie", "im 1"); + + $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)); + IPS_LogMessage("Batterie", "im 2"); + + + }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[] = $this->ReadPropertyInteger("MaxNachladen"); + $this->SetValue("PowerSteps", json_encode($dummy_array)); + IPS_LogMessage("Batterie", "im 3"); + + } + + } + + } + + + + + private function CheckIdle($power) + { + $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); + } + } + +} +?>