RegisterPropertyString('MQTTBaseTopic', 'Test VGT_Steuerung/Komm'); // --- Optionale Gateway-Konfig (Nur für IO/Socket relevant) --- $this->RegisterPropertyString('MQTTUser', ''); $this->RegisterPropertyString('MQTTPassword', ''); $this->RegisterPropertyBoolean('UpdateGatewayConfig', false); // --- Hardware Quellen --- $this->RegisterPropertyInteger('SourceSoC', 0); $this->RegisterPropertyInteger('SourcePowerProd', 0); $this->RegisterPropertyInteger('SourceIsReady', 0); $this->RegisterPropertyInteger('SourceIsRunning', 0); $this->RegisterPropertyInteger('SourceMinSoC', 0); $this->RegisterPropertyInteger('SourceMaxSoC', 0); $this->RegisterPropertyInteger('TargetControlVar', 0); // --- Interne Variablen --- $this->RegisterVariableString('Strategy', 'Strategy', '', 10); $this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20); $this->EnableAction('Strategy'); $this->EnableAction('PowerSetpoint'); } public function ApplyChanges() { parent::ApplyChanges(); // 1. Filter setzen (Abonnieren) $topic = $this->ReadPropertyString('MQTTBaseTopic'); if($topic !== "") { $cleanTopic = preg_quote($topic, '/'); // Dieser Filter funktioniert für beide Splitter-Varianten $this->SetReceiveDataFilter(".*\"Topic\":\"" . $cleanTopic . "/.*\".*"); } // 2. Gateway Config (Optional) if ($this->ReadPropertyBoolean('UpdateGatewayConfig')) { $this->ConfigureGateway(); } // 3. Events registrieren $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); } public function ReceiveData($JSONString) { $data = json_decode($JSONString); // Payload Dekodierung $payload = utf8_decode($data->Payload); $topic = $data->Topic; $baseTopic = $this->ReadPropertyString('MQTTBaseTopic'); if ($topic === $baseTopic . '/Writebefehl') { $this->ProcessWriteCommand($payload); } elseif ($topic === $baseTopic . '/Lesebefehl') { $this->ProcessReadCommand(); } } private function ProcessWriteCommand($jsonInput) { $data = json_decode($jsonInput, true); if ($data === null) return; 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']); } $this->ExecuteControlLogic(); $output = ['power_setpoint' => $this->GetValue('PowerSetpoint'), 'strategy' => $this->GetValue('Strategy')]; $this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Writebefehl Antwort', json_encode($output)); } private function ProcessReadCommand() { $safeGet = function($prop) { $id = $this->ReadPropertyInteger($prop); return IPS_VariableExists($id) ? GetValue($id) : 0; }; $mqttData = [ 'power_production' => -1 * $safeGet('SourcePowerProd'), 'is_ready' => (bool)$safeGet('SourceIsReady'), 'is_running' => (bool)$safeGet('SourceIsRunning'), 'state_of_charge' => $safeGet('SourceSoC'), 'min_soc' => $safeGet('SourceMinSoC'), 'max_soc' => $safeGet('SourceMaxSoC') ]; $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'); $socID = $this->ReadPropertyInteger('SourceSoC'); $soc = IPS_VariableExists($socID) ? GetValue($socID) : 0; if ($strategy == "activate") { RequestAction($targetID, $setpoint); } elseif ($strategy == "stop") { RequestAction($targetID, 0); } else { if ((int)$soc == 50) RequestAction($targetID, 0); elseif ($soc < 50) RequestAction($targetID, 2500); else RequestAction($targetID, -2500); } } protected function SendMQTT($Topic, $Payload) { // Standard DataID für MQTT. Funktioniert meistens auch mit dem 77B-Modul. $Data['DataID'] = '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}'; $Data['PacketType'] = 3; $Data['QualityOfService'] = 0; $Data['Retain'] = false; $Data['Topic'] = $Topic; $Data['Payload'] = $Payload; $this->SendDataToParent(json_encode($Data)); } // Automatische Konfiguration des Parents (falls aktiviert) private function ConfigureGateway() { $instance = IPS_GetInstance($this->InstanceID); $parentId = $instance['ConnectionID']; // Das ist dein 77B Modul oder der native Splitter if ($parentId > 0) { // Wir versuchen, User/Pass auf dem Parent zu setzen (manche Module haben das direkt) // Oder wir suchen den IO darunter. $user = $this->ReadPropertyString('MQTTUser'); $pass = $this->ReadPropertyString('MQTTPassword'); // Check: Hat der Parent direkt Username/Password? (Schnittcher Modul hat das oft) if (@IPS_GetProperty($parentId, 'Username') !== false) { IPS_SetProperty($parentId, 'Username', $user); IPS_SetProperty($parentId, 'Password', $pass); IPS_ApplyChanges($parentId); return; } // Wenn nicht, suchen wir den IO darunter (Native Symcon Logik) $parentInfo = IPS_GetInstance($parentId); $ioID = $parentInfo['ConnectionID']; if ($ioID > 0) { if (@IPS_GetProperty($ioID, 'Username') !== false) { IPS_SetProperty($ioID, 'Username', $user); IPS_SetProperty($ioID, 'Password', $pass); IPS_ApplyChanges($ioID); } } } } public function RequestAction($Ident, $Value) { $this->SetValue($Ident, $Value); $this->ExecuteControlLogic(); } public function MessageSink($TimeStamp, $SenderID, $Message, $Data) { if ($Message == VM_UPDATE) $this->ExecuteControlLogic(); } } ?>