InstanceID = $instanceID; $GLOBALS['ipsObjects'][$instanceID] = ['parent' => 0, 'ident' => '', 'name' => 'Modul']; $this->Create(); } public function Create() { } protected function RegisterPropertyBoolean(string $name, bool $value): void { $this->properties[$name] = $value; } protected function RegisterPropertyString(string $name, string $value): void { $this->properties[$name] = $value; } protected function ReadPropertyBoolean(string $name): bool { return (bool) $this->properties[$name]; } protected function ReadPropertyString(string $name): string { return (string) $this->properties[$name]; } protected function ConnectParent(string $moduleID): void { } protected function SendDataToParent(string $packet): void { $GLOBALS['sentPackets'][] = $packet; } protected function SendDebug(string $title, string $message, int $format): void { } public function setTestProperty(string $name, $value): void { $this->properties[$name] = $value; } } function IPS_GetObjectIDByIdent(string $ident, int $parentID) { foreach ($GLOBALS['ipsObjects'] as $id => $object) { if ($object['parent'] === $parentID && $object['ident'] === $ident) { return $id; } } return false; } function IPS_CreateCategory(): int { return ipsCreateObject('category'); } function IPS_CreateVariable(int $type): int { $id = ipsCreateObject('variable'); $GLOBALS['ipsVariables'][$id] = ['VariableType' => $type]; return $id; } function IPS_CreateScript(int $type): int { return ipsCreateObject('script'); } function ipsCreateObject(string $type): int { $id = ++$GLOBALS['ipsNextID']; $GLOBALS['ipsObjects'][$id] = [ 'parent' => 0, 'ident' => '', 'name' => '', 'type' => $type, 'profile' => '', ]; return $id; } function IPS_SetParent(int $id, int $parentID): void { $GLOBALS['ipsObjects'][$id]['parent'] = $parentID; } function IPS_SetIdent(int $id, string $ident): void { $GLOBALS['ipsObjects'][$id]['ident'] = $ident; } function IPS_SetName(int $id, string $name): void { $GLOBALS['ipsObjects'][$id]['name'] = $name; } function IPS_SetInfo(int $id, string $info): void { } function IPS_SetPosition(int $id, int $position): void { } function IPS_VariableProfileExists(string $profile): bool { return in_array($profile, ['~Switch', '~Temperature', '~Humidity'], true); } function IPS_SetVariableCustomProfile(int $id, string $profile): void { $GLOBALS['ipsObjects'][$id]['profile'] = $profile; } function IPS_SetVariableCustomAction(int $id, int $scriptID): void { } function IPS_SetHidden(int $id, bool $hidden): void { } function IPS_SetScriptContent(int $id, string $content): void { } function IPS_VariableExists(int $id): bool { return isset($GLOBALS['ipsVariables'][$id]); } function IPS_ScriptExists(int $id): bool { return ($GLOBALS['ipsObjects'][$id]['type'] ?? '') === 'script'; } function IPS_GetVariable(int $id): array { return $GLOBALS['ipsVariables'][$id]; } function SetValue(int $id, $value): void { $GLOBALS['ipsValues'][$id] = $value; } require_once __DIR__ . '/../ShellyModul/module.php'; } namespace Belevo\EnelixUtils\Tests { use PHPUnit\Framework\TestCase; final class ShellyModulTest extends TestCase { protected function setUp(): void { $GLOBALS['ipsNextID'] = 100; $GLOBALS['ipsObjects'] = []; $GLOBALS['ipsVariables'] = []; $GLOBALS['ipsValues'] = []; $GLOBALS['sentPackets'] = []; } public function testCustomNestedPrefixAndUnknownSourceAreAccepted(): void { $module = new \ShellyModul(1); $module->ReceiveData(json_encode([ 'PacketType' => 3, 'Topic' => 'gebaeude/wohnung/symcon/events/rpc', 'Payload' => json_encode([ 'src' => 'custom-client-name', 'method' => 'NotifyStatus', 'params' => [ 'switch:0' => ['output' => true, 'apower' => 12.5], 'cover:0' => ['current_pos' => 37], 'future:0' => ['new_value' => 99], ], ], JSON_THROW_ON_ERROR), ], JSON_THROW_ON_ERROR)); $names = array_column($GLOBALS['ipsObjects'], 'name'); self::assertContains('gebaeude/wohnung/symcon', $names); self::assertContains('Output 0', $names); self::assertContains('Switch 0 - Wirkleistung', $names); self::assertContains('Cover 0 - Position', $names); self::assertNotContains('Future 0 - New value', $names); self::assertContains(true, $GLOBALS['ipsValues']); self::assertContains(12.5, $GLOBALS['ipsValues']); } public function testComponentStatusUsesEnvironmentProfile(): void { $module = new \ShellyModul(1); $module->ReceiveData(json_encode([ 'PacketType' => 3, 'Topic' => 'symcon/status/humidity:0', 'Payload' => '{"id":0,"rh":54.3}', ], JSON_THROW_ON_ERROR)); $humidity = array_filter( $GLOBALS['ipsObjects'], static fn (array $object): bool => $object['name'] === 'Humidity 0 - Luftfeuchtigkeit' ); self::assertCount(1, $humidity); self::assertSame('~Humidity', array_values($humidity)[0]['profile']); self::assertContains(54.3, $GLOBALS['ipsValues']); } public function testOptionalTopicFilterCanRejectOtherPrefixes(): void { $module = new \ShellyModul(1); $module->setTestProperty('UseDeviceTopicFilter', true); $module->setTestProperty('DeviceTopicPrefix', 'shelly'); $module->ReceiveData(json_encode([ 'PacketType' => 3, 'Topic' => 'symcon/online', 'Payload' => 'true', ], JSON_THROW_ON_ERROR)); self::assertCount(1, $GLOBALS['ipsObjects']); self::assertSame([], $GLOBALS['ipsValues']); } } }