feat(manager): Energievisualisierung und Synchronisierung erweitern
Tests / test (push) Successful in 50s
Tests / test (push) Successful in 50s
This commit is contained in:
+52
-9
@@ -260,10 +260,14 @@
|
|||||||
"type": "Label",
|
"type": "Label",
|
||||||
"caption": "Energiezaehler werden in kWh erwartet; ueber den Faktor koennen beispielsweise Wh (0,001) umgerechnet werden."
|
"caption": "Energiezaehler werden in kWh erwartet; ueber den Faktor koennen beispielsweise Wh (0,001) umgerechnet werden."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Die Wechselrichter-Tabelle beschreibt die AC-Wandler der Anlage. PV-Flaechen und Batteriespeicher verweisen darauf, damit gemeinsame Leistungsgrenzen und die elektrische Kopplung eindeutig sind. Bei einem Hybridgeraet verwenden PV und Batterie dieselbe Wechselrichter-ID; bei einem AC-gekoppelten Speicher wird dessen separater Batteriewechselrichter erfasst."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "List",
|
"type": "List",
|
||||||
"name": "AnlagenWechselrichter",
|
"name": "AnlagenWechselrichter",
|
||||||
"caption": "Wechselrichter",
|
"caption": "Wechselrichter / AC-Wandler",
|
||||||
"rowCount": 4,
|
"rowCount": 4,
|
||||||
"add": true,
|
"add": true,
|
||||||
"delete": true,
|
"delete": true,
|
||||||
@@ -459,6 +463,10 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Der Batterieeintrag beschreibt den Speicher selbst: Kapazitaet, Leistung, Ladezustand und Energiezaehler. Die Wechselrichter-ID ist nur die Verknuepfung zum zugehoerigen AC-Wandler und keine doppelte Batteriekonfiguration."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "List",
|
"type": "List",
|
||||||
"name": "AnlagenBatterien",
|
"name": "AnlagenBatterien",
|
||||||
@@ -722,26 +730,61 @@
|
|||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "CheckBox",
|
||||||
"name": "EnergyPieAnzeigen",
|
"name": "EnergyPieAnzeigen",
|
||||||
"caption": "Energy Pie unter dem Manager anzeigen",
|
"caption": "Energy Pie unter dem Manager anzeigen"
|
||||||
"onChange": "IPS_RequestAction($id, 'FormEnergyPieAnzeigen', $EnergyPieAnzeigen);"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "CheckBox",
|
||||||
"name": "EnergiediagrammeAnzeigen",
|
"name": "EnergiediagrammeAnzeigen",
|
||||||
"caption": "Leistungs- und Energiediagramm unter dem Manager anzeigen",
|
"caption": "Leistungs- und Energiediagramm unter dem Manager anzeigen"
|
||||||
"onChange": "IPS_RequestAction($id, 'FormEnergiediagrammeAnzeigen', $EnergiediagrammeAnzeigen);"
|
},
|
||||||
|
{
|
||||||
|
"type": "RowLayout",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "Select",
|
||||||
|
"name": "DiagrammPVModus",
|
||||||
|
"caption": "PV in Diagrammen",
|
||||||
|
"options": [
|
||||||
|
{"caption": "Summe", "value": 0},
|
||||||
|
{"caption": "Einzelne Anlagen", "value": 1},
|
||||||
|
{"caption": "Summe und einzelne Anlagen", "value": 2}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Select",
|
||||||
|
"name": "DiagrammBatterieModus",
|
||||||
|
"caption": "Batterien in Diagrammen",
|
||||||
|
"options": [
|
||||||
|
{"caption": "Summe", "value": 0},
|
||||||
|
{"caption": "Einzelne Speicher", "value": 1},
|
||||||
|
{"caption": "Summe und einzelne Speicher", "value": 2}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CheckBox",
|
||||||
|
"name": "LadestationenSeparatAnzeigen",
|
||||||
|
"caption": "Ladestationen separat in Energiefluss und Diagrammen anzeigen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CheckBox",
|
||||||
|
"name": "VerbraucherSeparatAnzeigen",
|
||||||
|
"caption": "Uebrige Verbraucher separat in Energiefluss und Diagrammen anzeigen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "Bestehende Energy Pies, Diagramme und Energiefluesse bleiben bei Apply unveraendert. Fuer eine Neuerzeugung den jeweiligen Schalter ausschalten, Apply ausfuehren, wieder einschalten und erneut Apply ausfuehren."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "CheckBox",
|
||||||
"name": "FunFactsAnzeigen",
|
"name": "FunFactsAnzeigen",
|
||||||
"caption": "Energy Facts unter dem Manager anzeigen",
|
"caption": "Energy Facts unter dem Manager anzeigen"
|
||||||
"onChange": "IPS_RequestAction($id, 'FormFunFactsAnzeigen', $FunFactsAnzeigen);"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "CheckBox",
|
||||||
"name": "EnergieflussAnzeigen",
|
"name": "EnergieflussAnzeigen",
|
||||||
"caption": "Energiefluss unter dem Manager anzeigen",
|
"caption": "Energiefluss unter dem Manager anzeigen"
|
||||||
"onChange": "IPS_RequestAction($id, 'FormEnergieflussAnzeigen', $EnergieflussAnzeigen);"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Select",
|
"type": "Select",
|
||||||
|
|||||||
+62
-10
@@ -171,6 +171,10 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->RegisterPropertyInteger('EnergieLoeschenMonate', 0);
|
$this->RegisterPropertyInteger('EnergieLoeschenMonate', 0);
|
||||||
$this->RegisterPropertyBoolean('EnergyPieAnzeigen', false);
|
$this->RegisterPropertyBoolean('EnergyPieAnzeigen', false);
|
||||||
$this->RegisterPropertyBoolean('EnergiediagrammeAnzeigen', false);
|
$this->RegisterPropertyBoolean('EnergiediagrammeAnzeigen', false);
|
||||||
|
$this->RegisterPropertyInteger('DiagrammPVModus', 0);
|
||||||
|
$this->RegisterPropertyInteger('DiagrammBatterieModus', 0);
|
||||||
|
$this->RegisterPropertyBoolean('LadestationenSeparatAnzeigen', true);
|
||||||
|
$this->RegisterPropertyBoolean('VerbraucherSeparatAnzeigen', true);
|
||||||
$this->RegisterPropertyBoolean('FunFactsAnzeigen', false);
|
$this->RegisterPropertyBoolean('FunFactsAnzeigen', false);
|
||||||
$this->RegisterPropertyBoolean('EnergieflussAnzeigen', false);
|
$this->RegisterPropertyBoolean('EnergieflussAnzeigen', false);
|
||||||
$this->RegisterPropertyInteger('EnergieflussLeistungseinheit', 0);
|
$this->RegisterPropertyInteger('EnergieflussLeistungseinheit', 0);
|
||||||
@@ -203,6 +207,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->RegisterAttributeInteger('MessungLetzteEnergieaufzeichnung', 0);
|
$this->RegisterAttributeInteger('MessungLetzteEnergieaufzeichnung', 0);
|
||||||
$this->RegisterAttributeString('MessungEnergiePuffer', '{}');
|
$this->RegisterAttributeString('MessungEnergiePuffer', '{}');
|
||||||
$this->RegisterAttributeString('MessungZaehlerstaende', '{}');
|
$this->RegisterAttributeString('MessungZaehlerstaende', '{}');
|
||||||
|
$this->RegisterAttributeString('EnergiediagrammKonfiguration', '{}');
|
||||||
|
$this->RegisterAttributeString('EnergieflussKonfiguration', '{}');
|
||||||
|
$this->RegisterAttributeBoolean('EnergieflussNeuErzeugen', false);
|
||||||
|
|
||||||
// Die alten Timer bleiben deaktiviert registriert, damit bestehende Instanzen sauber migrieren.
|
// Die alten Timer bleiben deaktiviert registriert, damit bestehende Instanzen sauber migrieren.
|
||||||
$this->RegisterTimer('Regelzyklus', 0, '');
|
$this->RegisterTimer('Regelzyklus', 0, '');
|
||||||
@@ -238,8 +245,8 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$this->pruefeKonfiguration();
|
$this->pruefeKonfiguration();
|
||||||
$this->konfiguriereEnergiearchiv();
|
|
||||||
$this->synchronisiereEnergievisualisierungen();
|
$this->synchronisiereEnergievisualisierungen();
|
||||||
|
$this->konfiguriereEnergiearchiv();
|
||||||
} catch (Throwable $fehler) {
|
} catch (Throwable $fehler) {
|
||||||
$this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG);
|
$this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG);
|
||||||
$this->SetTimerInterval('Regelzyklus', 0);
|
$this->SetTimerInterval('Regelzyklus', 0);
|
||||||
@@ -616,8 +623,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
];
|
];
|
||||||
$this->WriteAttributeString('VerbraucherCache', json_encode($cache, JSON_THROW_ON_ERROR));
|
$this->WriteAttributeString('VerbraucherCache', json_encode($cache, JSON_THROW_ON_ERROR));
|
||||||
$this->aktualisiereEnergieflusswerte();
|
$this->aktualisiereEnergieflusswerte();
|
||||||
|
$this->aktualisiereDiagrammMesswerte();
|
||||||
|
if ($this->GetBuffer('VerbraucherSynchronisierungAktiv') !== '1') {
|
||||||
$this->regeln(false);
|
$this->regeln(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @param array<string, mixed> $daten */
|
/** @param array<string, mixed> $daten */
|
||||||
private function aktualisiereVerbraucherEnergie(int $instanzID, array $daten, int $jetzt): void
|
private function aktualisiereVerbraucherEnergie(int $instanzID, array $daten, int $jetzt): void
|
||||||
@@ -1008,13 +1018,20 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
foreach ($ids as $instanzID) {
|
foreach ($ids as $instanzID) {
|
||||||
$eintrag = $cache[(string) $instanzID] ?? null;
|
$eintrag = $cache[(string) $instanzID] ?? null;
|
||||||
$grund = '';
|
$grund = $this->verbraucherMeldegrund($eintrag, $betriebsart, $timeout);
|
||||||
if (!is_array($eintrag) || !isset($eintrag['EmpfangenAm'], $eintrag['Daten'])) {
|
$synchronisierungsfehler = '';
|
||||||
$grund = 'Noch keine Meldung';
|
if (in_array($grund, ['Noch keine Meldung', 'Meldung ist veraltet'], true)) {
|
||||||
} elseif (time() - (int) $eintrag['EmpfangenAm'] > $timeout) {
|
try {
|
||||||
$grund = 'Meldung ist veraltet';
|
$this->SetBuffer('VerbraucherSynchronisierungAktiv', '1');
|
||||||
} elseif (($eintrag['Daten']['Betriebsart'] ?? null) !== $betriebsart) {
|
IPS_RequestAction($instanzID, 'Melden', true);
|
||||||
$grund = 'Leistungsangebot gehoert nicht zur Betriebsart ' . $betriebsart;
|
} catch (Throwable $fehler) {
|
||||||
|
$synchronisierungsfehler = $fehler->getMessage();
|
||||||
|
} finally {
|
||||||
|
$this->SetBuffer('VerbraucherSynchronisierungAktiv', '0');
|
||||||
|
}
|
||||||
|
$cache = $this->leseJsonAttribut('VerbraucherCache');
|
||||||
|
$eintrag = $cache[(string) $instanzID] ?? null;
|
||||||
|
$grund = $this->verbraucherMeldegrund($eintrag, $betriebsart, $timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($grund !== '') {
|
if ($grund !== '') {
|
||||||
@@ -1025,8 +1042,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
try {
|
try {
|
||||||
$this->sendeManagerdaten($instanzID, $betriebsart, null);
|
$this->sendeManagerdaten($instanzID, $betriebsart, null);
|
||||||
} catch (Throwable $fehler) {
|
} catch (Throwable $fehler) {
|
||||||
$stoerungen[] = $detail['Name'] . ': Betriebsart konnte nicht uebermittelt werden: '
|
$synchronisierungsfehler = $fehler->getMessage();
|
||||||
. $fehler->getMessage();
|
}
|
||||||
|
if ($synchronisierungsfehler !== '') {
|
||||||
|
$stoerungen[] = $detail['Name'] . ': Vollmeldung konnte nicht angefordert werden: '
|
||||||
|
. $synchronisierungsfehler;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1039,6 +1059,27 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
return $aktuell;
|
return $aktuell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed>|null $eintrag */
|
||||||
|
private function verbraucherMeldegrund(
|
||||||
|
?array $eintrag,
|
||||||
|
string $betriebsart,
|
||||||
|
int $timeout
|
||||||
|
): string {
|
||||||
|
if (!isset($eintrag['EmpfangenAm'], $eintrag['Daten'])
|
||||||
|
|| !is_array($eintrag['Daten'])
|
||||||
|
) {
|
||||||
|
return 'Noch keine Meldung';
|
||||||
|
}
|
||||||
|
if (time() - (int) $eintrag['EmpfangenAm'] > $timeout) {
|
||||||
|
return 'Meldung ist veraltet';
|
||||||
|
}
|
||||||
|
if (($eintrag['Daten']['Betriebsart'] ?? null) !== $betriebsart) {
|
||||||
|
return 'Leistungsangebot gehoert nicht zur Betriebsart ' . $betriebsart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
private function setzeNichtGeregelteVerbraucher(string $grund): void
|
private function setzeNichtGeregelteVerbraucher(string $grund): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -2120,6 +2161,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->WriteAttributeInteger('MessungLetzteEnergieaufzeichnung', $jetzt);
|
$this->WriteAttributeInteger('MessungLetzteEnergieaufzeichnung', $jetzt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->aktualisiereDiagrammMesswerte(true);
|
||||||
$funFactsID = @IPS_GetObjectIDByIdent('EnergieFunFacts', $this->InstanceID);
|
$funFactsID = @IPS_GetObjectIDByIdent('EnergieFunFacts', $this->InstanceID);
|
||||||
if (is_int($funFactsID) && $funFactsID > 0 && IPS_VariableExists($funFactsID)) {
|
if (is_int($funFactsID) && $funFactsID > 0 && IPS_VariableExists($funFactsID)) {
|
||||||
$this->aktualisiereFunFacts($funFactsID);
|
$this->aktualisiereFunFacts($funFactsID);
|
||||||
@@ -2647,6 +2689,16 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
throw new InvalidArgumentException($property . ' darf nicht negativ sein.');
|
throw new InvalidArgumentException($property . ' darf nicht negativ sein.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (['DiagrammPVModus', 'DiagrammBatterieModus'] as $property) {
|
||||||
|
if (!in_array($this->ReadPropertyInteger($property), [0, 1, 2], true)) {
|
||||||
|
throw new InvalidArgumentException($property . ' muss 0, 1 oder 2 sein.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!in_array($this->ReadPropertyInteger('EnergieflussLeistungseinheit'), [0, 1], true)) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'EnergieflussLeistungseinheit muss 0 oder 1 sein.'
|
||||||
|
);
|
||||||
|
}
|
||||||
$energieLoeschen = $this->ReadPropertyInteger('EnergieLoeschenMonate');
|
$energieLoeschen = $this->ReadPropertyInteger('EnergieLoeschenMonate');
|
||||||
$energieVerdichten = $this->ReadPropertyInteger('EnergieVerdichtenMonate');
|
$energieVerdichten = $this->ReadPropertyInteger('EnergieVerdichtenMonate');
|
||||||
if ($energieLoeschen > 0 && $energieLoeschen <= $energieVerdichten) {
|
if ($energieLoeschen > 0 && $energieLoeschen <= $energieVerdichten) {
|
||||||
|
|||||||
+594
-45
@@ -55,6 +55,38 @@ trait ManagerEnergieTrait
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (IPS_GetChildrenIDs($this->InstanceID) as $variableID) {
|
||||||
|
$objekt = IPS_GetObject($variableID);
|
||||||
|
$ident = (string) ($objekt['ObjectIdent'] ?? '');
|
||||||
|
if ((int) ($objekt['ObjectType'] ?? -1) !== 2
|
||||||
|
|| !str_starts_with($ident, 'Diagramm')
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$istEnergie = str_contains($ident, 'Energie')
|
||||||
|
|| str_contains($ident, 'BatterieLaden_')
|
||||||
|
|| str_contains($ident, 'BatterieEntladen_');
|
||||||
|
AC_SetLoggingStatus($archivID, $variableID, $aktiv);
|
||||||
|
AC_SetAggregationType($archivID, $variableID, $istEnergie ? 1 : 0);
|
||||||
|
AC_SetGraphStatus($archivID, $variableID, $aktiv);
|
||||||
|
$regeln = [-1 => $istEnergie ? $energietyp : $leistungstyp];
|
||||||
|
$verdichten = $istEnergie
|
||||||
|
? $this->ReadPropertyInteger('EnergieVerdichtenMonate')
|
||||||
|
: 0;
|
||||||
|
if ($verdichten > 0) {
|
||||||
|
$regeln[$verdichten] = 3;
|
||||||
|
}
|
||||||
|
$loeschen = $istEnergie
|
||||||
|
? $this->ReadPropertyInteger('EnergieLoeschenMonate')
|
||||||
|
: $this->ReadPropertyInteger('LeistungLoeschenMonate');
|
||||||
|
if ($loeschen > 0) {
|
||||||
|
$regeln[$loeschen] = 7;
|
||||||
|
}
|
||||||
|
if ($aktiv && $this->setzeVerdichtung($archivID, $variableID, $regeln)) {
|
||||||
|
$geaendert[] = $variableID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IPS_ApplyChanges($archivID);
|
IPS_ApplyChanges($archivID);
|
||||||
foreach (array_unique($geaendert) as $variableID) {
|
foreach (array_unique($geaendert) as $variableID) {
|
||||||
AC_ReAggregateVariable($archivID, $variableID);
|
AC_ReAggregateVariable($archivID, $variableID);
|
||||||
@@ -129,6 +161,7 @@ trait ManagerEnergieTrait
|
|||||||
}
|
}
|
||||||
$this->entferneDiagrammUnterobjekt('Leistungsdiagramm');
|
$this->entferneDiagrammUnterobjekt('Leistungsdiagramm');
|
||||||
$this->entferneDiagrammUnterobjekt('Energiediagramm');
|
$this->entferneDiagrammUnterobjekt('Energiediagramm');
|
||||||
|
$this->WriteAttributeString('EnergiediagrammKonfiguration', '{}');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function synchronisiereFunFacts(bool $anzeigen): void
|
private function synchronisiereFunFacts(bool $anzeigen): void
|
||||||
@@ -154,9 +187,7 @@ trait ManagerEnergieTrait
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$instanzID = $this->findeUnterobjekt('Energiefluss');
|
$instanzID = $this->findeUnterobjekt('Energiefluss');
|
||||||
if ($instanzID === 0) {
|
if ($instanzID !== 0) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
$objekt = IPS_GetObject($instanzID);
|
$objekt = IPS_GetObject($instanzID);
|
||||||
$modulID = $objekt['ObjectType'] === 1
|
$modulID = $objekt['ObjectType'] === 1
|
||||||
? (string) IPS_GetInstance($instanzID)['ModuleInfo']['ModuleID']
|
? (string) IPS_GetInstance($instanzID)['ModuleInfo']['ModuleID']
|
||||||
@@ -166,6 +197,9 @@ trait ManagerEnergieTrait
|
|||||||
}
|
}
|
||||||
IPS_SetHidden($instanzID, true);
|
IPS_SetHidden($instanzID, true);
|
||||||
}
|
}
|
||||||
|
$this->WriteAttributeString('EnergieflussKonfiguration', '{}');
|
||||||
|
$this->WriteAttributeBoolean('EnergieflussNeuErzeugen', true);
|
||||||
|
}
|
||||||
|
|
||||||
private function entferneInstanzUnterobjekt(string $ident, string $modulID): void
|
private function entferneInstanzUnterobjekt(string $ident, string $modulID): void
|
||||||
{
|
{
|
||||||
@@ -216,6 +250,9 @@ trait ManagerEnergieTrait
|
|||||||
if ($modulID !== self::ENERGY_PIE_MODULE_ID) {
|
if ($modulID !== self::ENERGY_PIE_MODULE_ID) {
|
||||||
throw new RuntimeException('Unterobjekt EnergyPie hat einen unpassenden Typ.');
|
throw new RuntimeException('Unterobjekt EnergyPie hat einen unpassenden Typ.');
|
||||||
}
|
}
|
||||||
|
IPS_SetHidden($instanzID, false);
|
||||||
|
|
||||||
|
return 'Bestehende Energy-Pie-Konfiguration bleibt unveraendert.';
|
||||||
}
|
}
|
||||||
IPS_SetName($instanzID, 'Energy Pie');
|
IPS_SetName($instanzID, 'Energy Pie');
|
||||||
IPS_SetPosition($instanzID, 500);
|
IPS_SetPosition($instanzID, 500);
|
||||||
@@ -239,6 +276,7 @@ trait ManagerEnergieTrait
|
|||||||
if (!in_array(self::ENERGY_FLOW_MODULE_ID, IPS_GetModuleList(), true)) {
|
if (!in_array(self::ENERGY_FLOW_MODULE_ID, IPS_GetModuleList(), true)) {
|
||||||
throw new RuntimeException('Das Symcon-Modul Energy Distribution ist nicht installiert.');
|
throw new RuntimeException('Das Symcon-Modul Energy Distribution ist nicht installiert.');
|
||||||
}
|
}
|
||||||
|
$neuErzeugen = $this->ReadAttributeBoolean('EnergieflussNeuErzeugen');
|
||||||
$instanzID = $this->findeUnterobjekt('Energiefluss');
|
$instanzID = $this->findeUnterobjekt('Energiefluss');
|
||||||
if ($instanzID === 0) {
|
if ($instanzID === 0) {
|
||||||
$instanzID = IPS_CreateInstance(self::ENERGY_FLOW_MODULE_ID);
|
$instanzID = IPS_CreateInstance(self::ENERGY_FLOW_MODULE_ID);
|
||||||
@@ -252,7 +290,15 @@ trait ManagerEnergieTrait
|
|||||||
if ($modulID !== self::ENERGY_FLOW_MODULE_ID) {
|
if ($modulID !== self::ENERGY_FLOW_MODULE_ID) {
|
||||||
throw new RuntimeException('Unterobjekt Energiefluss hat einen unpassenden Typ.');
|
throw new RuntimeException('Unterobjekt Energiefluss hat einen unpassenden Typ.');
|
||||||
}
|
}
|
||||||
|
if (!$neuErzeugen) {
|
||||||
|
$this->visualisierungsKonfiguration('EnergieflussKonfiguration');
|
||||||
|
IPS_SetHidden($instanzID, false);
|
||||||
|
$this->aktualisiereEnergieflusswerte();
|
||||||
|
|
||||||
|
return 'Bestehende Energiefluss-Konfiguration bleibt unveraendert.';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
$this->visualisierungsKonfiguration('EnergieflussKonfiguration');
|
||||||
IPS_SetName($instanzID, 'Energiefluss');
|
IPS_SetName($instanzID, 'Energiefluss');
|
||||||
IPS_SetPosition($instanzID, 540);
|
IPS_SetPosition($instanzID, 540);
|
||||||
IPS_SetHidden($instanzID, false);
|
IPS_SetHidden($instanzID, false);
|
||||||
@@ -289,7 +335,6 @@ trait ManagerEnergieTrait
|
|||||||
$this->energieflussKnoten($netzID, 'Stromnetz', 'grid'),
|
$this->energieflussKnoten($netzID, 'Stromnetz', 'grid'),
|
||||||
$this->energieflussKnoten($hausID, 'Hausverbrauch', 'consumer'),
|
$this->energieflussKnoten($hausID, 'Hausverbrauch', 'consumer'),
|
||||||
];
|
];
|
||||||
$hatBatterieverbraucher = false;
|
|
||||||
$position = 640;
|
$position = 640;
|
||||||
foreach ($verbraucher as $eintrag) {
|
foreach ($verbraucher as $eintrag) {
|
||||||
$istID = $this->energieflussLeistungsvariable(
|
$istID = $this->energieflussLeistungsvariable(
|
||||||
@@ -311,17 +356,13 @@ trait ManagerEnergieTrait
|
|||||||
true,
|
true,
|
||||||
$sollID
|
$sollID
|
||||||
);
|
);
|
||||||
$hatBatterieverbraucher = $hatBatterieverbraucher
|
|
||||||
|| $eintrag['Typ'] === 'storage';
|
|
||||||
$position += 10;
|
$position += 10;
|
||||||
}
|
}
|
||||||
if (!$hatBatterieverbraucher) {
|
|
||||||
$knoten[] = $this->energieflussKnoten(
|
$knoten[] = $this->energieflussKnoten(
|
||||||
$batterieID,
|
$batterieID,
|
||||||
'Batteriespeicher',
|
'Batteriespeicher',
|
||||||
'storage'
|
'storage'
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
IPS_SetProperty($instanzID, 'Calculation', true);
|
IPS_SetProperty($instanzID, 'Calculation', true);
|
||||||
IPS_SetProperty(
|
IPS_SetProperty(
|
||||||
@@ -332,6 +373,7 @@ trait ManagerEnergieTrait
|
|||||||
IPS_SetProperty($instanzID, 'EnableLimits', false);
|
IPS_SetProperty($instanzID, 'EnableLimits', false);
|
||||||
IPS_SetProperty($instanzID, 'Restrictions', '[]');
|
IPS_SetProperty($instanzID, 'Restrictions', '[]');
|
||||||
IPS_ApplyChanges($instanzID);
|
IPS_ApplyChanges($instanzID);
|
||||||
|
$this->WriteAttributeBoolean('EnergieflussNeuErzeugen', false);
|
||||||
$this->aktualisiereEnergieflusswerte($verbraucher);
|
$this->aktualisiereEnergieflusswerte($verbraucher);
|
||||||
|
|
||||||
return 'Der Energiefluss wurde erstellt oder aktualisiert.';
|
return 'Der Energiefluss wurde erstellt oder aktualisiert.';
|
||||||
@@ -360,7 +402,10 @@ trait ManagerEnergieTrait
|
|||||||
|
|
||||||
private function energieflussLeistungsprofil(): string
|
private function energieflussLeistungsprofil(): string
|
||||||
{
|
{
|
||||||
if ($this->ReadPropertyInteger('EnergieflussLeistungseinheit') !== 1) {
|
$konfiguration = $this->visualisierungsKonfiguration(
|
||||||
|
'EnergieflussKonfiguration'
|
||||||
|
);
|
||||||
|
if ($konfiguration['EnergieflussLeistungseinheit'] !== 1) {
|
||||||
return '~Power';
|
return '~Power';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,18 +433,55 @@ trait ManagerEnergieTrait
|
|||||||
return $variableID;
|
return $variableID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<string, bool|int> */
|
||||||
|
private function visualisierungsKonfiguration(string $attribut): array
|
||||||
|
{
|
||||||
|
$konfiguration = $this->leseJsonAttribut($attribut);
|
||||||
|
$gueltig = isset(
|
||||||
|
$konfiguration['DiagrammPVModus'],
|
||||||
|
$konfiguration['DiagrammBatterieModus'],
|
||||||
|
$konfiguration['LadestationenSeparatAnzeigen'],
|
||||||
|
$konfiguration['VerbraucherSeparatAnzeigen'],
|
||||||
|
$konfiguration['EnergieflussLeistungseinheit']
|
||||||
|
);
|
||||||
|
if ($gueltig) {
|
||||||
|
return $konfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
$konfiguration = [
|
||||||
|
'DiagrammPVModus' => $this->ReadPropertyInteger('DiagrammPVModus'),
|
||||||
|
'DiagrammBatterieModus' => $this->ReadPropertyInteger('DiagrammBatterieModus'),
|
||||||
|
'LadestationenSeparatAnzeigen' =>
|
||||||
|
$this->ReadPropertyBoolean('LadestationenSeparatAnzeigen'),
|
||||||
|
'VerbraucherSeparatAnzeigen' =>
|
||||||
|
$this->ReadPropertyBoolean('VerbraucherSeparatAnzeigen'),
|
||||||
|
'EnergieflussLeistungseinheit' =>
|
||||||
|
$this->ReadPropertyInteger('EnergieflussLeistungseinheit'),
|
||||||
|
];
|
||||||
|
$this->WriteAttributeString(
|
||||||
|
$attribut,
|
||||||
|
json_encode($konfiguration, JSON_THROW_ON_ERROR)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $konfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list<array{
|
* @return list<array{
|
||||||
* InstanzID: int,
|
* InstanzID: int,
|
||||||
* Name: string,
|
* Name: string,
|
||||||
* Typ: string,
|
* Typ: string,
|
||||||
* Istleistung_W: float,
|
* Istleistung_W: float,
|
||||||
* Sollleistung_W: float
|
* Sollleistung_W: float,
|
||||||
|
* Energie_Wh: float
|
||||||
* }>
|
* }>
|
||||||
*/
|
*/
|
||||||
private function energieflussVerbraucher(): array
|
private function energieflussVerbraucher(
|
||||||
{
|
string $konfigurationsAttribut = 'EnergieflussKonfiguration'
|
||||||
|
): array {
|
||||||
|
$konfiguration = $this->visualisierungsKonfiguration($konfigurationsAttribut);
|
||||||
$cache = $this->leseJsonAttribut('VerbraucherCache');
|
$cache = $this->leseJsonAttribut('VerbraucherCache');
|
||||||
|
$energien = $this->leseJsonAttribut('VerbraucherEnergie');
|
||||||
$ergebnis = [];
|
$ergebnis = [];
|
||||||
foreach ($this->konfigurierteAktiveVerbraucherIDs() as $instanzID) {
|
foreach ($this->konfigurierteAktiveVerbraucherIDs() as $instanzID) {
|
||||||
if (!IPS_InstanceExists($instanzID)) {
|
if (!IPS_InstanceExists($instanzID)) {
|
||||||
@@ -416,17 +498,30 @@ trait ManagerEnergieTrait
|
|||||||
(string) IPS_GetInstance($instanzID)['ModuleInfo']['ModuleID']
|
(string) IPS_GetInstance($instanzID)['ModuleInfo']['ModuleID']
|
||||||
);
|
);
|
||||||
$katalog = self::VERBRAUCHER_LIZENZEN[$modulID]['Katalog'] ?? '';
|
$katalog = self::VERBRAUCHER_LIZENZEN[$modulID]['Katalog'] ?? '';
|
||||||
|
if ($katalog === 'battery') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($katalog === 'ev_charger'
|
||||||
|
&& !$konfiguration['LadestationenSeparatAnzeigen']
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($katalog !== 'ev_charger'
|
||||||
|
&& !$konfiguration['VerbraucherSeparatAnzeigen']
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$verbraucherEnergie = $energien[(string) $instanzID]['Energie_Wh'] ?? 0.0;
|
||||||
|
|
||||||
$ergebnis[] = [
|
$ergebnis[] = [
|
||||||
'InstanzID' => $instanzID,
|
'InstanzID' => $instanzID,
|
||||||
'Name' => IPS_GetName($instanzID),
|
'Name' => IPS_GetName($instanzID),
|
||||||
'Typ' => match ($katalog) {
|
'Typ' => $katalog === 'ev_charger' ? 'wallbox' : 'consumer',
|
||||||
'battery' => 'storage',
|
|
||||||
'ev_charger' => 'wallbox',
|
|
||||||
default => 'consumer',
|
|
||||||
},
|
|
||||||
'Istleistung_W' => $istleistung,
|
'Istleistung_W' => $istleistung,
|
||||||
'Sollleistung_W' => $sollleistung,
|
'Sollleistung_W' => $sollleistung,
|
||||||
|
'Energie_Wh' => is_numeric($verbraucherEnergie)
|
||||||
|
? (float) $verbraucherEnergie
|
||||||
|
: 0.0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +538,6 @@ trait ManagerEnergieTrait
|
|||||||
}
|
}
|
||||||
$verbraucher = $verbraucher ?? $this->energieflussVerbraucher();
|
$verbraucher = $verbraucher ?? $this->energieflussVerbraucher();
|
||||||
$verbraucherleistung = 0.0;
|
$verbraucherleistung = 0.0;
|
||||||
$hatBatterieverbraucher = false;
|
|
||||||
foreach ($verbraucher as $eintrag) {
|
foreach ($verbraucher as $eintrag) {
|
||||||
$this->setzeEnergieflussLeistungswert(
|
$this->setzeEnergieflussLeistungswert(
|
||||||
'EnergieflussIst_' . $eintrag['InstanzID'],
|
'EnergieflussIst_' . $eintrag['InstanzID'],
|
||||||
@@ -453,12 +547,8 @@ trait ManagerEnergieTrait
|
|||||||
'EnergieflussSoll_' . $eintrag['InstanzID'],
|
'EnergieflussSoll_' . $eintrag['InstanzID'],
|
||||||
(float) $eintrag['Sollleistung_W']
|
(float) $eintrag['Sollleistung_W']
|
||||||
);
|
);
|
||||||
if ($eintrag['Typ'] === 'storage') {
|
|
||||||
$hatBatterieverbraucher = true;
|
|
||||||
} else {
|
|
||||||
$verbraucherleistung += max(0.0, (float) $eintrag['Istleistung_W']);
|
$verbraucherleistung += max(0.0, (float) $eintrag['Istleistung_W']);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$leistungen = $this->leseMessleistungen();
|
$leistungen = $this->leseMessleistungen();
|
||||||
@@ -472,13 +562,11 @@ trait ManagerEnergieTrait
|
|||||||
'EnergieflussHaus',
|
'EnergieflussHaus',
|
||||||
max(0.0, $leistungen['Haus'] - $verbraucherleistung)
|
max(0.0, $leistungen['Haus'] - $verbraucherleistung)
|
||||||
);
|
);
|
||||||
if (!$hatBatterieverbraucher) {
|
|
||||||
$this->setzeEnergieflussLeistungswert(
|
$this->setzeEnergieflussLeistungswert(
|
||||||
'EnergieflussBatterie',
|
'EnergieflussBatterie',
|
||||||
$leistungen['Batterie']
|
$leistungen['Batterie']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private function setzeEnergieflussLeistungswert(string $ident, float $watt): void
|
private function setzeEnergieflussLeistungswert(string $ident, float $watt): void
|
||||||
{
|
{
|
||||||
@@ -486,33 +574,487 @@ trait ManagerEnergieTrait
|
|||||||
if (!is_int($variableID) || $variableID <= 0 || !IPS_VariableExists($variableID)) {
|
if (!is_int($variableID) || $variableID <= 0 || !IPS_VariableExists($variableID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$faktor = $this->ReadPropertyInteger('EnergieflussLeistungseinheit') === 1
|
$konfiguration = $this->visualisierungsKonfiguration(
|
||||||
? 0.001
|
'EnergieflussKonfiguration'
|
||||||
: 1.0;
|
);
|
||||||
|
$faktor = $konfiguration['EnergieflussLeistungseinheit'] === 1 ? 0.001 : 1.0;
|
||||||
SetValue($variableID, $watt * $faktor);
|
SetValue($variableID, $watt * $faktor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function erstelleEnergiediagramme(): string
|
private function erstelleEnergiediagramme(): string
|
||||||
{
|
{
|
||||||
$leistung = [
|
$konfiguration = $this->visualisierungsKonfiguration(
|
||||||
$this->chartDatensatz('PVLeistungArchiv', 'PV', '#F4C542', '~Power'),
|
'EnergiediagrammKonfiguration'
|
||||||
$this->chartDatensatz('HausverbrauchLeistungArchiv', 'Haus', '#22A06B', '~Power'),
|
);
|
||||||
$this->chartDatensatz('NetzleistungArchiv', 'Netz', '#E95D5D', '~Power'),
|
$pvAnlagen = $this->diagrammPVAnlagen();
|
||||||
$this->chartDatensatz('BatterieleistungArchiv', 'Batterie', '#8B5CF6', '~Power'),
|
$batterien = $this->diagrammBatterien();
|
||||||
];
|
$verbraucher = $this->energieflussVerbraucher(
|
||||||
$energie = [
|
'EnergiediagrammKonfiguration'
|
||||||
$this->chartDatensatz('PVEnergie', 'PV', '#F4C542', '~Electricity'),
|
);
|
||||||
$this->chartDatensatz('Hausenergie', 'Haus', '#22A06B', '~Electricity'),
|
$this->registriereDiagrammVariablen($pvAnlagen, $batterien, $verbraucher);
|
||||||
$this->chartDatensatz('NetzbezugEnergie', 'Netzbezug', '#E95D5D', '~Electricity'),
|
$this->aktualisiereDiagrammMesswerte(true);
|
||||||
$this->chartDatensatz('EinspeisungEnergie', 'Einspeisung', '#2F80ED', '~Electricity'),
|
|
||||||
$this->chartDatensatz('BatterieLadenEnergie', 'Batterie laden', '#8B5CF6', '~Electricity'),
|
$leistung = [];
|
||||||
$this->chartDatensatz('BatterieEntladenEnergie', 'Batterie entladen', '#F59E0B', '~Electricity'),
|
$energie = [];
|
||||||
];
|
if ($konfiguration['DiagrammPVModus'] !== 1) {
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
'PVLeistungArchiv',
|
||||||
|
'PV gesamt',
|
||||||
|
'#F4C542',
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'PVEnergie',
|
||||||
|
'PV gesamt',
|
||||||
|
'#F4C542',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($konfiguration['DiagrammPVModus'] !== 0) {
|
||||||
|
foreach ($pvAnlagen as $index => $anlage) {
|
||||||
|
$farbe = $this->diagrammFarbe($index);
|
||||||
|
if ($anlage['LeistungVariableID'] > 0) {
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
$anlage['LeistungIdent'],
|
||||||
|
$anlage['Name'],
|
||||||
|
$farbe,
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($anlage['EnergieVariableID'] > 0) {
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
$anlage['EnergieIdent'],
|
||||||
|
$anlage['Name'],
|
||||||
|
$farbe,
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hausTitel = $verbraucher === [] ? 'Haus' : 'Haus ohne separat dargestellte Verbraucher';
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
'DiagrammHausLeistung',
|
||||||
|
$hausTitel,
|
||||||
|
'#22A06B',
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
'NetzleistungArchiv',
|
||||||
|
'Netz',
|
||||||
|
'#E95D5D',
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'DiagrammHausEnergie',
|
||||||
|
$hausTitel,
|
||||||
|
'#22A06B',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'NetzbezugEnergie',
|
||||||
|
'Netzbezug',
|
||||||
|
'#E95D5D',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'EinspeisungEnergie',
|
||||||
|
'Netzeinspeisung',
|
||||||
|
'#2F80ED',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($konfiguration['DiagrammBatterieModus'] !== 1) {
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
'BatterieleistungArchiv',
|
||||||
|
'Batterie gesamt',
|
||||||
|
'#8B5CF6',
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'BatterieLadenEnergie',
|
||||||
|
'Batterie laden gesamt',
|
||||||
|
'#8B5CF6',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'BatterieEntladenEnergie',
|
||||||
|
'Batterie entladen gesamt',
|
||||||
|
'#F59E0B',
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($konfiguration['DiagrammBatterieModus'] !== 0) {
|
||||||
|
foreach ($batterien as $index => $batterie) {
|
||||||
|
$farbe = $this->diagrammFarbe($index + count($pvAnlagen));
|
||||||
|
if ($batterie['LeistungVariableID'] > 0) {
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
$batterie['LeistungIdent'],
|
||||||
|
$batterie['Name'],
|
||||||
|
$farbe,
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($batterie['LadeenergieVariableID'] > 0) {
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
$batterie['LadeenergieIdent'],
|
||||||
|
$batterie['Name'] . ' laden',
|
||||||
|
$farbe,
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($batterie['EntladeenergieVariableID'] > 0) {
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
$batterie['EntladeenergieIdent'],
|
||||||
|
$batterie['Name'] . ' entladen',
|
||||||
|
$farbe,
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($verbraucher as $index => $eintrag) {
|
||||||
|
$farbe = $this->diagrammFarbe(
|
||||||
|
$index + count($pvAnlagen) + count($batterien)
|
||||||
|
);
|
||||||
|
$leistung[] = $this->chartDatensatz(
|
||||||
|
'DiagrammVerbraucherLeistung_' . $eintrag['InstanzID'],
|
||||||
|
$eintrag['Name'],
|
||||||
|
$farbe,
|
||||||
|
'~Power'
|
||||||
|
);
|
||||||
|
$energie[] = $this->chartDatensatz(
|
||||||
|
'DiagrammVerbraucherEnergie_' . $eintrag['InstanzID'],
|
||||||
|
$eintrag['Name'],
|
||||||
|
$farbe,
|
||||||
|
'~Electricity',
|
||||||
|
'bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->erstelleDiagramm('Leistungsdiagramm', 'Leistungen', $leistung, 510);
|
$this->erstelleDiagramm('Leistungsdiagramm', 'Leistungen', $leistung, 510);
|
||||||
$this->erstelleDiagramm('Energiediagramm', 'Energien', $energie, 520);
|
$this->erstelleDiagramm('Energiediagramm', 'Energien', $energie, 520);
|
||||||
|
|
||||||
return 'Die Diagramme Leistungen und Energien wurden erstellt oder aktualisiert.';
|
return 'Die Diagramme Leistungen und Energien wurden erstellt oder aktualisiert.';
|
||||||
}
|
}
|
||||||
|
/** @return list<array<string, mixed>> */
|
||||||
|
private function diagrammPVAnlagen(): array
|
||||||
|
{
|
||||||
|
$verwendet = [];
|
||||||
|
foreach ($this->leseAnlagenKonfigurationsliste('AnlagenPVFlaechen') as $flaeche) {
|
||||||
|
$wechselrichterID = trim((string) ($flaeche['WechselrichterID'] ?? ''));
|
||||||
|
if ($wechselrichterID !== '') {
|
||||||
|
$verwendet[$wechselrichterID] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ergebnis = [];
|
||||||
|
foreach ($this->leseAnlagenKonfigurationsliste('AnlagenWechselrichter') as $eintrag) {
|
||||||
|
$id = trim((string) ($eintrag['ID'] ?? ''));
|
||||||
|
if ($id === '' || ($verwendet !== [] && !isset($verwendet[$id]))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($verwendet === []
|
||||||
|
&& !in_array((string) ($eintrag['Typ'] ?? ''), ['pv', 'hybrid'], true)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$suffix = substr(hash('sha256', 'pv:' . $id), 0, 12);
|
||||||
|
$leistungID = (int) ($eintrag['IstleistungVariableID'] ?? 0);
|
||||||
|
$energieID = (int) ($eintrag['ErzeugungsenergieVariableID'] ?? 0);
|
||||||
|
$ergebnis[] = [
|
||||||
|
'Name' => trim((string) ($eintrag['Name'] ?? '')) ?: $id,
|
||||||
|
'LeistungVariableID' => $this->istNumerischeVariable($leistungID)
|
||||||
|
? $leistungID
|
||||||
|
: 0,
|
||||||
|
'Leistungsfaktor' => (float) ($eintrag['Istleistungsfaktor'] ?? 1.0),
|
||||||
|
'EnergieVariableID' => $this->istNumerischeVariable($energieID)
|
||||||
|
? $energieID
|
||||||
|
: 0,
|
||||||
|
'Energiefaktor' => (float) ($eintrag['Erzeugungsenergiefaktor'] ?? 1.0),
|
||||||
|
'LeistungIdent' => 'DiagrammPVLeistung_' . $suffix,
|
||||||
|
'EnergieIdent' => 'DiagrammPVEnergie_' . $suffix,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ergebnis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<array<string, mixed>> */
|
||||||
|
private function diagrammBatterien(): array
|
||||||
|
{
|
||||||
|
$ergebnis = [];
|
||||||
|
foreach ($this->leseAnlagenKonfigurationsliste('AnlagenBatterien') as $eintrag) {
|
||||||
|
$id = trim((string) ($eintrag['ID'] ?? ''));
|
||||||
|
if ($id === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$suffix = substr(hash('sha256', 'batterie:' . $id), 0, 12);
|
||||||
|
$leistungID = (int) ($eintrag['LeistungVariableID'] ?? 0);
|
||||||
|
$ladenID = (int) ($eintrag['LadeenergieVariableID'] ?? 0);
|
||||||
|
$entladenID = (int) ($eintrag['EntladeenergieVariableID'] ?? 0);
|
||||||
|
$ergebnis[] = [
|
||||||
|
'Name' => trim((string) ($eintrag['Name'] ?? '')) ?: $id,
|
||||||
|
'LeistungVariableID' => $this->istNumerischeVariable($leistungID)
|
||||||
|
? $leistungID
|
||||||
|
: 0,
|
||||||
|
'Leistungsfaktor' => (float) ($eintrag['Leistungsfaktor'] ?? 1.0),
|
||||||
|
'LadeenergieVariableID' => $this->istNumerischeVariable($ladenID)
|
||||||
|
? $ladenID
|
||||||
|
: 0,
|
||||||
|
'EntladeenergieVariableID' => $this->istNumerischeVariable($entladenID)
|
||||||
|
? $entladenID
|
||||||
|
: 0,
|
||||||
|
'Energiefaktor' => (float) ($eintrag['Energiefaktor'] ?? 1.0),
|
||||||
|
'LeistungIdent' => 'DiagrammBatterieLeistung_' . $suffix,
|
||||||
|
'LadeenergieIdent' => 'DiagrammBatterieLaden_' . $suffix,
|
||||||
|
'EntladeenergieIdent' => 'DiagrammBatterieEntladen_' . $suffix,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ergebnis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<array<string, mixed>> $pvAnlagen
|
||||||
|
* @param list<array<string, mixed>> $batterien
|
||||||
|
* @param list<array<string, mixed>> $verbraucher
|
||||||
|
*/
|
||||||
|
private function registriereDiagrammVariablen(
|
||||||
|
array $pvAnlagen,
|
||||||
|
array $batterien,
|
||||||
|
array $verbraucher
|
||||||
|
): void {
|
||||||
|
$position = 800;
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
'DiagrammHausLeistung',
|
||||||
|
'Diagramm Hausleistung',
|
||||||
|
'~Power',
|
||||||
|
$position
|
||||||
|
);
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
'DiagrammHausEnergie',
|
||||||
|
'Diagramm Hausenergie',
|
||||||
|
'~Electricity',
|
||||||
|
$position + 1
|
||||||
|
);
|
||||||
|
$position += 10;
|
||||||
|
|
||||||
|
foreach ($pvAnlagen as $anlage) {
|
||||||
|
if ($anlage['LeistungVariableID'] > 0) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
$anlage['LeistungIdent'],
|
||||||
|
$anlage['Name'] . ' Leistung',
|
||||||
|
'~Power',
|
||||||
|
$position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($anlage['EnergieVariableID'] > 0) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
$anlage['EnergieIdent'],
|
||||||
|
$anlage['Name'] . ' Energie',
|
||||||
|
'~Electricity',
|
||||||
|
$position + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$position += 10;
|
||||||
|
}
|
||||||
|
foreach ($batterien as $batterie) {
|
||||||
|
if ($batterie['LeistungVariableID'] > 0) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
$batterie['LeistungIdent'],
|
||||||
|
$batterie['Name'] . ' Leistung',
|
||||||
|
'~Power',
|
||||||
|
$position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($batterie['LadeenergieVariableID'] > 0) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
$batterie['LadeenergieIdent'],
|
||||||
|
$batterie['Name'] . ' Ladeenergie',
|
||||||
|
'~Electricity',
|
||||||
|
$position + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($batterie['EntladeenergieVariableID'] > 0) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
$batterie['EntladeenergieIdent'],
|
||||||
|
$batterie['Name'] . ' Entladeenergie',
|
||||||
|
'~Electricity',
|
||||||
|
$position + 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$position += 10;
|
||||||
|
}
|
||||||
|
foreach ($verbraucher as $eintrag) {
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
'DiagrammVerbraucherLeistung_' . $eintrag['InstanzID'],
|
||||||
|
$eintrag['Name'] . ' Leistung',
|
||||||
|
'~Power',
|
||||||
|
$position
|
||||||
|
);
|
||||||
|
$this->diagrammMessvariable(
|
||||||
|
'DiagrammVerbraucherEnergie_' . $eintrag['InstanzID'],
|
||||||
|
$eintrag['Name'] . ' Energie',
|
||||||
|
'~Electricity',
|
||||||
|
$position + 1
|
||||||
|
);
|
||||||
|
$position += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function diagrammMessvariable(
|
||||||
|
string $ident,
|
||||||
|
string $name,
|
||||||
|
string $profil,
|
||||||
|
int $position
|
||||||
|
): int {
|
||||||
|
$this->RegisterVariableFloat($ident, $name, $profil, $position);
|
||||||
|
$variableID = $this->GetIDForIdent($ident);
|
||||||
|
IPS_SetHidden($variableID, true);
|
||||||
|
|
||||||
|
return $variableID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function aktualisiereDiagrammMesswerte(bool $energieAktualisieren = false): void
|
||||||
|
{
|
||||||
|
if ($this->findeUnterobjekt('Leistungsdiagramm') === 0
|
||||||
|
&& $this->findeUnterobjekt('Energiediagramm') === 0
|
||||||
|
&& $this->findeUnterobjekt('DiagrammHausLeistung') === 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$leistungen = $this->leseMessleistungen();
|
||||||
|
$pvAnlagen = $this->diagrammPVAnlagen();
|
||||||
|
$batterien = $this->diagrammBatterien();
|
||||||
|
$verbraucher = $this->energieflussVerbraucher(
|
||||||
|
'EnergiediagrammKonfiguration'
|
||||||
|
);
|
||||||
|
} catch (Throwable $fehler) {
|
||||||
|
$this->protokolliere('Energiediagramme', $fehler->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$separateLeistung = 0.0;
|
||||||
|
$separateEnergieKWh = 0.0;
|
||||||
|
foreach ($verbraucher as $eintrag) {
|
||||||
|
$leistung = max(0.0, (float) $eintrag['Istleistung_W']);
|
||||||
|
$separateLeistung += $leistung;
|
||||||
|
$separateEnergieKWh += max(0.0, (float) $eintrag['Energie_Wh']) / 1000.0;
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
'DiagrammVerbraucherLeistung_' . $eintrag['InstanzID'],
|
||||||
|
$leistung
|
||||||
|
);
|
||||||
|
if ($energieAktualisieren) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
'DiagrammVerbraucherEnergie_' . $eintrag['InstanzID'],
|
||||||
|
max(0.0, (float) $eintrag['Energie_Wh']) / 1000.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
'DiagrammHausLeistung',
|
||||||
|
max(0.0, $leistungen['Haus'] - $separateLeistung)
|
||||||
|
);
|
||||||
|
if ($energieAktualisieren) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
'DiagrammHausEnergie',
|
||||||
|
max(
|
||||||
|
0.0,
|
||||||
|
(float) $this->GetValue('Hausenergie') - $separateEnergieKWh
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($pvAnlagen as $anlage) {
|
||||||
|
if ($anlage['LeistungVariableID'] > 0) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
$anlage['LeistungIdent'],
|
||||||
|
max(
|
||||||
|
0.0,
|
||||||
|
(float) GetValue($anlage['LeistungVariableID'])
|
||||||
|
* $anlage['Leistungsfaktor']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($energieAktualisieren && $anlage['EnergieVariableID'] > 0) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
$anlage['EnergieIdent'],
|
||||||
|
max(
|
||||||
|
0.0,
|
||||||
|
(float) GetValue($anlage['EnergieVariableID'])
|
||||||
|
* $anlage['Energiefaktor']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($batterien as $batterie) {
|
||||||
|
if ($batterie['LeistungVariableID'] > 0) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
$batterie['LeistungIdent'],
|
||||||
|
(float) GetValue($batterie['LeistungVariableID'])
|
||||||
|
* $batterie['Leistungsfaktor']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($energieAktualisieren && $batterie['LadeenergieVariableID'] > 0) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
$batterie['LadeenergieIdent'],
|
||||||
|
max(
|
||||||
|
0.0,
|
||||||
|
(float) GetValue($batterie['LadeenergieVariableID'])
|
||||||
|
* $batterie['Energiefaktor']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($energieAktualisieren && $batterie['EntladeenergieVariableID'] > 0) {
|
||||||
|
$this->setzeDiagrammMesswert(
|
||||||
|
$batterie['EntladeenergieIdent'],
|
||||||
|
max(
|
||||||
|
0.0,
|
||||||
|
(float) GetValue($batterie['EntladeenergieVariableID'])
|
||||||
|
* $batterie['Energiefaktor']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setzeDiagrammMesswert(string $ident, float $wert): void
|
||||||
|
{
|
||||||
|
$variableID = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
|
||||||
|
if (is_int($variableID) && $variableID > 0 && IPS_VariableExists($variableID)) {
|
||||||
|
SetValue($variableID, $wert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function diagrammFarbe(int $index): string
|
||||||
|
{
|
||||||
|
$farben = [
|
||||||
|
'#A85D3C',
|
||||||
|
'#007C91',
|
||||||
|
'#6B5B95',
|
||||||
|
'#2E7D32',
|
||||||
|
'#C43E1C',
|
||||||
|
'#3D5A80',
|
||||||
|
'#8D6E63',
|
||||||
|
'#00897B',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $farben[$index % count($farben)];
|
||||||
|
}
|
||||||
|
|
||||||
/** @param list<array<string, mixed>> $datensaetze */
|
/** @param list<array<string, mixed>> $datensaetze */
|
||||||
private function erstelleDiagramm(
|
private function erstelleDiagramm(
|
||||||
string $ident,
|
string $ident,
|
||||||
@@ -521,7 +1063,8 @@ trait ManagerEnergieTrait
|
|||||||
int $position
|
int $position
|
||||||
): int {
|
): int {
|
||||||
$medienID = $this->findeUnterobjekt($ident);
|
$medienID = $this->findeUnterobjekt($ident);
|
||||||
if ($medienID === 0) {
|
$neu = $medienID === 0;
|
||||||
|
if ($neu) {
|
||||||
$medienID = IPS_CreateMedia(4);
|
$medienID = IPS_CreateMedia(4);
|
||||||
IPS_SetParent($medienID, $this->InstanceID);
|
IPS_SetParent($medienID, $this->InstanceID);
|
||||||
IPS_SetIdent($medienID, $ident);
|
IPS_SetIdent($medienID, $ident);
|
||||||
@@ -530,6 +1073,11 @@ trait ManagerEnergieTrait
|
|||||||
if ($objekt['ObjectType'] !== 5 || (int) IPS_GetMedia($medienID)['MediaType'] !== 4) {
|
if ($objekt['ObjectType'] !== 5 || (int) IPS_GetMedia($medienID)['MediaType'] !== 4) {
|
||||||
throw new RuntimeException('Unterobjekt ' . $ident . ' ist kein Diagramm.');
|
throw new RuntimeException('Unterobjekt ' . $ident . ' ist kein Diagramm.');
|
||||||
}
|
}
|
||||||
|
if (!$neu) {
|
||||||
|
IPS_SetHidden($medienID, false);
|
||||||
|
|
||||||
|
return $medienID;
|
||||||
|
}
|
||||||
IPS_SetName($medienID, $name);
|
IPS_SetName($medienID, $name);
|
||||||
IPS_SetPosition($medienID, $position);
|
IPS_SetPosition($medienID, $position);
|
||||||
IPS_SetHidden($medienID, false);
|
IPS_SetHidden($medienID, false);
|
||||||
@@ -546,16 +1094,17 @@ trait ManagerEnergieTrait
|
|||||||
string $ident,
|
string $ident,
|
||||||
string $titel,
|
string $titel,
|
||||||
string $farbe,
|
string $farbe,
|
||||||
string $profil
|
string $profil,
|
||||||
|
string $typ = 'line'
|
||||||
): array {
|
): array {
|
||||||
return [
|
return [
|
||||||
'variableID' => $this->GetIDForIdent($ident),
|
'variableID' => $this->GetIDForIdent($ident),
|
||||||
'fillColor' => 'clear',
|
'fillColor' => $typ === 'bar' ? $farbe : 'clear',
|
||||||
'strokeColor' => $farbe,
|
'strokeColor' => $farbe,
|
||||||
'timeOffset' => 0,
|
'timeOffset' => 0,
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'title' => $titel,
|
'title' => $titel,
|
||||||
'type' => 'line',
|
'type' => $typ,
|
||||||
'side' => 'left',
|
'side' => 'left',
|
||||||
'profile' => $profil,
|
'profile' => $profil,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ final class ManagerEnergieModulstrukturTest extends TestCase
|
|||||||
foreach ([
|
foreach ([
|
||||||
"RegisterPropertyBoolean('EnergyPieAnzeigen', false)",
|
"RegisterPropertyBoolean('EnergyPieAnzeigen', false)",
|
||||||
"RegisterPropertyBoolean('EnergiediagrammeAnzeigen', false)",
|
"RegisterPropertyBoolean('EnergiediagrammeAnzeigen', false)",
|
||||||
|
"RegisterPropertyInteger('DiagrammPVModus', 0)",
|
||||||
|
"RegisterPropertyInteger('DiagrammBatterieModus', 0)",
|
||||||
|
"RegisterPropertyBoolean('LadestationenSeparatAnzeigen', true)",
|
||||||
|
"RegisterPropertyBoolean('VerbraucherSeparatAnzeigen', true)",
|
||||||
|
"RegisterAttributeBoolean('EnergieflussNeuErzeugen', false)",
|
||||||
"RegisterPropertyBoolean('FunFactsAnzeigen', false)",
|
"RegisterPropertyBoolean('FunFactsAnzeigen', false)",
|
||||||
"RegisterPropertyBoolean('EnergieflussAnzeigen', false)",
|
"RegisterPropertyBoolean('EnergieflussAnzeigen', false)",
|
||||||
"RegisterPropertyInteger('EnergieflussLeistungseinheit', 0)",
|
"RegisterPropertyInteger('EnergieflussLeistungseinheit', 0)",
|
||||||
@@ -38,6 +43,10 @@ final class ManagerEnergieModulstrukturTest extends TestCase
|
|||||||
'ENERGY_PIE_MODULE_ID',
|
'ENERGY_PIE_MODULE_ID',
|
||||||
'ENERGY_FLOW_MODULE_ID',
|
'ENERGY_FLOW_MODULE_ID',
|
||||||
'energieflussKnoten',
|
'energieflussKnoten',
|
||||||
|
"'type' => \$typ",
|
||||||
|
"'bar'",
|
||||||
|
'EnergiediagrammKonfiguration',
|
||||||
|
'EnergieflussKonfiguration',
|
||||||
'IPS_DeleteInstance',
|
'IPS_DeleteInstance',
|
||||||
'IPS_DeleteMedia',
|
'IPS_DeleteMedia',
|
||||||
] as $erwartet) {
|
] as $erwartet) {
|
||||||
@@ -45,11 +54,14 @@ final class ManagerEnergieModulstrukturTest extends TestCase
|
|||||||
}
|
}
|
||||||
foreach ([
|
foreach ([
|
||||||
'Energieaufzeichnung',
|
'Energieaufzeichnung',
|
||||||
'FormEnergyPieAnzeigen',
|
|
||||||
'FormEnergiediagrammeAnzeigen',
|
|
||||||
'FormFunFactsAnzeigen',
|
|
||||||
'FormEnergieflussAnzeigen',
|
|
||||||
'EnergieflussLeistungseinheit',
|
'EnergieflussLeistungseinheit',
|
||||||
|
'DiagrammPVModus',
|
||||||
|
'DiagrammBatterieModus',
|
||||||
|
'LadestationenSeparatAnzeigen',
|
||||||
|
'VerbraucherSeparatAnzeigen',
|
||||||
|
'Bestehende Energy Pies, Diagramme und Energiefluesse bleiben bei Apply unveraendert',
|
||||||
|
'Wechselrichter / AC-Wandler',
|
||||||
|
'keine doppelte Batteriekonfiguration',
|
||||||
'MesswerteAnzeigen',
|
'MesswerteAnzeigen',
|
||||||
'IstleistungVariableID',
|
'IstleistungVariableID',
|
||||||
'LeistungVariableID',
|
'LeistungVariableID',
|
||||||
|
|||||||
@@ -6,8 +6,13 @@ use Belevo\EnelixEMS\SymconTest\TestContext;
|
|||||||
|
|
||||||
return static function (TestContext $test): void {
|
return static function (TestContext $test): void {
|
||||||
$netzleistungId = $test->createVariable(2, 'Netzleistung', -800.0);
|
$netzleistungId = $test->createVariable(2, 'Netzleistung', -800.0);
|
||||||
|
$netzbezugEnergieId = $test->createVariable(2, 'Netzbezug-Energie', 32.0);
|
||||||
|
$netzeinspeisungEnergieId = $test->createVariable(2, 'Netzeinspeisung-Energie', 16.0);
|
||||||
$pvLeistungId = $test->createVariable(2, 'PV-Leistung', 4200.0);
|
$pvLeistungId = $test->createVariable(2, 'PV-Leistung', 4200.0);
|
||||||
|
$pvEnergieId = $test->createVariable(2, 'PV-Energie', 120.0);
|
||||||
$batterieLeistungId = $test->createVariable(2, 'Batterieleistung', 700.0);
|
$batterieLeistungId = $test->createVariable(2, 'Batterieleistung', 700.0);
|
||||||
|
$batterieLadeenergieId = $test->createVariable(2, 'Batterie-Ladeenergie', 18.0);
|
||||||
|
$batterieEntladeenergieId = $test->createVariable(2, 'Batterie-Entladeenergie', 12.0);
|
||||||
$batterieSocId = $test->createVariable(2, 'Batterie-Ladezustand', 62.0);
|
$batterieSocId = $test->createVariable(2, 'Batterie-Ladezustand', 62.0);
|
||||||
$einKontaktId = $test->createActionVariable('Kontakt Verbraucher 1-Stufig');
|
$einKontaktId = $test->createActionVariable('Kontakt Verbraucher 1-Stufig');
|
||||||
$einStufigId = $test->createInstance(
|
$einStufigId = $test->createInstance(
|
||||||
@@ -82,6 +87,8 @@ return static function (TestContext $test): void {
|
|||||||
'ACNennleistung_kW' => 10.0,
|
'ACNennleistung_kW' => 10.0,
|
||||||
'IstleistungVariableID' => $pvLeistungId,
|
'IstleistungVariableID' => $pvLeistungId,
|
||||||
'Istleistungsfaktor' => 1.0,
|
'Istleistungsfaktor' => 1.0,
|
||||||
|
'ErzeugungsenergieVariableID' => $pvEnergieId,
|
||||||
|
'Erzeugungsenergiefaktor' => 1.0,
|
||||||
]];
|
]];
|
||||||
$pvKonfiguration = [[
|
$pvKonfiguration = [[
|
||||||
'ID' => 'pv-1',
|
'ID' => 'pv-1',
|
||||||
@@ -106,6 +113,9 @@ return static function (TestContext $test): void {
|
|||||||
'LeistungVariableID' => $batterieLeistungId,
|
'LeistungVariableID' => $batterieLeistungId,
|
||||||
'Leistungsfaktor' => 1.0,
|
'Leistungsfaktor' => 1.0,
|
||||||
'SOCVariableID' => $batterieSocId,
|
'SOCVariableID' => $batterieSocId,
|
||||||
|
'LadeenergieVariableID' => $batterieLadeenergieId,
|
||||||
|
'EntladeenergieVariableID' => $batterieEntladeenergieId,
|
||||||
|
'Energiefaktor' => 1.0,
|
||||||
]];
|
]];
|
||||||
$lizenzcode = trim((string) getenv('ENELIX_TEST_LICENSE_CODE'));
|
$lizenzcode = trim((string) getenv('ENELIX_TEST_LICENSE_CODE'));
|
||||||
$managerId = $test->createInstance(
|
$managerId = $test->createInstance(
|
||||||
@@ -113,6 +123,8 @@ return static function (TestContext $test): void {
|
|||||||
'Manager',
|
'Manager',
|
||||||
[
|
[
|
||||||
'NetzleistungVariableID' => $netzleistungId,
|
'NetzleistungVariableID' => $netzleistungId,
|
||||||
|
'NetzbezugEnergieVariableID' => $netzbezugEnergieId,
|
||||||
|
'NetzeinspeisungEnergieVariableID' => $netzeinspeisungEnergieId,
|
||||||
'EnergyPieAnzeigen' => true,
|
'EnergyPieAnzeigen' => true,
|
||||||
'EnergiediagrammeAnzeigen' => true,
|
'EnergiediagrammeAnzeigen' => true,
|
||||||
'FunFactsAnzeigen' => true,
|
'FunFactsAnzeigen' => true,
|
||||||
@@ -226,11 +238,17 @@ return static function (TestContext $test): void {
|
|||||||
});
|
});
|
||||||
$test->runCase('Energiewerte, Archivregeln und Unterobjekte werden erzeugt', static function (
|
$test->runCase('Energiewerte, Archivregeln und Unterobjekte werden erzeugt', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use ($managerId): void {
|
) use ($managerId, $pvLeistungId): void {
|
||||||
IPS_RequestAction($managerId, 'MesswerteAufzeichnen', true);
|
IPS_RequestAction($managerId, 'MesswerteAufzeichnen', true);
|
||||||
$test->assertSame(
|
$test->assertSame(
|
||||||
4200.0,
|
4200.0,
|
||||||
GetValue($test->objectByIdent('PVLeistungArchiv', $managerId))
|
GetValue($test->objectByIdent('PVLeistungArchiv', $managerId)),
|
||||||
|
sprintf(
|
||||||
|
'PV-Archiv unveraendert; Quelle %.1f W, Managerstatus %d, Konfiguration %s.',
|
||||||
|
(float) GetValue($pvLeistungId),
|
||||||
|
(int) IPS_GetInstance($managerId)['InstanceStatus'],
|
||||||
|
(string) IPS_GetProperty($managerId, 'AnlagenWechselrichter')
|
||||||
|
)
|
||||||
);
|
);
|
||||||
$test->assertSame(
|
$test->assertSame(
|
||||||
2700.0,
|
2700.0,
|
||||||
@@ -288,18 +306,69 @@ return static function (TestContext $test): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pvFlussID = $test->objectByIdent('EnergieflussPV', $managerId);
|
$pvFlussID = $test->objectByIdent('EnergieflussPV', $managerId);
|
||||||
$test->assertSame(4200.0, (float) GetValue($pvFlussID));
|
$test->assertSame(
|
||||||
|
4200.0,
|
||||||
|
(float) GetValue($pvFlussID),
|
||||||
|
'Der anfaengliche PV-Energiefluss ist falsch.'
|
||||||
|
);
|
||||||
$test->assertSame('~Power', IPS_GetVariable($pvFlussID)['VariableProfile']);
|
$test->assertSame('~Power', IPS_GetVariable($pvFlussID)['VariableProfile']);
|
||||||
|
|
||||||
IPS_SetProperty($managerId, 'EnergieflussLeistungseinheit', 1);
|
$pieID = $test->objectByIdent('EnergyPie', $managerId);
|
||||||
IPS_ApplyChanges($managerId);
|
$leistungsdiagrammID = $test->objectByIdent('Leistungsdiagramm', $managerId);
|
||||||
$test->assertSame(4.2, (float) GetValue($pvFlussID));
|
$energiediagrammID = $test->objectByIdent('Energiediagramm', $managerId);
|
||||||
$test->assertSame('Enelix.Power.kW', IPS_GetVariable($pvFlussID)['VariableProfile']);
|
$energiediagramm = json_decode(
|
||||||
|
base64_decode((string) IPS_GetMediaContent($energiediagrammID), true),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
$energietitel = array_column($energiediagramm['datasets'] ?? [], 'title');
|
||||||
|
foreach ($energiediagramm['datasets'] ?? [] as $datensatz) {
|
||||||
|
$test->assertSame('bar', $datensatz['type'] ?? null);
|
||||||
|
}
|
||||||
|
foreach ([
|
||||||
|
'Netzbezug',
|
||||||
|
'Netzeinspeisung',
|
||||||
|
'Batterie laden gesamt',
|
||||||
|
'Batterie entladen gesamt',
|
||||||
|
] as $titel) {
|
||||||
|
$test->assertTrue(in_array($titel, $energietitel, true));
|
||||||
|
}
|
||||||
|
|
||||||
IPS_RequestAction($managerId, 'FormEnergieflussAnzeigen', false);
|
$angepasstesDiagramm = base64_encode(
|
||||||
$test->assertSame(true, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
|
json_encode(['datasets' => [], 'custom' => 'bleibt'], JSON_THROW_ON_ERROR)
|
||||||
IPS_RequestAction($managerId, 'FormEnergieflussAnzeigen', true);
|
);
|
||||||
$test->assertSame(false, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
|
IPS_SetMediaContent($energiediagrammID, $angepasstesDiagramm);
|
||||||
|
IPS_SetProperty($pieID, 'Zaehlerfaktor', 2.0);
|
||||||
|
IPS_ApplyChanges($pieID);
|
||||||
|
IPS_SetProperty($energieflussID, 'Config', '[]');
|
||||||
|
IPS_ApplyChanges($energieflussID);
|
||||||
|
IPS_SetProperty($managerId, 'EnergieflussLeistungseinheit', 1);
|
||||||
|
IPS_SetProperty($managerId, 'DiagrammPVModus', 2);
|
||||||
|
IPS_SetProperty($managerId, 'DiagrammBatterieModus', 2);
|
||||||
|
IPS_ApplyChanges($managerId);
|
||||||
|
|
||||||
|
$test->assertSame($pieID, $test->objectByIdent('EnergyPie', $managerId));
|
||||||
|
$test->assertSame(
|
||||||
|
$leistungsdiagrammID,
|
||||||
|
$test->objectByIdent('Leistungsdiagramm', $managerId)
|
||||||
|
);
|
||||||
|
$test->assertSame(
|
||||||
|
$energiediagrammID,
|
||||||
|
$test->objectByIdent('Energiediagramm', $managerId)
|
||||||
|
);
|
||||||
|
$test->assertSame(
|
||||||
|
$angepasstesDiagramm,
|
||||||
|
(string) IPS_GetMediaContent($energiediagrammID)
|
||||||
|
);
|
||||||
|
$test->assertSame(2.0, (float) IPS_GetProperty($pieID, 'Zaehlerfaktor'));
|
||||||
|
$test->assertSame('[]', (string) IPS_GetProperty($energieflussID, 'Config'));
|
||||||
|
$test->assertSame(
|
||||||
|
4200.0,
|
||||||
|
(float) GetValue($pvFlussID),
|
||||||
|
'Der bestehende PV-Energiefluss wurde beim Apply veraendert.'
|
||||||
|
);
|
||||||
|
$test->assertSame('~Power', IPS_GetVariable($pvFlussID)['VariableProfile']);
|
||||||
|
|
||||||
foreach ([
|
foreach ([
|
||||||
'EnergyPieAnzeigen',
|
'EnergyPieAnzeigen',
|
||||||
@@ -322,7 +391,44 @@ return static function (TestContext $test): void {
|
|||||||
$ident . ' wurde beim Ausschalten nicht entfernt.'
|
$ident . ' wurde beim Ausschalten nicht entfernt.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$test->assertSame(true, (bool) IPS_GetObject($energieflussID)['ObjectIsHidden']);
|
$test->assertSame(
|
||||||
|
true,
|
||||||
|
(bool) IPS_GetObject($energieflussID)['ObjectIsHidden']
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ([
|
||||||
|
'EnergyPieAnzeigen',
|
||||||
|
'EnergiediagrammeAnzeigen',
|
||||||
|
'EnergieflussAnzeigen',
|
||||||
|
] as $property) {
|
||||||
|
IPS_SetProperty($managerId, $property, true);
|
||||||
|
}
|
||||||
|
IPS_ApplyChanges($managerId);
|
||||||
|
$neuerFlussID = $test->objectByIdent('Energiefluss', $managerId);
|
||||||
|
$test->assertSame($energieflussID, $neuerFlussID);
|
||||||
|
$test->assertSame(false, (bool) IPS_GetObject($neuerFlussID)['ObjectIsHidden']);
|
||||||
|
$test->assertTrue((string) IPS_GetProperty($neuerFlussID, 'Config') !== '[]');
|
||||||
|
$test->assertSame(4.2, (float) GetValue($pvFlussID));
|
||||||
|
$test->assertSame('Enelix.Power.kW', IPS_GetVariable($pvFlussID)['VariableProfile']);
|
||||||
|
|
||||||
|
$neuesLeistungsdiagramm = json_decode(
|
||||||
|
base64_decode(
|
||||||
|
(string) IPS_GetMediaContent(
|
||||||
|
$test->objectByIdent('Leistungsdiagramm', $managerId)
|
||||||
|
),
|
||||||
|
true
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
$leistungstitel = array_column(
|
||||||
|
$neuesLeistungsdiagramm['datasets'] ?? [],
|
||||||
|
'title'
|
||||||
|
);
|
||||||
|
foreach (['PV gesamt', 'Hybridwechselrichter', 'Batterie gesamt', 'Hausspeicher'] as $titel) {
|
||||||
|
$test->assertTrue(in_array($titel, $leistungstitel, true));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$zustandswert = static function (array $daten, int $instanzId, string $kennung) {
|
$zustandswert = static function (array $daten, int $instanzId, string $kennung) {
|
||||||
@@ -470,12 +576,11 @@ return static function (TestContext $test): void {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
$test->runCase('Veralteter Verbraucher blockiert aktuelle Verbraucher nicht', static function (
|
$test->runCase('Veraltete Verbraucher werden aktiv neu angefordert', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use (
|
) use (
|
||||||
$managerId,
|
$managerId,
|
||||||
$netzleistungId,
|
$netzleistungId,
|
||||||
$einStufigId,
|
|
||||||
$warmwasserId,
|
$warmwasserId,
|
||||||
$pufferspeicherId,
|
$pufferspeicherId,
|
||||||
$melden,
|
$melden,
|
||||||
@@ -496,17 +601,9 @@ return static function (TestContext $test): void {
|
|||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
|
|
||||||
$daten = $verbraucherstatus();
|
$daten = $verbraucherstatus();
|
||||||
$test->assertSame(false, $daten['Synchronisiert'] ?? null);
|
$test->assertSame(true, $daten['Synchronisiert'] ?? null);
|
||||||
$test->assertSame(2, count($daten['Verbraucher'] ?? []));
|
$test->assertSame(3, count($daten['Verbraucher'] ?? []));
|
||||||
$test->assertSame(1, count($daten['NichtGeregelt'] ?? []));
|
$test->assertSame(0, count($daten['NichtGeregelt'] ?? []));
|
||||||
$test->assertSame(
|
|
||||||
$einStufigId,
|
|
||||||
$daten['NichtGeregelt'][0]['InstanzID'] ?? null
|
|
||||||
);
|
|
||||||
$test->assertSame(
|
|
||||||
'Meldung ist veraltet',
|
|
||||||
$daten['NichtGeregelt'][0]['Grund'] ?? null
|
|
||||||
);
|
|
||||||
$test->assertTrue(
|
$test->assertTrue(
|
||||||
(float) GetValue($test->objectByIdent('Verteilbudget', $managerId)) > 0.0
|
(float) GetValue($test->objectByIdent('Verteilbudget', $managerId)) > 0.0
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user