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