Version 2.0.0 Beta

This commit is contained in:
2025-04-29 07:20:42 +02:00
parent 51de28b1c0
commit b7bb55b7fa
37 changed files with 3557 additions and 164 deletions

View File

@@ -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);`

View File

@@ -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"
}
}
]
}

View File

@@ -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": ""
}

View File

@@ -0,0 +1,337 @@
<?php
class Ansteuerung_Askoheat extends IPSModule
{
private $timerID;
public function Create()
{
parent::Create();
// Verbraucherspezifische Properties
$this->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;
}
}
}
?>

View File

@@ -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"
}
]
}

View File

@@ -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,31 +131,40 @@ 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"));
if ($power != $lastPower) {
@@ -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));
}
$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){
if ($Peak) {
if ($batterieladezustand <= $minimumentladen) {
$filtered_powersteps = array_filter($array_powersteps, function ($value) use ($maxleistung) {
return $value > $maxleistung; // Hochpass filtern
$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");
$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");
if($batterieladezustand>99){
IPS_LogMessage("Batterie", "im 1");
$filtered_powersteps = array_filter($array_powersteps, function ($value) {
return $value <= 0;
});
$filtered_powersteps_laden = array_values($filtered_powersteps);
$this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden));
}elseif($batterieladezustand>$aufdasnachladen && $hyst==false){
$this->SetValue("PowerSteps", json_encode($array_powersteps));
IPS_LogMessage("Batterie", "im 2");
}elseif($batterieladezustand>=$aufdasnachladen && $hyst==true){
$filtered_powersteps = array_filter($array_powersteps, function ($value) {
return $value >= 0;
});
$filtered_powersteps_laden = array_values($filtered_powersteps);
$this->SetValue("PowerSteps", json_encode($filtered_powersteps_laden));
}elseif($batterieladezustand<$aufdasnachladen){
$dummy_array[] = $this->ReadPropertyInteger("MaxNachladen");
$this->SetValue("PowerSteps", json_encode($dummy_array));
IPS_LogMessage("Batterie", "im 3");
}
}
}
private function CheckIdle($power)
{
$lastpower = GetValue("Aktuelle_Leistung");
@@ -215,5 +322,6 @@ public function RequestAction($Ident, $Value)
$this->SetValue("Idle", true);
}
}
}
?>

View File

@@ -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);`

View File

@@ -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
}
]
}

View File

@@ -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": ""
}

View File

@@ -0,0 +1,126 @@
<?php
class Belevo_Bezahl_Modul extends IPSModule
{
public function Create()
{
parent::Create();
$this->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 = "<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>Google Pay mit Stripe</title>
<!-- Stripe.js -->
<script src='https://js.stripe.com/v3/'></script>
<!-- Google Pay API -->
<script src='https://pay.google.com/gp/p/js/pay.js' async></script>
</head>
<body>
<h1>Google Pay Integration mit Stripe</h1>
<button id='google-pay-button'>Mit Google Pay bezahlen</button>
<script>
// Stripe initialisieren
const stripe = Stripe('pk_test_51Qkr79LJAcsNrpivA90lt7ULEzyXKR8l0pAqTBgfeuAIWlsLS4A3BdIBITc9UooFANbImvlJQ2F2jOZ0X5j8GI7Q00hNNasvQm'); // Ersetze mit deinem Stripe-Publishable-Key
const googlePayButton = document.getElementById('google-pay-button');
// Google Pay-Konfiguration
const googlePayConfig = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [
{
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
allowedCardNetworks: ['VISA', 'MASTERCARD'],
},
tokenizationSpecification: {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'stripe',
'stripe:version': '2020-08-27',
'stripe:publishableKey': 'pk_test_51Qkr79LJAcsNrpivA90lt7ULEzyXKR8l0pAqTBgfeuAIWlsLS4A3BdIBITc9UooFANbImvlJQ2F2jOZ0X5j8GI7Q00hNNasvQm', // Ersetze hier ebenfalls
},
},
},
],
merchantInfo: {
merchantId: 'TEST', // Für Testumgebungen
merchantName: 'Dein Unternehmen',
},
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: '100.00', // Betrag in CHF
currencyCode: 'CHF',
},
};
// Eventlistener für den Google Pay-Button
googlePayButton.addEventListener('click', async () => {
try {
const googlePayClient = new google.payments.api.PaymentsClient({ environment: 'TEST' });
// Prüfen, ob Google Pay verfügbar ist
const isReadyToPay = await googlePayClient.isReadyToPay(googlePayConfig);
if (!isReadyToPay.result) {
alert('Google Pay ist auf diesem Gerät nicht verfügbar.');
return;
}
// Google Pay PaymentData abrufen
const paymentData = await googlePayClient.loadPaymentData(googlePayConfig);
// Token aus dem PaymentData extrahieren
const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
// Token an das Backend senden
const response = await fetch('/path-to-your-backend.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: paymentToken }),
});
const result = await response.json();
if (result.clientSecret) {
// Zahlung mit Stripe abschließen
const stripeResult = await stripe.confirmCardPayment(result.clientSecret);
if (stripeResult.error) {
alert('Zahlung fehlgeschlagen: ' + stripeResult.error.message);
} else if (stripeResult.paymentIntent && stripeResult.paymentIntent.status === 'succeeded') {
alert('Zahlung erfolgreich abgeschlossen!');
}
} else {
alert('Ein Fehler ist im Backend aufgetreten.');
}
} catch (error) {
console.error('Fehler bei der Zahlung:', error);
alert('Ein Fehler ist aufgetreten: ' + error.message);
}
});
</script>
</body>
</html>";
SetValue($this->ReadPropertyInteger("HTMLBox"), $html);
}
}

