fix(manager): Batterie nach Prioritaet als Restverbraucher regeln
Tests / test (push) Canceled after 0s

This commit is contained in:
dh
2026-09-30 05:42:13 +00:00
parent bfdcf4536b
commit add1077674
3 changed files with 15 additions and 76 deletions
+4 -47
View File
@@ -761,27 +761,13 @@ class Manager extends IPSModule implements ManagerSchnittstelle
$fahrplanVorgabe = $this->aktuelleNetzfahrplanVorgabe(); $fahrplanVorgabe = $this->aktuelleNetzfahrplanVorgabe();
$zielnetzleistung = $betriebsart === ManagerRegler::BETRIEBSART_PEAK $zielnetzleistung = $betriebsart === ManagerRegler::BETRIEBSART_PEAK
? (float) $lastspitzengrenze ? (float) $lastspitzengrenze
: ($fahrplanVorgabe['Netzleistung_W'] : ($fahrplanVorgabe ?? $this->ReadPropertyFloat('SollwertSolarladen'));
?? $this->ReadPropertyFloat('SollwertSolarladen'));
$vorgegebeneSollwerte = [];
if ($betriebsart !== ManagerRegler::BETRIEBSART_PEAK
&& is_array($fahrplanVorgabe)
&& is_float($fahrplanVorgabe['Batterieleistung_W'])
) {
$batterieIDs = $this->aktiveBatterieVerbraucherIDs($verbraucher);
if (count($batterieIDs) === 1) {
$vorgegebeneSollwerte[$batterieIDs[0]] = (int) round(
$fahrplanVorgabe['Batterieleistung_W']
);
}
}
$ergebnis = ManagerRegler::verteile( $ergebnis = ManagerRegler::verteile(
$netzleistung, $netzleistung,
$zielnetzleistung, $zielnetzleistung,
$verbraucher, $verbraucher,
$betriebsart === ManagerRegler::BETRIEBSART_PEAK ? 'PrioritaetPeak' : 'PrioritaetPV', $betriebsart === ManagerRegler::BETRIEBSART_PEAK ? 'PrioritaetPeak' : 'PrioritaetPV',
$this->bezogeneVerbraucherEnergienWh(), $this->bezogeneVerbraucherEnergienWh()
$vorgegebeneSollwerte
); );
$this->setzeDiagnosewert('Verteilbudget', (float) $ergebnis['Verteilbudget_W']); $this->setzeDiagnosewert('Verteilbudget', (float) $ergebnis['Verteilbudget_W']);
$this->setzeDiagnosewert('Verbraucherstatus', json_encode([ $this->setzeDiagnosewert('Verbraucherstatus', json_encode([
@@ -2754,8 +2740,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
&& $this->aktuelleBatterieSoc() !== null; && $this->aktuelleBatterieSoc() !== null;
} }
/** @return array{Netzleistung_W: float, Batterieleistung_W: ?float}|null */ private function aktuelleNetzfahrplanVorgabe(): ?float
private function aktuelleNetzfahrplanVorgabe(): ?array
{ {
if (!$this->ReadPropertyBoolean('NetzfahrplanAktiv')) { if (!$this->ReadPropertyBoolean('NetzfahrplanAktiv')) {
return null; return null;
@@ -2789,42 +2774,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
} }
$abstand = abs($zeitpunkt - $jetzt); $abstand = abs($zeitpunkt - $jetzt);
if ($abstand < $naechsterAbstand) { if ($abstand < $naechsterAbstand) {
$batteryTarget = $punkt['batteryTargetW'] ?? null;
$naechsterAbstand = $abstand; $naechsterAbstand = $abstand;
$vorgabe = [ $vorgabe = (float) $punkt['gridTargetW'];
'Netzleistung_W' => (float) $punkt['gridTargetW'],
'Batterieleistung_W' => is_int($batteryTarget) || is_float($batteryTarget)
? (float) $batteryTarget
: null,
];
} }
} }
return $naechsterAbstand <= 1800 ? $vorgabe : null; return $naechsterAbstand <= 1800 ? $vorgabe : null;
} }
/**
* @param list<array{InstanzID: int, Daten: array<string, mixed>}> $verbraucher
* @return list<int>
*/
private function aktiveBatterieVerbraucherIDs(array $verbraucher): array
{
$ids = [];
foreach ($verbraucher as $eintrag) {
$instanzID = $eintrag['InstanzID'];
if (!IPS_InstanceExists($instanzID)) {
continue;
}
$instanz = IPS_GetInstance($instanzID);
$moduleID = strtoupper((string) ($instanz['ModuleInfo']['ModuleID'] ?? ''));
if ((self::VERBRAUCHER_LIZENZEN[$moduleID]['Katalog'] ?? null) === 'battery') {
$ids[] = $instanzID;
}
}
return $ids;
}
private function synchronisiereAnlagentopologie(): void private function synchronisiereAnlagentopologie(): void
{ {
try { try {
+4 -20
View File
@@ -106,8 +106,7 @@ final class ManagerRegler
float $zielnetzleistung, float $zielnetzleistung,
array $verbraucher, array $verbraucher,
string $prioritaetsfeld, string $prioritaetsfeld,
array $bezogeneEnergieWh = [], array $bezogeneEnergieWh = []
array $vorgegebeneSollwerte = []
): array { ): array {
if (!in_array($prioritaetsfeld, ['PrioritaetPV', 'PrioritaetPeak'], true)) { if (!in_array($prioritaetsfeld, ['PrioritaetPV', 'PrioritaetPeak'], true)) {
throw new InvalidArgumentException('Unbekanntes Prioritaetsfeld.'); throw new InvalidArgumentException('Unbekanntes Prioritaetsfeld.');
@@ -130,13 +129,7 @@ final class ManagerRegler
$festwert = self::istFestwert($daten['Leistungswerte_W']); $festwert = self::istFestwert($daten['Leistungswerte_W']);
$festgehalten = !$daten['AenderungMoeglich']; $festgehalten = !$daten['AenderungMoeglich'];
$vorgegebenerSollwert = $vorgegebeneSollwerte[$eintrag['InstanzID']] ?? null; if ($festwert || $festgehalten) {
$vorgegeben = is_int($vorgegebenerSollwert)
&& Nachrichtenvertrag::enthaeltLeistungswert(
$daten['Leistungswerte_W'],
$vorgegebenerSollwert
);
if (($festwert || $festgehalten) && !$vorgegeben) {
$nichtSteuerbar += $leistung; $nichtSteuerbar += $leistung;
} }
@@ -153,8 +146,6 @@ final class ManagerRegler
'Leistungswerte_W' => $daten['Leistungswerte_W'], 'Leistungswerte_W' => $daten['Leistungswerte_W'],
'Festwert' => $festwert, 'Festwert' => $festwert,
'Festgehalten' => $festgehalten, 'Festgehalten' => $festgehalten,
'Vorgegeben' => $vorgegeben,
'VorgegebenerSollwert' => $vorgegeben ? $vorgegebenerSollwert : null,
'Sollwert' => self::angenommenerSollwert($daten), 'Sollwert' => self::angenommenerSollwert($daten),
]; ];
} }
@@ -176,11 +167,6 @@ final class ManagerRegler
$sollwerte = []; $sollwerte = [];
$ausgangssumme = 0; $ausgangssumme = 0;
foreach ($steuerbar as $eintrag) { foreach ($steuerbar as $eintrag) {
if ($eintrag['Vorgegeben']) {
$sollwerte[$eintrag['InstanzID']] = $eintrag['VorgegebenerSollwert'];
$ausgangssumme += $eintrag['VorgegebenerSollwert'];
continue;
}
if ($eintrag['Festwert']) { if ($eintrag['Festwert']) {
$sollwerte[$eintrag['InstanzID']] = self::kleinsterLeistungswert( $sollwerte[$eintrag['InstanzID']] = self::kleinsterLeistungswert(
$eintrag['Leistungswerte_W'] $eintrag['Leistungswerte_W']
@@ -204,7 +190,7 @@ final class ManagerRegler
$rest = $verteilbudget - $nichtSteuerbar - $ausgangssumme; $rest = $verteilbudget - $nichtSteuerbar - $ausgangssumme;
foreach ($steuerbar as $eintrag) { foreach ($steuerbar as $eintrag) {
if ($eintrag['Vorgegeben'] || $eintrag['Festwert'] || $eintrag['Festgehalten']) { if ($eintrag['Festwert'] || $eintrag['Festgehalten']) {
continue; continue;
} }
@@ -233,9 +219,7 @@ final class ManagerRegler
$zugeteilt = $nichtSteuerbar; $zugeteilt = $nichtSteuerbar;
foreach ($steuerbar as $eintrag) { foreach ($steuerbar as $eintrag) {
if ($eintrag['Vorgegeben'] if (!$eintrag['Festwert'] && !$eintrag['Festgehalten']) {
|| (!$eintrag['Festwert'] && !$eintrag['Festgehalten'])
) {
$zugeteilt += $sollwerte[$eintrag['InstanzID']]; $zugeteilt += $sollwerte[$eintrag['InstanzID']];
} }
} }
+7 -9
View File
@@ -333,26 +333,24 @@ final class ManagerReglerTest extends TestCase
self::assertSame(-3000, $ergebnis['Restabweichung_W']); self::assertSame(-3000, $ergebnis['Restabweichung_W']);
} }
public function testExpliziterBatteriefahrplanBleibtVonAnderenVerbrauchernUnveraendert(): void public function testBatterieMitTieferPrioritaetUebernimmtNichtNutzbarenRest(): void
{ {
$ergebnis = ManagerRegler::verteile( $ergebnis = ManagerRegler::verteile(
-5000.0,
0.0, 0.0,
1000.0,
[ [
$this->verbraucher(20, 1, [0, 3000, 6000], 0),
$this->verbraucher( $this->verbraucher(
10, 10,
0, 6,
[['Von_W' => -5000, 'Bis_W' => 5000]], [['Von_W' => 0, 'Bis_W' => 10000]],
0 0
), ),
$this->verbraucher(20, 1, [0, 3000], 0),
], ],
'PrioritaetPV', 'PrioritaetPV'
[],
[10 => 1000]
); );
self::assertSame([10 => 1000, 20 => 0], $ergebnis['Sollwerte']); self::assertSame([20 => 3000, 10 => 2000], $ergebnis['Sollwerte']);
self::assertSame(0, $ergebnis['Restabweichung_W']); self::assertSame(0, $ergebnis['Restabweichung_W']);
} }