diff --git a/HauptManager/module.php b/HauptManager/module.php index bd7ef55..590b423 100644 --- a/HauptManager/module.php +++ b/HauptManager/module.php @@ -466,7 +466,7 @@ class HauptManager extends IPSModule //$schreibleistung = max($leistung, $minimalleistung); if (abs($leistung["Set_Leistung"]) > abs($minimalleistung)) { - $leistung = $leistung["Set_Leistung"]; + $leistung = $leistung["Set_Leistung"]*-1; } else { $leistung = $minimalleistung; } diff --git a/Ladestation_v2/form.json b/Ladestation_v2/form.json index 4faa18c..be54d2e 100644 --- a/Ladestation_v2/form.json +++ b/Ladestation_v2/form.json @@ -52,7 +52,7 @@ { "type": "NumberSpinner", "name": "Zeit_Zwischen_Zustandswechseln", - "caption": "Mindestlaufzeit des Verbrauchers bei Lastschaltung ", + "caption": "(Veraltet, auf 0 lassen, wird in nächster Version entfehrnt) Mindestlaufzeit des Verbrauchers bei Lastschaltung ", "suffix": "" }, { diff --git a/Ladestation_v2/module.php b/Ladestation_v2/module.php index 11a0054..b91d040 100644 --- a/Ladestation_v2/module.php +++ b/Ladestation_v2/module.php @@ -102,6 +102,9 @@ class Ladestation_v2 extends IPSModule $this->RegisterTimer("Timer_Do_UserCalc_EVC",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); $this->RegisterTimer("Timer_Refresh_Token",0,"IPS_RequestAction(" .$this->InstanceID .', "Refresh_Token", "");'); + $this->RegisterVariableInteger("Mindestaldestrom", "Mindestaldestrom", "", 0); + $this->EnableAction("Mindestaldestrom"); + } public function ApplyChanges() @@ -175,6 +178,10 @@ class Ladestation_v2 extends IPSModule case "Refresh_Token": $this->Refresh_Token(); break; + + case "Mindestaldestrom": + $this->SetValue("Mindestaldestrom", (int)$Value); + break; default: throw new Exception("Invalid Ident"); @@ -229,6 +236,15 @@ class Ladestation_v2 extends IPSModule } $this->SetValue("Car_detected", true); + + if ($this->GetValue("Is_1_ph")) { + $power = $this->GetValue("Mindestaldestrom") * 230; + } + else { + $power = $this->GetValue("Mindestaldestrom") * 400 * 1.71; + } + + $this->SetValue("Power", $power); } @@ -515,9 +531,11 @@ class Ladestation_v2 extends IPSModule { $maxCurrent = 32; if($is_1_ph){ + $maxCurrent = 2.5 + ($this->GetValue("Ladeleistung_Effektiv") / 230); } else{ + $maxCurrent = 2.5 + ($this->GetValue("Ladeleistung_Effektiv") / (1.71*400)); } if($maxCurrent>$this->ReadPropertyInteger("Max_Current_abs")){ @@ -547,15 +565,10 @@ class Ladestation_v2 extends IPSModule // power == 0: nur eine 0 zurückgeben $resultArray[] = 0; return $resultArray; - } - // power > 0: keine 0 am Anfang, Schleife normal durchlaufen - } else { - // Timer aus: wie bisher, 0 am Anfang - $resultArray[] = 0; - } + }else{ // Schleife wie gehabt - for ($i = 6; $i <= $current; $i++) { + for ($i = (max($this->GetValue("Mindestaldestrom") + 1, 6)); $i <= $current; $i++) { if ($is_1_ph) { $resultArray[] = $i * 230; } else { @@ -563,6 +576,29 @@ class Ladestation_v2 extends IPSModule } } + } + + // power > 0: keine 0 am Anfang, Schleife normal durchlaufen + } else { + // Timer aus: wie bisher, 0 am Anfang + + if ($is_1_ph) { + $resultArray[] = $this->GetValue("Mindestaldestrom") * 230; + } else { + $resultArray[] = $this->GetValue("Mindestaldestrom") * 400 * 1.71; + } + + + + // Schleife wie gehabt + for ($i = (max($this->GetValue("Mindestaldestrom") + 1, 6)); $i <= $current; $i++) { + if ($is_1_ph) { + $resultArray[] = $i * 230; + } else { + $resultArray[] = $i * 400 * 1.71; + } + } +} return $resultArray; } @@ -669,7 +705,12 @@ class Ladestation_v2 extends IPSModule } elseif (!$Peak && $solarladen) { $powerSteps = $this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current"), $this->GetValue("Aktuelle_Leistung"), $this->GetValue("IsTimerActive_Null_Timer")); } elseif ($solarladen && $Peak) { - $powerSteps = [0]; + if ($is_1_ph) { + $powerSteps = [$this->GetValue("Mindestaldestrom") * 230]; + } else { + $powerSteps = [$this->GetValue("Mindestaldestrom") * 400 * 1.71]; + } + } else { $powerSteps = $this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current"), $this->GetValue("Aktuelle_Leistung"), $this->GetValue("IsTimerActive_Null_Timer")); } @@ -695,7 +736,18 @@ class Ladestation_v2 extends IPSModule if($counter>(90/($this->ReadPropertyInteger("Interval")))){ $this->SetValue("Pending_Counter", 0); - $this->Calc_Max_Current($this->GetValue("Is_1_ph")); + + if((max(json_decode($this->GetValue("PowerSteps")))) >0){ + + if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))) { + + $this->Calc_Max_Current($this->GetValue("Is_1_ph")); + + + } + + } + } return $powerSteps; diff --git a/Manager/module.php b/Manager/module.php index b58c241..9ed3db2 100644 --- a/Manager/module.php +++ b/Manager/module.php @@ -170,7 +170,10 @@ class Manager extends IPSModule } //if(in_array(0, $powerSteps, true)){ + //if(in_array(0, $powerSteps, true)){ + + //} // Addiere die aktuell bereits verwendete Leistung auf, um sie bei der verteilung zu berücksichtigen $totalAktuelle_Leistung += ($Aktuelle_Leistung-$delta); @@ -287,7 +290,7 @@ class Manager extends IPSModule $instanceID = $entry["InstanceID"]; $minPowerStep = min($entry["PowerSteps"]); - $remainingPower -= $minPowerStep; + //$remainingPower -= $minPowerStep; } } // Verbraucher die nicht 0 annhemen können erhalten nun den minimalwert @@ -296,7 +299,7 @@ class Manager extends IPSModule $instanceID = $entry["InstanceID"]; $minPowerStep = max($entry["PowerSteps"]); - $remainingPower += $minPowerStep; + //$remainingPower += $minPowerStep; } } @@ -309,8 +312,42 @@ class Manager extends IPSModule // Nun die verteilen, die 0 erhalten können. $samePriorityUsers = $withZero; + // $userEnergyProv = []; + // $userEnergyProv = array_fill_keys(array_column($samePriorityUsers, "InstanceID"), 0); // Initialisierung für jeden Benutzer auf 0 setzen + + $userEnergyProv = []; - $userEnergyProv = array_fill_keys(array_column($samePriorityUsers, "InstanceID"), 0); // Initialisierung für jeden Benutzer auf 0 setzen + +foreach ($samePriorityUsers as $entry) { + $instanceID = $entry["InstanceID"]; + // Schutz: falls PowerSteps nicht gesetzt oder kein Array ist + $steps = (isset($entry["PowerSteps"]) && is_array($entry["PowerSteps"])) ? $entry["PowerSteps"] : [0]; + + // Wenn 0 als möglicher Step vorhanden ist -> 0 setzen + + $minStep = min($steps); + $maxStep = max($steps); + + if (in_array(0, $steps, true)) { + $userEnergyProv[$instanceID] = 0; + continue; + } elseif ($minStep > 0) { + // nur positive Schritte -> minimalen positiven Wert einsetzen + $userEnergyProv[$instanceID] = $minStep; + // entspricht deinem vorherigen Verhalten: remainingPower reduzieren + $remainingPower -= $minStep; + } elseif ($maxStep < 0) { + // nur negative Schritte -> maximalen (am wenigsten negativen) Wert einsetzen + $userEnergyProv[$instanceID] = $maxStep; + // entspricht deinem vorherigen Verhalten: remainingPower erhöhen (maxStep ist negativ) + $remainingPower += $maxStep; + } else { + // Mixed (positive & negative) aber kein 0 -> Fallback 0 (ändere wenn nötig) + $userEnergyProv[$instanceID] = 0; + } +} + + IPS_LogMessage("Manag", $remainingPower); diff --git a/Pufferspeicher/README.md b/Pufferspeicher/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Pufferspeicher/README.md @@ -0,0 +1,67 @@ +# Manager_1 +Beschreibung des Moduls. + +### Inhaltsverzeichnis + +1. [Funktionsumfang](#1-funktionsumfang) +2. [Voraussetzungen](#2-voraussetzungen) +3. [Software-Installation](#3-software-installation) +4. [Einrichten der Instanzen in IP-Symcon](#4-einrichten-der-instanzen-in-ip-symcon) +5. [Statusvariablen und Profile](#5-statusvariablen-und-profile) +6. [WebFront](#6-webfront) +7. [PHP-Befehlsreferenz](#7-php-befehlsreferenz) + +### 1. Funktionsumfang + +* + +### 2. Voraussetzungen + +- IP-Symcon ab Version 7.1 + +### 3. Software-Installation + +* Über den Module Store das 'Manager_1'-Modul installieren. +* Alternativ über das Module Control folgende URL hinzufügen + +### 4. Einrichten der Instanzen in IP-Symcon + + Unter 'Instanz hinzufügen' kann das 'Manager_1'-Modul mithilfe des Schnellfilters gefunden werden. + - Weitere Informationen zum Hinzufügen von Instanzen in der [Dokumentation der Instanzen](https://www.symcon.de/service/dokumentation/konzepte/instanzen/#Instanz_hinzufügen) + +__Konfigurationsseite__: + +Name | Beschreibung +-------- | ------------------ + | + | + +### 5. Statusvariablen und Profile + +Die Statusvariablen/Kategorien werden automatisch angelegt. Das Löschen einzelner kann zu Fehlfunktionen führen. + +#### Statusvariablen + +Name | Typ | Beschreibung +------ | ------- | ------------ + | | + | | + +#### Profile + +Name | Typ +------ | ------- + | + | + +### 6. WebFront + +Die Funktionalität, die das Modul im WebFront bietet. + +### 7. PHP-Befehlsreferenz + +`boolean GEF_BeispielFunktion(integer $InstanzID);` +Erklärung der Funktion. + +Beispiel: +`GEF_BeispielFunktion(12345);` \ No newline at end of file diff --git a/Pufferspeicher/form.json b/Pufferspeicher/form.json new file mode 100644 index 0000000..19e0f93 --- /dev/null +++ b/Pufferspeicher/form.json @@ -0,0 +1,99 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Konfiguration der nötigen Schaltkontakte und Nennleistungen" + }, + { + "type":"Select", + "name":"Puffertemperatur_glätten", + "caption":"Puffertemperatur glätten", + "options":[ + { + "caption":"Ja", + "value":true + }, + { + "caption":"Nein", + "value":false + } + ] + }, + { + "type": "NumberSpinner", + "name": "ZeitKonstante", + "caption": "Zeit Konstante", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte Erst für spätere Versionen, aktuell auf 5 lassen!", + "suffix": "Sekunden" + }, + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "PufferLeistung", + "caption": "Puffer Volllast", + "suffix": "Watt" + }, + { + "type": "NumberSpinner", + "name": "PufferTeilLeistung", + "caption": "Puffer Teillast", + "suffix": "Watt" + }, + { + "type": "Label", + "caption": "Endpunkte der Pufferfunktion bestimmen: VT = f(AT)" + }, + { + "type": "NumberSpinner", + "name": "MaxVT_Temp", + "caption": "Max Temperatur VT", + "suffix": "°C" + }, + { + "type": "NumberSpinner", + "name": "MinVT_Temp", + "caption": "Min Temperatur VT", + "suffix": "°C" + }, + { + "type": "NumberSpinner", + "name": "MaxAT_Temp", + "caption": "Max Temperatur AT", + "suffix": "°C" + }, + { + "type": "NumberSpinner", + "name": "MinAT_Temp", + "caption": "Min Temperatur AT", + "suffix": "°C" + }, + { + "type": "SelectVariable", + "name": "Pufferfuehler_PT1", + "caption": "Variable für Pufferfühler PT1", + "test": true + }, + { + "type": "SelectVariable", + "name": "Heizkontakt_Puffer", + "caption": "Heizkontakt Puffer", + "test": true + }, + { + "type": "SelectVariable", + "name": "Aussentemp", + "caption": "Aussentemperatur", + "suffix": "°C" + } + ] +} \ No newline at end of file diff --git a/Pufferspeicher/module.json b/Pufferspeicher/module.json new file mode 100644 index 0000000..c85e295 --- /dev/null +++ b/Pufferspeicher/module.json @@ -0,0 +1,12 @@ +{ + "id": "{1604D0D8-B142-132A-C6AC-9054C48BA497}", + "name": "Pufferspeicher", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Pufferspeicher/module.php b/Pufferspeicher/module.php new file mode 100644 index 0000000..dc34bb1 --- /dev/null +++ b/Pufferspeicher/module.php @@ -0,0 +1,246 @@ +RegisterPropertyInteger("PufferLeistung", 6000); + $this->RegisterPropertyInteger("PufferTeilLeistung", 3000); + $this->RegisterPropertyInteger("ZeitKonstante", 120); + $this->RegisterPropertyInteger("Pufferfuehler_PT1", 0); + $this->RegisterPropertyInteger("Heizkontakt_Puffer", 0); + $this->RegisterPropertyInteger("Heizkontakt_Puffer_Teillast", 0); + $this->RegisterPropertyInteger("Aussentemp", 20); + $this->RegisterPropertyInteger("MinVT_Temp", 20); + $this->RegisterPropertyInteger("MaxVT_Temp", 80); + $this->RegisterPropertyInteger("MaxAT_Temp", 20); + $this->RegisterPropertyInteger("MinAT_Temp", 0); + $this->RegisterPropertyBoolean("Puffertemperatur_glätten", false); + $this->RegisterPropertyString("Zeitplan", ""); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + + // Puffer spezifische Variablen + $this->RegisterVariableInteger("Steigung","Steigung","",0); + $this->RegisterVariableInteger("Maximaltemperatur"," Berechnete Maximaltemperatur VT","",60); + $this->RegisterVariableInteger("Puffertemperatur", "Puffertemperatur", "", 40); + $this->RegisterVariableInteger("Aussentemperatur", "Aussentemperatur", "", 15); + $this->RegisterVariableBoolean("Hysterese", "Hysterese","",false); + + + // Variabeln für Kommunkation mit Manager + $this->RegisterVariableInteger("Sperre_Prio", "Sperre_Prio"); + $this->RegisterVariableInteger("PV_Prio", "PV_Prio"); + $this->RegisterVariableBoolean("Idle", "Idle", "", 0); + $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0); + $this->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0); + $this->RegisterVariableString("PowerSteps", "PowerSteps"); + $this->RegisterVariableInteger("Power", "Power", '', 0); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving", "", true); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 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_Boiler",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_Boiler",$this->ReadPropertyInteger("Interval")*1000); + + } + + 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"); + } + } + + // Methode zum Setzen des aktuellen Stromverbrauchs + public function SetAktuelle_Leistung(int $power) + { + // Schalte Kontakt Teillast und Vollast entsprechend der Power-Einstellung + if ($power == $this->ReadPropertyInteger("PufferLeistung")) { + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer"), true); + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer_Teillast"), false); + } elseif ( + $power == $this->ReadPropertyInteger("PufferTeilLeistung") + ) { + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer"), false); + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer_Teillast"), true); + } else { + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer"), false); + SetValue($this->ReadPropertyInteger("Heizkontakt_Puffer_Teillast"), false); + } + + // Prüfe auf Änderung der Power 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(); + } + + // Methode zum Abrufen der aktuellen Daten + public function GetCurrentData(bool $Peak) + { + + + $boilertemperatur_glätten = $this->ReadPropertyBoolean("Puffertemperatur_glätten"); + + if ($boilertemperatur_glätten) { + // Wenn Glättung aktiviert ist, führe das Glätten durch + $boilerFuehlerPT1ID = $this->ReadPropertyInteger("Pufferfuehler_PT1"); + + if (IPS_VariableExists($boilerFuehlerPT1ID)) { + $boilerPT1 = GetValue($boilerFuehlerPT1ID); + } else { + $boilerPT1 = 0.0; // Standardwert + } + + $boilerTempID = $this->GetIDForIdent("Boilertemperatur"); + if (IPS_VariableExists($boilerTempID)) { + $boilerTemp = $this->GetValue("Boilertemperatur"); + } else { + $boilerTemp = 0.0; // Standardwert + } + + // PT + $time_constant= $this->ReadPropertyInteger("ZeitKonstante"); + $delta_t = 5; // Zeitdifferenz zwischen den Messungen (30 Sekunden) + $alpha = $delta_t / ($time_constant + $delta_t); + $newBoilerTemp = $boilerTemp + $alpha * ($boilerPT1 - $boilerTemp); + $this->SetValue("Puffertemperatur", $newBoilerTemp); + } else { + // Wenn Glättung nicht aktiviert ist, setze die Boilertemperatur direkt auf den Wert des Boilerfühlers + $boilerFuehlerPT1ID = $this->ReadPropertyInteger("Pufferfuehler_PT1"); + + if (IPS_VariableExists($boilerFuehlerPT1ID)) { + $boilerPT1 = GetValue($boilerFuehlerPT1ID); + } else { + $boilerPT1 = 0.0; // Standardwert + } + // Setze Boilertemperatur direkt auf den Wert des Boilerfühlers + $this->SetValue("Puffertemperatur", $boilerPT1); + } + + + + $at = GetValue($this->ReadPropertyInteger("Aussentemp")); + $this->SetValue("Aussentemperatur", $at); + $m = $this->GetValue("Steigung"); + $minVT = $this->ReadPropertyInteger("MinVT_Temp"); // z.B. 20 + $maxVT = $this->ReadPropertyInteger("MaxVT_Temp"); // z.B. 80 + $maxAT = $this->ReadPropertyInteger("MaxAT_Temp"); // z.B. 20 + $minAT = $this->ReadPropertyInteger("MinAT_Temp"); // z.B. 0 + $m = ($maxVT - $minVT) / ($minAT - $maxAT); + + $this->SetValue("Steigung", $m); + + if ($at < $minAT){ + $VT = $maxVT; + } elseif ($at > $maxAT){ + $VT = $minVT; + } else { + $VT = $m * $at + $maxVT; + } + $this->SetValue("Maximaltemperatur", $VT ); + + $boilerTemp = $this->GetValue("Puffertemperatur"); + $pufferLeistung = $this->ReadPropertyInteger("PufferLeistung"); + $pufferTeilLeistung = $this->ReadPropertyInteger("PufferTeilLeistung"); + $hyst = $this->GetValue("Hysterese"); + + + if($VT < $boilerTemp){ + $this->SetValue("Hysterese", false ); + }elseif($VT-5 >= $boilerTemp){ + $this->SetValue("Hysterese", true); + } + + + if ($Peak) { + $this->SetValue( "PowerSteps", json_encode([0]) ); + } else { + if ($boilerTemp < $VT && $hyst== true) { + $this->SetValue("PowerSteps", json_encode([0,$pufferTeilLeistung ,$pufferLeistung])); + } elseif ($boilerTemp > $VT - 5 && $hyst== false) { + $this->SetValue("PowerSteps", json_encode([0])); + } else { + $this->SetValue("PowerSteps", json_encode([0])); + } + } + } + + 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); + } + } + + 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); + } + } + + +} + +?>