feat(workflow): publish verified forecast controls and consolidated docs
Tests / test (push) Successful in 1m1s

Approved by Daniel Haefliger for develop and beta. Author dh_Agent, authenticated account dh. Preserve published battery, charging and overall Energy Pie changes. No deployment or plant control authorization.
This commit is contained in:
dh
2026-10-08 10:02:58 +00:00
parent af69151165
commit 74a2d6c685
82 changed files with 5054 additions and 617 deletions
+18 -61
View File
@@ -6,7 +6,7 @@ namespace Belevo\EnelixEMS;
use LogicException;
/** Form composition only. Existing configuration, control authority and backend stay unchanged. */
/** Exactly two operator switches; legacy configuration is retained but not exposed. */
final class ManagerPrognoseFormular
{
/** Stable identifiers remain for archives and integrations; operation belongs in Forecast. */
@@ -22,45 +22,25 @@ final class ManagerPrognoseFormular
public static function startErlaubt(array $zustand): bool
{
foreach (['prognoseAktiv', 'lizenziert', 'senderAktiv', 'empfangAktiv', 'managerAktiv',
'testErlaubt', 'aktivtestErlaubt', 'watchdogVerzichtErlaubt'] as $feld) {
foreach (['prognoseAktiv', 'lizenziert', 'ready'] as $feld) {
if (($zustand[$feld] ?? false) !== true) {
return false;
}
}
return ($zustand['legacyAktiv'] ?? true) === false
&& ($zustand['aktivtestAktiv'] ?? true) === false
&& isset($zustand['ende'], $zustand['jetzt'])
&& is_int($zustand['ende']) && is_int($zustand['jetzt'])
&& ($zustand['ende'] === 0 || $zustand['ende'] > $zustand['jetzt']);
return true;
}
public static function statustext(array $zustand): string
{
$text = ($zustand['aktivtestAktiv'] ?? false)
? 'Netzfahrplan: befristeter Testbetrieb eingeschaltet.'
: 'Netzfahrplan: Steuerung ausgeschaltet.';
if ($zustand['legacyAktiv'] ?? false) {
$text = 'Bisheriger Netzfahrplan eingeschaltet; neuer Netzfahrplan gesperrt.';
}
if (!($zustand['lizenziert'] ?? false)) {
$text .= ' Netzfahrplanlizenz fehlt.';
}
$ende = $zustand['ende'] ?? 0;
if (is_int($ende) && $ende > 0) {
$text .= ' Bestehendes Testende: ' . gmdate('d.m.Y H:i:s', $ende) . ' UTC.';
if ($ende <= ($zustand['jetzt'] ?? 0)) {
$text .= ' Testfreigabe abgelaufen.';
}
}
return $text . ' Kein freigegebener Dauerbetrieb. Bestehende Laufzeit-, Messwert- und Geraeteschutzpruefungen bleiben wirksam.';
$states = ['disabled' => 'Aus', 'collecting' => 'Daten sammeln', 'learning' => 'Lernen',
'ready' => 'Bereit', 'active' => 'Aktiv', 'interrupted' => 'Unterbrochen'];
return ($states[$zustand['state'] ?? 'disabled'] ?? 'Status unbekannt') . ': '
. ($zustand['reason'] ?? 'Aktuellen Status abwarten.');
}
public static function integrieren(array $formular, array $zustand): array
{
$gefunden = false;
$v4Konfiguriert = ($zustand['senderAktiv'] ?? false)
|| ($zustand['empfangAktiv'] ?? false) || ($zustand['messdatenAktiv'] ?? false);
foreach ($formular['elements'] as &$element) {
if (($element['name'] ?? null) !== 'PrognoseForecast') {
continue;
@@ -69,45 +49,22 @@ final class ManagerPrognoseFormular
throw new LogicException('Prognosebereich ist nicht eindeutig.');
}
$gefunden = true;
foreach ($element['items'] as &$feld) {
if (($feld['name'] ?? null) === 'NetzfahrplanAktiv' && $v4Konfiguriert) {
// An active legacy controller remains visible so it can still be disabled.
$feld['visible'] = (bool) ($zustand['legacyAktiv'] ?? false);
$feld['enabled'] = (bool) ($zustand['legacyAktiv'] ?? false);
$feld['caption'] = 'Bisheriger Netzfahrplan (konkurrierende Steuerung)';
}
}
unset($feld);
$element['items'] = [
['type' => 'CheckBox', 'name' => 'PrognoseAktiv',
'caption' => '1. Netzdaten senden und Prognosen lernen',
'onChange' => "IPS_RequestAction(\$id, 'FormPrognoseAktiv', \$PrognoseAktiv);"],
['type' => 'CheckBox', 'name' => 'NetzfahrplanRegelungAktiv',
'caption' => '2. Batterie nach Netzfahrplan regeln',
'enabled' => ($zustand['controlRequested'] ?? false) || self::startErlaubt($zustand)],
['type' => 'Label', 'name' => 'PrognoseNetzfahrplanStatus', 'caption' => self::statustext($zustand)],
['type' => 'Label', 'name' => 'PrognoseLizenzInformation',
'caption' => 'V4-Netzziel und Batteriekorrektur. Andere Verbraucher bleiben in der bisherigen Managerregelung.'],
];
$element['items'][] = [
'type' => 'Button', 'name' => 'PrognoseLizenzVerwalten',
'caption' => 'Prognose und Netzfahrplan im Lizenzportal verwalten', 'link' => true,
'onClick' => "echo 'https://license.enelix.ch';",
];
$element['items'][] = [
'type' => 'CheckBox', 'name' => 'NetzfahrplanV4EmpfangAktiv',
'caption' => 'Aktuellen Netzfahrplan empfangen und anzeigen',
'enabled' => (bool) (($zustand['lizenziert'] ?? false) || ($zustand['empfangAktiv'] ?? false)),
];
$element['items'][] = [
'type' => 'Label', 'name' => 'PrognoseNetzfahrplanStatus',
'caption' => self::statustext($zustand),
];
$element['items'][] = [
'type' => 'Button', 'name' => 'PrognoseNetzfahrplanStart',
'caption' => 'Netzfahrplan einschalten (Testbetrieb)',
'enabled' => self::startErlaubt($zustand),
'onClick' => "IPS_RequestAction(\$id, 'FormNetzfahrplanSchalten', true);",
];
$element['items'][] = [
'type' => 'Button', 'name' => 'PrognoseNetzfahrplanStop',
'caption' => 'Netzfahrplan ausschalten', 'enabled' => true,
'onClick' => "IPS_RequestAction(\$id, 'FormNetzfahrplanSchalten', false);",
];
$element['items'][] = [
'type' => 'Button', 'name' => 'PrognoseNetzfahrplanPruefen',
'caption' => 'Plan jetzt pruefen',
'onClick' => "IPS_RequestAction(\$id, 'NetzfahrplanV4Empfangen', true);",
];
}
unset($element);
if (!$gefunden) {