no message

This commit is contained in:
2026-02-10 11:56:21 +01:00
parent 8f051aced5
commit 5aa44ad8a2
3 changed files with 275 additions and 106 deletions

View File

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

View File

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

View File

@@ -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([
"topic" => "remote-control-response/$device",
"payload" => json_encode($json)
])
);
}
}
// In Antwort-Variable schreiben
$this->SetValue('MQTT_Read_Out', $json);
}
}
?> ?>