fix(manager): feste Leistungsangebote immer zuteilen
This commit is contained in:
@@ -90,6 +90,12 @@ melden, ohne dass der Manager seine interne Geraetelogik kennen muss.
|
||||
## Feste Regeln
|
||||
|
||||
- Prioritaeten beginnen bei 0; eine kleinere Zahl bedeutet hoehere Prioritaet.
|
||||
- Jeder verfuegbare, synchronisierte Verbraucher mit einem nicht leeren
|
||||
`Leistungswerte_W`-Angebot erhaelt einen Sollwert aus genau diesem Angebot.
|
||||
- `AenderungMoeglich=false` kennzeichnet ein fixes Angebot und ist kein
|
||||
Ausschlussgrund. Ein Angebot `[11000]` fuehrt deshalb zwingend zu `11000 W`.
|
||||
- Prioritaeten verteilen nur die ueber den jeweiligen Mindestwert hinaus
|
||||
verfuegbare Leistung; sie duerfen keinen angebotenen Mindestwert verdrängen.
|
||||
- `Leistungsquelle`: 0 nicht vorhanden, 1 berechnet, 2 gemessen.
|
||||
- Bei Leistungsquelle 0 ist `Istleistung_W` zwingend `null`.
|
||||
- Leistungsbereiche enthalten jeden ganzen Wattwert von `Von_W` bis `Bis_W`.
|
||||
|
||||
@@ -302,14 +302,19 @@ der aktiven Betriebsart und der aktuellen Leistung aller frisch gemeldeten
|
||||
Verbraucher. Eine gültige Istleistung wird bevorzugt; fehlt sie, bleibt der im
|
||||
Zustand bestätigte Sollwert konservativ reserviert.
|
||||
|
||||
Nicht verfügbare, nicht änderbare oder aktuell angebotlose Verbraucher behalten
|
||||
ihre Leistung und erhalten keine neue Vorgabe. Die übrigen Verbraucher werden
|
||||
nach der gemeldeten PV- beziehungsweise Peak-Priorität und danach stabil nach
|
||||
Instanz-ID sortiert. Von ihrem jeweils kleinsten erlaubten Leistungswert aus
|
||||
wird das Budget in dieser Reihenfolge aufgefüllt. Einzelwerte und ganzzahlige
|
||||
Bereiche werden direkt verarbeitet; Lücken werden nie durch unzulässige Werte
|
||||
geschlossen. Eine verbleibende Abweichung wird im `Verbraucherstatus`
|
||||
dokumentiert.
|
||||
Nicht verfügbare oder aktuell angebotlose Verbraucher behalten ihre Leistung
|
||||
und erhalten keine neue Vorgabe. Jeder verfügbare, synchronisierte Verbraucher
|
||||
mit einem nicht leeren Angebot erhält dagegen einen Sollwert aus diesem Angebot.
|
||||
Das gilt auch bei `AenderungMoeglich=false`: Ein fixes Angebot wie `[11000]`
|
||||
wird mit genau `11000 W` zugeteilt.
|
||||
|
||||
Die Verbraucher werden nach der gemeldeten PV- beziehungsweise Peak-Priorität
|
||||
und danach stabil nach Instanz-ID sortiert. Zuerst reserviert der Manager für
|
||||
jeden Verbraucher den kleinsten erlaubten Leistungswert. Nur das danach
|
||||
verbleibende Budget wird in Prioritätsreihenfolge aufgefüllt. Einzelwerte und
|
||||
ganzzahlige Bereiche werden direkt verarbeitet; Lücken werden nie durch
|
||||
unzulässige Werte geschlossen. Eine verbleibende Abweichung wird im
|
||||
`Verbraucherstatus` dokumentiert.
|
||||
|
||||
Die Betriebsart wechselt unterhalb des Solar-Sollwerts zu `PV` und oberhalb
|
||||
der wirksamen Lastspitzengrenze zu `Peak`. Zwischen den beiden Zielwerten
|
||||
|
||||
@@ -120,7 +120,7 @@ final class ManagerRegler
|
||||
$aktuelleLeistung += $leistung;
|
||||
|
||||
$daten = $eintrag['Daten'];
|
||||
if (!$daten['Verfuegbar'] || !$daten['AenderungMoeglich'] || $daten['Leistungswerte_W'] === []) {
|
||||
if (!$daten['Verfuegbar'] || $daten['Leistungswerte_W'] === []) {
|
||||
$nichtSteuerbar += $leistung;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -113,19 +113,19 @@ final class ManagerReglerTest extends TestCase
|
||||
self::assertSame(500, $ergebnis['Restabweichung_W']);
|
||||
}
|
||||
|
||||
public function testNichtAenderbarerVerbraucherReserviertSeineIstleistung(): void
|
||||
public function testFestwertWirdUnabhaengigVonAenderungMoeglichZugewiesen(): void
|
||||
{
|
||||
$fest = $this->verbraucher(10, 0, [0, 3000], 3000, false);
|
||||
$fest = $this->verbraucher(10, 0, [3000], 3000, false);
|
||||
$steuerbar = $this->verbraucher(20, 1, [0, ['Von_W' => 1, 'Bis_W' => 4000]], 0);
|
||||
|
||||
$ergebnis = ManagerRegler::verteile(3000.0, 5000.0, [$fest, $steuerbar], 'PrioritaetPV');
|
||||
|
||||
self::assertSame(3000, $ergebnis['NichtSteuerbar_W']);
|
||||
self::assertSame([20 => 2000], $ergebnis['Sollwerte']);
|
||||
self::assertSame(0, $ergebnis['NichtSteuerbar_W']);
|
||||
self::assertSame([10 => 3000, 20 => 2000], $ergebnis['Sollwerte']);
|
||||
self::assertSame(0, $ergebnis['Restabweichung_W']);
|
||||
}
|
||||
|
||||
public function testVeralteterVerbraucherBlockiertUeberschussverteilungNicht(): void
|
||||
public function testFestwerteWerdenMitHoeherPriorisierterBatterieZugewiesen(): void
|
||||
{
|
||||
$ergebnis = ManagerRegler::verteile(
|
||||
-2411.0,
|
||||
@@ -147,7 +147,13 @@ final class ManagerReglerTest extends TestCase
|
||||
|
||||
self::assertSame(12562, $ergebnis['Verteilbudget_W']);
|
||||
self::assertSame(
|
||||
[44234 => 2411, 29743 => 0, 38676 => 0],
|
||||
[
|
||||
44234 => -12288,
|
||||
29743 => 0,
|
||||
38676 => 0,
|
||||
43878 => 13850,
|
||||
46052 => 11000,
|
||||
],
|
||||
$ergebnis['Sollwerte']
|
||||
);
|
||||
self::assertSame(0, $ergebnis['Restabweichung_W']);
|
||||
@@ -155,7 +161,7 @@ final class ManagerReglerTest extends TestCase
|
||||
|
||||
public function testFehlendeIstleistungFaelltAufAngenommenenSollwertZurueck(): void
|
||||
{
|
||||
$verbraucher = $this->verbraucher(10, 0, [0, 3000], null, false);
|
||||
$verbraucher = $this->verbraucher(10, 0, [3000], null, false);
|
||||
$verbraucher['Daten']['Leistungsquelle'] = Nachrichtenvertrag::LEISTUNGSQUELLE_NICHT_VORHANDEN;
|
||||
$verbraucher['Daten']['Istleistung_W'] = null;
|
||||
$verbraucher['Daten']['Zustand'][0]['Wert'] = 3000;
|
||||
@@ -163,6 +169,7 @@ final class ManagerReglerTest extends TestCase
|
||||
$ergebnis = ManagerRegler::verteile(3000.0, 0.0, [$verbraucher], 'PrioritaetPV');
|
||||
|
||||
self::assertSame(3000, $ergebnis['AktuelleVerbraucherleistung_W']);
|
||||
self::assertSame([10 => 3000], $ergebnis['Sollwerte']);
|
||||
self::assertSame(-3000, $ergebnis['Restabweichung_W']);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user