View File

@@ -7,7 +7,7 @@
{
"type":"Select",
"name":"Boilertemperatur_glätten",
"caption":"Boilertemperatur glätten Ja oder Nein",
"caption":"Boilertemperatur glätten",
"options":[
{
"caption":"Ja",
@@ -25,23 +25,35 @@
"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"
}
}
]
}

View File

@@ -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")
);

67
HauptManager/README.md Normal file
View File

@@ -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);`

57
HauptManager/form.json Normal file
View File

@@ -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"
}
}
]
}
]
}

12
HauptManager/module.json Normal file
View File

@@ -0,0 +1,12 @@
{
"id": "{F1F645F9-7F78-2843-2728-5D1708B4F835}",
"name": "HauptManager",
"type": 3,
"vendor": "Belevo AG",
"aliases": [],
"parentRequirements": [],
"childRequirements": [],
"implemented": [],
"prefix": "GEF",
"url": ""
}

452
HauptManager/module.php Normal file
View File

@@ -0,0 +1,452 @@
<?php
class HauptManager extends IPSModule
{
public function Create()
{
parent::Create();
// Systemvariablen registrieren
$this->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);
}
}
}
?>

View File

@@ -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",

View File

@@ -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,9 +477,13 @@ 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 {

67
Ladestation_v2/README.md Normal file
View File

@@ -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);`

83
Ladestation_v2/form.json Normal file
View File

@@ -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"
}
]
}

View File

@@ -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": ""
}

621
Ladestation_v2/module.php Normal file
View File

@@ -0,0 +1,621 @@
<?php
class Ladestation_v2 extends IPSModule
{
public function Create()
{
parent::Create();
// Ladestationspezifische Properties
$this->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);
}
}
}
?>

View File

@@ -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",

View File

@@ -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", "");');
$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"]);
}
}
}
?>

View File

@@ -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",

View File

@@ -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");

View File

@@ -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);`

View File

@@ -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
}
]
}

View File

@@ -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": ""
}

View File

@@ -0,0 +1,220 @@
<?php
class Verbraucher_Sperrbar extends IPSModule
{
private $timerID;
public function Create()
{
parent::Create();
// Verbraucherspezifische Properties
$this->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;
}
}
}
?>

View File

@@ -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);`

View File

@@ -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
}
]
}
]
}

View File

@@ -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": ""
}

View File

@@ -0,0 +1,173 @@
<?php
class Verbraucher_extern extends IPSModule
{
private $timerID;
public function Create()
{
parent::Create();
// Verbraucherspezifische Properties
$this->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);
}
}
}
?>

View File

@@ -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"
}
]

View File

@@ -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);
@@ -36,6 +37,7 @@ class WP_Steuerung 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);
@@ -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

View File

@@ -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
}