Verbrauchermodule und betriebsartabhängige Angebote ergänzen
Tests / test (push) Successful in 42s

This commit is contained in:
dh
2026-09-21 18:46:17 +00:00
parent 7b6d1b2f07
commit 3c71626b5f
46 changed files with 4513 additions and 311 deletions
+58 -17
View File
@@ -24,6 +24,8 @@ class Manager extends IPSModule implements ManagerSchnittstelle
private const VERBRAUCHER_MODUL_IDS = [
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}',
];
private const MONATSNAMEN = [
1 => 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni',
@@ -357,25 +359,44 @@ class Manager extends IPSModule implements ManagerSchnittstelle
return;
}
$stoerungen = [];
$verbraucher = $this->aktuelleVerbraucher($stoerungen);
$lastspitzengrenze = ManagerRegler::wirksameLastspitzengrenze(
$this->ReadPropertyInteger('Lastspitzenmodus'),
$this->ReadPropertyFloat('Lastspitzengrenze'),
$this->dekodiereMonatsgrenzen($this->ReadPropertyString('Monatsgrenzen')),
(int) date('n')
);
$bisherigeBetriebsart = (string) $this->GetValue('Betriebsart');
$betriebsart = ManagerRegler::bestimmeBetriebsart(
true,
true,
$netzleistung,
(string) $this->GetValue('Betriebsart'),
$bisherigeBetriebsart,
$lastspitzengrenze !== null,
$this->ReadPropertyFloat('SollwertSolarladen'),
$lastspitzengrenze ?? 0.0,
$this->ReadPropertyFloat('Umschaltdifferenz')
);
$this->SetValue('Betriebsart', $betriebsart);
if ($betriebsart !== $bisherigeBetriebsart) {
$this->WriteAttributeString('LetzteSollwerte', '{}');
}
$stoerungen = [];
$synchronisiert = true;
$verbraucher = $this->aktuelleVerbraucher($stoerungen, $betriebsart, $synchronisiert);
$this->setzeDiagnosewert('WirksameLastspitzengrenze', $lastspitzengrenze ?? 0.0);
if (!$synchronisiert) {
$this->setzeDiagnosewert('Verteilbudget', 0.0);
$this->setzeDiagnosewert('Verbraucherstatus', json_encode([
'Betriebsart' => $betriebsart,
'Synchronisiert' => false,
'Verbraucher' => $verbraucher,
], JSON_THROW_ON_ERROR));
$this->aktualisiereStoerungen($verbraucher, $stoerungen);
$this->SetStatus(self::STATUS_AKTIV);
return;
}
$zielnetzleistung = $betriebsart === ManagerRegler::BETRIEBSART_PEAK
? (float) $lastspitzengrenze
: $this->ReadPropertyFloat('SollwertSolarladen');
@@ -385,12 +406,10 @@ class Manager extends IPSModule implements ManagerSchnittstelle
$verbraucher,
$betriebsart === ManagerRegler::BETRIEBSART_PEAK ? 'PrioritaetPeak' : 'PrioritaetPV'
);
$this->SetValue('Betriebsart', $betriebsart);
$this->setzeDiagnosewert('WirksameLastspitzengrenze', $lastspitzengrenze ?? 0.0);
$this->setzeDiagnosewert('Verteilbudget', (float) $ergebnis['Verteilbudget_W']);
$this->setzeDiagnosewert('Verbraucherstatus', json_encode([
'Betriebsart' => $betriebsart,
'Synchronisiert' => true,
'Restabweichung_W' => $ergebnis['Restabweichung_W'],
'Verbraucher' => $verbraucher,
], JSON_THROW_ON_ERROR));
@@ -401,7 +420,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
continue;
}
try {
$this->sendeSollwert((int) $instanzID, $sollleistung);
$this->sendeManagerdaten((int) $instanzID, $betriebsart, $sollleistung);
$letzteSollwerte[(string) $instanzID] = $sollleistung;
} catch (Throwable $fehler) {
$stoerungen[] = 'Sollwert an Instanz ' . $instanzID . ': ' . $fehler->getMessage();
@@ -437,8 +456,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
* @param list<string> $stoerungen
* @return list<array{InstanzID: int, Daten: array<string, mixed>}>
*/
private function aktuelleVerbraucher(array &$stoerungen): array
{
private function aktuelleVerbraucher(
array &$stoerungen,
string $betriebsart,
bool &$synchronisiert
): array {
$ids = $this->aktiveVerbraucherIDs();
$this->setzeDiagnosewert('VerbraucherAnzahl', count($ids));
$cache = $this->leseJsonAttribut('VerbraucherCache');
@@ -447,12 +469,23 @@ class Manager extends IPSModule implements ManagerSchnittstelle
foreach ($ids as $instanzID) {
$eintrag = $cache[(string) $instanzID] ?? null;
$grund = '';
if (!is_array($eintrag) || !isset($eintrag['EmpfangenAm'], $eintrag['Daten'])) {
$stoerungen[] = 'Noch keine Meldung von Instanz ' . $instanzID . '.';
continue;
$grund = 'Noch keine Meldung';
} elseif (time() - (int) $eintrag['EmpfangenAm'] > $timeout) {
$grund = 'Meldung ist veraltet';
} elseif (($eintrag['Daten']['Betriebsart'] ?? null) !== $betriebsart) {
$grund = 'Leistungsangebot gehoert nicht zur Betriebsart ' . $betriebsart;
}
if (time() - (int) $eintrag['EmpfangenAm'] > $timeout) {
$stoerungen[] = 'Meldung von Instanz ' . $instanzID . ' ist veraltet.';
if ($grund !== '') {
$synchronisiert = false;
$stoerungen[] = $grund . ' von Instanz ' . $instanzID . '.';
try {
$this->sendeManagerdaten($instanzID, $betriebsart, null);
} catch (Throwable $fehler) {
$stoerungen[] = 'Betriebsart an Instanz ' . $instanzID . ': ' . $fehler->getMessage();
}
continue;
}
$aktuell[] = ['InstanzID' => $instanzID, 'Daten' => $eintrag['Daten']];
@@ -624,8 +657,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
return false;
}
private function sendeSollwert(int $instanzID, int $sollleistung): void
{
private function sendeManagerdaten(
int $instanzID,
string $betriebsart,
?int $sollleistung
): void {
if (!IPS_InstanceExists($instanzID)) {
throw new RuntimeException('Instanz existiert nicht.');
}
@@ -636,11 +672,16 @@ class Manager extends IPSModule implements ManagerSchnittstelle
'EmpfaengerID' => $instanzID,
'Zeitpunkt' => time(),
],
'Betriebsart' => $betriebsart,
'Sollleistung_W' => $sollleistung,
];
Nachrichtenvertrag::pruefeManagerdaten($paket);
IPS_RequestAction($instanzID, 'ManagerdatenEmpfangen', json_encode($paket, JSON_THROW_ON_ERROR));
$this->protokolliere('Sollwert', ['InstanzID' => $instanzID, 'Sollleistung_W' => $sollleistung]);
$this->protokolliere('Managerdaten', [
'InstanzID' => $instanzID,
'Betriebsart' => $betriebsart,
'Sollleistung_W' => $sollleistung,
]);
}
/**