diff --git a/Shelly_Parser_MQTT/libs/ShellyParser.php b/Shelly_Parser_MQTT/libs/ShellyParser.php index 074df79..f3039ee 100644 --- a/Shelly_Parser_MQTT/libs/ShellyParser.php +++ b/Shelly_Parser_MQTT/libs/ShellyParser.php @@ -33,34 +33,51 @@ class ShellyParser public static function MapParams(array $params): array { $mapped = [ - 'input' => null, - 'output' => null, + 'outputs' => [], // switch:x → output + 'inputs' => [], // input:x → state oder switch:x.input 'temperature' => null ]; - // GEN3 / GEN4 Geräte → switch:0, switch:1, ... foreach ($params as $key => $value) { + + // ----------------------------- + // OUTPUTS (switch:0 → output) + // ----------------------------- if (str_starts_with($key, 'switch:') && is_array($value)) { - // Output + $index = (int)substr($key, 7); + if (isset($value['output'])) { - $mapped['output'] = (bool)$value['output']; + $mapped['outputs'][$index] = (bool)$value['output']; } - // Input (für Pro / Gen4 Geräte) + // Gen4 / Pro Geräte haben input im switch if (isset($value['input'])) { - $mapped['input'] = (bool)$value['input']; + $mapped['inputs'][$index] = (bool)$value['input']; + } + } + + // ----------------------------- + // INPUTS (input:0 → state) + // ----------------------------- + if (str_starts_with($key, 'input:') && is_array($value)) { + + $index = (int)substr($key, 6); + + if (isset($value['state'])) { + $mapped['inputs'][$index] = (bool)$value['state']; } } } - // Temperatur suchen (beliebig tief) + // Temperatur-Suche (verschachtelt) self::ExtractRecursive($params, $mapped); - return array_filter($mapped, fn($v) => $v !== null); + return $mapped; } + private static function ExtractRecursive(array $data, array &$mapped): void { foreach ($data as $key => $value) { diff --git a/Shelly_Parser_MQTT/module.php b/Shelly_Parser_MQTT/module.php index 21ba266..e794d2d 100644 --- a/Shelly_Parser_MQTT/module.php +++ b/Shelly_Parser_MQTT/module.php @@ -73,42 +73,29 @@ class Shelly_Parser_MQTT extends IPSModule * ---------------------------------------------------------*/ public function RequestAction($Ident, $Value) { - // Lokale Variable aktualisieren - $varID = @IPS_GetObjectIDByIdent($Ident, $this->InstanceID); - if (!$varID) { - // Falls Variable im Ordner liegt: - foreach (IPS_GetChildrenIDs($this->InstanceID) as $folder) { - foreach (IPS_GetChildrenIDs($folder) as $cid) { - if (IPS_GetObject($cid)['ObjectIdent'] === $Ident) { - $varID = $cid; - break 2; - } - } - } - } + // Output? z.B. BE_1_3_14_output_0 + if (str_contains($Ident, '_output_')) { - if ($varID) { - SetValue($varID, $Value); - } + SetValue(IPS_GetObjectIDByIdent($Ident, $this->FindDeviceFolder($Ident)), $Value); - // Prüfen ob das ein Output ist - if (str_ends_with($Ident, '_output')) { - - $deviceID = substr($Ident, 0, -strlen('_output')); + // Device & Index extrahieren + $parts = explode('_output_', $Ident); + $deviceID = $parts[0]; + $index = (int)$parts[1]; $topic = $deviceID . '/rpc/Switch.Set'; $payload = json_encode([ - 'id' => 0, + 'id' => $index, 'on' => (bool)$Value ]); $this->Publish($topic, $payload); - - if ($this->ReadPropertyBoolean('Debug')) { - IPS_LogMessage("Shelly_Parser_MQTT", "Switching $deviceID -> $Value"); - } + return; } + + // andere Variablen (falls nötig) + throw new Exception("Unknown Ident $Ident"); } @@ -157,72 +144,77 @@ class Shelly_Parser_MQTT extends IPSModule /* --------------------------------------------------------- * ONLINE-STATUS * ---------------------------------------------------------*/ - private function HandleOnline(string $deviceID, string $payload): void - { - $value = ($payload === 'true' || $payload === '1'); + private function HandleOnline(string $deviceID, string $payload): void + { + $value = ($payload === 'true' || $payload === '1'); - $varID = $this->EnsureBooleanVariable($deviceID, $deviceID . '_online', 'Online'); - SetValue($varID, $value); - } + $varID = $this->EnsureBooleanVariable($deviceID, $deviceID . '_online', 'Online'); + SetValue($varID, $value); + } - /* --------------------------------------------------------- - * RPC-EVENTS - * ---------------------------------------------------------*/ - private function HandleRPC(string $deviceID, string $payload): void + /* --------------------------------------------------------- + * RPC-EVENTS + * ---------------------------------------------------------*/ + private function HandleRPC(string $deviceID, string $payload): void { $json = json_decode($payload, true); if (!is_array($json)) { return; } - // Shelly prüfen + // Gerätetyp setzen $src = $json['src'] ?? ''; - if (!is_string($src) || !str_starts_with($src, 'shelly')) { + if (!str_starts_with($src, 'shelly')) { return; } - // Typ extrahieren (z.B. "1minig3", "1g4", "plusplugs", ...) $type = ShellyParser::ExtractType($src); $typeID = $this->EnsureStringVariable($deviceID, $deviceID . '_type', 'Typ'); SetValue($typeID, $type); - // Parameter extrahieren + // Mappen $params = $json['params'] ?? []; - if (!is_array($params)) { - return; - } - $mapped = ShellyParser::MapParams($params); - // Output - if (array_key_exists('output', $mapped)) { - $outID = $this->EnsureBooleanVariable($deviceID, $deviceID . '_output', 'Output'); - IPS_SetVariableCustomAction($outID, $this->InstanceID); - SetValue($outID, (bool)$mapped['output']); + // ----------------------------------- + // DYNAMISCHE OUTPUTS + // ----------------------------------- + foreach ($mapped['outputs'] as $index => $value) { + + $ident = $deviceID . "_output_" . $index; + $name = "Output $index"; + + $varID = $this->EnsureBooleanVariable($deviceID, $ident, $name); + + // Aktionsskript aktivieren für Schalten + IPS_SetVariableCustomAction($varID, $this->InstanceID); + + SetValue($varID, $value); } + // ----------------------------------- + // DYNAMISCHE INPUTS + // ----------------------------------- + foreach ($mapped['inputs'] as $index => $value) { - // Input (GEN4 / PRO) - if (array_key_exists('input', $mapped)) { - $inID = $this->EnsureBooleanVariable( - $deviceID, - $deviceID . '_input', - 'Input' - ); - SetValue($inID, (bool)$mapped['input']); + $ident = $deviceID . "_input_" . $index; + $name = "Input $index"; + + $varID = $this->EnsureBooleanVariable($deviceID, $ident, $name); + + SetValue($varID, $value); } - // Temperatur (falls gefunden) - if (array_key_exists('temperature', $mapped)) { - $tempID = $this->EnsureFloatVariable( - $deviceID, - $deviceID . '_temperature', - 'Temperatur' - ); - SetValue($tempID, (float)$mapped['temperature']); + // ----------------------------------- + // TEMPERATUR + // ----------------------------------- + if ($mapped['temperature'] !== null) { + $tempID = $this->EnsureFloatVariable($deviceID, $deviceID . '_temperature', 'Temperatur'); + SetValue($tempID, $mapped['temperature']); } } + /* --------------------------------------------------------- * Helper für Variablen * ---------------------------------------------------------*/ @@ -303,5 +295,18 @@ class Shelly_Parser_MQTT extends IPSModule return $folderID; } + + private function FindDeviceFolder(string $Ident): int + { + foreach (IPS_GetChildrenIDs($this->InstanceID) as $folder) { + foreach (IPS_GetChildrenIDs($folder) as $cid) { + if (IPS_GetObject($cid)['ObjectIdent'] === $Ident) { + return $folder; + } + } + } + return 0; + } + } ?>