feat(manager): add gated short-lease V4 control trial and local fallback

This commit is contained in:
ENELIX Agent
2026-10-02 14:01:41 +00:00
parent b5c1fa6be2
commit 9394fe3eb1
10 changed files with 918 additions and 4 deletions
+45 -3
View File
@@ -6,6 +6,7 @@ require_once __DIR__ . '/../libs/VerbraucherSchnittstelle.php';
require_once __DIR__ . '/../libs/VerbraucherBasisTrait.php';
require_once __DIR__ . '/../libs/Nachrichtenvertrag.php';
require_once __DIR__ . '/../libs/BatterieRegler.php';
require_once __DIR__ . '/../libs/BatterieNetzfahrplanV4TestTrait.php';
use Belevo\EnelixEMS\BatterieRegler;
use Belevo\EnelixEMS\Nachrichtenvertrag;
@@ -15,6 +16,7 @@ use Belevo\EnelixEMS\VerbraucherSchnittstelle;
class Batterie extends IPSModule implements VerbraucherSchnittstelle
{
use VerbraucherBasisTrait;
use \Belevo\EnelixEMS\BatterieNetzfahrplanV4TestTrait;
private const MANAGER_MODULE_ID = '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}';
private const STATUS_AKTIV = 102;
@@ -68,6 +70,7 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
parent::Create();
$this->registriereVerbraucherBasis();
$this->registriereV4BatterieTest();
$this->RegisterPropertyInteger('Batterietyp', BatterieRegler::TYP_UNKONFIGURIERT);
$this->RegisterPropertyInteger(
'Batteriemanagement',
@@ -152,6 +155,7 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
{
parent::ApplyChanges();
$this->V4BatterieTestStoppen();
$this->aktualisiereVariablen();
$this->registriereMesswertmeldungen();
$this->WriteAttributeBoolean('RegisterInitialisiert', false);
@@ -248,7 +252,22 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
$this->aktualisiere(true);
return;
case 'NetzfahrplanV4TestStart':
if (!is_string($wert)) throw new InvalidArgumentException('JSON-Testanmeldung erforderlich.');
$this->V4BatterieTestStarten($wert);
return;
case 'NetzfahrplanV4TestCommand':
if (!is_string($wert)) throw new InvalidArgumentException('JSON-Testbefehl erforderlich.');
$this->V4BatterieTestBefehl($wert);
return;
case 'NetzfahrplanV4TestStop':
$this->V4BatterieTestStoppen();
return;
case 'NetzfahrplanV4TestWatchdog':
$this->aktualisiere(true);
return;
case 'SichererZustand':
$this->V4BatterieTestStoppen();
$this->setzeZustand('SollwertGueltig', false);
$this->schreibeRegister(0, true);
$this->aktualisiere(true);
@@ -287,6 +306,14 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
/** @param array<string, mixed> $daten */
public function ManagerdatenEmpfangen(array $daten): void
{
$lock = 'ENELIX.V4.Battery.' . $this->InstanceID;
if (!IPS_SemaphoreEnter($lock, 1000)) throw new RuntimeException('Batterieannahme beschaeftigt.');
try { $this->ManagerdatenEmpfangenIntern($daten); }
finally { IPS_SemaphoreLeave($lock); }
}
private function ManagerdatenEmpfangenIntern(array $daten): void
{
Nachrichtenvertrag::pruefeManagerdaten($daten);
if ($daten['Kopf']['EmpfaengerID'] !== $this->InstanceID) {
@@ -302,8 +329,13 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
);
}
if ($this->v4BatterieTestAktiv()) {
// Ordinary manager messages cannot overwrite or renew the independent short test lease.
$this->planeMeldung();
return;
}
$this->WriteAttributeString('Betriebsart', $daten['Betriebsart']);
$this->aktualisiere(false);
$this->aktualisiereIntern(false);
$sollleistung = $daten['Sollleistung_W'];
if ($sollleistung === null) {
@@ -314,7 +346,7 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
)
) {
$this->setzeZustand('SollwertGueltig', false);
$this->aktualisiere(false);
$this->aktualisiereIntern(false);
}
$this->planeMeldung();
return;
@@ -341,11 +373,19 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
$this->setzeZustand('Sollleistung', $sollleistung);
$this->setzeZustand('SollwertGueltig', true);
$this->planeVorgabeTimeout(time());
$this->aktualisiere(false);
$this->aktualisiereIntern(false);
$this->planeMeldung();
}
private function aktualisiere(bool $meldungPlanen): void
{
$lock = 'ENELIX.V4.Battery.' . $this->InstanceID;
if (!IPS_SemaphoreEnter($lock, 0)) return;
try { $this->aktualisiereIntern($meldungPlanen); }
finally { IPS_SemaphoreLeave($lock); }
}
private function aktualisiereIntern(bool $meldungPlanen): void
{
try {
$jetzt = time();
@@ -426,6 +466,8 @@ class Batterie extends IPSModule implements VerbraucherSchnittstelle
$ziel = $verfuegbar && (bool) $this->leseZustand('SollwertGueltig')
? (int) $this->leseZustand('Sollleistung')
: 0;
$v4Ziel = $this->v4BatterieTestZiel($messwerte, $verfuegbar, $jetzt);
if ($v4Ziel !== null) $ziel = $v4Ziel;
$this->schreibeRegister($ziel, false);
$this->setzeZustand('Sollleistung', $ziel);
$this->setzeZustand('Verfuegbar', $verfuegbar);