diff --git a/MQTTBatterySDL/README.md b/MQTTBatterySDL/README.md new file mode 100644 index 0000000..e3abe65 --- /dev/null +++ b/MQTTBatterySDL/README.md @@ -0,0 +1,67 @@ +# Manager_1 +Beschreibung des Moduls. + +### Inhaltsverzeichnis + +1. [Funktionsumfang](#1-funktionsumfang) +2. [Voraussetzungen](#2-voraussetzungen) +3. [Software-Installation](#3-software-installation) +4. [Einrichten der Instanzen in IP-Symcon](#4-einrichten-der-instanzen-in-ip-symcon) +5. [Statusvariablen und Profile](#5-statusvariablen-und-profile) +6. [WebFront](#6-webfront) +7. [PHP-Befehlsreferenz](#7-php-befehlsreferenz) + +### 1. Funktionsumfang + +* + +### 2. Voraussetzungen + +- IP-Symcon ab Version 7.1 + +### 3. Software-Installation + +* Über den Module Store das 'Manager_1'-Modul installieren. +* Alternativ über das Module Control folgende URL hinzufügen + +### 4. Einrichten der Instanzen in IP-Symcon + + Unter 'Instanz hinzufügen' kann das 'Manager_1'-Modul mithilfe des Schnellfilters gefunden werden. + - Weitere Informationen zum Hinzufügen von Instanzen in der [Dokumentation der Instanzen](https://www.symcon.de/service/dokumentation/konzepte/instanzen/#Instanz_hinzufügen) + +__Konfigurationsseite__: + +Name | Beschreibung +-------- | ------------------ + | + | + +### 5. Statusvariablen und Profile + +Die Statusvariablen/Kategorien werden automatisch angelegt. Das Löschen einzelner kann zu Fehlfunktionen führen. + +#### Statusvariablen + +Name | Typ | Beschreibung +------ | ------- | ------------ + | | + | | + +#### Profile + +Name | Typ +------ | ------- + | + | + +### 6. WebFront + +Die Funktionalität, die das Modul im WebFront bietet. + +### 7. PHP-Befehlsreferenz + +`boolean GEF_BeispielFunktion(integer $InstanzID);` +Erklärung der Funktion. + +Beispiel: +`GEF_BeispielFunktion(12345);` \ No newline at end of file diff --git a/MQTTBatterySDL/form.json b/MQTTBatterySDL/form.json new file mode 100644 index 0000000..e7d7bcf --- /dev/null +++ b/MQTTBatterySDL/form.json @@ -0,0 +1,59 @@ +{ + "elements": [ + { + "type": "ValidationTextBox", + "name": "TopicSuffix", + "caption": "Topic Suffix / x" + }, + { + "type": "SelectVariable", + "name": "ReqActionID", + "caption": "Ausgabe-Variable / RequestAction" + }, + { + "type": "SelectVariable", + "name": "SoCID", + "caption": "SoC Variable" + }, + { + "type": "SelectVariable", + "name": "PowerProductionID", + "caption": "Aktuelle Leistung Variable" + }, + { + "type": "NumberSpinner", + "name": "TargetSoC", + "caption": "Ziel-Ladestand %", + "minimum": 0, + "maximum": 100 + }, + { + "type": "NumberSpinner", + "name": "ChargePower", + "caption": "Ladeleistung in W", + "minimum": 0, + "maximum": 100000 + }, + { + "type": "NumberSpinner", + "name": "DischargePower", + "caption": "Entladeleistung in W", + "minimum": 0, + "maximum": 100000 + }, + { + "type": "NumberSpinner", + "name": "MaxPowerSetpoint", + "caption": "Max. Power Setpoint", + "minimum": 0, + "maximum": 100000 + } + ], + "actions": [ + { + "type": "Button", + "caption": "Batterie-Steuerung testen", + "onClick": "MBSDL_RunBatteryControl($id);" + } + ] +} \ No newline at end of file diff --git a/MQTTBatterySDL/module.json b/MQTTBatterySDL/module.json new file mode 100644 index 0000000..82621a9 --- /dev/null +++ b/MQTTBatterySDL/module.json @@ -0,0 +1,14 @@ +{ + "id": "{08D264C2-E2B9-56D0-F0E3-9C9A5DF50F09}", + "name": "MQTTBatterySDL", + "type": 3, + "vendor": "Belevo AG", + "aliases": [ + "MQTT Battery SDL" + ], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "MBSDL", + "url": "" +} \ No newline at end of file diff --git a/MQTTBatterySDL/module.php b/MQTTBatterySDL/module.php new file mode 100644 index 0000000..fd677db --- /dev/null +++ b/MQTTBatterySDL/module.php @@ -0,0 +1,334 @@ +RegisterPropertyString('TopicSuffix', ''); + + $this->RegisterPropertyInteger('ReqActionID', 0); + $this->RegisterPropertyInteger('SoCID', 0); + $this->RegisterPropertyInteger('PowerProductionID', 0); + + $this->RegisterPropertyInteger('TargetSoC', 50); + $this->RegisterPropertyInteger('ChargePower', 2500); + $this->RegisterPropertyInteger('DischargePower', 2500); + $this->RegisterPropertyInteger('MaxPowerSetpoint', 10000); + + // Variablen + $this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 10); + $this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 20); + + $this->RegisterVariableFloat('MinSoC', 'Min SoC', '', 30); + $this->RegisterVariableFloat('MaxSoC', 'Max SoC', '', 40); + + $this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 50); + $this->EnableAction('PowerSetpoint'); + + $this->RegisterVariableString('Strategy', 'Strategy', '', 60); + $this->EnableAction('Strategy'); + + $this->RegisterVariableString('LastReadResponse', 'Letzte Lese-Antwort', '', 70); + $this->RegisterVariableString('LastWriteResponse', 'Letzte Steuer-Antwort', '', 80); + } + + public function ApplyChanges() + { + parent::ApplyChanges(); + + $this->SetStatus(IS_ACTIVE); + } + + public function RequestAction($Ident, $Value) + { + switch ($Ident) { + + case 'PowerSetpoint': + + $max = $this->ReadPropertyInteger('MaxPowerSetpoint'); + + if ($Value > $max) { + $Value = $max; + } + + if ($Value < ($max * -1)) { + $Value = $max * -1; + } + + SetValue($this->GetIDForIdent('PowerSetpoint'), $Value); + + $this->RunBatteryControl(); + + break; + + case 'Strategy': + + SetValueString( + $this->GetIDForIdent('Strategy'), + (string)$Value + ); + + $this->RunBatteryControl(); + + break; + } + } + + public function RunBatteryControl() + { + $reqActionID = $this->ReadPropertyInteger('ReqActionID'); + $socID = $this->ReadPropertyInteger('SoCID'); + $powerProductionID = $this->ReadPropertyInteger('PowerProductionID'); + + if (!$this->IsValidVariable($reqActionID)) { + $this->SendDebug( + 'RunBatteryControl', + 'Keine gültige Ausgabe-Variable gewählt', + 0 + ); + return; + } + + if (!$this->IsValidVariable($socID)) { + $this->SendDebug( + 'RunBatteryControl', + 'Keine gültige SoC Variable gewählt', + 0 + ); + return; + } + + $strategy = GetValueString( + $this->GetIDForIdent('Strategy') + ); + + $setpoint = GetValue( + $this->GetIDForIdent('PowerSetpoint') + ); + + $soc = GetValue($socID); + + $targetSoC = $this->ReadPropertyInteger('TargetSoC'); + + $chargePower = $this->ReadPropertyInteger('ChargePower'); + + $dischargePower = $this->ReadPropertyInteger('DischargePower'); + + // ------------------------------------------------- + // Strategy activate + // ------------------------------------------------- + + if ($strategy == 'activate') { + + RequestAction( + $reqActionID, + $setpoint * -1 + ); + + return; + } + + // ------------------------------------------------- + // Strategy stop + // ------------------------------------------------- + + if ($strategy == 'stop') { + + RequestAction($reqActionID, 0); + + if ($this->IsValidVariable($powerProductionID)) { + SetValue($powerProductionID, 0); + } + + return; + } + + // ------------------------------------------------- + // Ziel erreicht + // ------------------------------------------------- + + if ((int)$soc == $targetSoC) { + + RequestAction($reqActionID, 0); + + return; + } + + // ------------------------------------------------- + // Laden + // ------------------------------------------------- + + if ($soc < $targetSoC) { + + RequestAction( + $reqActionID, + abs($chargePower) + ); + + return; + } + + // ------------------------------------------------- + // Entladen + // ------------------------------------------------- + + if ($soc > $targetSoC) { + + RequestAction( + $reqActionID, + abs($dischargePower) * -1 + ); + + return; + } + } + + public function BuildReadResponse() + { + $socID = $this->ReadPropertyInteger('SoCID'); + + $powerProductionID = $this->ReadPropertyInteger( + 'PowerProductionID' + ); + + $data = [ + + 'power_production' => $this->IsValidVariable( + $powerProductionID + ) + ? GetValue($powerProductionID) + : 0, + + 'is_ready' => GetValue( + $this->GetIDForIdent('IsReady') + ), + + 'is_running' => GetValue( + $this->GetIDForIdent('IsRunning') + ), + + 'state_of_charge' => $this->IsValidVariable( + $socID + ) + ? GetValue($socID) + : 0, + + 'min_soc' => GetValue( + $this->GetIDForIdent('MinSoC') + ), + + 'max_soc' => GetValue( + $this->GetIDForIdent('MaxSoC') + ) + ]; + + $json = json_encode( + $data, + JSON_PRETTY_PRINT + ); + + SetValueString( + $this->GetIDForIdent('LastReadResponse'), + $json + ); + + return $json; + } + + public function HandleRemoteControlJSON(string $payload) + { + if ($payload == '') { + return; + } + + $data = json_decode($payload, true); + + if (!is_array($data)) { + return; + } + + // ------------------------------------------------- + // Power Setpoint + // ------------------------------------------------- + + if (isset($data['power_setpoint'])) { + + $max = $this->ReadPropertyInteger( + 'MaxPowerSetpoint' + ); + + $val = (int)$data['power_setpoint']; + + if ($val > $max) { + $val = $max; + } + + if ($val < ($max * -1)) { + $val = $max * -1; + } + + SetValue( + $this->GetIDForIdent('PowerSetpoint'), + $val + ); + } + + // ------------------------------------------------- + // Strategy + // ------------------------------------------------- + + if (isset($data['strategy'])) { + + SetValueString( + $this->GetIDForIdent('Strategy'), + (string)$data['strategy'] + ); + } + + // ------------------------------------------------- + // Batterie-Regelung ausführen + // ------------------------------------------------- + + $this->RunBatteryControl(); + + // ------------------------------------------------- + // Antwort bauen + // ------------------------------------------------- + + $output = [ + + 'power_setpoint' => GetValue( + $this->GetIDForIdent('PowerSetpoint') + ), + + 'strategy' => GetValueString( + $this->GetIDForIdent('Strategy') + ) + ]; + + $json = json_encode( + $output, + JSON_PRETTY_PRINT + ); + + SetValueString( + $this->GetIDForIdent('LastWriteResponse'), + $json + ); + + return $json; + } + + private function IsValidVariable(int $id) + { + return ( + $id > 0 + && IPS_ObjectExists($id) + && IPS_GetObject($id)['ObjectType'] == 2 + ); + } +} +?>