no message
This commit is contained in:
@@ -1,9 +1,64 @@
|
|||||||
{
|
{
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "ValidationTextBox",
|
"type": "Label",
|
||||||
"name": "DeviceID",
|
"caption": "Hardware Quellen (Eingänge)"
|
||||||
"caption": "Device ID"
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourceSoC",
|
||||||
|
"caption": "State of Charge (SoC)",
|
||||||
|
"validVariableTypes": [1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourcePowerProd",
|
||||||
|
"caption": "Power Production",
|
||||||
|
"validVariableTypes": [1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourceMinSoC",
|
||||||
|
"caption": "Min SoC",
|
||||||
|
"validVariableTypes": [1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourceMaxSoC",
|
||||||
|
"caption": "Max SoC",
|
||||||
|
"validVariableTypes": [1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Status Flags"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourceIsReady",
|
||||||
|
"caption": "Is Ready (Bool)",
|
||||||
|
"validVariableTypes": [0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "SourceIsRunning",
|
||||||
|
"caption": "Is Running (Bool)",
|
||||||
|
"validVariableTypes": [0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Steuerung (Ausgang)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SelectVariable",
|
||||||
|
"name": "TargetControlVar",
|
||||||
|
"caption": "Wechselrichter Sollwert (Ziel)",
|
||||||
|
"validVariableTypes": [1, 2]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Hinweis: Änderungen an Variablen werden sofort übernommen."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,12 @@
|
|||||||
"name": "VGT_Sub",
|
"name": "VGT_Sub",
|
||||||
"type": 3,
|
"type": 3,
|
||||||
"vendor": "Belevo",
|
"vendor": "Belevo",
|
||||||
"aliases": ["VGT MQTT Device"],
|
"aliases": [
|
||||||
"prefix": "VGT",
|
"VGT MQTT Device"
|
||||||
|
],
|
||||||
"parentRequirements": [],
|
"parentRequirements": [],
|
||||||
"childRequirements": [],
|
"childRequirements": [],
|
||||||
"implemented": [],
|
"implemented": [],
|
||||||
|
"prefix": "VGT",
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
}
|
}
|
||||||
@@ -6,128 +6,240 @@ class VGT_Sub extends IPSModule
|
|||||||
{
|
{
|
||||||
public function Create()
|
public function Create()
|
||||||
{
|
{
|
||||||
|
// Diese Zeile nicht löschen.
|
||||||
parent::Create();
|
parent::Create();
|
||||||
|
|
||||||
// DeviceID
|
// ---------------------------------------------------------------------
|
||||||
$this->RegisterPropertyString('DeviceID', '');
|
// 1. Eigenschaften registrieren (Links zu externer Hardware)
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
// Eingehende MQTT-Nachrichten
|
// Externe Quellen (zum Lesen)
|
||||||
$this->RegisterVariableString("InputJSON", "MQTT Input", "", 1);
|
$this->RegisterPropertyInteger('SourceSoC', 0); // State of Charge
|
||||||
$this->EnableAction("InputJSON");
|
$this->RegisterPropertyInteger('SourcePowerProd', 0); // Power Production
|
||||||
|
$this->RegisterPropertyInteger('SourceIsReady', 0); // Is Ready (Bool)
|
||||||
|
$this->RegisterPropertyInteger('SourceIsRunning', 0); // Is Running (Bool)
|
||||||
|
$this->RegisterPropertyInteger('SourceMinSoC', 0); // Min SoC
|
||||||
|
$this->RegisterPropertyInteger('SourceMaxSoC', 0); // Max SoC
|
||||||
|
|
||||||
// Ausgehende MQTT-Nachrichten
|
// Das Ziel (zum Schreiben/Steuern der Hardware)
|
||||||
$this->RegisterVariableString("OutputJSON", "MQTT Output", "", 2);
|
$this->RegisterPropertyInteger('TargetControlVar', 0); // Haupt-RequestAction Ziel
|
||||||
|
|
||||||
// Statusvariablen
|
// ---------------------------------------------------------------------
|
||||||
$this->RegisterVariableFloat('PowerProduction', 'Power Production', '', 10);
|
// 2. Interne Variablen erstellen
|
||||||
$this->EnableAction('PowerProduction');
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
$this->RegisterVariableFloat('StateOfCharge', 'State of Charge', '', 11);
|
// Die Steuerungsvariablen
|
||||||
$this->EnableAction('StateOfCharge');
|
$this->RegisterVariableString('Strategy', 'Strategy', '', 10);
|
||||||
|
|
||||||
$this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 12);
|
|
||||||
$this->EnableAction('IsRunning');
|
|
||||||
|
|
||||||
$this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 13);
|
|
||||||
$this->EnableAction('IsReady');
|
|
||||||
|
|
||||||
$this->RegisterVariableFloat('MinSoc', 'Min SoC', '', 14);
|
|
||||||
$this->EnableAction('MinSoc');
|
|
||||||
|
|
||||||
$this->RegisterVariableFloat('MaxSoc', 'Max SoC', '', 15);
|
|
||||||
$this->EnableAction('MaxSoc');
|
|
||||||
|
|
||||||
// Remote-Control
|
|
||||||
$this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20);
|
$this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20);
|
||||||
IPS_SetVariableCustomAction($this->GetIDForIdent('PowerSetpoint'), 0);
|
|
||||||
|
|
||||||
$this->RegisterVariableString('Strategy', 'Strategy', '', 21);
|
// Damit man sie im WebFront/Konsole ändern kann
|
||||||
IPS_SetVariableCustomAction($this->GetIDForIdent('Strategy'), 0);
|
$this->EnableAction('Strategy');
|
||||||
|
$this->EnableAction('PowerSetpoint');
|
||||||
|
|
||||||
|
// MQTT Schnittstelle (JSON Container)
|
||||||
|
// Input: Hier schreibt der MQTT Client rein
|
||||||
|
$this->RegisterVariableString('MQTT_Write_In', 'MQTT Write Command (Input)', '~TextBox', 30);
|
||||||
|
$this->RegisterVariableString('MQTT_Read_In', 'MQTT Read Command (Input)', '~TextBox', 50);
|
||||||
|
|
||||||
|
// Output: Hier schreibt das Modul die Antwort rein (MQTT liest das)
|
||||||
|
$this->RegisterVariableString('MQTT_Write_Out', 'MQTT Write Response (Output)', '~TextBox', 40);
|
||||||
|
$this->RegisterVariableString('MQTT_Read_Out', 'MQTT Read Response (Output)', '~TextBox', 60);
|
||||||
|
|
||||||
|
// Aktionen für Inputs aktivieren, damit Ereignisse darauf schreiben können
|
||||||
|
$this->EnableAction('MQTT_Write_In');
|
||||||
|
$this->EnableAction('MQTT_Read_In');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ApplyChanges()
|
||||||
|
{
|
||||||
|
// Diese Zeile nicht löschen
|
||||||
|
parent::ApplyChanges();
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// 3. Nachrichten registrieren (Events)
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Wir wollen sofort reagieren, wenn sich der externe SoC ändert
|
||||||
|
$socID = $this->ReadPropertyInteger('SourceSoC');
|
||||||
|
if (IPS_VariableExists($socID)) {
|
||||||
|
$this->RegisterMessage($socID, VM_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auch reagieren, wenn wir selbst Strategy oder Setpoint ändern
|
||||||
|
$this->RegisterMessage($this->GetIDForIdent('Strategy'), VM_UPDATE);
|
||||||
|
$this->RegisterMessage($this->GetIDForIdent('PowerSetpoint'), VM_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empfängt Events (z.B. Änderung des SoC oder der Strategie)
|
||||||
|
public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
|
||||||
|
{
|
||||||
|
if ($Message == VM_UPDATE) {
|
||||||
|
$socID = $this->ReadPropertyInteger('SourceSoC');
|
||||||
|
$stratID = $this->GetIDForIdent('Strategy');
|
||||||
|
$setID = $this->GetIDForIdent('PowerSetpoint');
|
||||||
|
|
||||||
|
// Wenn sich eine der steuerungsrelevanten Variablen ändert, Logik ausführen
|
||||||
|
if ($SenderID == $socID || $SenderID == $stratID || $SenderID == $setID) {
|
||||||
|
$this->ExecuteControlLogic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wird ausgeführt, wenn man Variable schaltet (WebFront, Skript oder MQTT-Event)
|
||||||
public function RequestAction($Ident, $Value)
|
public function RequestAction($Ident, $Value)
|
||||||
{
|
{
|
||||||
if ($Ident === "InputJSON") {
|
switch ($Ident) {
|
||||||
SetValueString($this->GetIDForIdent("InputJSON"), $Value);
|
case 'Strategy':
|
||||||
$this->ProcessIncoming($Value);
|
case 'PowerSetpoint':
|
||||||
return;
|
$this->SetValue($Ident, $Value);
|
||||||
|
// Sofort Logik neu berechnen
|
||||||
|
$this->ExecuteControlLogic();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MQTT_Write_In':
|
||||||
|
// Wert setzen (optional, zur Ansicht)
|
||||||
|
$this->SetValue($Ident, $Value);
|
||||||
|
// JSON verarbeiten
|
||||||
|
$this->ProcessWriteCommand($Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MQTT_Read_In':
|
||||||
|
// Wert setzen (optional)
|
||||||
|
$this->SetValue($Ident, $Value);
|
||||||
|
// Lesebefehl verarbeiten
|
||||||
|
$this->ProcessReadCommand();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid Ident");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetValue($this->GetIDForIdent($Ident), $Value);
|
// -------------------------------------------------------------------------
|
||||||
}
|
// LOGIK: Batterie Steuern (Skript 1)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
private function ProcessIncoming($jsonString)
|
private function ExecuteControlLogic()
|
||||||
{
|
{
|
||||||
$data = @json_decode($jsonString, true);
|
$targetID = $this->ReadPropertyInteger('TargetControlVar');
|
||||||
if (!is_array($data)) {
|
|
||||||
|
// Sicherheitscheck: Existiert das Ziel?
|
||||||
|
if (!IPS_VariableExists($targetID)) return;
|
||||||
|
|
||||||
|
// Interne Werte laden
|
||||||
|
$strategy = $this->GetValue('Strategy');
|
||||||
|
$setpoint = $this->GetValue('PowerSetpoint');
|
||||||
|
|
||||||
|
// SoC von extern holen
|
||||||
|
$socID = $this->ReadPropertyInteger('SourceSoC');
|
||||||
|
$soc = IPS_VariableExists($socID) ? GetValue($socID) : 0;
|
||||||
|
|
||||||
|
// Fall 1: STRATEGY = "activate"
|
||||||
|
if ($strategy == "activate") {
|
||||||
|
// Im Original: SetValue($idReqAction, ($setpoint));
|
||||||
|
RequestAction($targetID, $setpoint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($data['topic']) || !isset($data['payload'])) {
|
// Fall 2: STRATEGY = "stop"
|
||||||
|
if ($strategy == "stop") {
|
||||||
|
RequestAction($targetID, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$topic = $data['topic'];
|
// Fall 3: Alles andere
|
||||||
$payload = $data['payload'];
|
// Bei genau 50 -> auf 0 setzen
|
||||||
|
if ((int)$soc == 50) {
|
||||||
$device = $this->ReadPropertyString('DeviceID');
|
RequestAction($targetID, 0);
|
||||||
|
|
||||||
// Feedback Request
|
|
||||||
if ($topic === "feedback-request/$device") {
|
|
||||||
$this->SendFeedback($device);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remote Control Request
|
// Mode abhängig vom SoC
|
||||||
if ($topic === "remote-control-request/$device") {
|
if ($soc < 50) {
|
||||||
$this->ProcessRemoteControl($device, $payload);
|
// Laden (Positiver Betrag 2500)
|
||||||
return;
|
RequestAction($targetID, abs(2500));
|
||||||
|
} else {
|
||||||
|
// Entladen (Negativer Betrag -2500)
|
||||||
|
RequestAction($targetID, -2500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function SendFeedback($device)
|
// -------------------------------------------------------------------------
|
||||||
|
// LOGIK: Writebefehl + Antwort (Skript 2)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private function ProcessWriteCommand($jsonInput)
|
||||||
{
|
{
|
||||||
$response = [
|
if ($jsonInput == "") return;
|
||||||
"power_production" => GetValue($this->GetIDForIdent('PowerProduction')),
|
|
||||||
"state_of_charge" => GetValue($this->GetIDForIdent('StateOfCharge')),
|
$data = json_decode($jsonInput, true);
|
||||||
"is_running" => GetValue($this->GetIDForIdent('IsRunning')),
|
if ($data === null) return;
|
||||||
"is_ready" => GetValue($this->GetIDForIdent('IsReady')),
|
|
||||||
"min_soc" => GetValue($this->GetIDForIdent('MinSoc')),
|
// 1. power_setpoint verarbeiten
|
||||||
"max_soc" => GetValue($this->GetIDForIdent('MaxSoc'))
|
if (isset($data['power_setpoint'])) {
|
||||||
|
$val = $data['power_setpoint'];
|
||||||
|
|
||||||
|
// Begrenzen auf -6000 bis +6000
|
||||||
|
if ($val > 6000) {
|
||||||
|
$val = 6000;
|
||||||
|
} elseif ($val < -6000) {
|
||||||
|
$val = -6000;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->SetValue('PowerSetpoint', $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. strategy verarbeiten
|
||||||
|
if (isset($data['strategy'])) {
|
||||||
|
$this->SetValue('Strategy', $data['strategy']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Nach dem Schreiben Logik sofort ausführen, damit Hardware reagiert
|
||||||
|
$this->ExecuteControlLogic();
|
||||||
|
|
||||||
|
// 4. Antwort generieren (Werte wieder lesen)
|
||||||
|
$output = [
|
||||||
|
'power_setpoint' => $this->GetValue('PowerSetpoint'),
|
||||||
|
'strategy' => $this->GetValue('Strategy')
|
||||||
];
|
];
|
||||||
|
|
||||||
SetValueString(
|
$jsonOut = json_encode($output, JSON_PRETTY_PRINT);
|
||||||
$this->GetIDForIdent("OutputJSON"),
|
|
||||||
json_encode([
|
// In die Output-Variable schreiben (MQTT liest diese)
|
||||||
"topic" => "feedback-response/$device",
|
$this->SetValue('MQTT_Write_Out', $jsonOut);
|
||||||
"payload" => json_encode($response)
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ProcessRemoteControl($device, $payload)
|
// -------------------------------------------------------------------------
|
||||||
|
// LOGIK: Lesebefehl (Skript 3)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private function ProcessReadCommand()
|
||||||
{
|
{
|
||||||
$json = @json_decode($payload, true);
|
// IDs aus Properties laden
|
||||||
if (!is_array($json)) {
|
$idPowerProduction = $this->ReadPropertyInteger('SourcePowerProd');
|
||||||
return;
|
$idIsReady = $this->ReadPropertyInteger('SourceIsReady');
|
||||||
}
|
$idIsRunning = $this->ReadPropertyInteger('SourceIsRunning');
|
||||||
|
$idStateOfCharge = $this->ReadPropertyInteger('SourceSoC');
|
||||||
|
$idMinSOC = $this->ReadPropertyInteger('SourceMinSoC');
|
||||||
|
$idMaxSOC = $this->ReadPropertyInteger('SourceMaxSoC');
|
||||||
|
|
||||||
if (isset($json['power_setpoint'])) {
|
// Hilfsfunktion: Wert holen oder 0/false wenn ID fehlt
|
||||||
SetValue($this->GetIDForIdent('PowerSetpoint'), (int)$json['power_setpoint']);
|
$safeGet = function($id) {
|
||||||
}
|
return IPS_VariableExists($id) ? GetValue($id) : 0;
|
||||||
|
};
|
||||||
|
|
||||||
if (isset($json['strategy'])) {
|
// Daten zusammenstellen
|
||||||
SetValueString($this->GetIDForIdent('Strategy'), (string)$json['strategy']);
|
$data = [
|
||||||
}
|
// Achtung: Originalskript rechnete -1 * Wert
|
||||||
|
'power_production' => -1 * $safeGet($idPowerProduction),
|
||||||
|
'is_ready' => (bool)$safeGet($idIsReady),
|
||||||
|
'is_running' => (bool)$safeGet($idIsRunning),
|
||||||
|
'state_of_charge' => $safeGet($idStateOfCharge),
|
||||||
|
'min_soc' => $safeGet($idMinSOC),
|
||||||
|
'max_soc' => $safeGet($idMaxSOC)
|
||||||
|
];
|
||||||
|
|
||||||
SetValueString(
|
$json = json_encode($data, JSON_PRETTY_PRINT);
|
||||||
$this->GetIDForIdent("OutputJSON"),
|
|
||||||
json_encode([
|
// In Antwort-Variable schreiben
|
||||||
"topic" => "remote-control-response/$device",
|
$this->SetValue('MQTT_Read_Out', $json);
|
||||||
"payload" => json_encode($json)
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
Reference in New Issue
Block a user