no message

This commit is contained in:
dh
2025-11-24 11:19:07 +01:00
parent cd7d8261eb
commit e9b21d982f
+54 -65
View File
@@ -12,7 +12,7 @@ class Shelly_Parser_MQTT extends IPSModule
{ {
parent::Create(); parent::Create();
// MQTT verbinden // MQTT-Server
$this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}');
} }
@@ -20,15 +20,23 @@ class Shelly_Parser_MQTT extends IPSModule
{ {
parent::ApplyChanges(); parent::ApplyChanges();
// Parent verbinden
$this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}');
// Niemals im ApplyChanges Publish/Subscribe senden! // Subscribe wird erst beim ersten Paket ausgeführt
$this->Subscribed = false; $this->Subscribed = false;
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* SICHER SENDEN * DEBUG SHORTCUT
* ---------------------------------------------------------*/
private function Log($title, $msg)
{
$this->SendDebug($title, $msg, 0);
IPS_LogMessage("ShellyMQTT/$title", $msg);
}
/* ---------------------------------------------------------
* Sicher Senden (Parent OK?)
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
private function SafeSend(array $packet) private function SafeSend(array $packet)
{ {
@@ -38,24 +46,15 @@ class Shelly_Parser_MQTT extends IPSModule
return; return;
} }
if (IPS_GetInstance($parent)['InstanceStatus'] !== 102) { // IS_ACTIVE if (IPS_GetInstance($parent)['InstanceStatus'] !== 102) {
return; return;
} }
@ $this->SendDataToParent(json_encode($packet)); @$this->SendDataToParent(json_encode($packet));
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* DEBUG * Subscribe once
* ---------------------------------------------------------*/
private function Log($title, $msg)
{
IPS_LogMessage("ShellyMQTT: $title", $msg);
$this->SendDebug($title, $msg, 0);
}
/* ---------------------------------------------------------
* SUBSCRIBE – nur wenn der Parent sicher aktiv ist!
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
private function EnsureSubscribe() private function EnsureSubscribe()
{ {
@@ -74,11 +73,11 @@ class Shelly_Parser_MQTT extends IPSModule
'Payload' => '' 'Payload' => ''
]); ]);
$this->Log("Subscribe", "#"); $this->Log("Subscribe", "Subscribed to #");
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* MQTT SEND * MQTT Publish
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
private function Publish(string $topic, string $payload) private function Publish(string $topic, string $payload)
{ {
@@ -95,28 +94,28 @@ class Shelly_Parser_MQTT extends IPSModule
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* REQUEST ACTION * REQUEST ACTION (Schalten Shelly Output)
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
public function RequestAction($Ident, $Value) public function RequestAction($Ident, $Value)
{ {
$this->Log('RequestAction', "$Ident → " . var_export($Value, true)); $this->Log("RequestAction", "$Ident → " . json_encode($Value));
// Nur Outputs sind schaltbar
if (!str_contains($Ident, '_output_')) { if (!str_contains($Ident, '_output_')) {
throw new Exception("Unknown Ident: $Ident"); throw new Exception("Unknown Ident: $Ident");
} }
// Lokale Variable aktualisieren // Lokale Variable setzen
$varID = $this->FindVariableByIdent($Ident); $varID = $this->FindVariableByIdent($Ident);
if ($varID > 0) { if ($varID > 0) {
SetValue($varID, $Value); SetValue($varID, $Value);
} }
// deviceID und Index extrahieren // deviceID / Index extrahieren
[$deviceID, $suffix] = explode('_output_', $Ident); [$deviceID, $suffix] = explode('_output_', $Ident);
$index = intval($suffix); $index = intval($suffix);
$topic = $deviceID . '/rpc'; $topic = "$deviceID/rpc";
$payload = json_encode([ $payload = json_encode([
'id' => 1, 'id' => 1,
'src' => 'ips', 'src' => 'ips',
@@ -135,31 +134,22 @@ class Shelly_Parser_MQTT extends IPSModule
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
public function ReceiveData($JSONString) public function ReceiveData($JSONString)
{ {
$this->Log('ReceiveData', $JSONString);
// Erst beim ersten Datenpaket subscriben
$this->EnsureSubscribe(); $this->EnsureSubscribe();
$data = json_decode($JSONString, true); $data = json_decode($JSONString, true);
if (!is_array($data)) {
return; if (!is_array($data)) return;
}
$topic = $data['Topic'] ?? ''; $topic = $data['Topic'] ?? '';
$payload = $data['Payload'] ?? ''; $payload = $data['Payload'] ?? '';
if ($topic === '') { if ($topic === '') return;
return;
}
$this->Log('ReceiveTopic', "$topic → $payload"); $this->Log("ReceiveTopic", "$topic → $payload");
$parts = explode('/', $topic); $parts = explode('/', $topic);
$deviceID = $parts[0] ?? ''; $deviceID = $parts[0] ?? '';
if ($deviceID === '') { if ($deviceID === '') return;
return;
}
// Online // Online
if (($parts[1] ?? '') === 'online') { if (($parts[1] ?? '') === 'online') {
@@ -167,7 +157,7 @@ class Shelly_Parser_MQTT extends IPSModule
return; return;
} }
// RPC // Events RPC
if (($parts[1] ?? '') === 'events' && ($parts[2] ?? '') === 'rpc') { if (($parts[1] ?? '') === 'events' && ($parts[2] ?? '') === 'rpc') {
$this->HandleRPC($deviceID, $payload); $this->HandleRPC($deviceID, $payload);
return; return;
@@ -180,83 +170,82 @@ class Shelly_Parser_MQTT extends IPSModule
private function HandleOnline(string $deviceID, string $payload) private function HandleOnline(string $deviceID, string $payload)
{ {
$value = ($payload === 'true' || $payload === '1'); $value = ($payload === 'true' || $payload === '1');
$vid = $this->EnsureBooleanVariable($deviceID, $deviceID . '_online', 'Online');
$varID = $this->EnsureBooleanVariable($deviceID, $deviceID . '_online', 'Online'); SetValue($vid, $value);
SetValue($varID, $value);
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* RPC * RPC Handler
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
private function HandleRPC(string $deviceID, string $payload) private function HandleRPC(string $deviceID, string $payload)
{ {
$json = json_decode($payload, true); $json = json_decode($payload, true);
if (!is_array($json)) { if (!is_array($json)) return;
return;
}
$src = $json['src'] ?? ''; $src = $json['src'] ?? '';
if (!str_starts_with($src, 'shelly')) { if (!str_starts_with($src, 'shelly')) return;
return;
}
// Typ // Typ
$type = ShellyParser::ExtractType($src); $type = ShellyParser::ExtractType($src);
$typeID = $this->EnsureStringVariable($deviceID, $deviceID . '_type', 'Typ'); $tid = $this->EnsureStringVariable($deviceID, $deviceID . '_type', 'Typ');
SetValue($typeID, $type); SetValue($tid, $type);
$params = $json['params'] ?? []; $params = $json['params'] ?? [];
$mapped = ShellyParser::MapParams($params); $mapped = ShellyParser::MapParams($params);
// Outputs // Outputs
foreach ($mapped['outputs'] as $i => $val) { foreach ($mapped['outputs'] as $i => $val) {
$vid = $this->EnsureBooleanVariable($deviceID, $deviceID . '_output_' . $i, 'Output ' . $i); $vid = $this->EnsureBooleanVariable($deviceID, "{$deviceID}_output_$i", "Output $i");
SetValue($vid, $val); SetValue($vid, $val);
} }
// Inputs // Inputs
foreach ($mapped['inputs'] as $i => $val) { foreach ($mapped['inputs'] as $i => $val) {
$vid = $this->EnsureBooleanVariable($deviceID, $deviceID . '_input_' . $i, 'Input ' . $i); $vid = $this->EnsureBooleanVariable($deviceID, "{$deviceID}_input_$i", "Input $i");
SetValue($vid, $val); SetValue($vid, $val);
} }
// Temperatur // Temperatur
if ($mapped['temperature'] !== null) { if ($mapped['temperature'] !== null) {
$tid = $this->EnsureFloatVariable($deviceID, $deviceID . '_temperature', 'Temperatur'); $f = $this->EnsureFloatVariable($deviceID, "{$deviceID}_temperature", "Temperatur");
SetValue($tid, $mapped['temperature']); SetValue($f, $mapped['temperature']);
} }
} }
/* --------------------------------------------------------- /* ---------------------------------------------------------
* VARIABLEN ETC. * VARIABLEN – MIT AUTOMATISCHER REPARATUR
* ---------------------------------------------------------*/ * ---------------------------------------------------------*/
private function EnsureBooleanVariable(string $deviceID, string $ident, string $name): int private function EnsureBooleanVariable(string $deviceID, string $ident, string $name): int
{ {
$folder = $this->GetDeviceFolder($deviceID); $folder = $this->GetDeviceFolder($deviceID);
$vid = 0; $vid = 0;
// Gibt es die Variable schon?
foreach (IPS_GetChildrenIDs($folder) as $cid) { foreach (IPS_GetChildrenIDs($folder) as $cid) {
$obj = IPS_GetObject($cid); $obj = IPS_GetObject($cid);
// Auto-Repair für alte Versionen ohne Ident
if ($obj['ObjectName'] === $name && $obj['ObjectIdent'] === '') {
IPS_SetIdent($cid, $ident);
$vid = $cid;
break;
}
if ($obj['ObjectIdent'] === $ident) { if ($obj['ObjectIdent'] === $ident) {
$vid = $cid; $vid = $cid;
break; break;
} }
} }
// Neu anlegen, falls nicht vorhanden
if ($vid === 0) { if ($vid === 0) {
$vid = IPS_CreateVariable(0); // 0 = Boolean $vid = IPS_CreateVariable(0);
IPS_SetName($vid, $name); IPS_SetName($vid, $name);
IPS_SetIdent($vid, $ident); IPS_SetIdent($vid, $ident);
IPS_SetParent($vid, $folder); IPS_SetParent($vid, $folder);
} }
// ---- HIER: nur für Outputs Action + Profil setzen ---- // OUTPUT → Switch-UI + Action
if (str_contains($ident, '_output_')) { if (str_contains($ident, '_output_')) {
// Schaltprofil
IPS_SetVariableCustomProfile($vid, '~Switch'); IPS_SetVariableCustomProfile($vid, '~Switch');
// Aktion geht direkt an dieses Modul (RequestAction)
IPS_SetVariableCustomAction($vid, $this->InstanceID); IPS_SetVariableCustomAction($vid, $this->InstanceID);
} }
@@ -311,7 +300,7 @@ class Shelly_Parser_MQTT extends IPSModule
return $fid; return $fid;
} }
private function FindVariableByIdent(string $Ident) private function FindVariableByIdent(string $Ident): int
{ {
foreach (IPS_GetChildrenIDs($this->InstanceID) as $folder) { foreach (IPS_GetChildrenIDs($this->InstanceID) as $folder) {
foreach (IPS_GetChildrenIDs($folder) as $cid) { foreach (IPS_GetChildrenIDs($folder) as $cid) {