Files
Enelix-EMS/tests/Symcon/modules/LadestationStandAlone.php
T

232 lines
9.1 KiB
PHP

<?php
declare(strict_types=1);
use Belevo\EnelixEMS\SymconTest\TestContext;
return static function (TestContext $test): void {
$testPasswort = hash('sha256', __FILE__);
$goEAntwort = static function (int $status, float $leistung): string {
$nrg = array_fill(0, 12, 0);
$nrg[11] = $leistung;
return json_encode(['car' => $status, 'nrg' => $nrg], JSON_THROW_ON_ERROR);
};
$definitionen = [
'go-e alt' => [
'Geraetetyp' => 1,
'Geraeteadresse' => '192.0.2.10',
'Testantwort' => $goEAntwort(2, 1100),
'Phasenzahl' => 3,
'BefehlUrlTeil' => 'amp=16',
],
'go-e Gemini' => [
'Geraetetyp' => 2,
'Geraeteadresse' => '192.0.2.11',
'Testantwort' => $goEAntwort(2, 2300),
'Phasenzahl' => 1,
'BefehlUrlTeil' => 'amp=16',
],
'smart-me Pico' => [
'Geraetetyp' => 3,
'GeraeteID' => 'pico-id',
'Seriennummer' => 'serial-1',
'Benutzername' => 'api-user',
'Passwort' => $testPasswort,
'Testantwort' => json_encode([
'State' => 2,
'ActiveChargingPower' => 11.0,
'MaxAllowedChargingCurrent' => 16,
], JSON_THROW_ON_ERROR),
'Phasenzahl' => 3,
'BefehlUrlTeil' => 'current=16000',
],
];
$stationen = [];
foreach ($definitionen as $name => $definition) {
$properties = array_merge($definition, [
'MaximalerLadestrom' => 16,
'Ladefreigabe' => true,
'Solarladen' => true,
'EinstellungenInVisu' => true,
'DiagnosevariablenAnzeigen' => true,
'Testmodus' => true,
]);
unset($properties['Phasenzahl'], $properties['BefehlUrlTeil']);
$stationen[$name] = $test->createInstance(
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
'Ladestation ' . $name,
$properties
);
}
$solarPause = $test->createInstance(
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
'Ladestation Solarpause',
[
'Geraetetyp' => 1,
'Geraeteadresse' => '192.0.2.12',
'MaximalerLadestrom' => 16,
'Ladefreigabe' => true,
'Solarladen' => true,
'EinstellungenInVisu' => true,
'DiagnosevariablenAnzeigen' => true,
'Testmodus' => true,
'Testantwort' => $goEAntwort(2, 0),
]
);
$managerId = $test->createInstance(
'{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
'Hilfsmanager Ladestation',
[
'AutomatischeSuche' => false,
'VerbraucherZuordnung' => json_encode(array_map(
static fn (int $id): array => ['InstanzID' => $id, 'Aktiv' => true],
array_values($stationen)
), JSON_THROW_ON_ERROR),
]
);
$anforderungSenden = static function (
int $stationId,
int $leistung,
string $betriebsart = 'PV'
) use ($managerId): void {
IPS_RequestAction($stationId, 'ManagerdatenEmpfangen', json_encode([
'Kopf' => [
'Version' => '4.0',
'AbsenderID' => $managerId,
'EmpfaengerID' => $stationId,
'Zeitpunkt' => time(),
],
'Betriebsart' => $betriebsart,
'Sollleistung_W' => $leistung,
], JSON_THROW_ON_ERROR));
};
$test->runCase('Alle drei Geraetevarianten erkennen Fahrzeug und Phasen', static function (
TestContext $test
) use ($definitionen, $stationen): void {
foreach ($stationen as $name => $stationId) {
IPS_RequestAction($stationId, 'Aktiv', true);
$test->assertSame(true, GetValue($test->objectByIdent('FahrzeugVerbunden', $stationId)));
$test->assertSame(
$definitionen[$name]['Phasenzahl'],
GetValue($test->objectByIdent('Phasenzahl', $stationId))
);
$test->assertSame(false, GetValue($test->objectByIdent('FahrzeugGeladen', $stationId)));
IPS_RequestAction($stationId, 'Solarladen', false);
$befehl = (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId));
$diagnose = json_encode([
'Aktiv' => GetValue($test->objectByIdent('Aktiv', $stationId)),
'Ladefreigabe' => GetValue($test->objectByIdent('Ladefreigabe', $stationId)),
'Solarladen' => GetValue($test->objectByIdent('Solarladen', $stationId)),
'FahrzeugGeladen' => GetValue($test->objectByIdent('FahrzeugGeladen', $stationId)),
'Phasenzahl' => GetValue($test->objectByIdent('Phasenzahl', $stationId)),
'Status' => IPS_GetInstance($stationId)['InstanceStatus'],
'Stoertext' => GetValue($test->objectByIdent('Stoertext', $stationId)),
], JSON_THROW_ON_ERROR);
$test->assertTrue(str_contains(
$befehl,
$definitionen[$name]['BefehlUrlTeil']
), $name . ': Der erwartete 16-A-Geraetebefehl fehlt. Erhalten: ' . $befehl
. '; Diagnose: ' . $diagnose);
}
});
$test->runCase('Solarpause wird nicht als Ladeende erkannt', static function (
TestContext $test
) use ($solarPause): void {
IPS_RequestAction($solarPause, 'Solarladen', true);
$test->assertSame(
false,
GetValue($test->objectByIdent('FahrzeugGeladen', $solarPause))
);
$test->assertSame(
2,
GetValue($test->objectByIdent('Fahrzeugstatus', $solarPause))
);
});
$test->runCase('ApplyChanges prueft ein gespeichertes Ladeende neu', static function (
TestContext $test
) use ($goEAntwort, $solarPause): void {
IPS_RequestAction($solarPause, 'Solarladen', false);
IPS_RequestAction($solarPause, 'Statuszyklus', false);
$test->assertSame(
true,
GetValue($test->objectByIdent('FahrzeugGeladen', $solarPause))
);
IPS_SetProperty($solarPause, 'Testantwort', $goEAntwort(2, 2300));
IPS_ApplyChanges($solarPause);
$test->assertSame(
false,
GetValue($test->objectByIdent('FahrzeugGeladen', $solarPause))
);
$test->assertSame(
3,
GetValue($test->objectByIdent('Fahrzeugstatus', $solarPause))
);
});
$test->runCase('Solar- und Peakbetrieb liefern die Enelix-1-Angebote', static function (
TestContext $test
) use ($stationen, $anforderungSenden): void {
$stationId = $stationen['go-e alt'];
IPS_RequestAction($stationId, 'Solarladen', true);
$anforderungSenden($stationId, 4150);
$befehl = (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId));
$diagnose = json_encode([
'Sollleistung' => GetValue($test->objectByIdent('Sollleistung', $stationId)),
'SollwertGueltig' => GetValue($test->objectByIdent('SollwertGueltig', $stationId)),
'Status' => IPS_GetInstance($stationId)['InstanceStatus'],
'Stoertext' => GetValue($test->objectByIdent('Stoertext', $stationId)),
], JSON_THROW_ON_ERROR);
$test->assertTrue(str_contains(
$befehl,
'amp=6'
), 'Solarladen: Der 6-A-Befehl fehlt. Erhalten: ' . $befehl . '; Diagnose: ' . $diagnose);
IPS_RequestAction($stationId, 'Solarladen', false);
$angebot = (string) GetValue($test->objectByIdent('LeistungsangebotDiagnose', $stationId));
$test->assertSame('[11000]', $angebot, 'PV ohne Solarladen muss nur das Maximum anbieten.');
$abgewiesen = false;
try {
$anforderungSenden($stationId, 4150);
} catch (Throwable $fehler) {
$abgewiesen = true;
}
if (!$abgewiesen) {
$abgewiesen = GetValue($test->objectByIdent('SollwertGueltig', $stationId)) !== true
|| GetValue($test->objectByIdent('Sollleistung', $stationId)) !== 4150;
}
$test->assertSame(true, $abgewiesen, 'Normalbetrieb muss eine Zwischenstufe ablehnen.');
$anforderungSenden($stationId, 4150, 'Peak');
$test->assertSame(
'[0,4150,4850,5550,6250,6950,7600,8300,9000,9700,10300,11000]',
(string) GetValue($test->objectByIdent('LeistungsangebotDiagnose', $stationId))
);
$test->assertTrue(str_contains(
(string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId)),
'amp=6'
), 'Peak ohne Solarladen muss die Ladestufen annehmen.');
IPS_RequestAction($stationId, 'Solarladen', true);
$anforderungSenden($stationId, 0, 'Peak');
$test->assertSame(
'[0]',
(string) GetValue($test->objectByIdent('LeistungsangebotDiagnose', $stationId))
);
$test->assertTrue(str_contains(
(string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId)),
'alw=0'
), 'Peak mit Solarladen muss die Ladestation stoppen.');
});
};