feat(manager): Energieaufzeichnung und Visualisierungen integrieren
Tests / test (push) Successful in 47s

This commit is contained in:
dh
2026-09-27 19:29:37 +00:00
parent 40f41a2fb8
commit 708a8ecea2
11 changed files with 1426 additions and 56 deletions
+6 -3
View File
@@ -119,9 +119,12 @@ final class DemoanlageBootstrapTest extends TestCase
self::assertStringContainsString("'AnlagenWechselrichter'", $source);
self::assertStringContainsString("'AnlagenPVFlaechen'", $source);
self::assertStringContainsString("'AnlagenBatterien'", $source);
self::assertStringContainsString("'PrognosePVVariableID' => \$pvDisplay", $source);
self::assertStringContainsString("'PrognoseHausverbrauchVariableID' => \$houseDisplay", $source);
self::assertStringContainsString("'PrognoseSOCVariableID' => \$batterySoc", $source);
self::assertStringContainsString("'EnergyPieAnzeigen' => true", $source);
self::assertStringContainsString("'EnergiediagrammeAnzeigen' => true", $source);
self::assertStringContainsString("'FunFactsAnzeigen' => true", $source);
self::assertStringContainsString("'EnergieflussAnzeigen' => true", $source);
self::assertStringContainsString("'LeistungVariableID' => \$batteryActual", $source);
self::assertStringContainsString("'SOCVariableID' => \$batterySoc", $source);
self::assertStringContainsString("'PrognoseSendeintervall' => 60", $source);
self::assertStringContainsString("'IstleistungVariableID' => \$inverterActual", $source);
self::assertStringContainsString("'BegrenzungVariableID' => \$inverterLimit", $source);
+66
View File
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Belevo\EnelixEMS\Tests;
use Belevo\EnelixEMS\EnergieMessung;
use PHPUnit\Framework\TestCase;
final class EnergieMessungTest extends TestCase
{
public function testIntegriertVierLeistungenMitVorzeichenrichtung(): void
{
$werte = EnergieMessung::energieDeltas([
'PV' => 7200.0,
'Haus' => 3600.0,
'Netz' => -1800.0,
'Batterie' => 900.0,
], 300);
self::assertEqualsWithDelta(0.6, $werte['PVEnergie'], 0.000001);
self::assertEqualsWithDelta(0.3, $werte['Hausenergie'], 0.000001);
self::assertSame(0.0, $werte['NetzbezugEnergie']);
self::assertEqualsWithDelta(0.15, $werte['EinspeisungEnergie'], 0.000001);
self::assertEqualsWithDelta(0.075, $werte['BatterieLadenEnergie'], 0.000001);
self::assertSame(0.0, $werte['BatterieEntladenEnergie']);
}
public function testTrenntBezugUndBatterieentladung(): void
{
$werte = EnergieMessung::energieDeltas([
'PV' => -10.0,
'Haus' => -10.0,
'Netz' => 1000.0,
'Batterie' => -2000.0,
], 3600);
self::assertSame(0.0, $werte['PVEnergie']);
self::assertSame(0.0, $werte['Hausenergie']);
self::assertSame(1.0, $werte['NetzbezugEnergie']);
self::assertSame(0.0, $werte['EinspeisungEnergie']);
self::assertSame(0.0, $werte['BatterieLadenEnergie']);
self::assertSame(2.0, $werte['BatterieEntladenEnergie']);
}
public function testBerechnetHausverbrauchAusDerAnlagenbilanz(): void
{
self::assertSame(2700.0, EnergieMessung::hausleistung(4200.0, -800.0, 700.0));
self::assertSame(3500.0, EnergieMessung::hausleistung(2000.0, 500.0, -1000.0));
self::assertSame(0.0, EnergieMessung::hausleistung(500.0, -1200.0, 0.0));
}
public function testIgnoriertUngueltigeDauerUndNichtEndlicheWerte(): void
{
$werte = EnergieMessung::energieDeltas([
'PV' => INF,
'Haus' => NAN,
'Netz' => 1000.0,
'Batterie' => -1000.0,
], -1);
foreach ($werte as $wert) {
self::assertSame(0.0, $wert);
}
}
}
+93
View File
@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Belevo\EnelixEMS\Tests;
use PHPUnit\Framework\TestCase;
final class ManagerEnergieModulstrukturTest extends TestCase
{
public function testManagerKonfiguriertMessquellenUndArchivregeln(): void
{
$modul = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
$trait = (string) file_get_contents(__DIR__ . '/../libs/ManagerEnergieTrait.php');
$formular = (string) file_get_contents(__DIR__ . '/../Manager/form.json');
foreach ([
"RegisterPropertyBoolean('EnergyPieAnzeigen', false)",
"RegisterPropertyBoolean('EnergiediagrammeAnzeigen', false)",
"RegisterPropertyBoolean('FunFactsAnzeigen', false)",
"RegisterPropertyBoolean('EnergieflussAnzeigen', false)",
"RegisterPropertyInteger('LeistungsaufzeichnungMinuten', 1)",
"RegisterPropertyInteger('LeistungLoeschenMonate', 12)",
"RegisterPropertyInteger('EnergieaufzeichnungMinuten', 5)",
"RegisterPropertyInteger('EnergieVerdichtenMonate', 12)",
"RegisterPropertyInteger('EnergieLoeschenMonate', 0)",
] as $erwartet) {
self::assertStringContainsString($erwartet, $modul);
}
foreach ([
'AC_SetLoggingStatus',
'AC_SetAggregationType',
'AC_SetCompaction',
'AC_ReAggregateVariable',
'IPS_CreateMedia(4)',
'IPS_SetMediaContent',
'ENERGY_PIE_MODULE_ID',
'ENERGY_FLOW_MODULE_ID',
'energieflussKnoten',
'IPS_DeleteInstance',
'IPS_DeleteMedia',
] as $erwartet) {
self::assertStringContainsString($erwartet, $modul . $trait);
}
foreach ([
'Energieaufzeichnung',
'FormEnergyPieAnzeigen',
'FormEnergiediagrammeAnzeigen',
'FormFunFactsAnzeigen',
'FormEnergieflussAnzeigen',
'MesswerteAnzeigen',
'IstleistungVariableID',
'LeistungVariableID',
'SOCVariableID',
] as $erwartet) {
self::assertStringContainsString($erwartet, $formular);
}
}
public function testManagerFuehrtAlleMessvariablenUndRichtungszaehler(): void
{
$modul = (string) file_get_contents(__DIR__ . '/../Manager/module.php');
foreach ([
'PVLeistungArchiv',
'HausverbrauchLeistungArchiv',
'NetzleistungArchiv',
'BatterieleistungArchiv',
'PVEnergie',
'Hausenergie',
'NetzbezugEnergie',
'EinspeisungEnergie',
'BatterieLadenEnergie',
'BatterieEntladenEnergie',
] as $ident) {
self::assertStringContainsString("'" . $ident . "'", $modul);
}
self::assertStringContainsString("RegisterTimer(
'MesswerteAufzeichnen'", $modul);
self::assertStringContainsString('EnergieMessung::energieDeltas', $modul);
}
public function testFunFactsSindResponsivUndErklaerenUmrechnungen(): void
{
$trait = (string) file_get_contents(__DIR__ . '/../libs/ManagerEnergieTrait.php');
self::assertStringContainsString('grid-template-columns:repeat(3,minmax(0,1fr))', $trait);
self::assertStringContainsString('@media(max-width:820px)', $trait);
self::assertStringContainsString('10 kWh pro Liter Heizoel', $trait);
self::assertStringContainsString('2,4 Flugkilometern', $trait);
self::assertStringContainsString('AC_GetAggregatedValues', $trait);
}
}
+8 -3
View File
@@ -66,9 +66,14 @@ final class ManagerModulstrukturTest extends TestCase
'AnlagenWechselrichter',
'AnlagenPVFlaechen',
'AnlagenBatterien',
'PrognosePVVariableID',
'PrognoseHausverbrauchVariableID',
'PrognoseSOCVariableID',
'Istleistungsfaktor',
'LeistungVariableID',
'Leistungsfaktor',
'SOCVariableID',
'EnergyPieAnzeigen',
'EnergiediagrammeAnzeigen',
'FunFactsAnzeigen',
'EnergieflussAnzeigen',
'PrognoseSendeintervall',
'StoerueberwachungAktiv',
'StoerungsSendeintervall',
+87 -1
View File
@@ -5,7 +5,10 @@ declare(strict_types=1);
use Belevo\EnelixEMS\SymconTest\TestContext;
return static function (TestContext $test): void {
$netzleistungId = $test->createVariable(2, 'Netzleistung', 0.0);
$netzleistungId = $test->createVariable(2, 'Netzleistung', -800.0);
$pvLeistungId = $test->createVariable(2, 'PV-Leistung', 4200.0);
$batterieLeistungId = $test->createVariable(2, 'Batterieleistung', 700.0);
$batterieSocId = $test->createVariable(2, 'Batterie-Ladezustand', 62.0);
$einKontaktId = $test->createActionVariable('Kontakt Verbraucher 1-Stufig');
$einStufigId = $test->createInstance(
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
@@ -79,6 +82,8 @@ return static function (TestContext $test): void {
'ACNennleistung_kW' => 10.0,
'ACEinspeisegrenze_kW' => 8.0,
'ACBezugsgrenze_kW' => 0.0,
'IstleistungVariableID' => $pvLeistungId,
'Istleistungsfaktor' => 1.0,
]];
$pvKonfiguration = [[
'ID' => 'pv-1',
@@ -100,6 +105,9 @@ return static function (TestContext $test): void {
'MaxEntladeleistung_kW' => 5.0,
'WechselrichterID' => 'hybrid-1',
'Kopplung' => 'hybrid',
'LeistungVariableID' => $batterieLeistungId,
'Leistungsfaktor' => 1.0,
'SOCVariableID' => $batterieSocId,
]];
$lizenzcode = trim((string) getenv('ENELIX_TEST_LICENSE_CODE'));
$managerId = $test->createInstance(
@@ -107,6 +115,10 @@ return static function (TestContext $test): void {
'Manager',
[
'NetzleistungVariableID' => $netzleistungId,
'EnergyPieAnzeigen' => true,
'EnergiediagrammeAnzeigen' => true,
'FunFactsAnzeigen' => true,
'EnergieflussAnzeigen' => true,
'Lizenzcode' => $lizenzcode,
'AutomatischeSuche' => false,
'VerbraucherZuordnung' => json_encode($zuordnung, JSON_THROW_ON_ERROR),
@@ -214,6 +226,80 @@ return static function (TestContext $test): void {
$test->assertSame(['pv-1'], $topologie['sharedAcLimits'][0]['pvArrayIds'] ?? null);
$test->assertSame(['bat-1'], $topologie['sharedAcLimits'][0]['batteryIds'] ?? null);
});
$test->runCase('Energiewerte, Archivregeln und Unterobjekte werden erzeugt', static function (
TestContext $test
) use ($managerId): void {
IPS_RequestAction($managerId, 'MesswerteAufzeichnen', true);
$test->assertSame(
4200.0,
GetValue($test->objectByIdent('PVLeistungArchiv', $managerId))
);
$test->assertSame(
2700.0,
GetValue($test->objectByIdent('HausverbrauchLeistungArchiv', $managerId))
);
$test->assertSame(
-800.0,
GetValue($test->objectByIdent('NetzleistungArchiv', $managerId))
);
$test->assertSame(
700.0,
GetValue($test->objectByIdent('BatterieleistungArchiv', $managerId))
);
$archive = IPS_GetInstanceListByModuleID(
'{43192F0B-135B-4CE7-A0A7-1475603F3060}'
);
$test->assertTrue($archive !== []);
$archivID = (int) $archive[0];
$leistungID = $test->objectByIdent('PVLeistungArchiv', $managerId);
$energieID = $test->objectByIdent('PVEnergie', $managerId);
$test->assertSame(true, AC_GetLoggingStatus($archivID, $leistungID));
$test->assertSame(0, AC_GetAggregationType($archivID, $leistungID));
$test->assertSame(1, AC_GetAggregationType($archivID, $energieID));
foreach (['Leistungsdiagramm', 'Energiediagramm'] as $ident) {
$medienID = $test->objectByIdent($ident, $managerId);
$test->assertSame(4, (int) IPS_GetMedia($medienID)['MediaType']);
}
$html = (string) GetValue($test->objectByIdent('EnergieFunFacts', $managerId));
$test->assertTrue(str_contains($html, 'Solar'));
$test->assertTrue(str_contains($html, 'Netz &amp; Haus'));
$energieflussID = $test->objectByIdent('Energiefluss', $managerId);
$test->assertSame(
'{BA90FDB3-C203-8F26-B4D6-F3DB99905724}',
IPS_GetInstance($energieflussID)['ModuleInfo']['ModuleID']
);
IPS_RequestAction($managerId, 'FormEnergieflussAnzeigen', false);
$test->assertSame(true, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
IPS_RequestAction($managerId, 'FormEnergieflussAnzeigen', true);
$test->assertSame(false, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
foreach ([
'EnergyPieAnzeigen',
'EnergiediagrammeAnzeigen',
'FunFactsAnzeigen',
'EnergieflussAnzeigen',
] as $property) {
IPS_SetProperty($managerId, $property, false);
}
IPS_ApplyChanges($managerId);
foreach ([
'EnergyPie',
'Leistungsdiagramm',
'Energiediagramm',
'EnergieFunFacts',
] as $ident) {
$test->assertSame(
false,
@IPS_GetObjectIDByIdent($ident, $managerId),
$ident . ' wurde beim Ausschalten nicht entfernt.'
);
}
$test->assertSame(true, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
});
$zustandswert = static function (array $daten, int $instanzId, string $kennung) {
foreach ($daten['Verbraucher'] ?? [] as $verbraucher) {
if (($verbraucher['InstanzID'] ?? 0) !== $instanzId) {