Tests / test (push) Successful in 59s
Replace trait constants and array_is_list usage with equivalent PHP 8.0 constructs. Add strict list/expiry regressions and make isolated reflection tests PHP 8.0 compatible. No control activation, threshold or configuration change.
212 lines
8.5 KiB
PHP
212 lines
8.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Belevo\EnelixEMS;
|
|
|
|
use InvalidArgumentException;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
|
|
trait ManagerSDLTrait
|
|
{
|
|
private function pruefeSDLKonfiguration(): void
|
|
{
|
|
if (!$this->ReadPropertyBoolean('SDLAktiv')) {
|
|
return;
|
|
}
|
|
$leistungID = $this->ReadPropertyInteger('SDLLeistungVariableID');
|
|
if (!$this->istNumerischeVariable($leistungID)) {
|
|
throw new InvalidArgumentException('SDL benoetigt eine numerische Istleistungsvariable.');
|
|
}
|
|
$this->anlagenMessfaktor($this->ReadPropertyFloat('SDLLeistungsfaktor'), 'SDL');
|
|
$socID = $this->ReadPropertyInteger('SDLSOCVariableID');
|
|
if ($socID !== 0 && (!$this->istNumerischeVariable($socID) || $socID === $leistungID)) {
|
|
throw new InvalidArgumentException('SDL-SOC muss eine separate numerische Variable sein.');
|
|
}
|
|
$andereQuellen = array_merge($this->pvMessquellen(), $this->batterieMessquellen());
|
|
$andereQuellen[] = ['VariableID' => $this->ReadPropertyInteger('NetzleistungVariableID')];
|
|
foreach ($andereQuellen as $quelle) {
|
|
if ($leistungID === $quelle['VariableID']) {
|
|
throw new InvalidArgumentException(
|
|
'SDL-Leistung darf nicht zugleich als PV-, Netz- oder Batterieleistung bilanziert werden.'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function synchronisiereSDLMesskonfiguration(): void
|
|
{
|
|
$neu = json_encode([
|
|
$this->ReadPropertyBoolean('SDLAktiv'),
|
|
$this->ReadPropertyInteger('SDLLeistungVariableID'),
|
|
$this->ReadPropertyFloat('SDLLeistungsfaktor'),
|
|
], JSON_THROW_ON_ERROR);
|
|
$alt = $this->ReadAttributeString('SDLMesskonfiguration');
|
|
if ($neu !== $alt && ($alt !== '' || $this->ReadPropertyBoolean('SDLAktiv'))) {
|
|
// Bereits erfasste Energien bleiben erhalten; keine Rueckrechnung mit neuen Quellen.
|
|
$this->WriteAttributeInteger('MessungLetzterZeitstempel', 0);
|
|
$this->WriteAttributeString('MessungZaehlerstaende', '{}');
|
|
$this->WriteAttributeInteger('MessungLetzteLeistungsaufzeichnung', 0);
|
|
}
|
|
$this->WriteAttributeString('SDLMesskonfiguration', $neu);
|
|
}
|
|
|
|
private function aktuelleSDLLeistung(): float
|
|
{
|
|
if (!$this->ReadPropertyBoolean('SDLAktiv')) {
|
|
return 0.0;
|
|
}
|
|
$variableID = $this->ReadPropertyInteger('SDLLeistungVariableID');
|
|
if (!$this->istNumerischeVariable($variableID)) {
|
|
throw new RuntimeException('Die SDL-Istleistung ist nicht verfuegbar.');
|
|
}
|
|
$wert = GetValue($variableID);
|
|
if ((!is_int($wert) && !is_float($wert)) || !is_finite((float) $wert)) {
|
|
throw new RuntimeException('Die SDL-Istleistung ist keine endliche Zahl.');
|
|
}
|
|
$leistung = (float) $wert * $this->ReadPropertyFloat('SDLLeistungsfaktor');
|
|
if (!is_finite($leistung)) {
|
|
throw new RuntimeException('Die skalierte SDL-Istleistung ist nicht endlich.');
|
|
}
|
|
if ($this->ReadPropertyInteger('SDLSOCVariableID') === 0 || $this->aktuelleSDLSOC() !== null) {
|
|
$this->setzeDiagnosewert('SDLStatus', 'Aktiv');
|
|
}
|
|
|
|
return $leistung;
|
|
}
|
|
|
|
private function aktuelleSDLSOC(): ?float
|
|
{
|
|
if (!$this->ReadPropertyBoolean('SDLAktiv')) {
|
|
return null;
|
|
}
|
|
$variableID = $this->ReadPropertyInteger('SDLSOCVariableID');
|
|
if ($variableID === 0) {
|
|
return null;
|
|
}
|
|
if ($this->istNumerischeVariable($variableID)) {
|
|
$wert = (float) GetValue($variableID);
|
|
if (is_finite($wert) && $wert >= 0.0 && $wert <= 100.0) {
|
|
return $wert;
|
|
}
|
|
}
|
|
$this->setzeDiagnosewert('SDLStatus', 'Fehler: SDL-SOC muss zwischen 0 und 100 Prozent liegen.');
|
|
|
|
return null;
|
|
}
|
|
|
|
private function sdlAnzeigen(string $property): bool
|
|
{
|
|
return $this->ReadPropertyBoolean('SDLAktiv') && $this->ReadPropertyBoolean($property);
|
|
}
|
|
|
|
private function aktualisiereSDLStatus(): void
|
|
{
|
|
if (!$this->ReadPropertyBoolean('SDLAktiv')) {
|
|
$this->setzeDiagnosewert('SDLStatus', 'NichtVerwendet');
|
|
return;
|
|
}
|
|
try {
|
|
$this->aktuelleSDLLeistung();
|
|
$this->aktuelleSDLSOC();
|
|
} catch (Throwable $fehler) {
|
|
$this->setzeDiagnosewert('SDLStatus', 'Fehler: ' . $fehler->getMessage());
|
|
}
|
|
}
|
|
|
|
private function synchronisiereSDLEnergiefluss(int $instanzID, bool $profilAktualisieren = false): void
|
|
{
|
|
$anzeigen = $this->sdlAnzeigen('SDLEnergieflussAnzeigen');
|
|
$variableID = $this->findeUnterobjekt('EnergieflussSDL');
|
|
if (!$anzeigen && $variableID === 0) {
|
|
return;
|
|
}
|
|
if ($anzeigen && ($variableID === 0 || $profilAktualisieren)) {
|
|
$variableID = $this->energieflussLeistungsvariable(
|
|
'EnergieflussSDL', 'Energiefluss SDL', $this->energieflussLeistungsprofil(), 635
|
|
);
|
|
}
|
|
$alt = json_decode(IPS_GetProperty($instanzID, 'Config'), true, 512, JSON_THROW_ON_ERROR);
|
|
if (!is_array($alt) || array_keys($alt) !== array_keys(array_values($alt))) {
|
|
throw new RuntimeException('Die bestehende Energiefluss-Konfiguration ist keine Liste.');
|
|
}
|
|
$neu = [];
|
|
$gefunden = false;
|
|
$socID = $this->aktuelleSDLSOC() !== null
|
|
? $this->GetIDForIdent('SDLSOCArchiv') : 1;
|
|
foreach ($alt as $knoten) {
|
|
if ((int) ($knoten['VariableID'] ?? 0) !== $variableID) {
|
|
$neu[] = $knoten;
|
|
} elseif ($anzeigen && !$gefunden) {
|
|
$knoten['InfoVariableID'] = $socID;
|
|
$neu[] = $knoten;
|
|
$gefunden = true;
|
|
}
|
|
}
|
|
if ($anzeigen && !$gefunden) {
|
|
$neu[] = $this->energieflussKnoten($variableID, 'SDL / Regelenergie', 'storage', false, $socID);
|
|
}
|
|
if ($neu !== $alt) {
|
|
IPS_SetProperty($instanzID, 'Config', json_encode($neu, JSON_THROW_ON_ERROR));
|
|
IPS_ApplyChanges($instanzID);
|
|
}
|
|
}
|
|
|
|
private function synchronisiereSDLDiagramm(int $medienID, bool $energie): void
|
|
{
|
|
$idents = $energie
|
|
? ['SDLLadenEnergie', 'SDLEntladenEnergie', 'SDLSOCArchiv']
|
|
: ['SDLLeistungArchiv', 'SDLSOCArchiv'];
|
|
$verwaltet = array_map(fn (string $ident): int => $this->GetIDForIdent($ident), $idents);
|
|
$gewuenscht = [];
|
|
if ($this->sdlAnzeigen('SDLDiagrammeAnzeigen')) {
|
|
if ($energie) {
|
|
$gewuenscht[] = $this->chartDatensatz(
|
|
'SDLLadenEnergie', 'SDL laden', '#007C91', '~Electricity', 'bar'
|
|
);
|
|
$gewuenscht[] = $this->chartDatensatz(
|
|
'SDLEntladenEnergie', 'SDL entladen', '#C43E1C', '~Electricity', 'bar'
|
|
);
|
|
} else {
|
|
$gewuenscht[] = $this->chartDatensatz(
|
|
'SDLLeistungArchiv', 'SDL Istleistung', '#007C91', '~Power'
|
|
);
|
|
}
|
|
if ($this->ReadPropertyInteger('SDLSOCVariableID') > 0) {
|
|
$soc = $this->chartDatensatz('SDLSOCArchiv', 'SDL SOC', '#C43E1C', '~Intensity.100');
|
|
$soc['side'] = 'right';
|
|
$gewuenscht[] = $soc;
|
|
}
|
|
}
|
|
$inhalt = json_decode((string) base64_decode(IPS_GetMediaContent($medienID), true), true);
|
|
if (!is_array($inhalt) || !isset($inhalt['datasets']) || !is_array($inhalt['datasets'])) {
|
|
if (!$this->sdlAnzeigen('SDLDiagrammeAnzeigen')) {
|
|
return;
|
|
}
|
|
throw new RuntimeException('Das bestehende Diagramm hat keine gueltigen Datensaetze.');
|
|
}
|
|
$alt = $inhalt['datasets'];
|
|
$neu = [];
|
|
foreach ($alt as $datensatz) {
|
|
$id = (int) ($datensatz['variableID'] ?? 0);
|
|
if (!in_array($id, $verwaltet, true)) {
|
|
$neu[] = $datensatz;
|
|
continue;
|
|
}
|
|
foreach ($gewuenscht as $index => $ziel) {
|
|
if ($id === $ziel['variableID']) {
|
|
$neu[] = $datensatz;
|
|
unset($gewuenscht[$index]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$neu = array_merge($neu, array_values($gewuenscht));
|
|
if ($neu !== $alt) {
|
|
$inhalt['datasets'] = $neu;
|
|
IPS_SetMediaContent($medienID, base64_encode(json_encode($inhalt, JSON_THROW_ON_ERROR)));
|
|
}
|
|
}
|
|
}
|