Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
995b704e36 | ||
|
|
5ff0d405d4 |
+5
-7
@@ -2263,12 +2263,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
/** @param array<string, mixed> $lease */
|
||||
private function prognoseBerechtigungInLease(array $lease): bool
|
||||
{
|
||||
return Lizenzpruefung::berechtigungsMenge($lease, Lizenzpruefung::NETZFAHRPLAN) > 0
|
||||
|| (Lizenzpruefung::berechtigungsMenge($lease, Lizenzpruefung::PROGNOSE_PV) > 0
|
||||
&& Lizenzpruefung::berechtigungsMenge(
|
||||
$lease,
|
||||
Lizenzpruefung::PROGNOSE_VERBRAUCH
|
||||
) > 0);
|
||||
return Lizenzpruefung::hatPrognoseBerechtigung($lease);
|
||||
}
|
||||
|
||||
private function berechtigungLizenziert(string $kennung, ?string $lizenzcode = null): bool
|
||||
@@ -2418,7 +2413,10 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
if (!$lizenziert) {
|
||||
return 'Prognosen sind deaktiviert. Fuer die Manager-ID '
|
||||
. $managerID
|
||||
. ' fehlen forecast_pv plus forecast_load oder grid_schedule.';
|
||||
. ' ist keine Prognoseberechtigung vorhanden. Benoetigt wird entweder '
|
||||
. 'PV-Ertragsprognose zusammen mit Verbrauchsprognose oder der '
|
||||
. 'Intelligente Netzfahrplan. Nach der Erweiterung im Lizenzportal '
|
||||
. 'die Lizenz erneut pruefen und binden.';
|
||||
}
|
||||
|
||||
return ($aktiv ? 'Prognosen sind aktiviert. ' : 'Prognosen sind deaktiviert. ')
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -279,6 +279,7 @@ stabile ID gebunden werden.
|
||||
| HTTP `429` | Zu viele Aktivierungsversuche; vor dem naechsten Versuch warten. |
|
||||
| `Lizenzserver nicht erreichbar` | DNS, Internetzugang, HTTPS und Systemzeit des Symcon-Systems pruefen. Eine bestehende Lease gilt nur bis `offlineUntil`. |
|
||||
| `Offline-Freigabe ist abgelaufen.` | Verbindung zum Lizenzserver wiederherstellen und Lizenz erneut pruefen. |
|
||||
| `Keine Prognoseberechtigung vorhanden` | Im Lizenzportal entweder PV-Ertragsprognose zusammen mit Verbrauchsprognose oder den Intelligenten Netzfahrplan ergaenzen. Anschliessend im Manager `Lizenz pruefen und binden` ausloesen, die Prognose aktivieren und die Konfiguration speichern. |
|
||||
|
||||
Fuer eine genauere Diagnose koennen die Diagnosevariablen eingeblendet werden.
|
||||
`Lizenzstatus` zeigt dann den aktuellen Zustand. Mit aktiviertem Debug-Logging
|
||||
@@ -302,14 +303,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
|
||||
|
||||
@@ -117,6 +117,19 @@ final class Lizenzpruefung
|
||||
return $menge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Prognose ist entweder durch den Netzfahrplan oder durch beide
|
||||
* Einzelberechtigungen fuer PV und Verbrauch freigeschaltet.
|
||||
*
|
||||
* @param array<string, mixed> $lease
|
||||
*/
|
||||
public static function hatPrognoseBerechtigung(array $lease): bool
|
||||
{
|
||||
return self::berechtigungsMenge($lease, self::NETZFAHRPLAN) > 0
|
||||
|| (self::berechtigungsMenge($lease, self::PROGNOSE_PV) > 0
|
||||
&& self::berechtigungsMenge($lease, self::PROGNOSE_VERBRAUCH) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rechnet freie, bestehende Einzellizenzen auf nicht separat lizenzierte Waermepumpen an.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -228,6 +228,47 @@ final class LizenzpruefungTest extends TestCase
|
||||
Lizenzpruefung::pruefeVerbrauchermengen($lease, $pruefmengen);
|
||||
}
|
||||
|
||||
public function testPvUndVerbrauchGebenPrognoseFrei(): void
|
||||
{
|
||||
$lease = $this->lease('manager_standard');
|
||||
$lease['entitlements'][] = [
|
||||
'catalog_key' => Lizenzpruefung::PROGNOSE_PV,
|
||||
'quantity' => 1,
|
||||
'status' => 'active',
|
||||
];
|
||||
$lease['entitlements'][] = [
|
||||
'catalog_key' => Lizenzpruefung::PROGNOSE_VERBRAUCH,
|
||||
'quantity' => 1,
|
||||
'status' => 'active',
|
||||
];
|
||||
|
||||
self::assertTrue(Lizenzpruefung::hatPrognoseBerechtigung($lease));
|
||||
}
|
||||
|
||||
public function testEinzelnePrognoseBerechtigungReichtNichtAus(): void
|
||||
{
|
||||
$lease = $this->lease('manager_standard');
|
||||
$lease['entitlements'][] = [
|
||||
'catalog_key' => Lizenzpruefung::PROGNOSE_PV,
|
||||
'quantity' => 1,
|
||||
'status' => 'active',
|
||||
];
|
||||
|
||||
self::assertFalse(Lizenzpruefung::hatPrognoseBerechtigung($lease));
|
||||
}
|
||||
|
||||
public function testNetzfahrplanGibtPrognoseAlleineFrei(): void
|
||||
{
|
||||
$lease = $this->lease('manager_standard');
|
||||
$lease['entitlements'][] = [
|
||||
'catalog_key' => Lizenzpruefung::NETZFAHRPLAN,
|
||||
'quantity' => 1,
|
||||
'status' => 'active',
|
||||
];
|
||||
|
||||
self::assertTrue(Lizenzpruefung::hatPrognoseBerechtigung($lease));
|
||||
}
|
||||
|
||||
public function testLizenzcodeWirdWieAufDemServerNormalisiert(): void
|
||||
{
|
||||
self::assertSame(
|
||||
|
||||
@@ -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