From b7bb55b7fa5292ff979c7eacd35b78f4af93a59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=A4fliger?= Date: Tue, 29 Apr 2025 07:20:42 +0200 Subject: [PATCH] Version 2.0.0 Beta --- Ansteuerung_Askoheat/README.md | 67 +++ Ansteuerung_Askoheat/form.json | 103 +++++ Ansteuerung_Askoheat/module.json | 12 + Ansteuerung_Askoheat/module.php | 337 ++++++++++++++ Batterie/form.json | 40 +- Batterie/module.php | 246 +++++++--- Belevo_Bezahl_Modul/README.md | 67 +++ Belevo_Bezahl_Modul/form.json | 22 + Belevo_Bezahl_Modul/module.json | 12 + Belevo_Bezahl_Modul/module.php | 126 ++++++ Boiler_2_Stufig_Mit_Fueler/form.json | 54 ++- Boiler_2_Stufig_Mit_Fueler/module.php | 81 +++- HauptManager/README.md | 67 +++ HauptManager/form.json | 57 +++ HauptManager/module.json | 12 + HauptManager/module.php | 452 +++++++++++++++++++ Ladestation_Universal/form.json | 12 +- Ladestation_Universal/module.php | 124 ++++- Ladestation_v2/README.md | 67 +++ Ladestation_v2/form.json | 83 ++++ Ladestation_v2/module.json | 12 + Ladestation_v2/module.php | 621 ++++++++++++++++++++++++++ Manager/form.json | 26 ++ Manager/module.php | 303 ++++++++++--- Verbraucher_1_Stufig/form.json | 8 +- Verbraucher_1_Stufig/module.php | 9 +- Verbraucher_Sperrbar/README.md | 67 +++ Verbraucher_Sperrbar/form.json | 52 +++ Verbraucher_Sperrbar/module.json | 12 + Verbraucher_Sperrbar/module.php | 220 +++++++++ Verbraucher_extern/README.md | 67 +++ Verbraucher_extern/form.json | 76 ++++ Verbraucher_extern/module.json | 12 + Verbraucher_extern/module.php | 173 +++++++ WP_Steuerung/form.json | 6 + WP_Steuerung/module.php | 11 +- library.json | 5 +- 37 files changed, 3557 insertions(+), 164 deletions(-) create mode 100644 Ansteuerung_Askoheat/README.md create mode 100644 Ansteuerung_Askoheat/form.json create mode 100644 Ansteuerung_Askoheat/module.json create mode 100644 Ansteuerung_Askoheat/module.php create mode 100644 Belevo_Bezahl_Modul/README.md create mode 100644 Belevo_Bezahl_Modul/form.json create mode 100644 Belevo_Bezahl_Modul/module.json create mode 100644 Belevo_Bezahl_Modul/module.php create mode 100644 HauptManager/README.md create mode 100644 HauptManager/form.json create mode 100644 HauptManager/module.json create mode 100644 HauptManager/module.php create mode 100644 Ladestation_v2/README.md create mode 100644 Ladestation_v2/form.json create mode 100644 Ladestation_v2/module.json create mode 100644 Ladestation_v2/module.php create mode 100644 Verbraucher_Sperrbar/README.md create mode 100644 Verbraucher_Sperrbar/form.json create mode 100644 Verbraucher_Sperrbar/module.json create mode 100644 Verbraucher_Sperrbar/module.php create mode 100644 Verbraucher_extern/README.md create mode 100644 Verbraucher_extern/form.json create mode 100644 Verbraucher_extern/module.json create mode 100644 Verbraucher_extern/module.php diff --git a/Ansteuerung_Askoheat/README.md b/Ansteuerung_Askoheat/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Ansteuerung_Askoheat/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/Ansteuerung_Askoheat/form.json b/Ansteuerung_Askoheat/form.json new file mode 100644 index 0000000..9097e63 --- /dev/null +++ b/Ansteuerung_Askoheat/form.json @@ -0,0 +1,103 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Einstellungen für einstufigen Verbruacher Ein-Aus" + }, + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", + "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": "BoilerLeistung", + "caption": "Maximalleitsung Askoheat", + "suffix": "" + }, + { + "type": "SelectVariable", + "name": "Variable_Leistung", + "caption": "Variable mit der Nennleistung", + "test": true + }, + { + "type": "SelectVariable", + "name": "Variable_Temperatur", + "caption": "Variable mit der Solltemperatur Boiler", + "test": true + }, + { + "type": "SelectVariable", + "name": "Variable_Temperatur_Ist", + "caption": "Variable mit der Isttemperatur Boiler", + "test": true + }, + { + "type":"Select", + "name":"Boilertemperatur_glätten", + "caption":"Boilertemperatur glätten", + "options":[ + { + "caption":"Ja", + "value":true + }, + { + "caption":"Nein", + "value":false + } + ] + }, + { + "type": "NumberSpinner", + "name": "ZeitKonstante", + "caption": "Zeit Konstante", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Boilervolumen", + "caption": "Boilervolumen", + "suffix": "Liter" + }, + { + "type": "List", + "name": "Zeitplan", + "caption": "Zeitplan für Solltemperaturen", + "columns": [ + { + "caption": "Uhrzeit", + "name": "Uhrzeit", + "width": "150px", + "add": "00:00", + "edit": { + "type": "ValidationTextBox" + } + }, + { + "caption": "Solltemperatur", + "name": "Solltemperatur", + "width": "150px", + "add": 0, + "edit": { + "type": "NumberSpinner" + } + } + ], + "add": true, + "delete": true, + "sort": { + "column": "Uhrzeit", + "direction": "ascending" + } + } + + ] +} diff --git a/Ansteuerung_Askoheat/module.json b/Ansteuerung_Askoheat/module.json new file mode 100644 index 0000000..225b24c --- /dev/null +++ b/Ansteuerung_Askoheat/module.json @@ -0,0 +1,12 @@ +{ + "id": "{C042B0F6-CD02-9843-8D21-31BC3049BC14}", + "name": "Ansteuerung_Askoheat", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Ansteuerung_Askoheat/module.php b/Ansteuerung_Askoheat/module.php new file mode 100644 index 0000000..38b4a5d --- /dev/null +++ b/Ansteuerung_Askoheat/module.php @@ -0,0 +1,337 @@ +RegisterPropertyInteger("ZeitKonstante", 120); + $this->RegisterPropertyBoolean("Boilertemperatur_glätten", false); + $this->RegisterPropertyInteger("Boilervolumen", 300); + $this->RegisterPropertyString("Zeitplan", ""); + $this->RegisterPropertyInteger("BoilerLeistung", 3500); // Standardwert für Volllast + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + $this->RegisterPropertyInteger("Variable_Leistung", 0); // Recheninterval + $this->RegisterPropertyInteger("Variable_Temperatur", 0); // Recheninterval + $this->RegisterPropertyInteger("Variable_Temperatur_Ist", 0); // Recheninterval + + // 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"); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); + $this->RegisterVariableFloat("Boilertemperatur", "Boilertemperatur", "", 0); + + // Boiler spezifische Variablen + $this->RegisterVariableInteger("Mindesttemperatur","Mindesttemperatur","",45); + $this->RegisterVariableInteger("Maximaltemperatur","Maximaltemperatur","",60); + $this->RegisterVariableInteger("Legionellentemperatur","Legionellentemperatur","",65); + $this->RegisterVariableInteger("LegioCounter", "LegioCounter", "", 0); + $this->RegisterVariableInteger("Boilertemperatur", "Boilertemperatur", "", 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_Verb",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_Verb",$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"); + } + } + + + + public function getNextTimeAndTemperature($zeitplan) { + $arr = json_decode($zeitplan, true); + if (empty($arr)) { + return null; + } + $currentTime = new DateTime(); + $nextEntry = null; + $minDiff = PHP_INT_MAX; + + foreach ($arr as $entry) { + $entryTime = DateTime::createFromFormat('H:i', $entry['Uhrzeit']); + if ($entryTime < $currentTime) { + $entryTime->modify('+1 day'); + } + $diff = $currentTime->diff($entryTime)->format('%r%a') * 24 * 60 + $currentTime->diff($entryTime)->format('%r%h') * 60 + $currentTime->diff($entryTime)->format('%r%i'); + if ($diff < $minDiff) { + $minDiff = $diff; + $nextEntry = $entry; + } + } + + return $nextEntry; + } + + public function calculateRemainingTime($nextTime) { + $currentTime = new DateTime(); + $nextDateTime = DateTime::createFromFormat('H:i', $nextTime); + if ($nextDateTime < $currentTime) { + $nextDateTime->modify('+1 day'); + } + $interval = $currentTime->diff($nextDateTime); + return $interval->h + ($interval->i / 60); + } + + public function calculateRequiredHeat($boilervolumen, $tempDiff) { + // Annahme: spezifische Wärmekapazität von Wasser = 4.186 J/g°C + // 1 Liter Wasser = 1000 Gramm + $specificHeatCapacity = 4.186; // J/g°C + $waterMass = $boilervolumen * 1000; // Gramm + return $specificHeatCapacity * $waterMass * $tempDiff; // Joules + } + + public function canBoilerReachTemperature($boilervolumen, $boilerTemper, $nextTemp, $remainingTime, $vollleistung) { + $tempDiff = $nextTemp - $boilerTemper; + $requiredHeat = $this->calculateRequiredHeat($boilervolumen, $tempDiff); + $availableHeat = $vollleistung * $remainingTime * 3600; // Leistung in Watt * Zeit in Sekunden + return $availableHeat >= $requiredHeat; + } + + // Methode zum Setzen des aktuellen Stromverbrauchs + public function SetAktuelle_Leistung(int $power) + { + RequestAction($this->ReadPropertyInteger("Variable_Leistung"), $power); + + // 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(); + } + + + + public function Calc_Seven_Steps(int $power) + { + $steps = []; + $increment = $power / 7; + + for ($i = 0; $i <= 7; $i++) { + $steps[] = $i * $increment; + } + + return $steps; + } + + // Methode zum Abrufen der aktuellen Daten + public function GetCurrentData(bool $Peak) + { + $LegioCounter = $this->GetValue("LegioCounter"); + + + $boilertemperatur_glätten = $this->ReadPropertyBoolean("Boilertemperatur_glätten"); + + if ($boilertemperatur_glätten) { + // Wenn Glättung aktiviert ist, führe das Glätten durch + $boilerFuehlerPT1ID = $this->ReadPropertyInteger("Variable_Temperatur_Ist"); + + 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("Boilertemperatur", $newBoilerTemp); + } else { + // Wenn Glättung nicht aktiviert ist, setze die Boilertemperatur direkt auf den Wert des Boilerfühlers + $boilerFuehlerPT1ID = $this->ReadPropertyInteger("Variable_Temperatur_Ist"); + + if (IPS_VariableExists($boilerFuehlerPT1ID)) { + $boilerPT1 = GetValue($boilerFuehlerPT1ID); + } else { + $boilerPT1 = 0.0; // Standardwert + } + + // Setze Boilertemperatur direkt auf den Wert des Boilerfühlers + $this->SetValue("Boilertemperatur", $boilerPT1); + } + + + $boilerTemp = $this->GetValue("Boilertemperatur"); + $minTemp = $this->GetValue("Mindesttemperatur"); + $maxTemp = $this->GetValue("Maximaltemperatur"); + $LegioTemp = $this->GetValue("Legionellentemperatur"); + $vollLeistung = $this->ReadPropertyInteger("BoilerLeistung"); + + + $nextEntry = $this->getNextTimeAndTemperature($this->ReadPropertyString("Zeitplan")); + if ($nextEntry !== null) { + $remainingTime = $this->calculateRemainingTime($nextEntry['Uhrzeit']); + $nextTemp = $nextEntry['Solltemperatur']; + + if (!$this->canBoilerReachTemperature($this->ReadPropertyInteger("Boilervolumen"), $boilerTemp, $nextTemp, $remainingTime, $vollLeistung)) { + $minTemp = $nextTemp; + } + } + + + + $boilerIsOn = (GetValue($this->ReadPropertyInteger("Variable_Leistung"))>0); + $AktuelleVollast = GetValue( + $this->ReadPropertyInteger("Variable_Leistung") + ); + + + if ($boilerTemp > $LegioTemp) { + $LegioCounter = 0; + } else { + $LegioCounter = $LegioCounter + 1; + } + if ($LegioCounter > 69120) { + $maxTemp = $LegioTemp; + } + if ($LegioCounter > 120960 && $this->ist_nachts()) { + $minTemp = $LegioTemp; + } + if ($LegioCounter > 138240) { // Timeout für Legio wenn temperatur nicht erreicht werden kann, setze legionellenfunktion zurück + $LegioCounter = 0; + } + + $this->SetValue("LegioCounter", $LegioCounter); + + if ($Peak) { + if ($boilerTemp < $minTemp) { + $this->SetValue( "PowerSteps", json_encode($this->Calc_Seven_Steps($vollLeistung)) ); + } elseif ( + $boilerTemp < $minTemp + 5 && + ($boilerIsOn) + ) { + $this->SetValue( + "PowerSteps", + json_encode($this->Calc_Seven_Steps($vollLeistung)) + ); + } else { + $this->SetValue("PowerSteps", json_encode([0])); + } + } else { + if ($boilerTemp < $minTemp) { + $this->SetValue("PowerSteps", json_encode([$vollLeistung])); + } elseif ( + $boilerTemp < $minTemp + 5 && + ($boilerIsOn) + ) { + $this->SetValue("PowerSteps", json_encode([$vollLeistung])); + } elseif ($boilerTemp < $maxTemp - 5) { + $this->SetValue("PowerSteps", json_encode($this->Calc_Seven_Steps($vollLeistung))); + } elseif ( $boilerTemp < $maxTemp && ($boilerIsOn) + ) { + $this->SetValue( "PowerSteps", json_encode($this->Calc_Seven_Steps($vollLeistung))); + } 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); + } + } + + private function ist_nachts() + { + date_default_timezone_set("Europe/Berlin"); // Setze hier deine Zeitzone + + $aktuelle_zeit = strtotime(date("H:i")); // Aktuelle Zeit in Stunden und Minuten umwandeln + $start_nacht = strtotime("22:00"); // Startzeit der Nacht (22 Uhr) + $ende_nacht = strtotime("07:00"); // Endzeit der Nacht (7 Uhr) + + if ($aktuelle_zeit >= $start_nacht || $aktuelle_zeit < $ende_nacht) { + return true; + } else { + return false; + } + } +} + +?> diff --git a/Batterie/form.json b/Batterie/form.json index 4d7050d..2eb8f13 100644 --- a/Batterie/form.json +++ b/Batterie/form.json @@ -7,15 +7,27 @@ { "type": "NumberSpinner", "name": "IdleCounterMax", - "caption": "Zyklen zwischen zwei Leisutungsänderungen", + "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": "NumberSpinner", "name": "AufdasNachladen", @@ -29,12 +41,36 @@ "caption": "Minimum des Batterieladezustand", "suffix": "" }, + { + "type":"Select", + "name":"Batteriemanagement", + "caption":"Batteriemanagement", + "options":[ + { + "caption":"Durch Wechselrichter", + "value":1 + }, + { + "caption":"Durch EMS Symcon", + "value":4 + } + ] + }, { "type": "SelectVariable", "name": "Batterieladezustand", "caption": "Batterieladezustand", "test": true + }, + { + "type": "SelectVariable", + "name": "Netzbezug", + "caption": "Variable mit dem zu regelnden Netzbezug" + }, + { + "type": "SelectVariable", + "name": "Batterieleistung_Effektiv", + "caption": "Effektive, aktuelle Batterieleistung" } - ] } diff --git a/Batterie/module.php b/Batterie/module.php index 090fe3c..418aaaf 100644 --- a/Batterie/module.php +++ b/Batterie/module.php @@ -12,11 +12,17 @@ class Batterie extends IPSModule $this->RegisterPropertyInteger("AufdasNachladen",0); $this->RegisterPropertyInteger("MinimumEntladen",0); $this->RegisterPropertyInteger("Batterieladezustand",0); - - + $this->RegisterPropertyInteger("Batteriemanagement", 1); + $this->RegisterPropertyInteger("MaxNachladen",0); + $this->RegisterPropertyInteger("Netzbezug", 0); // Initialisierung mit 0 + $this->RegisterPropertyInteger("Interval", 2); // Recheninterval + $this->RegisterPropertyInteger("Batterieleistung_Effektiv", 0); // Recheninterval + // Variabeln für Kommunkation mit Manager - $this->RegisterVariableFloat("Ladestrom", "Ladestrom", "", 0); - $this->RegisterVariableFloat("Entladestrom", "Entladestrom", "", 0); + $this->RegisterVariableFloat("Entladeleistung","Entladeleistung", "",0); + $this->RegisterVariableInteger("Batteriemanagement_Variabel","Batteriemanagement_Variabel", "",0); + $this->RegisterVariableInteger("Laden3_Entladen4","Laden3_Entladen4", "",3); + $this->RegisterVariableFloat("Ladeleistung","Ladeleistung", "",0); $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0); $this->RegisterVariableString("PowerSteps", "PowerSteps"); $this->RegisterVariableBoolean("Idle", "Idle", "", 0); @@ -24,6 +30,10 @@ class Batterie extends IPSModule $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->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0); @@ -36,7 +46,7 @@ class Batterie extends IPSModule // Initialisiere Idle $this->SetValue("Idle", true); - $this->RegisterTimer("Timer_Do_UserCalc",5000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + $this->RegisterTimer("Timer_Do_UserCalc_Battery",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); } @@ -45,22 +55,53 @@ class Batterie extends IPSModule { parent::ApplyChanges(); - + $batterieManagement = $this->ReadPropertyInteger("Batteriemanagement"); + $this->SetValue("Batteriemanagement_Variabel", $batterieManagement); + $this->SetTimerInterval("Timer_Do_UserCalc_Battery",$this->ReadPropertyInteger("Interval")*1000); } - private function GeneratePowerSteps() -{ - $maxleistung = $this->ReadPropertyInteger("MaxBatterieleistung"); - $array_powersteps = []; - $stepSize = 250; // Schrittgröße - // Erstellen der PowerSteps - for ($i = 0; $i <= $maxleistung * 2; $i += $stepSize) { - $array_powersteps[] = $i; + 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; } - - return $array_powersteps; -} + @@ -90,30 +131,39 @@ public function RequestAction($Ident, $Value) public function SetAktuelle_Leistung(int $power) { - $batterieladezustand = $this->ReadPropertyInteger("Batterieladezustand"); // Als Property gelesen - $maxleistung = $this->ReadPropertyInteger("MaxBatterieleistung"); // Als Property gelesen - $spannung = $this->ReadPropertyInteger("Batteriespannung"); // Spannung ebenfalls als Property - $ladestrom = GetValue($this->GetIDForIdent("Ladestrom")); - $entladestrom = GetValue($this->GetIDForIdent("Entladestrom")); - IPS_LogMessage("Batterie", "power: " . $power); + $batterieManagement = $this->ReadPropertyInteger("Batteriemanagement"); + // Wechselrichter steuert das Laden/Entladen der Batterie + if ($batterieManagement == 1) { + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Ladeleistung", 0); + return; + } - if ($spannung <= 0) { - IPS_LogMessage("Batterie", "Fehler: Batteriespannung ist 0 oder ungültig."); - return; - } - // Batterie entladen oder laden basierend auf der Leistung - if ($power > $maxleistung) { - $ladestrom = ($power - $maxleistung) / $spannung; - $this->SetValue("Ladestrom", $ladestrom); - $this->SetValue("Entladestrom", 0); - //IPS_LogMessage("Batterie", "Ladestrom: " . $ladestrom); + + if($this->GetValue("Is_Peak_Shaving")==true){ + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden3_Entladen4", 3); } else { - $entladestrom = $power / $spannung; - $this->SetValue("Entladestrom", $entladestrom); - $this->SetValue("Ladestrom", 0); - //IPS_LogMessage("Batterie", "Entladestrom: " . $entladestrom); + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden3_Entladen4", 4); } + + }else{ + if ($power >= 0) { + $this->SetValue("Ladeleistung", $power); + $this->SetValue("Entladeleistung", 0); + $this->SetValue("Laden3_Entladen4", 3); + } else { + $this->SetValue("Entladeleistung", abs($power)); + $this->SetValue("Ladeleistung", 0); + $this->SetValue("Laden3_Entladen4", 4); + } + + } // Prüfe auf Änderung der Leistung im Vergleich zur letzten Einstellung $lastPower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); @@ -127,62 +177,119 @@ public function RequestAction($Ident, $Value) // 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) { - IPS_LogMessage("Batterie", "peak: " . ($Peak ? "true" : "false")); + IPS_LogMessage("Batterie", "Currentdata"); - $array_powersteps = $this->GeneratePowerSteps(); + $array_powersteps = $this->GeneratePowerSteps($this->GetValue("Aktuelle_Leistung")); $aufdasnachladen = $this->ReadPropertyInteger("AufdasNachladen"); $minimumentladen = $this->ReadPropertyInteger("MinimumEntladen"); - $batterieladezustand = GetValue($this->ReadPropertyInteger("Batterieladezustand")); - $maxleistung = $this->ReadPropertyInteger("MaxBatterieleistung"); + $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)); + } - - if ($Peak) { - if ($batterieladezustand <= $minimumentladen) { - $filtered_powersteps = array_filter($array_powersteps, function ($value) use ($maxleistung) { - return $value > $maxleistung; // Hochpass filtern + $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)); - IPS_LogMessage("Batterie", "Batterie laden: "); - } elseif ($batterieladezustand >= $aufdasnachladen) { - $filtered_powersteps_entladen = array_filter($array_powersteps, function ($value) use ($maxleistung) { - return $value < $maxleistung; // Tiefpass filtern + }elseif($batterieladezustand>$minimumentladen){ + + $this->SetValue("PowerSteps", json_encode($array_powersteps)); + } + else{ + + $filtered_powersteps = array_filter($array_powersteps, function ($value) { + return $value >= 0; }); - $this->SetValue("PowerSteps", json_encode($filtered_powersteps_entladen)); - IPS_LogMessage("Batterie", "Batterie entladen: " ); - - } elseif ($batterieladezustand < $aufdasnachladen && $batterieladezustand > $minimumentladen) { - $this->SetValue("PowerSteps", json_encode($array_powersteps)); - IPS_LogMessage("Batterie", "In Hysterese: "); - - } else { - $this->SetValue("PowerSteps", json_encode($array_powersteps[0])); - IPS_LogMessage("Batterie", "Weder noch: "); + $filtered_powersteps_laden = array_values($filtered_powersteps); + $this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden)); } - } else { // Solar + }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"); + + } - $filtered_powersteps_solar = array_filter($array_powersteps, function ($value) use ($maxleistung) { - return $value > $maxleistung; // Hochpass filtern - }); - - $this->SetValue("PowerSteps", json_encode($filtered_powersteps_solar)); - IPS_LogMessage("Batterie", "Solarmodus"); } + } + private function CheckIdle($power) { $lastpower = GetValue("Aktuelle_Leistung"); @@ -215,5 +322,6 @@ public function RequestAction($Ident, $Value) $this->SetValue("Idle", true); } } + } -?> \ No newline at end of file +?> diff --git a/Belevo_Bezahl_Modul/README.md b/Belevo_Bezahl_Modul/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Belevo_Bezahl_Modul/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/Belevo_Bezahl_Modul/form.json b/Belevo_Bezahl_Modul/form.json new file mode 100644 index 0000000..94901e5 --- /dev/null +++ b/Belevo_Bezahl_Modul/form.json @@ -0,0 +1,22 @@ +{ + "elements":[ + { + "type": "SelectVariable", + "name": "Reservate", + "caption": "Betrag reservieren", + "test": true + }, + { + "type": "SelectVariable", + "name": "GetAmount", + "caption": "Betrag Abziehen", + "test": true + }, + { + "type": "SelectVariable", + "name": "HTMLBox", + "caption": "HTMLBox", + "test": true + } + ] + } \ No newline at end of file diff --git a/Belevo_Bezahl_Modul/module.json b/Belevo_Bezahl_Modul/module.json new file mode 100644 index 0000000..80bb7ae --- /dev/null +++ b/Belevo_Bezahl_Modul/module.json @@ -0,0 +1,12 @@ +{ + "id": "{466A36DA-3C90-06E8-1D57-161D921B45EE}", + "name": "Belevo_Bezahl_Modul", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Belevo_Bezahl_Modul/module.php b/Belevo_Bezahl_Modul/module.php new file mode 100644 index 0000000..280c23e --- /dev/null +++ b/Belevo_Bezahl_Modul/module.php @@ -0,0 +1,126 @@ +RegisterPropertyInteger("Reservate", 0); + $this->RegisterPropertyInteger("GetAmount", 0); + $this->RegisterPropertyInteger("HTMLBox", 0); + $this->RegisterVariableInteger("ReservationAmount", "ReservationAmount", '', 0); + $this->RegisterVariableBoolean("AmountIsReserved", "AmountIsReserved", '', false); + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetHTMLContent(); + } + + private function SetHTMLContent() + { + $apiKey = "pk_test_51Qkr79LJAcsNrpivA90lt7ULEzyXKR8l0pAqTBgfeuAIWlsLS4A3BdIBITc9UooFANbImvlJQ2F2jOZ0X5j8GI7Q00hNNasvQm"; // Test-API-Schlüssel + + $html = " + + + + Google Pay mit Stripe + + + + + + +

