diff --git a/Shelly_Parser_MQTT/module.php b/Shelly_Parser_MQTT/module.php index 7d53075..8541c2e 100644 --- a/Shelly_Parser_MQTT/module.php +++ b/Shelly_Parser_MQTT/module.php @@ -10,19 +10,98 @@ class Shelly_Parser_MQTT extends IPSModule { parent::Create(); - // MQTT verbinden + // MQTT verbinden (nur Verknüpfung, noch kein Subscribe!) $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); - - // Alles abonnieren - $this->Subscribe('#'); } public function ApplyChanges() { parent::ApplyChanges(); + // Parent verbinden $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); - $this->Subscribe('#'); + + // Auf Statusänderungen der eigenen Instanz hören + $this->RegisterMessage($this->InstanceID, IM_CHANGESTATUS); + + // Auf Statusänderungen des Parents hören, falls vorhanden + $inst = IPS_GetInstance($this->InstanceID); + $parentID = $inst['ConnectionID'] ?? 0; + if ($parentID > 0 && IPS_InstanceExists($parentID)) { + $this->RegisterMessage($parentID, IM_CHANGESTATUS); + } + + // WICHTIG: + // KEIN Subscribe() hier aufrufen! + // Subscribe passiert erst, wenn Instanz/Parent wirklich aktiv ist (MessageSink). + } + + /* --------------------------------------------------------- + * MESSAGE SINK – REAKTION AUF STATUSÄNDERUNGEN + * ---------------------------------------------------------*/ + public function MessageSink($TimeStamp, $SenderID, $Message, $Data) + { + $this->SendDebug('MessageSink', 'Sender=' . $SenderID . ' Message=' . $Message . ' Data=' . print_r($Data, true), 0); + + if ($Message === IM_CHANGESTATUS) { + + // Eigene Instanz-Statusänderung + if ($SenderID === $this->InstanceID) { + $newStatus = $Data[0] ?? 0; + $this->Log('STATUS', 'Instance status changed to ' . $newStatus); + if ($newStatus === IS_ACTIVE) { + // Jetzt ist das Modul aktiv → Subscribe starten + $this->Log('STATUS', 'Instance is ACTIVE → performing MQTT subscribe'); + $this->Subscribe('#'); + } + return; + } + + // Parent-Statusänderung + $inst = IPS_GetInstance($this->InstanceID); + $parentID = $inst['ConnectionID'] ?? 0; + + if (($parentID > 0) && ($SenderID === $parentID)) { + $newStatus = $Data[0] ?? 0; + $this->Log('STATUS', 'Parent status changed to ' . $newStatus); + + if ($newStatus === IS_ACTIVE) { + // Parent wieder aktiv → neu subscriben + $this->Log('STATUS', 'Parent is ACTIVE → performing MQTT subscribe'); + $this->Subscribe('#'); + } + } + } + } + + /* --------------------------------------------------------- + * HILFSFUNKTIONEN FÜR PARENT-CHECK & SICHERES SENDEN + * ---------------------------------------------------------*/ + private function HasActiveParent(): bool + { + if (!IPS_InstanceExists($this->InstanceID)) { + return false; + } + + $inst = IPS_GetInstance($this->InstanceID); + $parentID = $inst['ConnectionID'] ?? 0; + if ($parentID <= 0 || !IPS_InstanceExists($parentID)) { + return false; + } + + $parentStatus = IPS_GetInstance($parentID)['InstanceStatus']; + return ($parentStatus === IS_ACTIVE); + } + + private function SafeSendToParent(array $packet): void + { + if (!$this->HasActiveParent()) { + $this->Log('MQTT', 'Cannot send to parent – parent not active or not available'); + return; + } + + // Fehler unterdrücken, falls doch mal etwas schiefgeht + @$this->SendDataToParent(json_encode($packet)); } /* --------------------------------------------------------- @@ -47,11 +126,11 @@ class Shelly_Parser_MQTT extends IPSModule 'Payload' => '' ]; - $this->SendDataToParent(json_encode([ + $this->SafeSendToParent([ 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}' - ] + $packet)); + ] + $packet); - $this->Log("Subscribe", $topic); + $this->Log('Subscribe', $topic); } /* --------------------------------------------------------- @@ -67,11 +146,11 @@ class Shelly_Parser_MQTT extends IPSModule 'Payload' => $payload ]; - $this->SendDataToParent(json_encode([ + $this->SafeSendToParent([ 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}' - ] + $packet)); + ] + $packet); - $this->Log("Publish", "$topic → $payload"); + $this->Log('Publish', "$topic → $payload"); } /* --------------------------------------------------------- @@ -109,7 +188,7 @@ class Shelly_Parser_MQTT extends IPSModule ] ]); - $this->Log("MQTT SEND", "$topic : $payload"); + $this->Log('MQTT SEND', "$topic : $payload"); // Senden $this->Publish($topic, $payload); @@ -123,19 +202,25 @@ class Shelly_Parser_MQTT extends IPSModule $this->Log('ReceiveData', $JSONString); $data = json_decode($JSONString, true); - if (!is_array($data)) return; + if (!is_array($data)) { + return; + } $topic = $data['Topic'] ?? ''; $payload = $data['Payload'] ?? ''; - if ($topic === '') return; + if ($topic === '') { + return; + } $this->Log('ReceiveTopic', "$topic → $payload"); $parts = explode('/', $topic); $deviceID = $parts[0] ?? ''; - if ($deviceID === '') return; + if ($deviceID === '') { + return; + } // Online-Status if (($parts[1] ?? '') === 'online') { @@ -158,7 +243,7 @@ class Shelly_Parser_MQTT extends IPSModule { $value = ($payload === 'true' || $payload === '1'); - $this->Log("Online", "$deviceID = $value"); + $this->Log('Online', "$deviceID = " . ($value ? 'true' : 'false')); $varID = $this->EnsureBooleanVariable($deviceID, $deviceID . '_online', 'Online'); SetValue($varID, $value); @@ -169,13 +254,17 @@ class Shelly_Parser_MQTT extends IPSModule * ---------------------------------------------------------*/ private function HandleRPC(string $deviceID, string $payload): void { - $this->Log("RPC", "$deviceID : $payload"); + $this->Log('RPC', "$deviceID : $payload"); $json = json_decode($payload, true); - if (!is_array($json)) return; + if (!is_array($json)) { + return; + } $src = $json['src'] ?? ''; - if (!str_starts_with($src, 'shelly')) return; + if (!str_starts_with($src, 'shelly')) { + return; + } // Typ $type = ShellyParser::ExtractType($src); @@ -188,15 +277,15 @@ class Shelly_Parser_MQTT extends IPSModule // Outputs foreach ($mapped['outputs'] as $index => $value) { - $ident = $deviceID . "_output_" . $index; - $varID = $this->EnsureBooleanVariable($deviceID, $ident, "Output $index"); + $ident = $deviceID . '_output_' . $index; + $varID = $this->EnsureBooleanVariable($deviceID, $ident, 'Output ' . $index); SetValue($varID, $value); } // Inputs foreach ($mapped['inputs'] as $index => $value) { - $ident = $deviceID . "_input_" . $index; - $varID = $this->EnsureBooleanVariable($deviceID, $ident, "Input $index"); + $ident = $deviceID . '_input_' . $index; + $varID = $this->EnsureBooleanVariable($deviceID, $ident, 'Input ' . $index); SetValue($varID, $value); } @@ -212,7 +301,7 @@ class Shelly_Parser_MQTT extends IPSModule * ---------------------------------------------------------*/ private function EnsureActionScript(): int { - $scriptName = "~ShellyMQTT_Action_" . $this->InstanceID; + $scriptName = '~ShellyMQTT_Action_' . $this->InstanceID; foreach (IPS_GetChildrenIDs($this->InstanceID) as $cid) { $obj = IPS_GetObject($cid); @@ -257,6 +346,7 @@ IPS_RequestAction($instance, $ident, $value); if ($o['ObjectIdent'] === $ident) { + // Outputs schaltbar machen if (str_contains($ident, '_output_')) { $actionScript = $this->EnsureActionScript(); IPS_SetVariableCustomAction($cid, $actionScript); @@ -291,8 +381,9 @@ IPS_RequestAction($instance, $ident, $value); $folderID = $this->GetDeviceFolder($deviceID); foreach (IPS_GetChildrenIDs($folderID) as $cid) { - if (IPS_GetObject($cid)['ObjectIdent'] === $ident) + if (IPS_GetObject($cid)['ObjectIdent'] === $ident) { return $cid; + } } $id = $this->RegisterVariableFloat($ident, $name); @@ -305,8 +396,9 @@ IPS_RequestAction($instance, $ident, $value); $folderID = $this->GetDeviceFolder($deviceID); foreach (IPS_GetChildrenIDs($folderID) as $cid) { - if (IPS_GetObject($cid)['ObjectIdent'] === $ident) + if (IPS_GetObject($cid)['ObjectIdent'] === $ident) { return $cid; + } } $id = $this->RegisterVariableString($ident, $name); @@ -322,8 +414,9 @@ IPS_RequestAction($instance, $ident, $value); $folderIdent = 'folder_' . $deviceID; foreach (IPS_GetChildrenIDs($this->InstanceID) as $cid) { - if (IPS_GetObject($cid)['ObjectIdent'] === $folderIdent) + if (IPS_GetObject($cid)['ObjectIdent'] === $folderIdent) { return $cid; + } } $folderID = IPS_CreateCategory(); @@ -350,4 +443,4 @@ IPS_RequestAction($instance, $ident, $value); } } -?> +?> \ No newline at end of file