This commit is contained in:
@@ -92,6 +92,7 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
|
|||||||
$this->RegisterAttributeBoolean('ZustandAenderungMoeglich', false);
|
$this->RegisterAttributeBoolean('ZustandAenderungMoeglich', false);
|
||||||
$this->RegisterAttributeBoolean('ZustandTemperaturGueltig', false);
|
$this->RegisterAttributeBoolean('ZustandTemperaturGueltig', false);
|
||||||
$this->RegisterAttributeBoolean('ZustandNachladenAktiv', false);
|
$this->RegisterAttributeBoolean('ZustandNachladenAktiv', false);
|
||||||
|
$this->RegisterAttributeBoolean('MaximaltemperaturErreicht', false);
|
||||||
$this->RegisterAttributeBoolean('ZustandLegionellenbetriebAktiv', false);
|
$this->RegisterAttributeBoolean('ZustandLegionellenbetriebAktiv', false);
|
||||||
$this->RegisterAttributeInteger('ZustandLegioCounter', 0);
|
$this->RegisterAttributeInteger('ZustandLegioCounter', 0);
|
||||||
|
|
||||||
@@ -362,7 +363,13 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
|
|||||||
(float) $this->ReadAttributeFloat('ZustandLegionellentemperatur')
|
(float) $this->ReadAttributeFloat('ZustandLegionellentemperatur')
|
||||||
);
|
);
|
||||||
$hysterese = $this->ReadPropertyFloat('Hysterese');
|
$hysterese = $this->ReadPropertyFloat('Hysterese');
|
||||||
$aktuelleLeistung = (int) round((float) $this->leseZustand('Istleistung'));
|
$maximaltemperaturErreicht = $this->ReadAttributeBoolean('MaximaltemperaturErreicht');
|
||||||
|
if ($temperatur >= $maximum) {
|
||||||
|
$maximaltemperaturErreicht = true;
|
||||||
|
} elseif ($temperatur <= $maximum - $hysterese) {
|
||||||
|
$maximaltemperaturErreicht = false;
|
||||||
|
}
|
||||||
|
$this->WriteAttributeBoolean('MaximaltemperaturErreicht', $maximaltemperaturErreicht);
|
||||||
|
|
||||||
$nachladen = (bool) $this->leseZustand('NachladenAktiv');
|
$nachladen = (bool) $this->leseZustand('NachladenAktiv');
|
||||||
if ($temperatur < $minimum) {
|
if ($temperatur < $minimum) {
|
||||||
@@ -390,12 +397,9 @@ class VerbraucherWarmwassererwaermer extends IPSModule implements VerbraucherSch
|
|||||||
if ($nachladen || $zeitplanErfordertHeizen) {
|
if ($nachladen || $zeitplanErfordertHeizen) {
|
||||||
return [[$maximalleistung], false, true, $maximalleistung];
|
return [[$maximalleistung], false, true, $maximalleistung];
|
||||||
}
|
}
|
||||||
if ($temperatur >= $maximum) {
|
if ($maximaltemperaturErreicht) {
|
||||||
return [[0], false, true, 0];
|
return [[0], false, true, 0];
|
||||||
}
|
}
|
||||||
if ($aktuelleLeistung > 0 && $temperatur >= $maximum - $hysterese) {
|
|
||||||
return [[$aktuelleLeistung], false, true, $aktuelleLeistung];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$alleLeistungen, true, true, null];
|
return [$alleLeistungen, true, true, null];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,12 @@ encode_base64() {
|
|||||||
|
|
||||||
mode_base64="$(encode_base64 "$mode")"
|
mode_base64="$(encode_base64 "$mode")"
|
||||||
selection_base64="$(encode_base64 "$selection")"
|
selection_base64="$(encode_base64 "$selection")"
|
||||||
php_code="require_once IPS_GetKernelDir() . 'modules/Enelix-EMS/tests/Symcon/bootstrap.php'; "
|
php_code="ob_start(); require_once IPS_GetKernelDir() . 'modules/Enelix-EMS/tests/Symcon/bootstrap.php'; "
|
||||||
php_code+="\$mode = base64_decode('$mode_base64'); "
|
php_code+="\$mode = base64_decode('$mode_base64'); "
|
||||||
php_code+="\$selection = array_values(array_filter(explode(',', base64_decode('$selection_base64')), "
|
php_code+="\$selection = array_values(array_filter(explode(',', base64_decode('$selection_base64')), "
|
||||||
php_code+="static fn (string \$value): bool => \$value !== '')); "
|
php_code+="static fn (string \$value): bool => \$value !== '')); "
|
||||||
php_code+="\$result = enelixEmsRunSymconTests(\$mode, \$selection); "
|
php_code+="\$result = enelixEmsRunSymconTests(\$mode, \$selection); "
|
||||||
|
php_code+="ob_end_clean(); "
|
||||||
php_code+="echo implode(':', ["
|
php_code+="echo implode(':', ["
|
||||||
php_code+="base64_encode(json_encode(\$result, JSON_THROW_ON_ERROR)), "
|
php_code+="base64_encode(json_encode(\$result, JSON_THROW_ON_ERROR)), "
|
||||||
php_code+="base64_encode(json_encode(\$result['report'], JSON_THROW_ON_ERROR)), "
|
php_code+="base64_encode(json_encode(\$result['report'], JSON_THROW_ON_ERROR)), "
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ return static function (TestContext $test): void {
|
|||||||
'Mindesteinschaltdauer' => 0,
|
'Mindesteinschaltdauer' => 0,
|
||||||
'Mindestausschaltdauer' => 0,
|
'Mindestausschaltdauer' => 0,
|
||||||
'PrioritaetPV' => 0,
|
'PrioritaetPV' => 0,
|
||||||
|
'PrioritaetPeak' => 0,
|
||||||
'DiagnosevariablenAnzeigen' => true,
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -38,106 +39,195 @@ return static function (TestContext $test): void {
|
|||||||
'LastwechselSperrzeit' => 1,
|
'LastwechselSperrzeit' => 1,
|
||||||
'LegionellenfunktionAktiv' => false,
|
'LegionellenfunktionAktiv' => false,
|
||||||
'PrioritaetPV' => 1,
|
'PrioritaetPV' => 1,
|
||||||
|
'PrioritaetPeak' => 1,
|
||||||
'DiagnosevariablenAnzeigen' => true,
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$zuordnung = [
|
||||||
|
['InstanzID' => $einStufigId, 'Aktiv' => true],
|
||||||
|
['InstanzID' => $warmwasserId, 'Aktiv' => true],
|
||||||
|
];
|
||||||
$managerId = $test->createInstance(
|
$managerId = $test->createInstance(
|
||||||
'{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
|
'{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
|
||||||
'Manager',
|
'Manager',
|
||||||
[
|
[
|
||||||
'NetzleistungVariableID' => $netzleistungId,
|
'NetzleistungVariableID' => $netzleistungId,
|
||||||
'AutomatischeSuche' => false,
|
'AutomatischeSuche' => false,
|
||||||
'VerbraucherZuordnung' => '[]',
|
'VerbraucherZuordnung' => json_encode($zuordnung, JSON_THROW_ON_ERROR),
|
||||||
'DiagnosevariablenAnzeigen' => true,
|
'KeepAlive' => 30,
|
||||||
|
'VerbraucherTimeout' => 10,
|
||||||
|
'Lastspitzenmodus' => 1,
|
||||||
|
'Lastspitzengrenze' => 0.0,
|
||||||
'SollwertSolarladen' => 0.0,
|
'SollwertSolarladen' => 0.0,
|
||||||
|
'Umschaltdifferenz' => 0.0,
|
||||||
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$setAssignment = static function (array $ids) use ($test, $managerId): void {
|
$melden = static function () use ($einStufigId, $warmwasserId): void {
|
||||||
$assignment = array_map(
|
foreach ([$einStufigId, $warmwasserId] as $instanzId) {
|
||||||
static fn (int $id): array => ['InstanzID' => $id, 'Aktiv' => true],
|
IPS_RequestAction($instanzId, 'Aktiv', true);
|
||||||
$ids
|
IPS_RequestAction($instanzId, 'Melden', true);
|
||||||
);
|
|
||||||
$test->configureInstance($managerId, [
|
|
||||||
'VerbraucherZuordnung' => json_encode($assignment, JSON_THROW_ON_ERROR),
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
$reportConsumers = static function (array $ids): void {
|
|
||||||
foreach ($ids as $id) {
|
|
||||||
IPS_RequestAction($id, 'Aktiv', true);
|
|
||||||
IPS_RequestAction($id, 'Melden', true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
$regeln = static function (float $netzleistung) use (
|
||||||
$test->runCase('Manager funktioniert ohne Verbraucher', static function (TestContext $test) use (
|
$netzleistungId,
|
||||||
|
$managerId,
|
||||||
|
$einStufigId,
|
||||||
|
$warmwasserId
|
||||||
|
): void {
|
||||||
|
IPS_RequestAction($einStufigId, 'Melden', true);
|
||||||
|
IPS_RequestAction($warmwasserId, 'Melden', true);
|
||||||
|
SetValue($netzleistungId, $netzleistung);
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
|
};
|
||||||
|
$kontaktzustand = static fn (): array => [
|
||||||
|
(bool) GetValue($einKontaktId),
|
||||||
|
(bool) GetValue($warmKontakte[0]),
|
||||||
|
(bool) GetValue($warmKontakte[1]),
|
||||||
|
];
|
||||||
|
$warteAufKontakte = static function (array $erwartet, string $schritt) use (
|
||||||
|
$test,
|
||||||
|
$kontaktzustand,
|
||||||
$managerId
|
$managerId
|
||||||
): void {
|
): void {
|
||||||
IPS_RequestAction($managerId, 'Aktiv', true);
|
$deadline = microtime(true) + 5.0;
|
||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
do {
|
||||||
$test->assertInstanceStatus($managerId);
|
if ($kontaktzustand() === $erwartet) {
|
||||||
$test->assertSame('PV', GetValue($test->objectByIdent('Betriebsart', $managerId)));
|
return;
|
||||||
});
|
}
|
||||||
|
IPS_Sleep(50);
|
||||||
|
} while (microtime(true) < $deadline);
|
||||||
|
|
||||||
$test->runCase('Manager steuert Verbraucher 1-Stufig', static function (TestContext $test) use (
|
$test->fail(sprintf(
|
||||||
$setAssignment,
|
'%s: Kontaktbild %s statt %s; Betriebsart %s; Verteilbudget %.0f W.',
|
||||||
$reportConsumers,
|
$schritt,
|
||||||
$netzleistungId,
|
json_encode($kontaktzustand(), JSON_THROW_ON_ERROR),
|
||||||
$managerId,
|
json_encode($erwartet, JSON_THROW_ON_ERROR),
|
||||||
$einStufigId,
|
(string) GetValue($test->objectByIdent('Betriebsart', $managerId)),
|
||||||
$einKontaktId
|
(float) GetValue($test->objectByIdent('Verteilbudget', $managerId))
|
||||||
): void {
|
|
||||||
$setAssignment([$einStufigId]);
|
|
||||||
SetValue($netzleistungId, -1000.0);
|
|
||||||
$reportConsumers([$einStufigId]);
|
|
||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
|
||||||
$test->waitUntil(static fn (): bool => GetValue($einKontaktId) === true);
|
|
||||||
$test->assertSame(true, GetValue($einKontaktId));
|
|
||||||
});
|
|
||||||
|
|
||||||
$test->runCase('Manager steuert Wassererwärmer', static function (TestContext $test) use (
|
|
||||||
$setAssignment,
|
|
||||||
$reportConsumers,
|
|
||||||
$netzleistungId,
|
|
||||||
$managerId,
|
|
||||||
$warmwasserId,
|
|
||||||
$warmKontakte
|
|
||||||
): void {
|
|
||||||
$setAssignment([$warmwasserId]);
|
|
||||||
SetValue($netzleistungId, -2000.0);
|
|
||||||
$reportConsumers([$warmwasserId]);
|
|
||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
|
||||||
$test->waitUntil(static fn (): bool => GetValue($warmKontakte[1]) === true);
|
|
||||||
$test->assertSame([false, true], array_map(
|
|
||||||
static fn (int $id): bool => (bool) GetValue($id),
|
|
||||||
$warmKontakte
|
|
||||||
));
|
));
|
||||||
});
|
};
|
||||||
|
$verbraucherstatus = static function () use ($test, $managerId): array {
|
||||||
|
$json = (string) GetValue($test->objectByIdent('Verbraucherstatus', $managerId));
|
||||||
|
$daten = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
$test->runCase('Manager steuert beide Verbrauchertypen gemeinsam', static function (
|
return is_array($daten) ? $daten : [];
|
||||||
|
};
|
||||||
|
$zustandswert = static function (array $daten, int $instanzId, string $kennung) {
|
||||||
|
foreach ($daten['Verbraucher'] ?? [] as $verbraucher) {
|
||||||
|
if (($verbraucher['InstanzID'] ?? 0) !== $instanzId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($verbraucher['Daten']['Zustand'] ?? [] as $zustand) {
|
||||||
|
if (($zustand['Kennung'] ?? '') === $kennung) {
|
||||||
|
return $zustand['Wert'] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$test->runCase('Manager und alle vorhandenen Verbrauchertypen sind verknüpft', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use (
|
) use ($managerId, $einStufigId, $warmwasserId, $melden): void {
|
||||||
$setAssignment,
|
IPS_RequestAction($managerId, 'Aktiv', true);
|
||||||
$reportConsumers,
|
$melden();
|
||||||
$netzleistungId,
|
|
||||||
$managerId,
|
|
||||||
$einStufigId,
|
|
||||||
$warmwasserId,
|
|
||||||
$einKontaktId,
|
|
||||||
$warmKontakte
|
|
||||||
): void {
|
|
||||||
$setAssignment([$einStufigId, $warmwasserId]);
|
|
||||||
SetValue($netzleistungId, -3000.0);
|
|
||||||
$reportConsumers([$einStufigId, $warmwasserId]);
|
|
||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
$test->waitUntil(static fn (): bool => (
|
|
||||||
GetValue($einKontaktId) === true && GetValue($warmKontakte[1]) === true
|
foreach ([$managerId, $einStufigId, $warmwasserId] as $instanzId) {
|
||||||
));
|
$test->assertInstanceStatus($instanzId);
|
||||||
|
}
|
||||||
$test->assertSame(
|
$test->assertSame(
|
||||||
2,
|
2,
|
||||||
GetValue($test->objectByIdent('VerbraucherAnzahl', $managerId))
|
GetValue($test->objectByIdent('VerbraucherAnzahl', $managerId))
|
||||||
);
|
);
|
||||||
$test->assertSame(true, GetValue($einKontaktId));
|
$test->assertSame(
|
||||||
$test->assertSame(true, GetValue($warmKontakte[1]));
|
2,
|
||||||
|
GetValue($test->objectByIdent('VerbraucherVerfuegbar', $managerId))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Netzleistung wird in beide Richtungen in PV und Peak geregelt', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($managerId, $regeln, $warteAufKontakte): void {
|
||||||
|
$regeln(-3000.0);
|
||||||
|
$warteAufKontakte([true, false, true], 'Netz -3000 W');
|
||||||
|
$test->assertSame('PV', GetValue($test->objectByIdent('Betriebsart', $managerId)));
|
||||||
|
|
||||||
|
$regeln(-1000.0);
|
||||||
|
$warteAufKontakte([true, false, true], 'Netz -1000 W');
|
||||||
|
$regeln(0.0);
|
||||||
|
$warteAufKontakte([true, false, true], 'Netz 0 W');
|
||||||
|
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
$regeln(1000.0);
|
||||||
|
$warteAufKontakte([true, true, false], 'Netz +1000 W');
|
||||||
|
$test->assertSame('Peak', GetValue($test->objectByIdent('Betriebsart', $managerId)));
|
||||||
|
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
$regeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, false], 'Netz +3000 W');
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Keep-alive ist aktiv und erneuert unveränderte Sollwerte', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($managerId, $einStufigId): void {
|
||||||
|
$sollwertId = $test->objectByIdent('Sollleistung', $einStufigId);
|
||||||
|
$vorher = (int) IPS_GetVariable($sollwertId)['VariableUpdated'];
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
|
$test->waitUntil(
|
||||||
|
static fn (): bool => (int) IPS_GetVariable($sollwertId)['VariableUpdated'] > $vorher
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Alle definierten Nachrichtenauslöser aktualisieren den Manager', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
|
$managerId,
|
||||||
|
$einStufigId,
|
||||||
|
$warmwasserId,
|
||||||
|
$temperaturId,
|
||||||
|
$melden,
|
||||||
|
$verbraucherstatus,
|
||||||
|
$zustandswert
|
||||||
|
): void {
|
||||||
|
$melden();
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', false);
|
||||||
|
$daten = $verbraucherstatus();
|
||||||
|
$test->assertSame(2, count($daten['Verbraucher'] ?? []));
|
||||||
|
|
||||||
|
SetValue($temperaturId, 53.0);
|
||||||
|
$test->waitUntil(static function () use (
|
||||||
|
$managerId,
|
||||||
|
$warmwasserId,
|
||||||
|
$verbraucherstatus,
|
||||||
|
$zustandswert
|
||||||
|
): bool {
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', false);
|
||||||
|
$wert = $zustandswert(
|
||||||
|
$verbraucherstatus(),
|
||||||
|
$warmwasserId,
|
||||||
|
'Wassertemperatur_C'
|
||||||
|
);
|
||||||
|
return is_numeric($wert) && abs((float) $wert - 53.0) < 0.01;
|
||||||
|
}, 4000, 100);
|
||||||
|
|
||||||
|
IPS_RequestAction($einStufigId, 'Melden', true);
|
||||||
|
IPS_RequestAction($warmwasserId, 'Melden', true);
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
|
$daten = $verbraucherstatus();
|
||||||
|
$test->assertTrue(
|
||||||
|
is_bool($zustandswert($daten, $einStufigId, 'Schaltzustand'))
|
||||||
|
);
|
||||||
|
$test->assertTrue(
|
||||||
|
is_int($zustandswert($daten, $warmwasserId, 'AktiveStufe'))
|
||||||
|
);
|
||||||
|
$test->assertSame(false, GetValue(
|
||||||
|
$test->objectByIdent('Sammelstoerung', $managerId)
|
||||||
|
));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,14 +6,18 @@ use Belevo\EnelixEMS\SymconTest\TestContext;
|
|||||||
|
|
||||||
return static function (TestContext $test): void {
|
return static function (TestContext $test): void {
|
||||||
$kontaktId = $test->createActionVariable('Schaltkontakt');
|
$kontaktId = $test->createActionVariable('Schaltkontakt');
|
||||||
|
$rueckmeldungId = $test->createVariable(0, 'Rückmeldung', false);
|
||||||
$verbraucherId = $test->createInstance(
|
$verbraucherId = $test->createInstance(
|
||||||
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
||||||
'Verbraucher 1-Stufig',
|
'Verbraucher 1-Stufig',
|
||||||
[
|
[
|
||||||
'Nennleistung' => 1200,
|
'Nennleistung' => 1200,
|
||||||
'SchaltkontaktVariableID' => $kontaktId,
|
'SchaltkontaktVariableID' => $kontaktId,
|
||||||
'Mindesteinschaltdauer' => 0,
|
'RueckmeldungVariableID' => $rueckmeldungId,
|
||||||
'Mindestausschaltdauer' => 0,
|
'Mindestlaufzeit' => 0,
|
||||||
|
'Mindesteinschaltdauer' => 2,
|
||||||
|
'Mindestausschaltdauer' => 2,
|
||||||
|
'VorgabeTimeout' => 30,
|
||||||
'DiagnosevariablenAnzeigen' => true,
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -28,21 +32,10 @@ return static function (TestContext $test): void {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$test->runCase('Instanz und Variablen werden angelegt', static function (TestContext $test) use (
|
$anforderungSenden = static function (int $leistung) use (
|
||||||
|
$managerId,
|
||||||
$verbraucherId
|
$verbraucherId
|
||||||
): void {
|
): void {
|
||||||
$test->assertInstanceStatus($verbraucherId);
|
|
||||||
foreach (['Aktiv', 'Schaltzustand', 'Tageslaufzeit', 'Istleistung', 'Sollleistung'] as $ident) {
|
|
||||||
$test->objectByIdent($ident, $verbraucherId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$test->runCase('Sollwert schaltet den Verbraucher ein', static function (TestContext $test) use (
|
|
||||||
$managerId,
|
|
||||||
$verbraucherId,
|
|
||||||
$kontaktId
|
|
||||||
): void {
|
|
||||||
IPS_RequestAction($verbraucherId, 'Aktiv', true);
|
|
||||||
$paket = [
|
$paket = [
|
||||||
'Kopf' => [
|
'Kopf' => [
|
||||||
'Version' => '3.0',
|
'Version' => '3.0',
|
||||||
@@ -50,41 +43,149 @@ return static function (TestContext $test): void {
|
|||||||
'EmpfaengerID' => $verbraucherId,
|
'EmpfaengerID' => $verbraucherId,
|
||||||
'Zeitpunkt' => time(),
|
'Zeitpunkt' => time(),
|
||||||
],
|
],
|
||||||
'Sollleistung_W' => 1200,
|
'Sollleistung_W' => $leistung,
|
||||||
];
|
];
|
||||||
IPS_RequestAction(
|
IPS_RequestAction(
|
||||||
$verbraucherId,
|
$verbraucherId,
|
||||||
'ManagerdatenEmpfangen',
|
'ManagerdatenEmpfangen',
|
||||||
json_encode($paket, JSON_THROW_ON_ERROR)
|
json_encode($paket, JSON_THROW_ON_ERROR)
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
$test->runCase('Instanz und Diagnosevariablen werden angelegt', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($verbraucherId): void {
|
||||||
|
$test->assertInstanceStatus($verbraucherId);
|
||||||
|
foreach ([
|
||||||
|
'Aktiv', 'Schaltzustand', 'Tageslaufzeit', 'Istleistung', 'Sollleistung',
|
||||||
|
'AenderungMoeglich', 'Rueckmeldefehler', 'SchaltbefehlAusstehend',
|
||||||
|
'RestMindestzeit',
|
||||||
|
] as $ident) {
|
||||||
|
$test->objectByIdent($ident, $verbraucherId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Nur angebotene Leistungsanforderungen werden angenommen', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
|
$verbraucherId,
|
||||||
|
$kontaktId,
|
||||||
|
$rueckmeldungId,
|
||||||
|
$anforderungSenden
|
||||||
|
): void {
|
||||||
|
IPS_RequestAction($verbraucherId, 'Aktiv', true);
|
||||||
|
IPS_Sleep(2100);
|
||||||
|
|
||||||
|
$anforderungSenden(600);
|
||||||
|
$test->assertSame(false, GetValue($kontaktId));
|
||||||
|
$test->assertSame(
|
||||||
|
0,
|
||||||
|
(int) GetValue($test->objectByIdent('Sollleistung', $verbraucherId))
|
||||||
|
);
|
||||||
|
$anforderungSenden(1200);
|
||||||
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === true);
|
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === true);
|
||||||
$test->assertSame(true, GetValue($kontaktId));
|
$test->assertSame(false, GetValue(
|
||||||
|
$test->objectByIdent('Schaltzustand', $verbraucherId)
|
||||||
|
));
|
||||||
|
$test->assertSame(true, GetValue(
|
||||||
|
$test->objectByIdent('SchaltbefehlAusstehend', $verbraucherId)
|
||||||
|
));
|
||||||
|
|
||||||
|
SetValue($rueckmeldungId, true);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue(
|
||||||
|
$test->objectByIdent('Schaltzustand', $verbraucherId)
|
||||||
|
) === true);
|
||||||
$test->assertSame(
|
$test->assertSame(
|
||||||
1200,
|
1200,
|
||||||
(int) round((float) GetValue($test->objectByIdent('Istleistung', $verbraucherId)))
|
(int) round((float) GetValue($test->objectByIdent('Istleistung', $verbraucherId)))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$test->runCase('Sollwert null schaltet den Verbraucher aus', static function (TestContext $test) use (
|
$test->runCase('Mindesteinschaltdauer verhindert zu frühes Ausschalten', static function (
|
||||||
$managerId,
|
TestContext $test
|
||||||
|
) use (
|
||||||
$verbraucherId,
|
$verbraucherId,
|
||||||
$kontaktId
|
$kontaktId,
|
||||||
|
$rueckmeldungId,
|
||||||
|
$anforderungSenden
|
||||||
): void {
|
): void {
|
||||||
$paket = [
|
$anforderungSenden(0);
|
||||||
'Kopf' => [
|
$test->assertSame(true, GetValue($kontaktId));
|
||||||
'Version' => '3.0',
|
$test->assertTrue(
|
||||||
'AbsenderID' => $managerId,
|
(int) GetValue($test->objectByIdent('RestMindestzeit', $verbraucherId)) > 0
|
||||||
'EmpfaengerID' => $verbraucherId,
|
|
||||||
'Zeitpunkt' => time(),
|
|
||||||
],
|
|
||||||
'Sollleistung_W' => 0,
|
|
||||||
];
|
|
||||||
IPS_RequestAction(
|
|
||||||
$verbraucherId,
|
|
||||||
'ManagerdatenEmpfangen',
|
|
||||||
json_encode($paket, JSON_THROW_ON_ERROR)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
IPS_Sleep(2100);
|
||||||
|
$anforderungSenden(0);
|
||||||
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === false);
|
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === false);
|
||||||
|
$test->assertSame(true, GetValue(
|
||||||
|
$test->objectByIdent('SchaltbefehlAusstehend', $verbraucherId)
|
||||||
|
));
|
||||||
|
|
||||||
|
SetValue($rueckmeldungId, false);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue(
|
||||||
|
$test->objectByIdent('Schaltzustand', $verbraucherId)
|
||||||
|
) === false);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Mindestausschaltdauer verhindert zu frühes Einschalten', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
|
$kontaktId,
|
||||||
|
$rueckmeldungId,
|
||||||
|
$anforderungSenden
|
||||||
|
): void {
|
||||||
|
$anforderungSenden(1200);
|
||||||
$test->assertSame(false, GetValue($kontaktId));
|
$test->assertSame(false, GetValue($kontaktId));
|
||||||
|
|
||||||
|
IPS_Sleep(2100);
|
||||||
|
$anforderungSenden(1200);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === true);
|
||||||
|
SetValue($rueckmeldungId, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Tägliche Mindestlaufzeit wird spätestens rechtzeitig erzwungen', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
|
$verbraucherId,
|
||||||
|
$kontaktId,
|
||||||
|
$rueckmeldungId,
|
||||||
|
$anforderungSenden
|
||||||
|
): void {
|
||||||
|
IPS_Sleep(2100);
|
||||||
|
$anforderungSenden(0);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === false);
|
||||||
|
SetValue($rueckmeldungId, false);
|
||||||
|
|
||||||
|
IPS_SetProperty($verbraucherId, 'Mindestlaufzeit', 86400);
|
||||||
|
IPS_ApplyChanges($verbraucherId);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue($kontaktId) === true);
|
||||||
|
$test->assertSame(1200, (int) GetValue(
|
||||||
|
$test->objectByIdent('Sollleistung', $verbraucherId)
|
||||||
|
));
|
||||||
|
SetValue($rueckmeldungId, true);
|
||||||
|
|
||||||
|
IPS_SetProperty($verbraucherId, 'Mindestlaufzeit', 0);
|
||||||
|
IPS_ApplyChanges($verbraucherId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Physische Rückmeldung bestätigt und überwacht den Zustand', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($verbraucherId, $kontaktId, $rueckmeldungId): void {
|
||||||
|
$test->assertSame(true, GetValue($kontaktId));
|
||||||
|
SetValue($rueckmeldungId, false);
|
||||||
|
IPS_RequestAction($verbraucherId, 'Melden', true);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue(
|
||||||
|
$test->objectByIdent('Rueckmeldefehler', $verbraucherId)
|
||||||
|
) === true);
|
||||||
|
$test->assertSame(true, GetValue(
|
||||||
|
$test->objectByIdent('Stoerung', $verbraucherId)
|
||||||
|
));
|
||||||
|
|
||||||
|
SetValue($rueckmeldungId, true);
|
||||||
|
IPS_RequestAction($verbraucherId, 'Melden', true);
|
||||||
|
$test->waitUntil(static fn (): bool => GetValue(
|
||||||
|
$test->objectByIdent('Rueckmeldefehler', $verbraucherId)
|
||||||
|
) === false);
|
||||||
|
$test->assertInstanceStatus($verbraucherId);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use Belevo\EnelixEMS\SymconTest\TestContext;
|
|||||||
|
|
||||||
return static function (TestContext $test): void {
|
return static function (TestContext $test): void {
|
||||||
$temperaturId = $test->createVariable(2, 'Boilertemperatur', 52.0, null, '~Temperature');
|
$temperaturId = $test->createVariable(2, 'Boilertemperatur', 52.0, null, '~Temperature');
|
||||||
|
$netzleistungId = $test->createVariable(2, 'Netzleistung', 0.0);
|
||||||
$kontakte = [
|
$kontakte = [
|
||||||
$test->createActionVariable('Heizstufe 1'),
|
$test->createActionVariable('Heizstufe 1'),
|
||||||
$test->createActionVariable('Heizstufe 2'),
|
$test->createActionVariable('Heizstufe 2'),
|
||||||
@@ -25,9 +26,15 @@ return static function (TestContext $test): void {
|
|||||||
'Wassererwärmer',
|
'Wassererwärmer',
|
||||||
[
|
[
|
||||||
'Boilerfuehler_PT1' => $temperaturId,
|
'Boilerfuehler_PT1' => $temperaturId,
|
||||||
|
'Boilervolumen' => 300,
|
||||||
'LeistungsStufen' => json_encode($stufen, JSON_THROW_ON_ERROR),
|
'LeistungsStufen' => json_encode($stufen, JSON_THROW_ON_ERROR),
|
||||||
'LastwechselSperrzeit' => 1,
|
'LastwechselSperrzeit' => 1,
|
||||||
'LegionellenfunktionAktiv' => false,
|
'Hysterese' => 5.0,
|
||||||
|
'TemperaturMaxAlter' => 120,
|
||||||
|
'LegionellenfunktionAktiv' => true,
|
||||||
|
'LegionellenMinimalintervallTage' => 4,
|
||||||
|
'LegionellenMaximalintervallTage' => 7,
|
||||||
|
'EinstellungenInVisu' => true,
|
||||||
'DiagnosevariablenAnzeigen' => true,
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -35,63 +42,175 @@ return static function (TestContext $test): void {
|
|||||||
'{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
|
'{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}',
|
||||||
'Hilfsmanager',
|
'Hilfsmanager',
|
||||||
[
|
[
|
||||||
|
'NetzleistungVariableID' => $netzleistungId,
|
||||||
'AutomatischeSuche' => false,
|
'AutomatischeSuche' => false,
|
||||||
'VerbraucherZuordnung' => json_encode([
|
'VerbraucherZuordnung' => json_encode([
|
||||||
['InstanzID' => $verbraucherId, 'Aktiv' => true],
|
['InstanzID' => $verbraucherId, 'Aktiv' => true],
|
||||||
], JSON_THROW_ON_ERROR),
|
], JSON_THROW_ON_ERROR),
|
||||||
|
'Lastspitzenmodus' => 1,
|
||||||
|
'Lastspitzengrenze' => 0.0,
|
||||||
|
'SollwertSolarladen' => 0.0,
|
||||||
|
'Umschaltdifferenz' => 0.0,
|
||||||
|
'KeepAlive' => 5,
|
||||||
|
'DiagnosevariablenAnzeigen' => true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$test->runCase('Instanz und Diagnosevariablen werden angelegt', static function (
|
$kontaktzustand = static fn (): array => array_map(
|
||||||
|
static fn (int $id): bool => (bool) GetValue($id),
|
||||||
|
$kontakte
|
||||||
|
);
|
||||||
|
$warteAufKontakte = static function (array $erwartet) use (
|
||||||
|
$test,
|
||||||
|
$kontaktzustand
|
||||||
|
): void {
|
||||||
|
$test->waitUntil(
|
||||||
|
static fn (): bool => $kontaktzustand() === $erwartet,
|
||||||
|
4000,
|
||||||
|
50
|
||||||
|
);
|
||||||
|
$test->assertSame($erwartet, $kontaktzustand());
|
||||||
|
};
|
||||||
|
$temperaturSetzen = static function (float $wert) use (
|
||||||
|
$temperaturId,
|
||||||
|
$verbraucherId
|
||||||
|
): void {
|
||||||
|
SetValue($temperaturId, $wert);
|
||||||
|
IPS_RequestAction($verbraucherId, 'Melden', true);
|
||||||
|
};
|
||||||
|
$managerRegeln = static function (float $netzleistung) use (
|
||||||
|
$netzleistungId,
|
||||||
|
$verbraucherId,
|
||||||
|
$managerId
|
||||||
|
): void {
|
||||||
|
SetValue($netzleistungId, $netzleistung);
|
||||||
|
IPS_RequestAction($verbraucherId, 'Melden', true);
|
||||||
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
|
};
|
||||||
|
|
||||||
|
$test->runCase('Instanzen und Diagnosevariablen werden angelegt', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use ($verbraucherId): void {
|
) use ($verbraucherId, $managerId): void {
|
||||||
$test->assertInstanceStatus($verbraucherId);
|
$test->assertInstanceStatus($verbraucherId);
|
||||||
|
$test->assertInstanceStatus($managerId);
|
||||||
foreach ([
|
foreach ([
|
||||||
'Aktiv', 'Boilertemperatur', 'Mindesttemperatur', 'Maximaltemperatur',
|
'Aktiv', 'Boilertemperatur', 'Mindesttemperatur', 'Maximaltemperatur',
|
||||||
'Istleistung', 'Sollleistung', 'AktiveStufe', 'TemperaturGueltig',
|
'Legionellentemperatur', 'Istleistung', 'Sollleistung', 'AktiveStufe',
|
||||||
|
'TemperaturGueltig', 'NachladenAktiv', 'LegionellenbetriebAktiv',
|
||||||
] as $ident) {
|
] as $ident) {
|
||||||
$test->objectByIdent($ident, $verbraucherId);
|
$test->objectByIdent($ident, $verbraucherId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$test->runCase('Temperaturmessung wird übernommen', static function (TestContext $test) use (
|
$test->runCase('Temperaturmessung und Verbraucher werden aktiviert', static function (
|
||||||
$verbraucherId
|
TestContext $test
|
||||||
): void {
|
) use ($verbraucherId, $managerId): void {
|
||||||
IPS_RequestAction($verbraucherId, 'Aktiv', true);
|
IPS_RequestAction($verbraucherId, 'Aktiv', true);
|
||||||
|
IPS_RequestAction($managerId, 'Aktiv', true);
|
||||||
IPS_RequestAction($verbraucherId, 'Melden', true);
|
IPS_RequestAction($verbraucherId, 'Melden', true);
|
||||||
$temperature = (float) GetValue($test->objectByIdent('Boilertemperatur', $verbraucherId));
|
$test->assertEquals(
|
||||||
$test->assertEquals(52.0, $temperature, 0.01);
|
52.0,
|
||||||
|
(float) GetValue($test->objectByIdent('Boilertemperatur', $verbraucherId)),
|
||||||
|
0.01
|
||||||
|
);
|
||||||
$test->assertSame(
|
$test->assertSame(
|
||||||
true,
|
true,
|
||||||
GetValue($test->objectByIdent('TemperaturGueltig', $verbraucherId))
|
GetValue($test->objectByIdent('TemperaturGueltig', $verbraucherId))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$test->runCase('Sollwert wählt genau eine Leistungsstufe', static function (
|
$test->runCase('Unter Minimum wird in PV und Peak bis über die Hysterese geheizt', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use ($managerId, $verbraucherId, $kontakte): void {
|
) use (
|
||||||
$paket = [
|
$temperaturSetzen,
|
||||||
'Kopf' => [
|
$managerRegeln,
|
||||||
'Version' => '3.0',
|
$warteAufKontakte,
|
||||||
'AbsenderID' => $managerId,
|
$managerId
|
||||||
'EmpfaengerID' => $verbraucherId,
|
): void {
|
||||||
'Zeitpunkt' => time(),
|
$temperaturSetzen(44.0);
|
||||||
],
|
$managerRegeln(-3000.0);
|
||||||
'Sollleistung_W' => 2000,
|
$warteAufKontakte([false, false, true]);
|
||||||
];
|
$test->assertSame('PV', GetValue($test->objectByIdent('Betriebsart', $managerId)));
|
||||||
IPS_RequestAction(
|
|
||||||
|
$managerRegeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, true]);
|
||||||
|
$test->assertSame('Peak', GetValue($test->objectByIdent('Betriebsart', $managerId)));
|
||||||
|
|
||||||
|
$temperaturSetzen(49.9);
|
||||||
|
$managerRegeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, true]);
|
||||||
|
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
$temperaturSetzen(50.0);
|
||||||
|
$managerRegeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, false]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Zwischen Minimum und Maximum wählt PV Stufen und Peak null', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($temperaturSetzen, $managerRegeln, $warteAufKontakte): void {
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
$temperaturSetzen(52.0);
|
||||||
|
$managerRegeln(-3000.0);
|
||||||
|
$warteAufKontakte([false, false, true]);
|
||||||
|
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
$managerRegeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, false]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Maximum sperrt bis unter die obere Hysterese', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use ($temperaturSetzen, $managerRegeln, $warteAufKontakte): void {
|
||||||
|
$temperaturSetzen(60.0);
|
||||||
|
$managerRegeln(-3000.0);
|
||||||
|
$warteAufKontakte([false, false, false]);
|
||||||
|
|
||||||
|
$temperaturSetzen(58.0);
|
||||||
|
$managerRegeln(-3000.0);
|
||||||
|
$warteAufKontakte([false, false, false]);
|
||||||
|
|
||||||
|
$temperaturSetzen(55.0);
|
||||||
|
$managerRegeln(-3000.0);
|
||||||
|
$warteAufKontakte([false, false, true]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Legionellenziel erlaubt Peak-Stufen und lädt in PV maximal', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
$verbraucherId,
|
$verbraucherId,
|
||||||
'ManagerdatenEmpfangen',
|
$temperaturSetzen,
|
||||||
json_encode($paket, JSON_THROW_ON_ERROR)
|
$managerRegeln,
|
||||||
);
|
$warteAufKontakte
|
||||||
$test->waitUntil(static fn (): bool => GetValue($kontakte[1]) === true);
|
): void {
|
||||||
$test->assertSame(
|
IPS_RequestAction($verbraucherId, 'Maximaltemperatur', 65.0);
|
||||||
[false, true, false],
|
$temperaturSetzen(55.0);
|
||||||
array_map(static fn (int $id): bool => (bool) GetValue($id), $kontakte)
|
$managerRegeln(-3000.0);
|
||||||
);
|
$warteAufKontakte([false, false, true]);
|
||||||
$test->assertSame(
|
|
||||||
2,
|
IPS_Sleep(1100);
|
||||||
GetValue($test->objectByIdent('AktiveStufe', $verbraucherId))
|
$managerRegeln(2000.0);
|
||||||
);
|
$warteAufKontakte([true, false, false]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$test->runCase('Zeitplan erzwingt rechtzeitiges Aufheizen wie ein Minimum', static function (
|
||||||
|
TestContext $test
|
||||||
|
) use (
|
||||||
|
$verbraucherId,
|
||||||
|
$temperaturSetzen,
|
||||||
|
$managerRegeln,
|
||||||
|
$warteAufKontakte
|
||||||
|
): void {
|
||||||
|
IPS_Sleep(1100);
|
||||||
|
IPS_RequestAction($verbraucherId, 'Maximaltemperatur', 60.0);
|
||||||
|
$temperaturSetzen(52.0);
|
||||||
|
$managerRegeln(3000.0);
|
||||||
|
$warteAufKontakte([false, false, false]);
|
||||||
|
|
||||||
|
IPS_SetProperty($verbraucherId, 'Zeitplan', json_encode([
|
||||||
|
['Uhrzeit' => date('H:i', time() + 60), 'Solltemperatur' => 60],
|
||||||
|
], JSON_THROW_ON_ERROR));
|
||||||
|
IPS_ApplyChanges($verbraucherId);
|
||||||
|
$warteAufKontakte([false, false, true]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user