createInstance( '{B7552FC9-87BC-49D0-8CCB-076BBB045BBE}', 'Easee Gateway fuer Ladestation', [ 'Active' => true, 'Testmodus' => true, ] ); $station = $test->createInstance( '{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}', 'Easee Ladestation', [ 'Betriebsmodus' => 0, 'Ladestationskennung' => 'EH123456', 'MaximalerLadestrom' => 16, 'Ladefreigabe' => true, 'Solarladen' => true, 'EinstellungenInVisu' => true, 'DiagnosevariablenAnzeigen' => true, ] ); IPS_ConnectInstance($station, $gateway); IPS_ApplyChanges($station); $nurSolar = $test->createInstance( '{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}', 'Easee nur Solarladen', [ 'Betriebsmodus' => 1, 'Ladestationskennung' => 'EH654321', 'MaximalerLadestrom' => 16, 'Ladefreigabe' => true, 'Solarladen' => false, 'EinstellungenInVisu' => true, 'DiagnosevariablenAnzeigen' => true, ] ); IPS_ConnectInstance($nurSolar, $gateway); IPS_ApplyChanges($nurSolar); $sendeBeobachtung = static function ( string $seriennummer, int $id, $value ) use ($gateway): void { IPS_RequestAction($gateway, 'TestObservation', json_encode([ 'serialNumber' => $seriennummer, 'id' => $id, 'value' => $value, ], JSON_THROW_ON_ERROR)); }; foreach (['EH123456', 'EH654321'] as $seriennummer) { $sendeBeobachtung($seriennummer, 47, 16.0); $sendeBeobachtung($seriennummer, 104, 32.0); $sendeBeobachtung($seriennummer, 109, 3); $sendeBeobachtung($seriennummer, 110, 30); $sendeBeobachtung($seriennummer, 120, 1.0); $sendeBeobachtung($seriennummer, 182, 2.1); $sendeBeobachtung($seriennummer, 183, 2.0); $sendeBeobachtung($seriennummer, 184, 2.2); } $test->runCase('Fahrzeug und drei Phasen folgen direkt den API-Ereignissen', static function ( TestContext $test ) use ($station): void { $test->assertSame( true, GetValue($test->objectByIdent('FahrzeugVerbunden', $station)) ); $test->assertSame( 3, GetValue($test->objectByIdent('Phasenzahl', $station)) ); $test->assertSame( 3, GetValue($test->objectByIdent('Fahrzeugstatus', $station)) ); $test->assertEquals( 2.2, (float) GetValue($test->objectByIdent('Ladestrom', $station)), 0.01 ); }); $test->runCase('Event erzeugt ohne Polling ein dreiphasiges Leistungsangebot', static function ( TestContext $test ) use ($station): void { IPS_RequestAction($station, 'Aktiv', true); $test->assertSame( '[0,4104,4788,5472,6156,6840,7524,8208,8892,9576,10260,10944]', (string) GetValue( $test->objectByIdent('LeistungsangebotDiagnose', $station) ) ); $test->assertTrue(str_contains( (string) GetValue( $test->objectByIdent('LetzterGeraetebefehl', $station) ), '"Ampere":0' )); }); $test->runCase('Wartezustand startet konservativ ohne aktive Phase', static function ( TestContext $test ) use ($sendeBeobachtung, $station): void { $sendeBeobachtung('EH123456', 42, true); $sendeBeobachtung('EH123456', 43, true); $sendeBeobachtung('EH123456', 96, 55); $sendeBeobachtung('EH123456', 102, true); $sendeBeobachtung('EH123456', 109, 2); $sendeBeobachtung('EH123456', 110, 0); IPS_RequestAction($station, 'Solarladen', false); $test->assertSame( 0, GetValue($test->objectByIdent('Phasenzahl', $station)) ); $test->assertInstanceStatus($station); $test->assertSame( '[3680]', (string) GetValue( $test->objectByIdent('LeistungsangebotDiagnose', $station) ) ); $test->assertTrue(str_contains( (string) GetValue( $test->objectByIdent('LetzterGeraetebefehl', $station) ), '"Ampere":16' )); $test->assertTrue(str_contains( (string) GetValue( $test->objectByIdent('LetzterStartbefehl', $station) ), '"Aktion":"StartCharging"' )); $test->assertSame( 55, GetValue($test->objectByIdent('GrundKeinLadestrom', $station)) ); $test->assertSame( true, GetValue($test->objectByIdent('AutorisierungErforderlich', $station)) ); IPS_RequestAction($station, 'Solarladen', true); $sendeBeobachtung('EH123456', 110, 30); $sendeBeobachtung('EH123456', 109, 3); }); $test->runCase('Nur-Solar-Variante laesst Solarladen nicht abschalten', static function ( TestContext $test ) use ($nurSolar): void { IPS_RequestAction($nurSolar, 'Solarladen', false); $test->assertSame( true, GetValue($test->objectByIdent('Solarladen', $nurSolar)) ); }); $test->runCase('Unbekannter API-Status sperrt die Regelung', static function ( TestContext $test ) use ($sendeBeobachtung, $station): void { $sendeBeobachtung('EH123456', 109, 99); $test->assertSame( false, GetValue($test->objectByIdent('FahrzeugVerbunden', $station)) ); $test->assertInstanceStatus($station, 203); $sendeBeobachtung('EH123456', 109, 3); $test->assertSame( true, GetValue($test->objectByIdent('FahrzeugVerbunden', $station)) ); $test->assertInstanceStatus($station); }); $test->runCase('Solarumschaltung wartet auf die neue Manager-Vorgabe', static function ( TestContext $test ) use ($station, $sendeBeobachtung): void { $managerId = $test->createInstance( '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}', 'Hilfsmanager Easee-Uebergang', [ 'AutomatischeSuche' => false, 'VerbraucherZuordnung' => json_encode([ ['InstanzID' => $station, 'Aktiv' => true], ], JSON_THROW_ON_ERROR), ] ); $sendeSollwert = static function (int $leistung) use ($managerId, $station): void { IPS_RequestAction($station, 'ManagerdatenEmpfangen', json_encode([ 'Kopf' => [ 'Version' => '4.0', 'AbsenderID' => $managerId, 'EmpfaengerID' => $station, 'Zeitpunkt' => time(), ], 'Betriebsart' => 'PV', 'Sollleistung_W' => $leistung, ], JSON_THROW_ON_ERROR)); }; $sendeSollwert(4104); $befehlVorUmschaltung = (string) GetValue( $test->objectByIdent('LetzterGeraetebefehl', $station) ); IPS_RequestAction($station, 'Solarladen', false); $test->assertSame( $befehlVorUmschaltung, (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $station)) ); $test->assertSame( 0, GetValue($test->objectByIdent('Sollleistung', $station)), 'Die verworfene Manager-Vorgabe darf nicht als aktuelle Sollleistung stehen bleiben.' ); $test->assertSame(false, GetValue($test->objectByIdent('SollwertGueltig', $station))); $sendeSollwert(10944); $test->assertTrue(str_contains( (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $station)), '"Ampere":16' )); IPS_RequestAction($station, 'Solarladen', true); $sendeSollwert(0); $test->assertSame(true, GetValue($test->objectByIdent('SollwertGueltig', $station))); $test->assertSame(0, GetValue($test->objectByIdent('Sollleistung', $station))); $sendeSollwert(10944); $sendeBeobachtung('EH123456', 109, 1); $test->assertSame('[0]', GetValue($test->objectByIdent('LeistungsangebotDiagnose', $station))); $test->assertSame(false, GetValue($test->objectByIdent('SollwertGueltig', $station))); $test->assertSame(0, GetValue($test->objectByIdent('Sollleistung', $station))); $test->assertTrue(str_contains( (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $station)), '"Ampere":0' )); $sendeBeobachtung('EH123456', 110, 30); $sendeBeobachtung('EH123456', 109, 3); $sendeSollwert(10944); IPS_RequestAction($station, 'VorgabeTimeout', 0); $test->assertSame(false, GetValue($test->objectByIdent('SollwertGueltig', $station))); $test->assertSame(0, GetValue($test->objectByIdent('Sollleistung', $station))); }); $test->runCase('SignalR-Abbruch erreicht die Ladestation', static function ( TestContext $test ) use ($gateway, $station): void { IPS_RequestAction( $gateway, 'TestSignalRFrame', json_encode(['type' => 7], JSON_THROW_ON_ERROR) ); $test->assertInstanceStatus($gateway, 203); $test->assertInstanceStatus($station, 202); $test->assertSame( false, GetValue($test->objectByIdent('GatewayVerbunden', $station)) ); IPS_RequestAction($gateway, 'TestSignalRFrame', '{}'); $test->assertInstanceStatus($gateway); $test->assertInstanceStatus($station); $test->assertSame( true, GetValue($test->objectByIdent('GatewayVerbunden', $station)) ); }); $test->runCase('Gateway-Ausfall verwirft Fahrzeug- und Phasenstatus', static function ( TestContext $test ) use ($gateway, $station): void { IPS_SetProperty($gateway, 'Active', false); IPS_ApplyChanges($gateway); $test->assertSame( false, GetValue($test->objectByIdent('FahrzeugVerbunden', $station)) ); $test->assertSame( 0, GetValue($test->objectByIdent('Phasenzahl', $station)) ); $test->assertInstanceStatus($station, 202); }); $test->runCase('Leistungswerte und Fahrzeugstatus folgen ihrer Sichtbarkeitsgruppe', static function ( TestContext $test ) use ($station): void { IPS_SetProperty($station, 'EinstellungenInVisu', true); IPS_SetProperty($station, 'DiagnosevariablenAnzeigen', false); IPS_ApplyChanges($station); $test->assertTrue(@IPS_GetObjectIDByIdent('Istleistung', $station) !== false); $test->assertTrue(@IPS_GetObjectIDByIdent('Sollleistung', $station) !== false); $test->assertSame(false, @IPS_GetObjectIDByIdent('Fahrzeugstatus', $station)); IPS_SetProperty($station, 'EinstellungenInVisu', false); IPS_SetProperty($station, 'DiagnosevariablenAnzeigen', true); IPS_ApplyChanges($station); $test->assertSame(false, @IPS_GetObjectIDByIdent('Istleistung', $station)); $test->assertSame(false, @IPS_GetObjectIDByIdent('Sollleistung', $station)); $test->assertTrue(@IPS_GetObjectIDByIdent('Fahrzeugstatus', $station) !== false); }); };