RegisterPropertyString('MQTTBaseTopic', 'Test VGT_Steuerung/Komm'); // Externe Hardware-Quellen (Lesen) $this->RegisterPropertyInteger('SourceSoC', 0); $this->RegisterPropertyInteger('SourcePowerProd', 0); $this->RegisterPropertyInteger('SourceIsReady', 0); $this->RegisterPropertyInteger('SourceIsRunning', 0); $this->RegisterPropertyInteger('SourceMinSoC', 0); $this->RegisterPropertyInteger('SourceMaxSoC', 0); // Hardware-Ziel (Schreiben) $this->RegisterPropertyInteger('TargetControlVar', 0); // --------------------------------------------------------------------- // 2. Variablen im Modul erstellen (zur Anzeige & Steuerung) // --------------------------------------------------------------------- // Diese Variablen spiegeln den aktuellen Zustand wider $this->RegisterVariableString('Strategy', 'Strategy', '', 10); $this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20); // Visualisierung der gelesenen Hardware-Werte (optional, aber gut zur Kontrolle) $this->RegisterVariableFloat('Visu_SoC', 'State of Charge', '~Intensity.100', 30); $this->RegisterVariableFloat('Visu_Production', 'Power Production', '~Watt', 40); $this->RegisterVariableBoolean('Visu_IsReady', 'Is Ready', '~Switch', 50); $this->EnableAction('Strategy'); $this->EnableAction('PowerSetpoint'); } public function ApplyChanges() { parent::ApplyChanges(); // --------------------------------------------------------------------- // 3. MQTT Filter setzen (Abonnement) // --------------------------------------------------------------------- // Wir sagen dem Parent (MQTT Splitter): "Schick mir alles, was auf mein Topic kommt" $topic = $this->ReadPropertyString('MQTTBaseTopic'); // Regex Filter für ReceiveData: Alles was mit dem Topic beginnt // Wir escapen Slash /, damit Regex funktioniert $cleanTopic = preg_quote($topic, '/'); // Filter: Topic muss matchen $this->SetReceiveDataFilter(".*\"Topic\":\"" . $cleanTopic . "/.*\".*"); // --------------------------------------------------------------------- // 4. Events registrieren (Hardware überwachen) // --------------------------------------------------------------------- // Wenn sich der externe SoC ändert, müssen wir die Logik ausführen $socID = $this->ReadPropertyInteger('SourceSoC'); if (IPS_VariableExists($socID)) { $this->RegisterMessage($socID, VM_UPDATE); } $this->RegisterMessage($this->GetIDForIdent('Strategy'), VM_UPDATE); $this->RegisterMessage($this->GetIDForIdent('PowerSetpoint'), VM_UPDATE); } // ------------------------------------------------------------------------- // MQTT EMPFANG (Ersatz für Events auf MQTT-Variablen) // ------------------------------------------------------------------------- public function ReceiveData($JSONString) { $data = json_decode($JSONString); // UTF-8 Payload decodieren $payload = utf8_decode($data->Payload); $topic = $data->Topic; $baseTopic = $this->ReadPropertyString('MQTTBaseTopic'); // Prüfen: Ist es der Writebefehl? if ($topic === $baseTopic . '/Writebefehl') { $this->ProcessWriteCommand($payload); } // Prüfen: Ist es der Lesebefehl? elseif ($topic === $baseTopic . '/Lesebefehl') { $this->ProcessReadCommand(); } } // ------------------------------------------------------------------------- // LOGIK: Interne Verarbeitung // ------------------------------------------------------------------------- // Hardware-Überwachung (MessageSink) bleibt gleich public function MessageSink($TimeStamp, $SenderID, $Message, $Data) { if ($Message == VM_UPDATE) { // Visualisierung aktualisieren (SoC im Modul anzeigen) $socID = $this->ReadPropertyInteger('SourceSoC'); if ($SenderID == $socID) { $this->SetValue('Visu_SoC', $Data[0]); } // Steuerungslogik immer ausführen wenn sich was ändert $this->ExecuteControlLogic(); } } // Manuelles Schalten im WebFront public function RequestAction($Ident, $Value) { switch ($Ident) { case 'Strategy': case 'PowerSetpoint': $this->SetValue($Ident, $Value); $this->ExecuteControlLogic(); break; } } // ------------------------------------------------------------------------- // CORE LOGIK // ------------------------------------------------------------------------- private function ProcessWriteCommand($jsonInput) { if ($jsonInput == "") return; $data = json_decode($jsonInput, true); if ($data === null) return; // 1. Variablen setzen if (isset($data['power_setpoint'])) { $val = $data['power_setpoint']; if ($val > 6000) $val = 6000; elseif ($val < -6000) $val = -6000; $this->SetValue('PowerSetpoint', $val); } if (isset($data['strategy'])) { $this->SetValue('Strategy', $data['strategy']); } // 2. Hardware sofort ansteuern $this->ExecuteControlLogic(); // 3. Antwort senden (an .../Writebefehl Antwort) $output = [ 'power_setpoint' => $this->GetValue('PowerSetpoint'), 'strategy' => $this->GetValue('Strategy') ]; $this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Writebefehl Antwort', json_encode($output)); } private function ProcessReadCommand() { // Hardware Werte lesen $data = $this->GatherHardwareData(); // Lokale Visu-Variablen updaten (damit man im Modul sieht was passiert) $this->SetValue('Visu_Production', $data['raw_prod']); // Hilfswert speichern $this->SetValue('Visu_IsReady', $data['is_ready']); // JSON für MQTT $mqttData = [ 'power_production' => -1 * $data['raw_prod'], // Vorzeichen wie im Original 'is_ready' => $data['is_ready'], 'is_running' => $data['is_running'], 'state_of_charge' => $data['soc'], 'min_soc' => $data['min_soc'], 'max_soc' => $data['max_soc'] ]; // Senden an .../Lesebefehl Antwort $this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Lesebefehl Antwort', json_encode($mqttData)); } private function ExecuteControlLogic() { $targetID = $this->ReadPropertyInteger('TargetControlVar'); if (!IPS_VariableExists($targetID)) return; $strategy = $this->GetValue('Strategy'); $setpoint = $this->GetValue('PowerSetpoint'); // SoC holen (Live) $socID = $this->ReadPropertyInteger('SourceSoC'); $soc = IPS_VariableExists($socID) ? GetValue($socID) : 0; if ($strategy == "activate") { RequestAction($targetID, $setpoint); } elseif ($strategy == "stop") { RequestAction($targetID, 0); } else { // Logic: soc == 50 -> 0 if ((int)$soc == 50) { RequestAction($targetID, 0); } elseif ($soc < 50) { RequestAction($targetID, 2500); } else { RequestAction($targetID, -2500); } } } // Hilfsfunktion: Hardware Daten sammeln private function GatherHardwareData() { $safeGet = function($propName) { $id = $this->ReadPropertyInteger($propName); return IPS_VariableExists($id) ? GetValue($id) : 0; }; return [ 'raw_prod' => $safeGet('SourcePowerProd'), 'is_ready' => (bool)$safeGet('SourceIsReady'), 'is_running' => (bool)$safeGet('SourceIsRunning'), 'soc' => $safeGet('SourceSoC'), 'min_soc' => $safeGet('SourceMinSoC'), 'max_soc' => $safeGet('SourceMaxSoC'), ]; } // Hilfsfunktion: MQTT Senden protected function SendMQTT($Topic, $Payload) { $Data['DataID'] = '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}'; // MQTT Client/Splitter GUID $Data['PacketType'] = 3; // Publish $Data['QualityOfService'] = 0; $Data['Retain'] = false; $Data['Topic'] = $Topic; $Data['Payload'] = $Payload; $JSON = json_encode($Data); // An Parent senden $this->SendDataToParent($JSON); } } ?>