feat(manager): integrate forecast controls and merge V4 development
Tests / test (push) Failing after 49s
Tests / test (push) Failing after 49s
Merge the V4 development history with current manager, SDL and setpoint fixes. Retain guarded trial behavior and consolidate controls in Prognose / Forecast. Exclude the unverified accounting-evidence change; no runtime deployment or new dispatch permission. Validated: 357 PHPUnit tests / 1758 assertions, 150 PHP syntax checks, 310 backend tests, 16 portal tests and isolated UI/receiver checks. develop and beta publication explicitly approved by Daniel Haefliger.
This commit is contained in:
@@ -799,6 +799,7 @@
|
||||
},
|
||||
{
|
||||
"type": "ExpansionPanel",
|
||||
"name": "PrognoseForecast",
|
||||
"caption": "Prognose / Forecast",
|
||||
"items": [
|
||||
{
|
||||
|
||||
@@ -12,6 +12,11 @@ require_once __DIR__ . '/../libs/StoerungsSnapshot.php';
|
||||
require_once __DIR__ . '/../libs/EnergieMessung.php';
|
||||
require_once __DIR__ . '/../libs/ManagerEnergieTrait.php';
|
||||
require_once __DIR__ . '/../libs/ManagerSDLTrait.php';
|
||||
require_once __DIR__ . '/../libs/NetzfahrplanV4Betriebsdaten.php';
|
||||
require_once __DIR__ . '/../libs/ManagerNetzfahrplanV4Trait.php';
|
||||
require_once __DIR__ . '/../libs/ManagerNetzfahrplanV4TestTrait.php';
|
||||
require_once __DIR__ . '/../libs/ManagerNetzfahrplanV4AktivtestTrait.php';
|
||||
require_once __DIR__ . '/../libs/ManagerPrognoseFormular.php';
|
||||
|
||||
use Belevo\EnelixEMS\Anlagentopologie;
|
||||
use Belevo\EnelixEMS\EinspeiseRegler;
|
||||
@@ -19,6 +24,7 @@ use Belevo\EnelixEMS\EnergieMessung;
|
||||
use Belevo\EnelixEMS\ManagerEnergieTrait;
|
||||
use Belevo\EnelixEMS\Lizenzpruefung;
|
||||
use Belevo\EnelixEMS\ManagerRegler;
|
||||
use Belevo\EnelixEMS\ManagerPrognoseFormular;
|
||||
use Belevo\EnelixEMS\ManagerSchnittstelle;
|
||||
use Belevo\EnelixEMS\Nachrichtenvertrag;
|
||||
use Belevo\EnelixEMS\StoerungsSnapshot;
|
||||
@@ -27,6 +33,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
{
|
||||
use ManagerEnergieTrait;
|
||||
use \Belevo\EnelixEMS\ManagerSDLTrait;
|
||||
use \Belevo\EnelixEMS\ManagerNetzfahrplanV4Trait;
|
||||
use \Belevo\EnelixEMS\ManagerNetzfahrplanV4TestTrait;
|
||||
use \Belevo\EnelixEMS\ManagerNetzfahrplanV4AktivtestTrait;
|
||||
|
||||
private const STATUS_AKTIV = 102;
|
||||
private const STATUS_MESSWERT_UNGUELTIG = 201;
|
||||
@@ -118,6 +127,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
public function Create(): void
|
||||
{
|
||||
parent::Create();
|
||||
$this->registriereNetzfahrplanV4();
|
||||
$this->registriereV4ManagerTest();
|
||||
$this->registriereV4ManagerAktivtest();
|
||||
|
||||
$this->RegisterPropertyInteger('Rolle', 0);
|
||||
$this->RegisterPropertyInteger('NetzleistungVariableID', 0);
|
||||
@@ -257,8 +269,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
public function ApplyChanges(): void
|
||||
{
|
||||
parent::ApplyChanges();
|
||||
$this->v4ManagerTestAbbrechen('Manager neu initialisiert');
|
||||
$this->SetTimerInterval('NetzfahrplanV4Senden', 0);
|
||||
$this->stoppeNetzfahrplanV4Vorschau();
|
||||
|
||||
$this->initialisiereLizenzInstallationID();
|
||||
$this->konfiguriereNetzfahrplanV4Daten();
|
||||
$this->aktualisiereVariablen();
|
||||
|
||||
try {
|
||||
@@ -315,6 +331,10 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
return;
|
||||
}
|
||||
$this->SetStatus(self::STATUS_AKTIV);
|
||||
if ($this->ReadPropertyBoolean('NetzfahrplanV4SchattenAktiv')) {
|
||||
$this->SetTimerInterval('NetzfahrplanV4Senden', 90000);
|
||||
}
|
||||
$this->konfiguriereNetzfahrplanV4Vorschau();
|
||||
$this->synchronisiereAnlagentopologie();
|
||||
if ($this->prognoseTelemetrieKonfiguriert()) {
|
||||
$this->SetTimerInterval(
|
||||
@@ -451,6 +471,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->ReadPropertyBoolean('SDLAktiv')
|
||||
);
|
||||
|
||||
$formular = ManagerPrognoseFormular::integrieren($formular, $this->prognoseBedienzustand());
|
||||
return json_encode($formular, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
@@ -489,6 +510,48 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->regeln(false);
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4Empfangen':
|
||||
$this->empfangeNetzfahrplanV4();
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4VorschauAktualisieren':
|
||||
$this->aktualisiereNetzfahrplanV4Vorschau();
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4TestStart':
|
||||
if (!is_string($wert)) throw new InvalidArgumentException('Explizite JSON-Testfreigabe erforderlich.');
|
||||
$this->V4ManagerTestStarten($wert);
|
||||
return;
|
||||
case 'NetzfahrplanV4TestStop':
|
||||
$this->V4ManagerTestStoppen();
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4Aktivtest':
|
||||
$this->V4ManagerAktivtestSchalten((bool) $wert);
|
||||
return;
|
||||
|
||||
case 'FormNetzfahrplanSchalten':
|
||||
if (!is_bool($wert)) {
|
||||
throw new InvalidArgumentException('Netzfahrplan-Schaltung muss ein boolescher Wert sein.');
|
||||
}
|
||||
if ($wert && !ManagerPrognoseFormular::startErlaubt($this->prognoseBedienzustand())) {
|
||||
throw new RuntimeException('Netzfahrplan nicht freigegeben. Gespeicherte Konfiguration, Lizenz und Testfreigabe pruefen.');
|
||||
}
|
||||
try {
|
||||
$this->V4ManagerAktivtestSchalten($wert);
|
||||
} finally {
|
||||
$this->aktualisierePrognoseBedienung();
|
||||
}
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4DatenErfassen':
|
||||
$this->ErfasseNetzfahrplanV4Daten();
|
||||
return;
|
||||
|
||||
case 'NetzfahrplanV4Senden':
|
||||
$this->sendeNetzfahrplanV4();
|
||||
return;
|
||||
|
||||
case 'PrognoseSenden':
|
||||
$this->sendePrognoseTelemetrie();
|
||||
return;
|
||||
@@ -520,6 +583,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
if (!$aktiv) {
|
||||
$this->UpdateFormField('NetzfahrplanAktiv', 'value', false);
|
||||
}
|
||||
$this->aktualisierePrognoseBedienung($aktiv);
|
||||
return;
|
||||
|
||||
case 'FormSDLAktiv':
|
||||
@@ -727,6 +791,28 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
}
|
||||
|
||||
private function regeln(bool $erneuern): void
|
||||
{
|
||||
$lock = 'ENELIX.V4.Control.' . $this->InstanceID;
|
||||
if (!IPS_SemaphoreEnter($lock, 0)) return;
|
||||
try {
|
||||
$trialBefore=(bool)$this->v4ManagerTestSession();
|
||||
$this->regelnIntern($erneuern);
|
||||
if ($trialBefore && !$this->v4ManagerTestSession() && $this->GetValue('Aktiv')
|
||||
&& IPS_GetInstance($this->InstanceID)['InstanceStatus'] === self::STATUS_AKTIV) {
|
||||
$this->WriteAttributeString('LetzteSollwerte','{}');
|
||||
$this->regelnIntern(true); // exactly one fresh fallback, no cached pre-trial target
|
||||
}
|
||||
if ($this->v4ManagerTestSession()
|
||||
&& (!$this->GetValue('Aktiv') || IPS_GetInstance($this->InstanceID)['InstanceStatus'] !== self::STATUS_AKTIV)) {
|
||||
$this->v4ManagerTestAbbrechen('Manager nicht mehr betriebsbereit');
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->v4ManagerTestAbbrechen('Regelungsfehler');
|
||||
throw $e;
|
||||
} finally { IPS_SemaphoreLeave($lock); }
|
||||
}
|
||||
|
||||
private function regelnIntern(bool $erneuern): void
|
||||
{
|
||||
if (!$this->aktualisiereLizenzfreigabe($this->ReadPropertyString('Lizenzcode'), false)) {
|
||||
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||
@@ -831,6 +917,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
: $this->nichtGeregelteGeraeteText($nichtGeregelt)
|
||||
);
|
||||
|
||||
$this->v4ManagerTestUebergabe($ergebnis, $verbraucher, $synchronisiert);
|
||||
$letzteSollwerte = $this->leseJsonAttribut('LetzteSollwerte');
|
||||
foreach ($ergebnis['Sollwerte'] as $instanzID => $sollleistung) {
|
||||
if (!$erneuern && ($letzteSollwerte[(string) $instanzID] ?? null) === $sollleistung) {
|
||||
@@ -840,6 +927,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->sendeManagerdaten((int) $instanzID, $betriebsart, $sollleistung);
|
||||
$letzteSollwerte[(string) $instanzID] = $sollleistung;
|
||||
} catch (Throwable $fehler) {
|
||||
$this->v4ManagerTestAbbrechen('Andere Verbraucher-Stellwertuebergabe fehlgeschlagen');
|
||||
$stoerungen[] = 'Sollwert an Instanz ' . $instanzID . ': ' . $fehler->getMessage();
|
||||
}
|
||||
}
|
||||
@@ -2600,6 +2688,35 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$aktiv && $netzfahrplanLizenziert
|
||||
&& $this->peakShavingLizenziert($lizenzcode)
|
||||
);
|
||||
$this->aktualisierePrognoseBedienung(null, $lizenzcode);
|
||||
}
|
||||
|
||||
private function prognoseBedienzustand(?bool $aktiv = null, ?string $lizenzcode = null): array
|
||||
{
|
||||
return [
|
||||
'prognoseAktiv' => ($aktiv ?? true) && $this->ReadPropertyBoolean('PrognoseAktiv'),
|
||||
'lizenziert' => $this->berechtigungLizenziert(Lizenzpruefung::NETZFAHRPLAN, $lizenzcode),
|
||||
'senderAktiv' => $this->ReadPropertyBoolean('NetzfahrplanV4SchattenAktiv'),
|
||||
'empfangAktiv' => $this->ReadPropertyBoolean('NetzfahrplanV4EmpfangAktiv'),
|
||||
'messdatenAktiv' => $this->ReadPropertyBoolean('NetzfahrplanV4MessdatenAktiv'),
|
||||
'legacyAktiv' => $this->ReadPropertyBoolean('NetzfahrplanAktiv'),
|
||||
'managerAktiv' => $this->GetValue('Aktiv')
|
||||
&& IPS_GetInstance($this->InstanceID)['InstanceStatus'] === self::STATUS_AKTIV,
|
||||
'testErlaubt' => $this->ReadPropertyBoolean('NetzfahrplanV4RegeltestErlaubt'),
|
||||
'aktivtestErlaubt' => $this->ReadPropertyBoolean('NetzfahrplanV4AktivtestErlaubt'),
|
||||
'watchdogVerzichtErlaubt' => $this->ReadPropertyBoolean('NetzfahrplanV4WatchdogVerzichtErlaubt'),
|
||||
'aktivtestAktiv' => (bool) $this->GetValue('NetzfahrplanV4Aktivtest'),
|
||||
'ende' => $this->ReadAttributeInteger('NetzfahrplanV4AktivtestEnde'),
|
||||
'jetzt' => time(),
|
||||
];
|
||||
}
|
||||
|
||||
private function aktualisierePrognoseBedienung(?bool $aktiv = null, ?string $lizenzcode = null): void
|
||||
{
|
||||
$zustand = $this->prognoseBedienzustand($aktiv, $lizenzcode);
|
||||
$this->UpdateFormField('PrognoseNetzfahrplanStart', 'enabled', ManagerPrognoseFormular::startErlaubt($zustand));
|
||||
$this->UpdateFormField('PrognoseNetzfahrplanStatus', 'caption', ManagerPrognoseFormular::statustext($zustand));
|
||||
$this->UpdateFormField('NetzfahrplanV4EmpfangAktiv', 'enabled', $zustand['lizenziert'] || $zustand['empfangAktiv']);
|
||||
}
|
||||
|
||||
private function prognoseLizenzStatustext(bool $aktiv, bool $lizenziert): string
|
||||
|
||||
Reference in New Issue
Block a user