Google Pay Integration mit Stripe

+ + + + +"; + + SetValue($this->ReadPropertyInteger("HTMLBox"), $html); + } +} \ No newline at end of file diff --git a/Boiler_2_Stufig_Mit_Fueler/form.json b/Boiler_2_Stufig_Mit_Fueler/form.json index d6bd2a4..9cb05ce 100644 --- a/Boiler_2_Stufig_Mit_Fueler/form.json +++ b/Boiler_2_Stufig_Mit_Fueler/form.json @@ -7,7 +7,7 @@ { "type":"Select", "name":"Boilertemperatur_glätten", - "caption":"Boilertemperatur glätten Ja oder Nein", + "caption":"Boilertemperatur glätten", "options":[ { "caption":"Ja", @@ -24,24 +24,36 @@ "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 Leisutungsänderungen", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", "suffix": "" }, { "type": "NumberSpinner", "name": "BoilerLeistungTeillast", "caption": "Leistug Teillast", - "suffix": "" + "suffix": "Watt" }, { "type": "NumberSpinner", "name": "BoilerLeistungVolllast", "caption": "Leistug Vollast", - "suffix": "" + "suffix": "Watt" + }, + { + "type": "NumberSpinner", + "name": "Boilervolumen", + "caption": "Boilervolumen", + "suffix": "Liter" }, { "type": "SelectVariable", @@ -60,7 +72,37 @@ "name": "Kontakt_Volllast", "caption": "Schaltkontakt Volllast", "test": true + }, + { + "type": "List", + "name": "Zeitplan", + "caption": "Zeitplan für Solltemperaturen", + "columns": [ + { + "caption": "Uhrzeit", + "name": "Uhrzeit", + "width": "150px", + "add": "00:00", + "edit": { + "type": "ValidationTextBox" + } + }, + { + "caption": "Solltemperatur", + "name": "Solltemperatur", + "width": "150px", + "add": 0, + "edit": { + "type": "NumberSpinner" + } + } + ], + "add": true, + "delete": true, + "sort": { + "column": "Uhrzeit", + "direction": "ascending" + } } - ] -} +} \ No newline at end of file diff --git a/Boiler_2_Stufig_Mit_Fueler/module.php b/Boiler_2_Stufig_Mit_Fueler/module.php index 65ed8fb..5dfffd2 100644 --- a/Boiler_2_Stufig_Mit_Fueler/module.php +++ b/Boiler_2_Stufig_Mit_Fueler/module.php @@ -14,6 +14,10 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule $this->RegisterPropertyInteger("Kontakt_Teillast", 0); $this->RegisterPropertyInteger("Kontakt_Volllast", 0); $this->RegisterPropertyBoolean("Boilertemperatur_glätten", false); + $this->RegisterPropertyInteger("Boilervolumen", 300); + $this->RegisterPropertyString("Zeitplan", ""); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + // Boiler spezifische Variablen @@ -21,7 +25,6 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule $this->RegisterVariableInteger("Maximaltemperatur","Maximaltemperatur","",60); $this->RegisterVariableInteger("Legionellentemperatur","Legionellentemperatur","",65); $this->RegisterVariableInteger("LegioCounter", "LegioCounter", "", 0); - //$this->RegisterVariableInteger("Boilertemperatur", "Boilertemperatur", "", 0); $this->RegisterVariableInteger("Boilertemperatur", "Boilertemperatur", "", 0); @@ -32,8 +35,9 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0); $this->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0); $this->RegisterVariableString("PowerSteps", "PowerSteps"); - $this->RegisterVariableInteger("Power", "Power", "", 0); + $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); @@ -43,13 +47,14 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule // Initialisiere Idle $this->SetValue("Idle", true); - $this->RegisterTimer("Timer_Do_UserCalc",5000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + $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); @@ -78,6 +83,57 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule } } + + + public function getNextTimeAndTemperature($zeitplan) { + $arr = json_decode($zeitplan, true); + if (empty($arr)) { + return null; + } + $currentTime = new DateTime(); + $nextEntry = null; + $minDiff = PHP_INT_MAX; + + foreach ($arr as $entry) { + $entryTime = DateTime::createFromFormat('H:i', $entry['Uhrzeit']); + if ($entryTime < $currentTime) { + $entryTime->modify('+1 day'); + } + $diff = $currentTime->diff($entryTime)->format('%r%a') * 24 * 60 + $currentTime->diff($entryTime)->format('%r%h') * 60 + $currentTime->diff($entryTime)->format('%r%i'); + if ($diff < $minDiff) { + $minDiff = $diff; + $nextEntry = $entry; + } + } + + return $nextEntry; + } + + public function calculateRemainingTime($nextTime) { + $currentTime = new DateTime(); + $nextDateTime = DateTime::createFromFormat('H:i', $nextTime); + if ($nextDateTime < $currentTime) { + $nextDateTime->modify('+1 day'); + } + $interval = $currentTime->diff($nextDateTime); + return $interval->h + ($interval->i / 60); + } + + public function calculateRequiredHeat($boilervolumen, $tempDiff) { + // Annahme: spezifische Wärmekapazität von Wasser = 4.186 J/g°C + // 1 Liter Wasser = 1000 Gramm + $specificHeatCapacity = 4.186; // J/g°C + $waterMass = $boilervolumen * 1000; // Gramm + return $specificHeatCapacity * $waterMass * $tempDiff; // Joules + } + + public function canBoilerReachTemperature($boilervolumen, $boilerTemper, $nextTemp, $remainingTime, $vollleistung) { + $tempDiff = $nextTemp - $boilerTemper; + $requiredHeat = $this->calculateRequiredHeat($boilervolumen, $tempDiff); + $availableHeat = $vollleistung * $remainingTime * 3600; // Leistung in Watt * Zeit in Sekunden + return $availableHeat >= $requiredHeat; + } + // Methode zum Setzen des aktuellen Stromverbrauchs public function SetAktuelle_Leistung(int $power) { @@ -107,7 +163,7 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule // 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(); } @@ -139,7 +195,7 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule // PT $time_constant= $this->ReadPropertyInteger("ZeitKonstante"); - $delta_t = 30; // Zeitdifferenz zwischen den Messungen (30 Sekunden) + $delta_t = 5; // Zeitdifferenz zwischen den Messungen (30 Sekunden) $alpha = $delta_t / ($time_constant + $delta_t); $newBoilerTemp = $boilerTemp + $alpha * ($boilerPT1 - $boilerTemp); $this->SetValue("Boilertemperatur", $newBoilerTemp); @@ -158,8 +214,6 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule } - - $boilerTemp = $this->GetValue("Boilertemperatur"); $minTemp = $this->GetValue("Mindesttemperatur"); $maxTemp = $this->GetValue("Maximaltemperatur"); @@ -167,6 +221,19 @@ class Boiler_2_Stufig_Mit_Fueler extends IPSModule $teilLeistung = $this->ReadPropertyInteger("BoilerLeistungTeillast"); $vollLeistung = $this->ReadPropertyInteger("BoilerLeistungVolllast"); + + $nextEntry = $this->getNextTimeAndTemperature($this->ReadPropertyString("Zeitplan")); + if ($nextEntry !== null) { + $remainingTime = $this->calculateRemainingTime($nextEntry['Uhrzeit']); + $nextTemp = $nextEntry['Solltemperatur']; + + if (!$this->canBoilerReachTemperature($this->ReadPropertyInteger("Boilervolumen"), $boilerTemp, $nextTemp, $remainingTime, $vollLeistung)) { + $minTemp = $nextTemp; + } + } + + + $AktuelleVollast = GetValue( $this->ReadPropertyInteger("Kontakt_Volllast") ); diff --git a/HauptManager/README.md b/HauptManager/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/HauptManager/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/HauptManager/form.json b/HauptManager/form.json new file mode 100644 index 0000000..1406fc9 --- /dev/null +++ b/HauptManager/form.json @@ -0,0 +1,57 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Einstellungen Energiemanager" + }, + { + "type": "NumberSpinner", + "name": "Peakleistung", + "caption": "Sollwertvorgabe für Peakshaving", + "suffix": "Watt" + }, + { + "type": "NumberSpinner", + "name": "Ueberschussleistung", + "caption": "Sollwertvorgabe für Solarladen", + "suffix": "Watt" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte", + "suffix": "Sekunden" + }, + { + "type": "List", + "name": "Verbraucher_Liste", + "caption": "Verbraucher, die gemanagt werden sollen.", + "add": true, + "delete": true, + "sortable": true, + "columns": [ + { + "caption": "Verbraucher Lesen", + "name": "User_Up", + "width": "auto", + "add": 0, + "edit": { + "type": "SelectVariable", + "filter": "String" + } + }, + { + "caption": "Verbraucher Steuern", + "name": "User_Down", + "width": "auto", + "add": 0, + "edit": { + "type": "SelectVariable", + "filter": "String" + } + } + + ] + } + ] +} \ No newline at end of file diff --git a/HauptManager/module.json b/HauptManager/module.json new file mode 100644 index 0000000..721695b --- /dev/null +++ b/HauptManager/module.json @@ -0,0 +1,12 @@ +{ + "id": "{F1F645F9-7F78-2843-2728-5D1708B4F835}", + "name": "HauptManager", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/HauptManager/module.php b/HauptManager/module.php new file mode 100644 index 0000000..9f25774 --- /dev/null +++ b/HauptManager/module.php @@ -0,0 +1,452 @@ +RegisterPropertyInteger("Peakleistung", 0); + $this->RegisterPropertyInteger("Ueberschussleistung", 0); + $this->RegisterPropertyInteger("Netzbezug", 0); // Initialisierung mit 0 + $this->RegisterPropertyString("Verbraucher_Liste", "[]"); + $this->RegisterPropertyInteger("Interval", 3); // Recheninterval + + $this->RegisterVariableInteger("Gesamtnetzbezug", "Gesamtnetzbezug", "", 0); + + // Timer registrieren + $this->RegisterTimer("Timer_DistributeEnergy",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "DistributeEnergy", "");'); + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_DistributeEnergy",$this->ReadPropertyInteger("Interval")*1000); + + //Liste aller Verbraucher einlesen + } + + public function RequestAction($Ident, $Value) + { + switch ($Ident) { + case "DistributeEnergy": + $this->DistributeEnergy(); + break; + case "ApplyChanges": + $this->ApplyChanges(); + break; + default: + throw new Exception("Invalid Ident"); + } + } + + public function DistributeEnergy() + { + $Verbraucher_Liste = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); + + $currentTime = time(); + $Netzbezug = 0; + $Verbraucher_Liste_Korr = []; + + foreach ($Verbraucher_Liste as $user) { + + $decodedUser = json_decode(GetValue($user["User_Up"]), true); + + if (isset($decodedUser["Timestamp"]) && (($currentTime - $decodedUser["Timestamp"])) < 30) { + + foreach ($decodedUser["Users"] as $subuser) { + $subuser['Writeback'] = $user["User_Down"]; + + $Verbraucher_Liste_Korr[0]["User"][] = $subuser; + + } + $Netzbezug += $decodedUser["Netzbezug"]; + }else{ + + RequestAction($user["User_Down"],'{"timestamp":'.time().',"Is_Peak_Shaving":'.true.',"User":[]}'); + } + + } + + + $this->SetValue("Gesamtnetzbezug", $Netzbezug); + + + $Peakleistung = $this->ReadPropertyInteger("Peakleistung"); + $Ueberschussleistung = $this->ReadPropertyInteger("Ueberschussleistung"); + $Is_Peak_Shaving = false; + // Fallunterscheidung ob auf Solarladen oder Peakshaving gerregelt wird. + if ($Netzbezug < ($Peakleistung - $Ueberschussleistung) / 2) { + $remainingPower = -1 * (-1 * $Ueberschussleistung + $Netzbezug); + $Is_Peak_Shaving = false; + } else { + $remainingPower = $Peakleistung - $Netzbezug; + $Is_Peak_Shaving = true; + } + $resultArray = []; + // Alle Energieverbraucher auslesen und dekodieren + + if (empty($Verbraucher_Liste_Korr[0]["User"])) { + // Liste ist leer, daher nichts zu tun + IPS_LogMessage("Manager", "aufgerufen leere liste"); + + return; + } + + $allIdle = true; // Variable zur Überprüfung, ob alle Benutzer Idle = true sind + $totalAktuelle_Leistung = 0; // Variable zur Summierung der Aktuelle_Leistung Werte + + // Fülle das Array mit allen entsprechenden Werten der Verbraucher ab + foreach ($Verbraucher_Liste_Korr[0]["User"] as $user) { + + // Überprüfen, ob alle Benutzer Idle = true sind, wenn einer nicht ist, wird später verworfen... + if (!$user["Idle"]) { + $allIdle = false; + IPS_LogMessage("Manager", "nciht idle"); + + } + + // Addiere die aktuell bereits verwendete Leistung auf, um sie bei der verteilung zu berücksichtigen + if(in_array(0, $user["PowerSteps"], true)){ + + // Addiere die aktuell bereits verwendete Leistung auf, um sie bei der verteilung zu berücksichtigen + $totalAktuelle_Leistung += ($user["Aktuelle_Leistung"]- $user["Leistung_Delta"]); + + } + } + + // Berücksichtigung der bereits verteilten Leistungen (nachher kann dafür wieder bei 0 begonnen werden zu verteilen) + $remainingPower += $totalAktuelle_Leistung; + + // Wenn nicht alle Benutzer Idle = true sind, rufe SetAktuelle_Leistung mit Aktuelle_Leistung Werten auf, (alle Verbraucher behalten die aktuelle Leistung) + if (!$allIdle) { + // Schritt 1: Benutzer nach Writeback-Wert aufteilen + $writebackArrays = []; + foreach ($Verbraucher_Liste_Korr[0]["User"] as $user) { + $writeback = $user['Writeback']; + IPS_LogMessage("Manager", $writeback); + + if (!isset($writebackArrays[$writeback])) { + $writebackArrays[$writeback] = []; + } + $writebackArrays[$writeback][] = $user; + } + + // Schritt 2: Foreach-Schleife pro Writeback-Array + foreach ($writebackArrays as $writeback => $users) { + $resultArray = [ + 'timestamp' => time(), + 'Is_Peak_Shaving' => $Is_Peak_Shaving, + 'User' => [] + ]; + + foreach ($users as $user) { + $resultArray['User'][] = [ + 'InstanceID' => $user['InstanceID'], + 'Set_Leistung' => $user['Aktuelle_Leistung'] + ]; + } + + // Schritt 3: Array in String konvertieren + $resultString = json_encode($resultArray); + + // Schritt 4: RequestAction aufrufen + RequestAction($writeback, $resultString); + } + return; + } + + // Sortiere die Verbruacher nach Priorität entweder der PV_Prio oder der Peak Prio + usort($Verbraucher_Liste_Korr[0]["User"], function ($a, $b) use ( + $Is_Peak_Shaving + ) { + $primaryKey = $Is_Peak_Shaving ? "Sperre_Prio" : "PV_Prio"; + // Wenn die Prio geleich ist, sortiere danach welcher verbraucher bisher am wenigsten Energie bekommen hat. + if ($a[$primaryKey] == $b[$primaryKey]) { + return round($a["Bezogene_Energie"]/2000) <=> round($b["Bezogene_Energie"]/2000); + } + return $a[$primaryKey] <=> $b[$primaryKey]; + }); + + // Primärschlüssel für die Priorität basierend auf dem Parameter auswählen (für sortierung in gruppen anschliessend) + $priorityKey = $Is_Peak_Shaving ? "Sperre_Prio" : "PV_Prio"; + + // Schleife durch alle Prioritäten + $priorities = array_unique( + array_column($Verbraucher_Liste_Korr[0]["User"], $priorityKey) + ); + $groupedUsers = []; + + foreach ($priorities as $priority) { + $groupedUsers[$priority] = array_filter( + $Verbraucher_Liste_Korr[0]["User"], + function ($user) use ($priority, $priorityKey) { + return $user[$priorityKey] == $priority; + } + ); + } + + + + // Jetzt werden die energien pro gruppe verteilt (Immer alle pro prio in einer gruppe miteinander) + foreach ($groupedUsers as $priority => $users) { + // Verbraucher mit gleicher Priorität sammeln + $samePriorityUsers = isset($groupedUsers[$priority]) + ? $groupedUsers[$priority] + : []; + + + // Wenn keine Verbraucher mit gleicher Priorität vorhanden sind, überspringen + if (empty($samePriorityUsers)) { + continue; + } + $withZero = []; + $withoutZero = []; + // Verbraucher die nicht 0 Annhemen können, bekommen einfach den tiefsten wert + foreach ($samePriorityUsers as $entry) { + if (min($entry["PowerSteps"]) <= 0) { + $withZero[] = $entry; + } else { + $withoutZero[] = $entry; + } + } + + + // Verbraucher die nicht 0 annhemen können erhalten nun den minimalwert + if (!empty($withoutZero)) { + foreach ($withoutZero as $entry) { + $resultArray[] = [ + 'user' => $user['InstanceID'], + 'Writeback' => $user['Writeback'], + 'Set_Leistung' => min($entry["PowerSteps"]) + ]; + //$remainingPower -= $entry["Aktuelle_Leistung"]; + } + } + + // Nun die verteilen, die 0 erhalten können. + $samePriorityUsers = $withZero; + // Array für die verteilte Energie pro User erstellen + $userEnergyProv = []; + + foreach ($samePriorityUsers as $user) { + $userEnergyProv[$user['InstanceID']] = [ + 'user' => $user['InstanceID'], + 'Writeback' => $user['Writeback'], + //'Leistung_Delta' => $user["Leistung_Delta"], + 'Set_Leistung' => 0 + ]; + } + + if($remainingPower>=0){ + // Alle Schritte der Benutzer in einem Array sammeln + $allSteps = []; + foreach ($samePriorityUsers as $user) { + foreach ($user["PowerSteps"] as $step) { + $allSteps[] = [ + "user" => $user["InstanceID"], + "Writeback" => $user["Writeback"], + "step" => $step + //"Leistung_Delta" => $user["Leistung_Delta"] + ]; + } + } + + + // Sortiere die Schritte nach Größe + usort($allSteps, function ($a, $b) { + return $a["step"] <=> $b["step"]; + }); + + + // Iteriere durch alle Schritte + foreach ($allSteps as $entry) { + $user = $entry["user"]; + $manager = $entry["Writeback"]; + $powerstep = $entry["step"]; + + + $aktleistung = array_filter($userEnergyProv, function($entry2) use ($user, $manager) { + + + return $entry2["user"] == $user && $entry2["Writeback"] == $manager; + }); + + foreach($aktleistung as $entry){ + $aktleistung = $entry; + } + + // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if ($remainingPower >= $powerstep - $aktleistung['Set_Leistung']) { + // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + $remainingPower -= $powerstep - $aktleistung['Set_Leistung']; + + array_walk($userEnergyProv, function(&$entry3) use ($user, $manager, $powerstep) { + if ($entry3["user"] == $user && $entry3["Writeback"] == $manager) { + $entry3["Set_Leistung"] = $powerstep; + } + }); + } + + } + + // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt + foreach ($userEnergyProv as $userInstanceID => $leistung) { + $minimalleitsung = min( + array_column( + array_filter($allSteps, function ($entry) use ( + $userInstanceID + ) { + return $entry["user"] == $userInstanceID; + }), + "step" + ) + ); + + IPS_LogMessage("Manager", $userInstanceID); + IPS_LogMessage("Manager", $minimalleitsung); + IPS_LogMessage("Manager", $remainingPower); + // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen + $leistung = max($leistung["Set_Leistung"], $minimalleitsung); + + + // Methode SetAktuelle_Leistung für jeden Verbraucher mit der entsprechenden Energie aufrufen + + $resultArray[] = $userEnergyProv[$userInstanceID]; //[ + // 'InstanceID' => $user['InstanceID'], + // 'Writeback' => $user['Writeback'], + // 'Set_Leistung' => $leistung + // ]; + + } + + + } + else{ + + // Alle Schritte der Benutzer in einem Array sammeln + $allSteps = []; + foreach ($samePriorityUsers as $user) { + foreach ($user["PowerSteps"] as $step) { + $allSteps[] = [ + "user" => $user["InstanceID"], + "Writeback" => $user["Writeback"], + "step" => $step*-1 + //"Leistung_Delta" => $user["Leistung_Delta"] + ]; + } + } + + + // Sortiere die Schritte nach Größe + usort($allSteps, function ($a, $b) { + return $a["step"] <=> $b["step"]; + }); + + $remainingPower = $remainingPower *-1; + + // Iteriere durch alle Schritte + foreach ($allSteps as $entry) { + $user = $entry["user"]; + $manager = $entry["Writeback"]; + $powerstep = $entry["step"]; + + + $aktleistung = array_filter($userEnergyProv, function($entry2) use ($user, $manager) { + + + return $entry2["user"] == $user && $entry2["Writeback"] == $manager; + }); + + foreach($aktleistung as $entry){ + $aktleistung = $entry; + } + + // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if ($remainingPower >= $powerstep - $aktleistung['Set_Leistung']) { + // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + $remainingPower -= $powerstep - $aktleistung['Set_Leistung']; + + array_walk($userEnergyProv, function(&$entry3) use ($user, $manager, $powerstep) { + if ($entry3["user"] == $user && $entry3["Writeback"] == $manager) { + $entry3["Set_Leistung"] = $powerstep; + } + }); + } + + } + $remainingPower = $remainingPower *-1; + + // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt + foreach ($userEnergyProv as $userInstanceID => $leistung) { + $minimalleitsung = min( + array_column( + array_filter($allSteps, function ($entry) use ( + $userInstanceID + ) { + return $entry["user"] == $userInstanceID; + }), + "step" + ) + ); + + IPS_LogMessage("Manager", $userInstanceID); + IPS_LogMessage("Manager", $minimalleitsung); + IPS_LogMessage("Manager", $remainingPower); + // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen + $leistung = max($leistung["Set_Leistung"], $minimalleitsung)*-1; + + + // Methode SetAktuelle_Leistung für jeden Verbraucher mit der entsprechenden Energie aufrufen + + $resultArray[] = $userEnergyProv[$userInstanceID]; //[ + // 'InstanceID' => $user['InstanceID'], + // 'Writeback' => $user['Writeback'], + // 'Set_Leistung' => $leistung + // ]; + + } + + } + } + + //IPS_LogMessage("Manager", print_r($resultArray)); + + $writebackArrays = []; + foreach ($resultArray as $user) { + $writeback = $user['Writeback']; + + if (!isset($writebackArrays[$writeback])) { + $writebackArrays[$writeback] = []; + } + $writebackArrays[$writeback][] = $user; + } + + // Schritt 2: Foreach-Schleife pro Writeback-Array + foreach ($writebackArrays as $writeback => $users) { + $resultArray = [ + 'timestamp' => time(), + 'Is_Peak_Shaving' => $Is_Peak_Shaving, + 'User' => [] + ]; + + foreach ($users as $user) { + $resultArray['User'][] = [ + 'InstanceID' => $user['user'], + 'Set_Leistung' => $user['Set_Leistung'] + ]; + } + + // Schritt 3: Array in String konvertieren + $resultString = json_encode($resultArray); + + // Schritt 4: RequestAction aufrufen + RequestAction($writeback, $resultString); + } + + + + } +} +?> \ No newline at end of file diff --git a/Ladestation_Universal/form.json b/Ladestation_Universal/form.json index 96d720b..242d2d5 100644 --- a/Ladestation_Universal/form.json +++ b/Ladestation_Universal/form.json @@ -16,6 +16,10 @@ { "caption": "Smart-Me Pico", "value": 3 + }, + { + "caption": "Dummy Station (Ohne Ansteuerung)", + "value": 4 } ] }, @@ -42,9 +46,15 @@ { "type": "NumberSpinner", "name": "IdleCounterMax", - "caption": "Zyklen zwischen zwei Leistungsänderungen", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", "suffix": "" }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte", + "suffix": "Sekunden" + }, { "type": "ValidationTextBox", "name": "IP_Adresse", diff --git a/Ladestation_Universal/module.php b/Ladestation_Universal/module.php index 47658bd..30a8510 100644 --- a/Ladestation_Universal/module.php +++ b/Ladestation_Universal/module.php @@ -17,6 +17,7 @@ class Ladestation_Universal extends IPSModule $this->RegisterPropertyString("Seriennummer", ""); $this->RegisterPropertyString("Username", ""); $this->RegisterPropertyString("Password", ""); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval // Ladestationspezifische Variabeln @@ -38,6 +39,8 @@ class Ladestation_Universal extends IPSModule $this->RegisterVariableString("PowerSteps", "PowerSteps"); $this->RegisterVariableInteger("Power", "Power"); $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); + $this->RegisterVariableInteger("Power_Count", "Power_Count", "", 0); // Hilfsvariabeln für Idle zustand $this->RegisterPropertyInteger("IdleCounterMax", 2); @@ -47,13 +50,15 @@ class Ladestation_Universal extends IPSModule // Initialisiere Idle $this->SetValue("Idle", true); - $this->RegisterTimer("Timer_Do_UserCalc",5000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + $this->RegisterTimer("Timer_Do_UserCalc_EVC",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); } public function ApplyChanges() { parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_EVC",$this->ReadPropertyInteger("Interval")*1000); + // Zusätzliche Anpassungen nach Bedarf } @@ -82,12 +87,15 @@ class Ladestation_Universal extends IPSModule + public function SetAktuelle_Leistung(int $power) { $internalPower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); // Aktuelle Leistungsvorgabe setzen SetValue($this->GetIDForIdent("Aktuelle_Leistung"), $power); + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + if ($power != $internalPower) { // Setze die interne Leistungsvorgabe @@ -173,6 +181,8 @@ class Ladestation_Universal extends IPSModule $maxLeistung = $this->ReadPropertyInteger("MaxLeistung"); } + + $ch = curl_init(); // Setze die URL @@ -182,12 +192,28 @@ class Ladestation_Universal extends IPSModule CURLOPT_URL, "http://" . $this->ReadPropertyString("IP_Adresse") . "/api/status" ); + // Setze die Option, die Antwort als String zurückzugeben + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + // Führe die Anfrage aus und speichere die Antwort + $response = curl_exec($ch); + + // Schließe cURL + curl_close($ch); }elseif($this->ReadPropertyInteger("Ladestation")==1){ curl_setopt( $ch, CURLOPT_URL, "http://" . $this->ReadPropertyString("IP_Adresse") . "/mqtt?payload=" ); + // Setze die Option, die Antwort als String zurückzugeben + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + // Führe die Anfrage aus und speichere die Antwort + $response = curl_exec($ch); + + // Schließe cURL + curl_close($ch); } elseif($this->ReadPropertyInteger("Ladestation")==3){ curl_setopt( @@ -197,10 +223,7 @@ class Ladestation_Universal extends IPSModule ); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $this->ReadPropertyString("Username") . ":" . $this->ReadPropertyString("Password")); - } - - - // Setze die Option, die Antwort als String zurückzugeben + // Setze die Option, die Antwort als String zurückzugeben curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Führe die Anfrage aus und speichere die Antwort @@ -208,13 +231,20 @@ class Ladestation_Universal extends IPSModule // Schließe cURL curl_close($ch); + } + elseif($this->ReadPropertyInteger("Ladestation")==4){ + + $response = true; + + } + // Überprüfe, ob die Antwort nicht leer ist if ($response) { // Dekodiere die JSON-Antwort $data = json_decode($response, true); - if($this->ReadPropertyInteger("Ladestation")==2||$this->ReadPropertyInteger("Ladestation")==1){ + if($this->ReadPropertyInteger("Ladestation")==2){ // Überprüfe, ob das JSON-Dekodieren erfolgreich war und der Schlüssel "car" existiert if (json_last_error() === JSON_ERROR_NONE && isset($data["car"])) { // Speichere den Wert von "car" in der Variable $status @@ -233,6 +263,26 @@ class Ladestation_Universal extends IPSModule } } } + if($this->ReadPropertyInteger("Ladestation")==1){ + // Überprüfe, ob das JSON-Dekodieren erfolgreich war und der Schlüssel "car" existiert + if (json_last_error() === JSON_ERROR_NONE && isset($data["car"])) { + // Speichere den Wert von "car" in der Variable $status + + SetValue( + $this->GetIDForIdent("Ladeleistung_Effektiv"), + $data["nrg"][11]*10 + ); + + SetValue($this->GetIDForIdent("Fahrzeugstatus"), $data["car"]); + + if ($data["nrg"][6] > 1 && $data["car"] == 2) { + SetValue($this->GetIDForIdent("Lademodus"), 1); + } elseif ($data["nrg"][6] <= 1 && $data["car"] == 2) { + SetValue($this->GetIDForIdent("Lademodus"), 0); + } + } + } + if($this->ReadPropertyInteger("Ladestation")==3){ // Überprüfe, ob das JSON-Dekodieren erfolgreich war und der Schlüssel "car" existiert if (json_last_error() === JSON_ERROR_NONE && isset($data["State"])) { @@ -245,7 +295,7 @@ class Ladestation_Universal extends IPSModule SetValue($this->GetIDForIdent("Fahrzeugstatus"), $data["State"]); - if($data["MaxAllowedChargingCurrent"]>0 && $data["State"] != 1){ + if(($this->GetValue("Ladeleistung_Effektiv")>0)&& ($data["MaxAllowedChargingCurrent"]>0)){ if ($data["ActiveChargingPower"]/$data["MaxAllowedChargingCurrent"] > 0.4/* && $data["State"] != 1*/) { SetValue($this->GetIDForIdent("Lademodus"), 1); } elseif ($data["State"] != 1) { @@ -257,12 +307,46 @@ class Ladestation_Universal extends IPSModule } } } + if($this->ReadPropertyInteger("Ladestation")==4){ + + // Nichts zu tun hier... + + + } + } // Peak-Wert speichern $this->SetValue("Peak", $Peak); + + IPS_LogMessage("Lades", "Hier"); + + $akt = $this->GetValue("Ladeleistung_Effektiv"); + $pow = $this->GetValue("Aktuelle_Leistung"); + IPS_LogMessage("akt", $akt); + IPS_LogMessage("pow", $pow); + + $timeout = $this->ReadPropertyInteger("Interval")*$this->ReadPropertyInteger("IdleCounterMax")*2; + if(($akt<(0.8*$pow)) && ($pow>0)){ + IPS_LogMessage("Lades", "Hier2"); + + $dummy = $this->GetValue("Power_Count")+1; + $this->SetValue("Power_Count", $dummy); + + }elseif($this->GetValue("Power_Count")<=$timeout) { + IPS_LogMessage("Lades", "Hier3"); + + $this->SetValue("Power_Count", 0); + + } + IPS_LogMessage("Lades", "Hier4"); + + + + + // Array für die Powersteps initialisieren $powerSteps = [0]; @@ -284,16 +368,26 @@ class Ladestation_Universal extends IPSModule } elseif ($solarladen && $Peak) { $powerSteps = [0]; } else { + if($this->GetValue("Power_Count")>$timeout){ + + $maxLeistung = 1.05 * $this->GetValue("Ladeleistung_Effektiv"); + IPS_LogMessage("Lades", "Hier5"); + + } + $powerSteps += $this->getRangeLimits( $minLeistung, $maxLeistung, GetValue($this->GetIDForIdent("Lademodus")) ); } + }else{ + + $this->SetValue("Power_Count", 0); } // PowerSteps in der RegisterVariable speichern SetValue($this->GetIDForIdent("PowerSteps"), json_encode($powerSteps)); - + $this->SetValue("Leistung_Delta", $this->GetValue("Ladeleistung_Effektiv")-$this->GetValue("Ladeleistung")); // Rückgabe der Powersteps return $powerSteps; } @@ -304,14 +398,16 @@ class Ladestation_Universal extends IPSModule if($this->ReadPropertyInteger("Ladestation")==2){ $baseUrl ="http://" . $this->ReadPropertyString("IP_Adresse") . "/api/set?"; + }elseif($this->ReadPropertyInteger("Ladestation")==1){ $baseUrl ="http://" . $this->ReadPropertyString("IP_Adresse") . "/mqtt?payload="; + }elseif($this->ReadPropertyInteger("Ladestation")==3){ $baseUrl ="https://api.smart-me.com/pico/loadmanagementgroup/current/" . $this->ReadPropertyString("Seriennummer") . "?current="; + } // Base URL - IPS_LogMessage("Ladestation", "Aufgerufene ip" . $baseUrl); $value = $this->convertPowerToCurrent( $value, GetValue($this->GetIDForIdent("Lademodus")) @@ -381,7 +477,11 @@ class Ladestation_Universal extends IPSModule }elseif($this->ReadPropertyInteger("Ladestation")==3){ // Nichts zu tun für Smart-Me station +} }elseif($this->ReadPropertyInteger("Ladestation")==4){ + // Nichts zu tun für Dummy station } + + // Second request @@ -449,9 +549,11 @@ class Ladestation_Universal extends IPSModule // Return responses return; - } + }elseif($this->ReadPropertyInteger("Ladestation")==4){ + // Nichts zu tun für Dummy station +} - } + // If value is out of range else { diff --git a/Ladestation_v2/README.md b/Ladestation_v2/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Ladestation_v2/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/Ladestation_v2/form.json b/Ladestation_v2/form.json new file mode 100644 index 0000000..e3eefbd --- /dev/null +++ b/Ladestation_v2/form.json @@ -0,0 +1,83 @@ +{ + "elements": [ + { + "type": "Select", + "name": "Ladestation", + "caption": "Ladestation", + "options": [ + { + "caption": "Go-E Wallbox (Alte Version)", + "value": 1 + }, + { + "caption": "Go-E Germini / Germini Flex", + "value": 2 + }, + { + "caption": "Smart-Me Pico", + "value": 3 + }, + { + "caption": "Dummy Station (Ohne Ansteuerung)", + "value": 4 + }, + { + "caption": "Easee", + "value": 5 + } + ] + }, + { + "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": "Max_Current_abs", + "caption": "Maximaler Ladestrom", + "suffix": "Ampere" + }, + { + "type": "NumberSpinner", + "name": "Zeit_Zwischen_Zustandswechseln", + "caption": "Mindestlaufzeit des Verbrauchers bei Lastschaltung", + "suffix": "" + }, + { + "type": "ValidationTextBox", + "name": "IP_Adresse", + "caption": "IP-Adresse Ladestation" + }, + { + "type": "ValidationTextBox", + "name": "ID", + "caption": "ID" + + }, + { + "type": "ValidationTextBox", + "name": "Seriennummer", + "caption": "Seriennummer" + + }, + { + "type": "ValidationTextBox", + "name": "Username", + "caption": "Username" + + }, + { "type": "PasswordTextBox", + "name": "Password", + "caption": "Passwort" + } + + ] +} \ No newline at end of file diff --git a/Ladestation_v2/module.json b/Ladestation_v2/module.json new file mode 100644 index 0000000..100a622 --- /dev/null +++ b/Ladestation_v2/module.json @@ -0,0 +1,12 @@ +{ + "id": "{51E121F0-E2E9-D0C2-C8BD-92601B143EB8}", + "name": "Ladestation_v2", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Ladestation_v2/module.php b/Ladestation_v2/module.php new file mode 100644 index 0000000..b6f1de4 --- /dev/null +++ b/Ladestation_v2/module.php @@ -0,0 +1,621 @@ +RegisterPropertyString("IP_Adresse", "0.0.0.0"); + $this->RegisterPropertyInteger("Ladestation", 2); + $this->RegisterPropertyString("ID", ""); + $this->RegisterPropertyString("Seriennummer", ""); + $this->RegisterPropertyString("Username", ""); + $this->RegisterPropertyString("Password", ""); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + $this->RegisterPropertyInteger("Max_Current_abs", 32); // Recheninterval + $this->RegisterPropertyInteger("Zeit_Zwischen_Zustandswechseln", 1); + + + // Ladestationspezifische Variabeln + $this->RegisterVariableFloat("Max_Current","Maximaler Ladestrom","", 0); + IPS_SetHidden($this->GetIDForIdent("Max_Current"), true); + $this->RegisterVariableBoolean("Is_1_ph", "Auto lädt 1-Phasig", "~Switch", false); + $this->RegisterVariableBoolean("Car_detected", "Auto erkannt","~Switch", false); + $this->RegisterVariableInteger("Pending_Counter", "Pending_Counter", "", 0); + IPS_SetHidden($this->GetIDForIdent("Pending_Counter"), true); + $this->RegisterVariableBoolean("Car_is_full", "Auto fertig geladen", "~Switch", false); + $this->RegisterVariableBoolean("Ladebereit", "Ladestation ein", "~Switch", true); + $this->EnableAction("Ladebereit"); + $this->RegisterVariableBoolean("Solarladen", "Solarladen ein", "~Switch", false); + $this->EnableAction("Solarladen"); + $this->RegisterVariableInteger("Fahrzeugstatus", "Fahrzeugstatus", "", 0); + IPS_SetHidden($this->GetIDForIdent("Fahrzeugstatus"), true); + + $this->RegisterVariableFloat("Ladeleistung_Effektiv", "Aktuelle Ladeleistung", "", 0); + $this->RegisterVariableBoolean("Peak", "Peak", "", 0); + IPS_SetHidden($this->GetIDForIdent("Peak"), true); + + $this->RegisterVariableBoolean("IsTimerActive", "IsTimerActive", "", false); + $this->RegisterTimer("ZustandswechselTimer",0,"IPS_RequestAction(" .$this->InstanceID .', "ResetTimer", "");'); + + + + // Variabeln für Kommunkation mit Manager + $this->RegisterVariableInteger("Sperre_Prio", "Priorität Sperre", "", 0); + $this->EnableAction("Sperre_Prio"); + IPS_SetHidden($this->GetIDForIdent("Sperre_Prio"), true); + + $this->RegisterVariableInteger("PV_Prio", "Priorität Solarladen", "", 0); + $this->EnableAction("PV_Prio"); + IPS_SetHidden($this->GetIDForIdent("PV_Prio"), true); + + $this->RegisterVariableBoolean("Idle", "Idle", "", 0); + IPS_SetHidden($this->GetIDForIdent("Idle"), true); + + $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0); + IPS_SetHidden($this->GetIDForIdent("Aktuelle_Leistung"), true); + + $this->RegisterVariableFloat("Bezogene_Energie", "Gesamter Energiebezug", "", 0); + IPS_SetHidden($this->GetIDForIdent("Bezogene_Energie"), true); + + $this->RegisterVariableString("PowerSteps", "Leistungsschritte"); + IPS_SetHidden($this->GetIDForIdent("PowerSteps"), true); + + $this->RegisterVariableInteger("Power", "Power"); + IPS_SetHidden($this->GetIDForIdent("Power"), true); + + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + IPS_SetHidden($this->GetIDForIdent("Is_Peak_Shaving"), true); + + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); + IPS_SetHidden($this->GetIDForIdent("Leistung_Delta"), true); + + // Hilfsvariabeln für Idle zustand + $this->RegisterPropertyInteger("IdleCounterMax", 2); + $this->RegisterVariableInteger("IdleCounter", "IdleCounter", "", 0); + IPS_SetHidden($this->GetIDForIdent("IdleCounter"), true); + $this->SetValue("IdleCounter", 0); + + // Initialisiere Idle + $this->SetValue("Idle", true); + + $this->RegisterTimer("Timer_Do_UserCalc_EVC",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_EVC",$this->ReadPropertyInteger("Interval")*1000); + + // Zusätzliche Anpassungen nach Bedarf + } + + + 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": + + + if($this->Detect_Car($this->ReadPropertyInteger("Ladestation"))){ + $this->SetAktuelle_Leistung($this->GetValue("Power")); + $this->GetCurrentData($this->GetValue("Is_Peak_Shaving")); + } + else{ + SetValue($this->GetIDForIdent("PowerSteps"), json_encode([0])); + $this->SetValue("PowerSteps", json_encode([0])); + + + } + break; + + case "Sperre_Prio": + $this->SetValue("Sperre_Prio", (bool)$Value); + break; + + case "PV_Prio": + $this->SetValue("PV_Prio", (bool)$Value); + break; + + case "Solarladen": + $this->SetValue("Solarladen", (bool)$Value); + break; + + case "Ladebereit": + $this->SetValue("Ladebereit", (bool)$Value); + break; + + case "ResetTimer": + $this->ResetTimer(); + break; + + default: + throw new Exception("Invalid Ident"); + } + } + + + public function Detect_Car(int $carType) + { + + if($this->GetValue("Car_detected")==true){ + if($this->Get_Car_Status($carType)==true){ + $this->SetValue("Car_detected", true); + if($this->GetValue("Max_Current")<6){ + $this->SetValue("Car_is_full", true); + } + + }else{ + $this->SetValue("Car_detected", false); + $this->SetValue("Car_is_full", false); + + } + } + else{ + if($this->Get_Car_Status($carType)==true){ + + $this->sendPowerToStation($this->ReadPropertyInteger("Max_Current_abs")); + + $counter = $this->GetValue("Pending_Counter"); + + if($counter>(60/($this->ReadPropertyInteger("Interval")))){ + + $this->SetValue("Pending_Counter", 0); + if($this->GetValue("Ladeleistung_Effektiv")>7500){ + $this->SetValue("Is_1_ph", false); + $this->Calc_Max_Current(false); + + } + else{ + $this->SetValue("Is_1_ph", true); + $this->Calc_Max_Current(true); + + } + + $this->SetValue("Car_detected", true); + + + } + else{ + $this->SetValue("Pending_Counter", $counter+1); + $this->SetValue("Car_detected", false); + + } + + }else{ + $this->SetValue("Car_detected", false); + $this->sendPowerToStation($this->ReadPropertyInteger("Max_Current_abs")); + } + } + + return $this->GetValue("Car_detected"); + + } + + + // Methode zum Setzen der PowerSteps und Timer starten + public function SetTimerOn() + { + // Timer setzen, der nach "Zeit_Zwischen_Zustandswechseln" abläuft + $zeitZwischenZustandswechseln = $this->ReadPropertyInteger("Zeit_Zwischen_Zustandswechseln"); + + if($zeitZwischenZustandswechseln>0){ + $this->SetTimerInterval("ZustandswechselTimer", $zeitZwischenZustandswechseln * 60000); // Timer in Millisekunden + // Timer-Status auf true setzen + $this->SetValue("IsTimerActive", true); + }else{ + $this->SetValue("IsTimerActive", false); + + } + } + + // Methode zum Zurücksetzen von PowerSteps nach Ablauf des Timers + public function ResetTimer() + { + // Timer stoppen + $this->SetTimerInterval("ZustandswechselTimer", 0); + + // Timer-Status auf false setzen + $this->SetValue("IsTimerActive", false); + } + + + public function Get_Car_Status(int $carType) + { + $ch = curl_init(); + $car_on_station = $this->GetValue("Car_detected"); + switch ($carType) { + case 1: + curl_setopt($ch, CURLOPT_URL, "http://" . $this->ReadPropertyString("IP_Adresse") . "/mqtt?payload="); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + curl_close($ch); + $data = json_decode($response, true); + + if (json_last_error() === JSON_ERROR_NONE && isset($data["car"])) { + /*if ($data["car"] != 1) { + $this->SetValue("Car_detected", true); + } + else{ + $this->SetValue("Car_detected", false); + }*/ + if ($data["car"] != 1) { + $car_on_station = true; + } + else{ + $car_on_station = false; + } + $this->SetValue("Ladeleistung_Effektiv", $data["nrg"][11]*10); + $this->SetValue("Fahrzeugstatus", $data["car"]); + } + break; + + case 2: + curl_setopt($ch, CURLOPT_URL, "http://" . $this->ReadPropertyString("IP_Adresse") . "/api/status"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + curl_close($ch); + $data = json_decode($response, true); + + if (json_last_error() === JSON_ERROR_NONE && isset($data["car"])) { + /*if ($data["car"] != 1) { + $this->SetValue("Car_detected", true); + } + else{ + $this->SetValue("Car_detected", false); + }*/ + if ($data["car"] != 1) { + $car_on_station = true; + } + else{ + $car_on_station = false; + } + $this->SetValue("Ladeleistung_Effektiv", $data["nrg"][11]); + $this->SetValue("Fahrzeugstatus", $data["car"]); + } + break; + + case 3: + curl_setopt($ch, CURLOPT_URL, "https://api.smart-me.com/pico/charging/" . $this->ReadPropertyString("ID")); + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($ch, CURLOPT_USERPWD, $this->ReadPropertyString("Username") . ":" . $this->ReadPropertyString("Password")); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + curl_close($ch); + $data = json_decode($response, true); + + if (json_last_error() === JSON_ERROR_NONE && isset($data["State"])) { + /*if ($data["car"] != 1) { + $this->SetValue("Car_detected", true); + } + else{ + $this->SetValue("Car_detected", false); + }*/ + if ($data["State"] != 1) { + $car_on_station = true; + } + else{ + $car_on_station = false; + } + $this->SetValue("Ladeleistung_Effektiv", round($data["ActiveChargingPower"]*1000)); + $this->SetValue("Fahrzeugstatus", $data["State"]); + + } + break; + + case 4: + $this->SetValue("Car_detected", true); + break; + + case 5: + echo "Fall 5"; + break; + + default: + $this->SetValue("Car_detected", false); + $this->SetValue("Fahrzeugstatus", -1); + break; + } + + + return $car_on_station; + } + + public function Calc_Max_Current(bool $is_1_ph) + { + $maxCurrent = 32; + if($is_1_ph){ + $maxCurrent = 1.5 + ($this->GetValue("Ladeleistung_Effektiv") / 230); + } + else{ + $maxCurrent = 1.5 + ($this->GetValue("Ladeleistung_Effektiv") / (1.71*400)); + } + if($maxCurrent>$this->ReadPropertyInteger("Max_Current_abs")){ + $maxCurrent = $this->ReadPropertyInteger("Max_Current_abs"); + } + $this->SetValue("Max_Current", $maxCurrent); + } + + public function Get_Current_From_Power(bool $is_1_ph, int $power) + { + if ($is_1_ph) { + $current = round($power / 230); + } else { + $current = round($power / (400 * 1.71)); + } + + return $current; + } + + public function Get_Array_From_Current(bool $is_1_ph, float $current) + { + $resultArray = []; + $resultArray[] = 0; + for ($i = 6; $i <= $current; $i++) { + if ($is_1_ph) { + $resultArray[] = $i * 230; + } else { + $resultArray[] = $i * 400 * 1.71; + } + } + + return $resultArray; + } + + + + public function SetAktuelle_Leistung(int $power) + { + // Hier eine Leistungsänderung detektieren für Idle und interne Mindestlaufzeiten + $this->CheckIdle($power); + if ($this->GetValue("Aktuelle_Leistung") != $power) { + $this->SetTimerOn(); + } + + $internalPower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); + + // Aktuelle Leistungsvorgabe setzen + SetValue($this->GetIDForIdent("Aktuelle_Leistung"), $power); + if($power <= 0){ + $this->SetValue("Pending_Counter", 0); + } + + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + + if ($power != $internalPower) { + // Setze die interne Leistungsvorgabe + + // Idle für 4 Zyklen auf false setzen + SetValue($this->GetIDForIdent("Idle"), false); + SetValue( + $this->GetIDForIdent("IdleCounter"), + $this->ReadPropertyInteger("IdleCounterMax") + ); + } else { + // IdleCallCounter herunterzählen, wenn power == interne Leistungsvorgabe + $idleCounter = GetValue($this->GetIDForIdent("IdleCounter")); + if ($idleCounter > 0) { + $idleCounter--; + $this->SetValue("Pending_Counter", 0); + SetValue($this->GetIDForIdent("IdleCounter"), $idleCounter); + if ($idleCounter == 0) { + SetValue($this->GetIDForIdent("Idle"), true); + } + } + } + + // Ladeleistung setzen + $peak = GetValue($this->GetIDForIdent("Peak")); + $solarladen = GetValue($this->GetIDForIdent("Solarladen")); + $Ladebereit = GetValue($this->GetIDForIdent("Ladebereit")); + if (!$Ladebereit) { + + $this->sendPowerToStation(0); + + } elseif (!$peak && !$solarladen) { + // Wenn weder Peak noch Solarladen aktiv sind, setze Ladeleistung auf MaxLeistung + $this->sendPowerToStation($this->Get_Current_From_Power($this->GetValue("Is_1_ph"), $power)); + + } else { + // Ansonsten setze Ladeleistung auf die aktuelle Leistungsvorgabe (Aktuelle_Leistung) + $this->sendPowerToStation($this->Get_Current_From_Power($this->GetValue("Is_1_ph"), $power)); + } + } + + // Methode zum Abrufen der aktuellen Daten + public function GetCurrentData(bool $Peak) + { + + // Überprüfen, ob der Timer aktiv ist + if ($this->GetValue("IsTimerActive")) { + // Timer ist aktiv, PowerSteps setzen + $this->SetValue("PowerSteps", json_encode([$this->GetValue("Aktuelle_Leistung")])); + $this->SetValue("Leistung_Delta", $this->GetValue("Aktuelle_Leistung")-$this->GetValue("Ladeleistung_Effektiv")); + + return; + }else{ + $this->SetValue("Leistung_Delta", 0); + } + + // Aktuelle Properties abrufen + $ladebereit = GetValue($this->GetIDForIdent("Ladebereit")); + $solarladen = GetValue($this->GetIDForIdent("Solarladen")); + + + // Peak-Wert speichern + $this->SetValue("Peak", $Peak); + + // Array für die Powersteps initialisieren + $powerSteps = []; + + // Konfiguration des powerSteps-Arrays basierend auf den Properties + if (!$ladebereit) { + $powerSteps = [0]; + } elseif (!$Peak && !$solarladen) { + $powerSteps = [max($this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current")))]; + } elseif (!$Peak && $solarladen) { + $powerSteps = $this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current")); + } elseif ($solarladen && $Peak) { + $powerSteps = [0]; + } else { + $powerSteps = $this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current")); + } + + // PowerSteps in der RegisterVariable speichern + SetValue($this->GetIDForIdent("PowerSteps"), json_encode($powerSteps)); + // Rückgabe der Powersteps + $counter = $this->GetValue("Pending_Counter"); + + if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))){ + $this->SetValue("Pending_Counter", $counter+1); + + }elseif(max($this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current")))<(1.11*$this->GetValue("Ladeleistung_Effektiv"))){ // diesen elseif ggf wieder rauslöschen + $this->SetValue("Pending_Counter", $counter+1); + + } + else{ + + $this->SetValue("Pending_Counter", 0); + + } + + if($counter>(90/($this->ReadPropertyInteger("Interval")))){ + + $this->SetValue("Pending_Counter", 0); + $this->Calc_Max_Current($this->GetValue("Is_1_ph")); + } + + + + + return $powerSteps; + } + + public function sendPowerToStation(float $value) + { + $baseUrl = ""; + $stationType = $this->ReadPropertyInteger("Ladestation"); + + switch ($stationType) { + case 1: + $baseUrl = "http://" . $this->ReadPropertyString("IP_Adresse") . "/mqtt?payload="; + break; + case 2: + $baseUrl = "http://" . $this->ReadPropertyString("IP_Adresse") . "/api/set?"; + break; + case 3: + $baseUrl = "https://api.smart-me.com/pico/loadmanagementgroup/current/" . $this->ReadPropertyString("Seriennummer") . "?current="; + break; + case 4: + // Nichts zu tun für Dummy station + return; + } + + $ch = curl_init(); + IPS_LogMessage("value", "nach konvertierung" . $value); + + if ($value == 0) { + switch ($stationType) { + case 1: + $url = $baseUrl . "alw=0"; + break; + case 2: + $url = $baseUrl . "frc=1&sua=false"; + + break; + case 3: + $url = $baseUrl . "0"; + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($ch, CURLOPT_USERPWD, $this->ReadPropertyString("Username") . ":" . $this->ReadPropertyString("Password")); + break; + case 4: + // Nichts zu tun für Dummy station + return; + default: + return "Invalid station type."; + } + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($ch); + curl_close($ch); + return $response; + } elseif ($value >= 1 && $value <= 32) { + switch ($stationType) { + case 1: + $url1 = $baseUrl . "alw=1"; + $url2 = $baseUrl . "amp=$value"; + break; + case 2: + $url1 = $baseUrl . "frc=2"; + $url2 = $baseUrl . "amp=$value"; + break; + case 3: + $url2 = $baseUrl . ($value * 1000); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($ch, CURLOPT_USERPWD, $this->ReadPropertyString("Username") . ":" . $this->ReadPropertyString("Password")); + break; + case 4: + // Nichts zu tun für Dummy station + return; + default: + return "Invalid station type."; + } + + if (isset($url1)) { + curl_setopt($ch, CURLOPT_URL, $url1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response1 = curl_exec($ch); + if (curl_errno($ch)) { + curl_close($ch); + return "Error:" . curl_error($ch); + } + } + + curl_setopt($ch, CURLOPT_URL, $url2); + $response2 = curl_exec($ch); + if (curl_errno($ch)) { + curl_close($ch); + return "Error:" . curl_error($ch); + } + curl_close($ch); + return; + } else { + return "Invalid value. Must be between 0 and 32."; + } + } + + public function CheckIdle($power) + { + $lastpower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); + if ($lastpower != $power) { + $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); + } + } + + +} +?> diff --git a/Manager/form.json b/Manager/form.json index e3e25f0..84dadcb 100644 --- a/Manager/form.json +++ b/Manager/form.json @@ -22,6 +22,32 @@ "name": "Netzbezug", "caption": "Variable mit dem zu regelnden Netzbezug" }, + { + "type": "CheckBox", + "name": "HauptmanagerAktiv", + "caption": "Hauptmanager Aktiv" + }, + { + "type": "NumberSpinner", + "name": "ManagerID", + "caption": "Manager ID" + }, + { + "type": "SelectVariable", + "name": "DatenHoch", + "caption": "Daten Hoch" + }, + { + "type": "SelectVariable", + "name": "DatenZuruck", + "caption": "Daten Zurück" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte", + "suffix": "Sekunden" + }, { "type": "List", "name": "Verbraucher_Liste", diff --git a/Manager/module.php b/Manager/module.php index 6da2dc3..5b79bb3 100644 --- a/Manager/module.php +++ b/Manager/module.php @@ -11,23 +11,51 @@ class Manager extends IPSModule $this->RegisterPropertyInteger("Ueberschussleistung", 0); $this->RegisterPropertyInteger("Netzbezug", 0); // Initialisierung mit 0 $this->RegisterPropertyString("Verbraucher_Liste", "[]"); + $this->RegisterPropertyBoolean("HauptmanagerAktiv", false); // Initialisierung mit 0 + $this->RegisterPropertyInteger("ManagerID", 0); // Initialisierung mit 0 + $this->RegisterPropertyInteger("DatenHoch", 0); // Initialisierung mit 0 + $this->RegisterPropertyInteger("DatenZuruck", 0); // Initialisierung mit 0 + $this->RegisterPropertyInteger("Interval", 2); // Recheninterval - // Timer registrieren - $this->RegisterTimer("Timer_DistributeEnergy",5000,"IPS_RequestAction(" .$this->InstanceID .', "DistributeEnergy", "");'); + // Timer registrieren + + $this->RegisterTimer("Timer_DistributeEnergy",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "DistributeEnergy", "");'); } public function ApplyChanges() { parent::ApplyChanges(); //Liste aller Verbraucher einlesen - $Verbraucher_Liste = $this->ReadPropertyString("Verbraucher_Liste"); + $this->SetTimerInterval("Timer_DistributeEnergy",$this->ReadPropertyInteger("Interval")*1000); + } public function RequestAction($Ident, $Value) { switch ($Ident) { case "DistributeEnergy": + if($this->ReadPropertyBoolean("HauptmanagerAktiv")==true ){ + + $data = json_decode(GetValue($this->ReadPropertyInteger("DatenZuruck")), true); + IPS_LogMessage("Manager", print_r($data)); + IPS_LogMessage("Manager", $data["timestamp"]); + + if (isset($data["timestamp"])) { + $timestamp = $data["timestamp"]; + $currentTime = time(); + IPS_LogMessage("Manager", ($currentTime - $timestamp)); + + if (($currentTime - $timestamp) < 3600) { + $this->DistributeEnergy_Extern(); + } + } else { + $this->DistributeEnergy(); + } + + }else{ $this->DistributeEnergy(); + } + break; case "ApplyChanges": $this->ApplyChanges(); @@ -52,6 +80,7 @@ class Manager extends IPSModule $remainingPower = $Peakleistung - $Netzbezug; $Is_Peak_Shaving = true; } + IPS_LogMessage("Manag anfang", $remainingPower); // Alle Energieverbraucher auslesen und dekodieren $Verbraucher_Liste = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); @@ -80,18 +109,18 @@ class Manager extends IPSModule foreach ($Verbraucher_Liste as $user) { if (!IPS_InstanceExists($user["Verbraucher"])) { IPS_LogMessage("Manager", "aufgerufen komisch"); - continue; } // Werte direkt von der Verbraucher-Instanz abrufen - $Aktuelle_Leistung = GetValue(IPS_GetObjectIDByIdent("Aktuelle_Leistung", $user["Verbraucher"])); + $Aktuelle_Leistung = GetValue(IPS_GetObjectIDByIdent("Power", $user["Verbraucher"])); // Aktuelle Leistung durch Power ersetzt $Bezogene_Energie = GetValue(IPS_GetObjectIDByIdent("Bezogene_Energie", $user["Verbraucher"])); $PV_Prio = GetValue(IPS_GetObjectIDByIdent("PV_Prio", $user["Verbraucher"])); $Sperre_Prio = GetValue(IPS_GetObjectIDByIdent("Sperre_Prio", $user["Verbraucher"])); $idle = GetValue(IPS_GetObjectIDByIdent("Idle", $user["Verbraucher"])); $powerStepsJson = GetValue(IPS_GetObjectIDByIdent("PowerSteps", $user["Verbraucher"])); $powerSteps = json_decode($powerStepsJson, true); + $delta = GetValue(IPS_GetObjectIDByIdent("Leistung_Delta", $user["Verbraucher"])); // Verbraucher-Daten zum gefilterten Array hinzufügen $filteredVerbraucher[] = [ @@ -103,6 +132,7 @@ class Manager extends IPSModule "Sperre_Prio" => $Sperre_Prio, "Idle" => $idle, "PowerSteps" => $powerSteps, + "Leistung_Delta" => $delta ]; // Überprüfen, ob alle Benutzer Idle = true sind, wenn einer nicht ist, wird später verworfen... @@ -111,13 +141,18 @@ class Manager extends IPSModule IPS_LogMessage("Manager", "nciht idle"); } + 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; + $totalAktuelle_Leistung += ($Aktuelle_Leistung-$delta); + + } + } // Berücksichtigung der bereits verteilten Leistungen (nachher kann dafür wieder bei 0 begonnen werden zu verteilen) $remainingPower += $totalAktuelle_Leistung; + // Abbrechen wenn es keine gefilterten User gibt if (empty($filteredVerbraucher)) { return; @@ -140,14 +175,13 @@ class Manager extends IPSModule $primaryKey = $Is_Peak_Shaving ? "Sperre_Prio" : "PV_Prio"; // Wenn die Prio geleich ist, sortiere danach welcher verbraucher bisher am wenigsten Energie bekommen hat. if ($a[$primaryKey] == $b[$primaryKey]) { - return $a["Bezogene_Energie"] <=> $b["Bezogene_Energie"]; + return round($a["Bezogene_Energie"]/2000) <=> round($b["Bezogene_Energie"]/2000); } return $a[$primaryKey] <=> $b[$primaryKey]; }); // Primärschlüssel für die Priorität basierend auf dem Parameter auswählen (für sortierung in gruppen anschliessend) $priorityKey = $Is_Peak_Shaving ? "Sperre_Prio" : "PV_Prio"; - // Schleife durch alle Prioritäten $priorities = array_unique( array_column($filteredVerbraucher, $priorityKey) @@ -177,7 +211,7 @@ class Manager extends IPSModule $withoutZero = []; // Verbraucher die nicht 0 Annhemen können, bekommen einfach den tiefsten wert foreach ($samePriorityUsers as $entry) { - if (in_array(0, $entry["PowerSteps"])) { + if (min($entry["PowerSteps"]) <= 0) { $withZero[] = $entry; } else { $withoutZero[] = $entry; @@ -190,69 +224,149 @@ class Manager extends IPSModule $minPowerStep = min($entry["PowerSteps"]); IPS_RequestAction($instanceID,"SetAktuelle_Leistung",$minPowerStep); - $remainingPower -= $entry["Aktuelle_Leistung"]; + //$remainingPower -= $entry["Aktuelle_Leistung"]; } } + // Nun die verteilen, die 0 erhalten können. $samePriorityUsers = $withZero; - // Array für die verteilte Energie pro User erstellen + $userEnergyProv = []; $userEnergyProv = array_fill_keys(array_column($samePriorityUsers, "InstanceID"), 0); // Initialisierung für jeden Benutzer auf 0 setzen - // Alle Schritte der Benutzer in einem Array sammeln - $allSteps = []; - foreach ($samePriorityUsers as $user) { - foreach ($user["PowerSteps"] as $step) { - $allSteps[] = [ - "user" => $user["InstanceID"], - "step" => $step, - ]; + IPS_LogMessage("Manag", $remainingPower); + + if($remainingPower>=0){ + // Alle Schritte der Benutzer in einem Array sammeln + $allSteps = []; + foreach ($samePriorityUsers as $user) { + foreach ($user["PowerSteps"] as $step) { + if($step>=0){ + $allSteps[] = [ + "user" => $user["InstanceID"], + //"Leistung_Delta" => $user["Leistung_Delta"], + "step" => $step, + ];} + } + } + + // Sortiere die Schritte nach Größe + usort($allSteps, function ($a, $b) { + return $a["step"] <=> $b["step"]; + }); + + //if remaining power >0 + // Iteriere durch alle Schritte + foreach ($allSteps as $entry) { + $user = $entry["user"]; + $powerstep = $entry["step"]; + + // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if ($remainingPower >= $powerstep - $userEnergyProv[$user]) { // oder bedingung testen + // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + $remainingPower -= $powerstep - $userEnergyProv[$user]; + $userEnergyProv[$user] = $powerstep; + } + + } + + //else + + + // mache invertierte verteilung + + + // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt + foreach ($userEnergyProv as $userInstanceID => $leistung) { + $minimalleitsung = min( + array_column( + array_filter($allSteps, function ($entry) use ( + $userInstanceID + ) { + return $entry["user"] == $userInstanceID; + }), + "step" + ) + ); + + // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen + $leistung = max($leistung, $minimalleitsung); + + + + // Methode SetAktuelle_Leistung für jeden Verbraucher mit der entsprechenden Energie aufrufen + if (IPS_InstanceExists($userInstanceID)) { + IPS_RequestAction($userInstanceID,"SetAktuelle_Leistung",$leistung); + IPS_LogMessage("Manager", "aufgerufen setleistung if". $leistung); + + } + } + } + else{ + // Alle Schritte der Benutzer in einem Array sammeln + $allSteps = []; + foreach ($samePriorityUsers as $user) { + foreach ($user["PowerSteps"] as $step) { + if($step<=0){ + $allSteps[] = [ + "user" => $user["InstanceID"], + "Leistung_Delta" => $user["Leistung_Delta"], + "step" => -1*$step, + ];} + } + } + + // Sortiere die Schritte nach Größe + usort($allSteps, function ($a, $b) { + return $a["step"] <=> $b["step"]; + }); + + + $remainingPower = $remainingPower *-1; + // Iteriere durch alle Schritte + foreach ($allSteps as $entry) { + $user = $entry["user"]; + $powerstep = $entry["step"]; + + // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist + if ($remainingPower >= $powerstep - $userEnergyProv[$user]) { // oder bedingung testen + // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer + $remainingPower -= $powerstep - $userEnergyProv[$user]; + $userEnergyProv[$user] = $powerstep; + } + + } + $remainingPower = $remainingPower *-1; + + + // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt + foreach ($userEnergyProv as $userInstanceID => $leistung) { + $minimalleitsung = min( + array_column( + array_filter($allSteps, function ($entry) use ( + $userInstanceID + ) { + return $entry["user"] == $userInstanceID; + }), + "step" + ) + ); + + // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen + $schreibleistung = max($leistung, $minimalleitsung)*-1; + + + + // Methode SetAktuelle_Leistung für jeden Verbraucher mit der entsprechenden Energie aufrufen + if (IPS_InstanceExists($userInstanceID)) { + IPS_RequestAction($userInstanceID,"SetAktuelle_Leistung",$schreibleistung); + IPS_LogMessage("Manager", "aufgerufen setleistung else ".$schreibleistung); + + } } } - // Sortiere die Schritte nach Größe - usort($allSteps, function ($a, $b) { - return $a["step"] <=> $b["step"]; - }); - - // Iteriere durch alle Schritte - foreach ($allSteps as $entry) { - $user = $entry["user"]; - $powerstep = $entry["step"]; - - // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist - if ($remainingPower >= $powerstep - $userEnergyProv[$user]) { - // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer - $remainingPower -= $powerstep - $userEnergyProv[$user]; - $userEnergyProv[$user] = $powerstep; - } - - } - - // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt - foreach ($userEnergyProv as $userInstanceID => $leistung) { - $minimalleitsung = min( - array_column( - array_filter($allSteps, function ($entry) use ( - $userInstanceID - ) { - return $entry["user"] == $userInstanceID; - }), - "step" - ) - ); - - // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen - $leistung = max($leistung, $minimalleitsung); - - // Methode SetAktuelle_Leistung für jeden Verbraucher mit der entsprechenden Energie aufrufen - if (IPS_InstanceExists($userInstanceID)) { - IPS_RequestAction($userInstanceID,"SetAktuelle_Leistung",$leistung); - IPS_LogMessage("Manager", "aufgerufen setleistung normal"); - - } - } } @@ -260,5 +374,72 @@ class Manager extends IPSModule } + + public function DistributeEnergy_Extern() + { + // Systemvariablen abrufen + $Netzbezug = GetValue($this->ReadPropertyInteger("Netzbezug")); + + + $Verbraucher_Liste = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); + $filteredVerbraucher = []; + // Fülle das Array mit allen entsprechenden Werten der Verbraucher ab + foreach ($Verbraucher_Liste as $user) { + + + // Werte direkt von der Verbraucher-Instanz abrufen + $Aktuelle_Leistung = GetValue(IPS_GetObjectIDByIdent("Aktuelle_Leistung", $user["Verbraucher"])); + $Bezogene_Energie = GetValue(IPS_GetObjectIDByIdent("Bezogene_Energie", $user["Verbraucher"])); + $PV_Prio = GetValue(IPS_GetObjectIDByIdent("PV_Prio", $user["Verbraucher"])); + $Sperre_Prio = GetValue(IPS_GetObjectIDByIdent("Sperre_Prio", $user["Verbraucher"])); + $idle = GetValue(IPS_GetObjectIDByIdent("Idle", $user["Verbraucher"])); + $powerStepsJson = GetValue(IPS_GetObjectIDByIdent("PowerSteps", $user["Verbraucher"])); + $delta = GetValue(IPS_GetObjectIDByIdent("Leistung_Delta", $user["Verbraucher"])); + $powerSteps = json_decode($powerStepsJson, true); + + // Verbraucher-Daten zum gefilterten Array hinzufügen + $filteredVerbraucher[] = [ + "Verbraucher" => $user["Verbraucher"], + "InstanceID" => $user["Verbraucher"], + "Aktuelle_Leistung" => $Aktuelle_Leistung, + "Bezogene_Energie" => $Bezogene_Energie, + "PV_Prio" => $PV_Prio, + "Sperre_Prio" => $Sperre_Prio, + "Idle" => $idle, + "PowerSteps" => $powerSteps, + "Leistung_Delta" => $delta, + "ParentManager" => $this->ReadPropertyInteger("ManagerID") + + ]; + + } + + + $sendarray = []; + + $sendarray = [ + "Users" => $filteredVerbraucher, + "Netzbezug" => $Netzbezug, + "Timestamp" => time() + + ]; + + RequestAction($this->ReadPropertyInteger("DatenHoch"), json_encode($sendarray)); + + $answerArray = json_decode(GetValue($this->ReadPropertyInteger("DatenZuruck")), true); + + foreach($answerArray["User"] as $user){ + IPS_RequestAction($user["InstanceID"],"GetCurrentData", $answerArray["Is_Peak_Shaving"]); + + IPS_RequestAction($user["InstanceID"],"SetAktuelle_Leistung",$user["Set_Leistung"]); + + + } + + + + + } + } ?> diff --git a/Verbraucher_1_Stufig/form.json b/Verbraucher_1_Stufig/form.json index 8b4b348..9f97652 100644 --- a/Verbraucher_1_Stufig/form.json +++ b/Verbraucher_1_Stufig/form.json @@ -8,9 +8,15 @@ { "type": "NumberSpinner", "name": "IdleCounterMax", - "caption": "Zyklen zwischen zwei Leisutungsänderungen", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", "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": "Mindesttlaufzeit", diff --git a/Verbraucher_1_Stufig/module.php b/Verbraucher_1_Stufig/module.php index e4313cc..f9fad90 100644 --- a/Verbraucher_1_Stufig/module.php +++ b/Verbraucher_1_Stufig/module.php @@ -12,6 +12,7 @@ class Verbraucher_1_Stufig extends IPSModule $this->RegisterPropertyInteger("Mindesttlaufzeit", 4); // Standardwert für Volllast $this->RegisterPropertyInteger("Zeit_Zwischen_Zustandswechseln", 1); $this->RegisterPropertyInteger("Schaltkontakt1", 0); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval // Verbraucherspezifische Variabeln $this->RegisterVariableBoolean("IstNacht", "IstNacht", "", 0); @@ -31,6 +32,7 @@ class Verbraucher_1_Stufig extends IPSModule $this->RegisterVariableString("PowerSteps", "PowerSteps"); $this->RegisterVariableInteger("Power", "Power"); $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); // Hilfsvariabeln für Idle zustand $this->RegisterPropertyInteger("IdleCounterMax", 2); @@ -40,13 +42,15 @@ class Verbraucher_1_Stufig extends IPSModule // Initialisiere Idle $this->SetValue("Idle", true); - $this->RegisterTimer("Timer_Do_UserCalc",5000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + $this->RegisterTimer("Timer_Do_UserCalc_Verb",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); } public function ApplyChanges() { parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_Verb",$this->ReadPropertyInteger("Interval")*1000); + } public function RequestAction($Ident, $Value) @@ -77,6 +81,7 @@ class Verbraucher_1_Stufig extends IPSModule + // Methode zum Setzen der PowerSteps und Timer starten public function SetTimerOn() { @@ -117,6 +122,8 @@ class Verbraucher_1_Stufig extends IPSModule $this->SetTimerOn(); } $this->SetValue("Aktuelle_Leistung", $power); + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + $boilerLeistung = $this->ReadPropertyInteger("BoilerLeistung"); $schaltkontaktID = $this->ReadPropertyInteger("Schaltkontakt1"); diff --git a/Verbraucher_Sperrbar/README.md b/Verbraucher_Sperrbar/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Verbraucher_Sperrbar/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/Verbraucher_Sperrbar/form.json b/Verbraucher_Sperrbar/form.json new file mode 100644 index 0000000..8e4ec62 --- /dev/null +++ b/Verbraucher_Sperrbar/form.json @@ -0,0 +1,52 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Einstellungen für einstufigen Verbruacher Ein-Aus" + }, + + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", + "suffix": " Zyklen" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte ", + "suffix": "Sekunden" + }, + { + "type": "NumberSpinner", + "name": "Mindestsperrleistung", + "caption": "Minimaler Leistungswert um eine Sperre zu starten", + "suffix": "Watt" + }, + { + "type": "NumberSpinner", + "name": "MaxSperrZeit", + "caption": "Maximale Sperrzeit Verbraucher pro Tag", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Zeit_Zwischen_Zustandswechseln", + "caption": "Mindestlaufzeit des Verbrauchers bei Lastschaltung", + "suffix": "" + }, + { + "type": "SelectVariable", + "name": "Leistung", + "caption": "Variable mit aktueller Leistung des Verbrauchers", + "suffix": "" + }, + { + "type": "SelectVariable", + "name": "Schaltkontakt1", + "caption": "Zu schaltenden Kontakt für Sperre", + "test": true + } + + ] +} diff --git a/Verbraucher_Sperrbar/module.json b/Verbraucher_Sperrbar/module.json new file mode 100644 index 0000000..12e41fa --- /dev/null +++ b/Verbraucher_Sperrbar/module.json @@ -0,0 +1,12 @@ +{ + "id": "{0A15319E-AC03-0E5A-33B4-A46BB9330B17}", + "name": "Verbraucher_Sperrbar", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Verbraucher_Sperrbar/module.php b/Verbraucher_Sperrbar/module.php new file mode 100644 index 0000000..2e67c40 --- /dev/null +++ b/Verbraucher_Sperrbar/module.php @@ -0,0 +1,220 @@ +RegisterPropertyInteger("Leistung", 0); // Standardwert für Volllast + $this->RegisterPropertyInteger("MaxSperrZeit", 4); + $this->RegisterPropertyInteger("Zeit_Zwischen_Zustandswechseln", 1); + $this->RegisterPropertyInteger("Schaltkontakt1", 0); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + $this->RegisterPropertyInteger("Mindestsperrleistung", 100); + + + // Verbraucherspezifische Variabeln + $this->RegisterVariableInteger("DailyOnTime", "DailyOnTime", "", 0); + $this->RegisterVariableBoolean("IsTimerActive", "IsTimerActive", "", 0); + $this->RegisterVariableBoolean("IstNacht", "IstNacht", "", 0); + $this->RegisterVariableInteger("Letzte_Sperrleistung", "Letzte_Sperrleistung", "", 0); + + + // Verbraucherspezifischer Timer + $this->SetValue("IsTimerActive", false); + $this->RegisterTimer("ZustandswechselTimer",0,"IPS_RequestAction(" .$this->InstanceID .', "ResetTimer", "");'); + + // 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"); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $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_Verb",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_Verb",$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 "ResetTimer": + $this->ResetTimer(); + 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 der PowerSteps und Timer starten + public function SetTimerOn() + { + // Timer setzen, der nach "Zeit_Zwischen_Zustandswechseln" abläuft + $zeitZwischenZustandswechseln = $this->ReadPropertyInteger("Zeit_Zwischen_Zustandswechseln"); + + if($zeitZwischenZustandswechseln>0){ + $this->SetTimerInterval("ZustandswechselTimer", $zeitZwischenZustandswechseln * 60000); // Timer in Millisekunden + // Timer-Status auf true setzen + $this->SetValue("IsTimerActive", true); + }else{ + $this->SetValue("IsTimerActive", false); + + } + } + + // Methode zum Zurücksetzen von PowerSteps nach Ablauf des Timers + public function ResetTimer() + { + // Timer stoppen + $this->SetTimerInterval("ZustandswechselTimer", 0); + + // Timer-Status auf false setzen + $this->SetValue("IsTimerActive", false); + } + + // Methode zum Setzen des aktuellen Stromverbrauchs + public function SetAktuelle_Leistung(float $power) + { + // Hier eine Leistungsänderung detektieren für Idle und interne Mindestlaufzeiten + $this->CheckIdle($power); + if ($this->GetValue("Aktuelle_Leistung") != $power) { + $this->SetTimerOn(); + } + $this->SetValue("Aktuelle_Leistung", $power); + + // Verbrauchte Energie berechnen + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + + $Leistung = GetValue($this->ReadPropertyInteger("Leistung")); + $schaltkontaktID = $this->ReadPropertyInteger("Schaltkontakt1"); + + + if ($this->GetValue("Is_Peak_Shaving") == false) { + $schaltkontaktStatus = false; + } elseif($power==0 && ((GetValue($schaltkontaktID)==true)||($Leistung>=$this->ReadPropertyInteger("Mindestsperrleistung")))){ + $schaltkontaktStatus = true; + }else{ + $schaltkontaktStatus = false; + } + + // Schaltkontaktstatus ändern + SetValue($this->ReadPropertyInteger("Schaltkontakt1"), $schaltkontaktStatus); + + if ($schaltkontaktStatus==true) { + $this->SetValue("DailyOnTime", $this->GetValue("DailyOnTime") + 1); + } + } + + // Methode zum Abrufen der aktuellen Daten + public function GetCurrentData(bool $Peak) + { + $IstNacht = $this->GetValue("IstNacht"); + $NeuesIstNacht = $this->ist_nachts(); + + if ($IstNacht == false && $NeuesIstNacht == true) { + $this->SetValue("DailyOnTime", 0); + } + + $this->SetValue("IstNacht", $NeuesIstNacht); + + if(GetValue($this->ReadPropertyInteger("Leistung"))>=$this->ReadPropertyInteger("Mindestsperrleistung")){ + $this->SetValue("Letzte_Sperrleistung", GetValue($this->ReadPropertyInteger("Leistung"))) ; + } + + // Überprüfen, ob der Timer aktiv ist + if ($this->GetValue("IsTimerActive")) { + // Timer ist aktiv, PowerSteps setzen + $this->SetValue("PowerSteps", json_encode([$this->GetValue("Aktuelle_Leistung")])); + return; + } + + $DailyOnTime = $this->GetValue("DailyOnTime"); + $maxlaufzeit = $this->ReadPropertyInteger("MaxSperrZeit") * 60 * 60 / $this->ReadPropertyInteger("Interval"); + + if($Peak==false){ + $this->SetValue("PowerSteps",json_encode([0])); + } // Wenn Maxlaufzeit nicht erreicht ist + elseif($DailyOnTime < $maxlaufzeit) { + if((GetValue($this->ReadPropertyInteger("Leistung"))>=$this->ReadPropertyInteger("Mindestsperrleistung")) || GetValue($this->ReadPropertyInteger("Schaltkontakt1"))==true) { + $this->SetValue("PowerSteps", json_encode([0, (int)$this->GetValue("Letzte_Sperrleistung")])); + } else { + $this->SetValue("PowerSteps",json_encode([0])); + } + } + // Andernfalls + else { + $this->SetValue("PowerSteps",json_encode([$this->GetValue("Letzte_Sperrleistung")])); + } + + } + + public function CheckIdle($power) + { + $lastpower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); + if ($lastpower != $power) { + $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 ist_nachts() + { + date_default_timezone_set("Europe/Berlin"); // Setze hier deine Zeitzone + + $aktuelle_zeit = strtotime(date("H:i")); // Aktuelle Zeit in Stunden und Minuten umwandeln + $start_nacht = strtotime("24:00"); // Startzeit der Nacht (22 Uhr) + $ende_nacht = strtotime("07:00"); // Endzeit der Nacht (7 Uhr) + + if ($aktuelle_zeit >= $start_nacht || $aktuelle_zeit < $ende_nacht) { + return true; + } else { + return false; + } + } +} + +?> diff --git a/Verbraucher_extern/README.md b/Verbraucher_extern/README.md new file mode 100644 index 0000000..b059e3a --- /dev/null +++ b/Verbraucher_extern/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/Verbraucher_extern/form.json b/Verbraucher_extern/form.json new file mode 100644 index 0000000..afd2264 --- /dev/null +++ b/Verbraucher_extern/form.json @@ -0,0 +1,76 @@ +{ + "elements": [ + { + "type": "Label", + "caption": "Einstellungen für einstufigen Verbruacher Ein-Aus" + }, + + { + "type": "NumberSpinner", + "name": "IdleCounterMax", + "caption": "Zyklen zwischen zwei Leistungsänderungen (Multipliziert sich mit Interval)", + "suffix": "" + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte Erst für spätere Versionen", + "suffix": "Sekunden" + }, + { + "type": "SelectVariable", + "name": "Is_Peak", + "caption": "Variable zur Signalisierung der Peakleistung", + "suffix": "" + }, + { + "type": "SelectVariable", + "name": "delta_power", + "caption": "Variable mit dem Leistungsunterschied", + "suffix": "" + }, + { + "type": "List", + "name": "Verbraucher_Liste", + "caption": "Verbraucher, die gemanagt werden sollen.", + "add": true, + "delete": true, + "sortable": true, + "columns": [ + { + "caption": "Anfragende Variable", + "name": "Read_Var", + "width": "auto", + "add": 0, + "edit": { + "type": "SelectVariable", + "filter": "Verbraucher" + } + }, + { + "caption": "Zu schreibende Variable", + "name": "Write_Var", + "width": "auto", + "add": 0, + "edit": { + "type": "SelectVariable", + "filter": "Verbraucher" + } + }, + { + "type": "NumberSpinner", + "name": "P_Nenn", + "width": "auto", + "add": 0, + "edit": { + "type": "NumberSpinner" + }, + "caption": "Nennleistung des Verbrauchers", + "test": true + } + + ] + } + + ] +} diff --git a/Verbraucher_extern/module.json b/Verbraucher_extern/module.json new file mode 100644 index 0000000..5861b98 --- /dev/null +++ b/Verbraucher_extern/module.json @@ -0,0 +1,12 @@ +{ + "id": "{E3D14937-80F8-5728-A3D7-991EA2DBC2D4}", + "name": "Verbraucher_extern", + "type": 3, + "vendor": "Belevo AG", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "GEF", + "url": "" +} \ No newline at end of file diff --git a/Verbraucher_extern/module.php b/Verbraucher_extern/module.php new file mode 100644 index 0000000..718597f --- /dev/null +++ b/Verbraucher_extern/module.php @@ -0,0 +1,173 @@ +RegisterPropertyString("Verbraucher_Liste", "[]"); + $this->RegisterPropertyInteger("Is_Peak", 0); + $this->RegisterPropertyInteger("delta_power", 0); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval + + // 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"); + $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $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_Verb",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_Verb",$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"); + } + } + + + private function berechneKombinationen(array $verbraucherListe){ + $kombinationen = []; + foreach ($verbraucherListe as $verbraucher) { + + if (GetValue($verbraucher['Read_Var']) == 1) { + $tempListe = []; + if(empty($kombinationen)){ + $kombinationen[] = $verbraucher['P_Nenn']; + }else{ + foreach ($kombinationen as $wert) { + $tempListe[] = $wert + $verbraucher['P_Nenn']; + } + $kombinationen = array_merge($kombinationen, $tempListe); + } + } + } + sort($kombinationen); + return array_values(array_unique($kombinationen)); + } + + + private function find($target, $values, $current, &$result) { + if ($target == 0) { + $result[] = $current; + return; + } + if ($target < 0) { + return; + } + for ($i = 0; $i < count($values); $i++) { + $newValues = array_slice($values, $i + 1); + $this->find($target - $values[$i], $newValues, array_merge($current, [$values[$i]]), $result); + } + } + + private function berechneInverseKombinationen() + { + $values = json_decode($this->GetValue("PowerSteps")); + $result = []; + + $this->find($this->GetValue("Power"), $values, [], $result); + + $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); + + + $firstCombination = $result[0]; + + foreach ($verbraucherListe as &$verbraucher) { + if (in_array($verbraucher['P_Nenn'], $firstCombination)) { + SetValue($verbraucher['Write_Var'], 1); + } else { + SetValue($verbraucher['Write_Var'], 0); + } + } + + return $result; + + } + + + public function SetAktuelle_Leistung(float $power) { + $this->CheckIdle($power); + $this->SetValue("Aktuelle_Leistung", $power); + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); + + $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); + + $this->berechneInverseKombinationen(); + $this->SetValue("Leistung_Delta", GetValue($this->ReadPropertyInteger("delta_power"))); + } + + public function GetCurrentData(bool $Peak) + { + $this->SetValue("Is_Peak_Shaving", $Peak); + SetValue($this->ReadPropertyInteger("Is_Peak"), $Peak); + + $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true); + $kombinationen = $this->berechneKombinationen($verbraucherListe); + $this->SetValue("PowerSteps", json_encode($kombinationen)); + } + + + + + public function CheckIdle($power) + { + $lastpower = GetValue($this->GetIDForIdent("Aktuelle_Leistung")); + if ($lastpower != $power) { + $this->SetValue("Idle", false); + $this->SetValue("IdleCounter",$this->ReadPropertyInteger("IdleCounterMax")); + } + $idleCounter = $this->GetValue("IdleCounter"); + if ($idleCounter > 0) { + $this->SetValue("Idle", false); + $this->SetValue("IdleCounter", $idleCounter - 1); + } else { + $this->SetValue("Idle", true); + } + } + + +} + +?> diff --git a/WP_Steuerung/form.json b/WP_Steuerung/form.json index a86a354..de137ee 100644 --- a/WP_Steuerung/form.json +++ b/WP_Steuerung/form.json @@ -65,6 +65,12 @@ "name": "WW_Temp", "caption": "Variable mit der Aktuellen Warmwassertemperatur", "test": true + }, + { + "type": "NumberSpinner", + "name": "Interval", + "caption": "Intervall Neuberechnung der Werte Erst für spätere Versionen, aktuell auf 5 lassen!", + "suffix": "Sekunden" } ] diff --git a/WP_Steuerung/module.php b/WP_Steuerung/module.php index 1983100..2907fa1 100644 --- a/WP_Steuerung/module.php +++ b/WP_Steuerung/module.php @@ -16,6 +16,7 @@ class WP_Steuerung extends IPSModule $this->RegisterPropertyBoolean("Schwellwert_Anwenden", false); $this->RegisterPropertyInteger("Schwellwert", 0); $this->RegisterPropertyInteger("WW_Temp", 1); + $this->RegisterPropertyInteger("Interval", 5); // Recheninterval // WP-Spezifische Variabeln $this->RegisterVariableBoolean("Sperrzeit", "Sperrzeit", "", false); @@ -32,10 +33,11 @@ class WP_Steuerung extends IPSModule $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->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0); $this->RegisterVariableString("PowerSteps", "PowerSteps"); $this->RegisterVariableInteger("Power", "Power"); $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving"); + $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0); // Hilfsvariabeln für Idle zustand $this->RegisterPropertyInteger("IdleCounterMax", 2); @@ -45,13 +47,15 @@ class WP_Steuerung extends IPSModule // Initialisiere Idle $this->SetValue("Idle", true); - $this->RegisterTimer("Timer_Do_UserCalc",5000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); + $this->RegisterTimer("Timer_Do_UserCalc_WP",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");'); } public function ApplyChanges() { parent::ApplyChanges(); + $this->SetTimerInterval("Timer_Do_UserCalc_WP",$this->ReadPropertyInteger("Interval")*1000); + } @@ -82,6 +86,7 @@ class WP_Steuerung extends IPSModule } + // Methode zum Setzen des aktuellen Stromverbrauchs public function SetAktuelle_Leistung(float $power) { @@ -259,6 +264,8 @@ class WP_Steuerung extends IPSModule $newCount = $this->GetValue("WP_Laufzeit_Zahler"); $this->SetValue("WP_Laufzeit_Zahler", $newCount + 1); } + + $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600)))); } // Methode zum Abrufen der aktuellen Daten diff --git a/library.json b/library.json index aba6bba..8670923 100644 --- a/library.json +++ b/library.json @@ -4,10 +4,9 @@ "author": "Daniel Haefliger", "url": "https://git.belevo.ch/dh/Symcon_Belevo_Energiemanagement", "compatibility": { - "version": "7.1" + "version": "8.0" }, - "version": "1.0011", - + "version": "2.000", "build": 0, "date": 0 } \ No newline at end of file