feat: Lizenzkontingente im Manager durchsetzen
This commit is contained in:
+8
-1
@@ -26,6 +26,13 @@
|
|||||||
"name": "LizenzPruefen",
|
"name": "LizenzPruefen",
|
||||||
"caption": "Lizenz pruefen und binden",
|
"caption": "Lizenz pruefen und binden",
|
||||||
"onClick": "IPS_RequestAction($id, 'FormLizenzPruefen', $Lizenzcode);"
|
"onClick": "IPS_RequestAction($id, 'FormLizenzPruefen', $Lizenzcode);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Button",
|
||||||
|
"name": "LizenzVerwalten",
|
||||||
|
"caption": "Lizenz verwalten",
|
||||||
|
"link": true,
|
||||||
|
"onClick": "echo 'https://license.enelix.ch';"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -296,6 +303,6 @@
|
|||||||
{"code": 102, "icon": "active", "caption": "Aktiv"},
|
{"code": 102, "icon": "active", "caption": "Aktiv"},
|
||||||
{"code": 201, "icon": "inactive", "caption": "Netzleistungsmessung fehlt oder ist veraltet"},
|
{"code": 201, "icon": "inactive", "caption": "Netzleistungsmessung fehlt oder ist veraltet"},
|
||||||
{"code": 202, "icon": "error", "caption": "Konfiguration ungueltig"},
|
{"code": 202, "icon": "error", "caption": "Konfiguration ungueltig"},
|
||||||
{"code": 203, "icon": "error", "caption": "Lizenz fehlt oder ist abgelaufen"}
|
{"code": 203, "icon": "error", "caption": "Lizenz nicht freigegeben oder Verbraucherkontingent ueberschritten"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+437
-29
@@ -21,14 +21,35 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
private const LIZENZ_ENDPOINT = 'https://license.enelix.ch/api/v1/licenses/activate';
|
private const LIZENZ_ENDPOINT = 'https://license.enelix.ch/api/v1/licenses/activate';
|
||||||
private const LIZENZ_RETRY_SEKUNDEN = 3600;
|
private const LIZENZ_RETRY_SEKUNDEN = 3600;
|
||||||
private const VM_UPDATE = 10603;
|
private const VM_UPDATE = 10603;
|
||||||
private const VERBRAUCHER_MODUL_IDS = [
|
private const VERBRAUCHER_LIZENZEN = [
|
||||||
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
|
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}' => [
|
||||||
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
'Katalog' => 'boiler_multi',
|
||||||
'{A31C9274-54F7-4BD2-9804-7AF23E86C4D1}',
|
'Name' => 'Boiler mehrstufig',
|
||||||
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
|
],
|
||||||
'{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}',
|
'{15879A4E-D0C2-4495-83DE-46E1E462591E}' => [
|
||||||
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}',
|
'Katalog' => 'consumer_single',
|
||||||
'{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}',
|
'Name' => 'Verbraucher einstufig',
|
||||||
|
],
|
||||||
|
'{A31C9274-54F7-4BD2-9804-7AF23E86C4D1}' => [
|
||||||
|
'Katalog' => 'consumer_single',
|
||||||
|
'Name' => 'Waermepumpe',
|
||||||
|
],
|
||||||
|
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}' => [
|
||||||
|
'Katalog' => 'ev_charger',
|
||||||
|
'Name' => 'EV-Ladestation Stand-Alone',
|
||||||
|
],
|
||||||
|
'{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}' => [
|
||||||
|
'Katalog' => 'ev_charger',
|
||||||
|
'Name' => 'EV-Ladestation Gateway',
|
||||||
|
],
|
||||||
|
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}' => [
|
||||||
|
'Katalog' => 'buffer_storage',
|
||||||
|
'Name' => 'Pufferspeicher',
|
||||||
|
],
|
||||||
|
'{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}' => [
|
||||||
|
'Katalog' => 'battery',
|
||||||
|
'Name' => 'Batteriespeicher',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
private const MONATSNAMEN = [
|
private const MONATSNAMEN = [
|
||||||
1 => 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni',
|
1 => 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni',
|
||||||
@@ -41,6 +62,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
'VerbraucherAnzahl',
|
'VerbraucherAnzahl',
|
||||||
'VerbraucherVerfuegbar',
|
'VerbraucherVerfuegbar',
|
||||||
'Verbraucherstatus',
|
'Verbraucherstatus',
|
||||||
|
'NichtGeregelteGeraete',
|
||||||
'Monatsgrenzen',
|
'Monatsgrenzen',
|
||||||
'Prognosestatus',
|
'Prognosestatus',
|
||||||
'SDLStatus',
|
'SDLStatus',
|
||||||
@@ -90,6 +112,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->RegisterAttributeString('LizenzLease', '{}');
|
$this->RegisterAttributeString('LizenzLease', '{}');
|
||||||
$this->RegisterAttributeString('LizenzcodeHash', '');
|
$this->RegisterAttributeString('LizenzcodeHash', '');
|
||||||
$this->RegisterAttributeInteger('LizenzNaechsterVersuch', 0);
|
$this->RegisterAttributeInteger('LizenzNaechsterVersuch', 0);
|
||||||
|
$this->RegisterAttributeInteger('LizenzBerechtigungenNaechsterVersuch', 0);
|
||||||
$this->RegisterAttributeString('LizenzLetzterFehler', '');
|
$this->RegisterAttributeString('LizenzLetzterFehler', '');
|
||||||
if ($this->ReadAttributeString('LizenzInstallationID') === '') {
|
if ($this->ReadAttributeString('LizenzInstallationID') === '') {
|
||||||
$this->WriteAttributeString('LizenzInstallationID', $this->erzeugeUuidV4());
|
$this->WriteAttributeString('LizenzInstallationID', $this->erzeugeUuidV4());
|
||||||
@@ -133,6 +156,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
$this->aktiveVerbraucherIDs();
|
||||||
|
} catch (Throwable $fehler) {
|
||||||
|
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||||
|
$this->setzeDiagnosewert('Lizenzstatus', 'Nicht freigegeben: ' . $fehler->getMessage());
|
||||||
|
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->SetStatus(self::STATUS_AKTIV);
|
$this->SetStatus(self::STATUS_AKTIV);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +177,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
);
|
);
|
||||||
$automatisch = $this->ReadPropertyBoolean('AutomatischeSuche');
|
$automatisch = $this->ReadPropertyBoolean('AutomatischeSuche');
|
||||||
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
||||||
$monatsgrenzenSichtbar = $lastspitzenmodus === 2
|
$peakShavingLizenziert = $this->peakShavingLizenziert();
|
||||||
|
$monatsgrenzenSichtbar = $peakShavingLizenziert
|
||||||
|
&& $lastspitzenmodus === 2
|
||||||
&& $this->GetBuffer('MonatsgrenzenSichtbar') === '1';
|
&& $this->GetBuffer('MonatsgrenzenSichtbar') === '1';
|
||||||
|
|
||||||
$this->setzeFormularParameter(
|
$this->setzeFormularParameter(
|
||||||
@@ -181,17 +214,24 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
'values',
|
'values',
|
||||||
$this->automatischeVerbraucherFuerFormular()
|
$this->automatischeVerbraucherFuerFormular()
|
||||||
);
|
);
|
||||||
|
$lastspitzenOptionen = $this->lastspitzenOptionen($peakShavingLizenziert);
|
||||||
|
$this->setzeFormularParameter(
|
||||||
|
$formular['elements'],
|
||||||
|
'Lastspitzenmodus',
|
||||||
|
'options',
|
||||||
|
$lastspitzenOptionen
|
||||||
|
);
|
||||||
$this->setzeFormularParameter(
|
$this->setzeFormularParameter(
|
||||||
$formular['elements'],
|
$formular['elements'],
|
||||||
'Lastspitzengrenze',
|
'Lastspitzengrenze',
|
||||||
'visible',
|
'visible',
|
||||||
$lastspitzenmodus === 1
|
$peakShavingLizenziert && $lastspitzenmodus === 1
|
||||||
);
|
);
|
||||||
$this->setzeFormularParameter(
|
$this->setzeFormularParameter(
|
||||||
$formular['elements'],
|
$formular['elements'],
|
||||||
'MonatsgrenzenUmschalten',
|
'MonatsgrenzenUmschalten',
|
||||||
'visible',
|
'visible',
|
||||||
$lastspitzenmodus === 2
|
$peakShavingLizenziert && $lastspitzenmodus === 2
|
||||||
);
|
);
|
||||||
$this->setzeFormularParameter(
|
$this->setzeFormularParameter(
|
||||||
$formular['elements'],
|
$formular['elements'],
|
||||||
@@ -242,6 +282,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
}
|
}
|
||||||
$this->aktualisiereLizenzfreigabe($wert, true);
|
$this->aktualisiereLizenzfreigabe($wert, true);
|
||||||
$this->UpdateFormField('LizenzInformation', 'caption', $this->lizenzStatustext($wert));
|
$this->UpdateFormField('LizenzInformation', 'caption', $this->lizenzStatustext($wert));
|
||||||
|
$this->aktualisiereLastspitzenformular();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'FormAutomatischeSuche':
|
case 'FormAutomatischeSuche':
|
||||||
@@ -277,6 +318,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
case 'FormLastspitzenmodus':
|
case 'FormLastspitzenmodus':
|
||||||
$modus = (int) $wert;
|
$modus = (int) $wert;
|
||||||
|
if ($modus !== 0 && !$this->peakShavingLizenziert()) {
|
||||||
|
$this->UpdateFormField('Lastspitzenmodus', 'value', 0);
|
||||||
|
$this->UpdateFormField('Lastspitzengrenze', 'visible', false);
|
||||||
|
$this->UpdateFormField('MonatsgrenzenUmschalten', 'visible', false);
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'Konstant und Monatlich benoetigen eine Peak-Shaving-Lizenz.'
|
||||||
|
);
|
||||||
|
}
|
||||||
$this->UpdateFormField('Lastspitzengrenze', 'visible', $modus === 1);
|
$this->UpdateFormField('Lastspitzengrenze', 'visible', $modus === 1);
|
||||||
$this->UpdateFormField('MonatsgrenzenUmschalten', 'visible', $modus === 2);
|
$this->UpdateFormField('MonatsgrenzenUmschalten', 'visible', $modus === 2);
|
||||||
if ($modus !== 2) {
|
if ($modus !== 2) {
|
||||||
@@ -346,6 +395,17 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
if (!$this->aktualisiereLizenzfreigabe($this->ReadPropertyString('Lizenzcode'), false)) {
|
if (!$this->aktualisiereLizenzfreigabe($this->ReadPropertyString('Lizenzcode'), false)) {
|
||||||
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||||
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
||||||
|
$this->setzeNichtGeregelteVerbraucher('Lizenz nicht freigegeben');
|
||||||
|
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$this->aktiveVerbraucherIDs();
|
||||||
|
} catch (Throwable $fehler) {
|
||||||
|
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||||
|
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
||||||
|
$this->setzeDiagnosewert('Lizenzstatus', 'Nicht freigegeben: ' . $fehler->getMessage());
|
||||||
|
$this->setzeNichtGeregelteVerbraucher($fehler->getMessage());
|
||||||
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -358,6 +418,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
if (!$aktiv || !$netzleistungGueltig) {
|
if (!$aktiv || !$netzleistungGueltig) {
|
||||||
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||||
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
||||||
|
$this->setzeNichtGeregelteVerbraucher(
|
||||||
|
$aktiv ? 'Netzleistungsmessung fehlt oder ist veraltet' : 'Manager ist deaktiviert'
|
||||||
|
);
|
||||||
$this->SetStatus($aktiv ? self::STATUS_MESSWERT_UNGUELTIG : self::STATUS_AKTIV);
|
$this->SetStatus($aktiv ? self::STATUS_MESSWERT_UNGUELTIG : self::STATUS_AKTIV);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -385,8 +448,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
}
|
}
|
||||||
|
|
||||||
$stoerungen = [];
|
$stoerungen = [];
|
||||||
|
$nichtGeregelt = [];
|
||||||
$synchronisiert = true;
|
$synchronisiert = true;
|
||||||
$verbraucher = $this->aktuelleVerbraucher($stoerungen, $betriebsart, $synchronisiert);
|
$verbraucher = $this->aktuelleVerbraucher(
|
||||||
|
$stoerungen,
|
||||||
|
$nichtGeregelt,
|
||||||
|
$betriebsart,
|
||||||
|
$synchronisiert
|
||||||
|
);
|
||||||
$this->setzeDiagnosewert('WirksameLastspitzengrenze', $lastspitzengrenze ?? 0.0);
|
$this->setzeDiagnosewert('WirksameLastspitzengrenze', $lastspitzengrenze ?? 0.0);
|
||||||
if (!$synchronisiert) {
|
if (!$synchronisiert) {
|
||||||
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
||||||
@@ -394,7 +463,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
'Betriebsart' => $betriebsart,
|
'Betriebsart' => $betriebsart,
|
||||||
'Synchronisiert' => false,
|
'Synchronisiert' => false,
|
||||||
'Verbraucher' => $verbraucher,
|
'Verbraucher' => $verbraucher,
|
||||||
|
'NichtGeregelt' => $nichtGeregelt,
|
||||||
], JSON_THROW_ON_ERROR));
|
], JSON_THROW_ON_ERROR));
|
||||||
|
$this->setzeDiagnosewert(
|
||||||
|
'NichtGeregelteGeraete',
|
||||||
|
$this->nichtGeregelteGeraeteText($nichtGeregelt)
|
||||||
|
);
|
||||||
$this->aktualisiereStoerungen($verbraucher, $stoerungen);
|
$this->aktualisiereStoerungen($verbraucher, $stoerungen);
|
||||||
$this->SetStatus(self::STATUS_AKTIV);
|
$this->SetStatus(self::STATUS_AKTIV);
|
||||||
return;
|
return;
|
||||||
@@ -415,7 +489,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
'Synchronisiert' => true,
|
'Synchronisiert' => true,
|
||||||
'Restabweichung_W' => $ergebnis['Restabweichung_W'],
|
'Restabweichung_W' => $ergebnis['Restabweichung_W'],
|
||||||
'Verbraucher' => $verbraucher,
|
'Verbraucher' => $verbraucher,
|
||||||
|
'NichtGeregelt' => [],
|
||||||
], JSON_THROW_ON_ERROR));
|
], JSON_THROW_ON_ERROR));
|
||||||
|
$this->setzeDiagnosewert(
|
||||||
|
'NichtGeregelteGeraete',
|
||||||
|
'Alle aktiven Verbraucher werden geregelt.'
|
||||||
|
);
|
||||||
|
|
||||||
$letzteSollwerte = $this->leseJsonAttribut('LetzteSollwerte');
|
$letzteSollwerte = $this->leseJsonAttribut('LetzteSollwerte');
|
||||||
foreach ($ergebnis['Sollwerte'] as $instanzID => $sollleistung) {
|
foreach ($ergebnis['Sollwerte'] as $instanzID => $sollleistung) {
|
||||||
@@ -457,10 +536,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param list<string> $stoerungen
|
* @param list<string> $stoerungen
|
||||||
|
* @param list<array<string, mixed>> $nichtGeregelt
|
||||||
* @return list<array{InstanzID: int, Daten: array<string, mixed>}>
|
* @return list<array{InstanzID: int, Daten: array<string, mixed>}>
|
||||||
*/
|
*/
|
||||||
private function aktuelleVerbraucher(
|
private function aktuelleVerbraucher(
|
||||||
array &$stoerungen,
|
array &$stoerungen,
|
||||||
|
array &$nichtGeregelt,
|
||||||
string $betriebsart,
|
string $betriebsart,
|
||||||
bool &$synchronisiert
|
bool &$synchronisiert
|
||||||
): array {
|
): array {
|
||||||
@@ -483,11 +564,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
if ($grund !== '') {
|
if ($grund !== '') {
|
||||||
$synchronisiert = false;
|
$synchronisiert = false;
|
||||||
$stoerungen[] = $grund . ' von Instanz ' . $instanzID . '.';
|
$detail = $this->verbraucherDetail($instanzID, $grund, $eintrag);
|
||||||
|
$nichtGeregelt[] = $detail;
|
||||||
|
$stoerungen[] = $detail['Name'] . ': ' . $grund . '.';
|
||||||
try {
|
try {
|
||||||
$this->sendeManagerdaten($instanzID, $betriebsart, null);
|
$this->sendeManagerdaten($instanzID, $betriebsart, null);
|
||||||
} catch (Throwable $fehler) {
|
} catch (Throwable $fehler) {
|
||||||
$stoerungen[] = 'Betriebsart an Instanz ' . $instanzID . ': ' . $fehler->getMessage();
|
$stoerungen[] = $detail['Name'] . ': Betriebsart konnte nicht uebermittelt werden: '
|
||||||
|
. $fehler->getMessage();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -500,8 +584,124 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
return $aktuell;
|
return $aktuell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setzeNichtGeregelteVerbraucher(string $grund): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$ids = $this->konfigurierteAktiveVerbraucherIDs();
|
||||||
|
} catch (Throwable $fehler) {
|
||||||
|
$ids = [];
|
||||||
|
$grund .= '; Verbraucherzuordnung ungueltig: ' . $fehler->getMessage();
|
||||||
|
}
|
||||||
|
$cache = $this->leseJsonAttribut('VerbraucherCache');
|
||||||
|
$nichtGeregelt = [];
|
||||||
|
$stoerungen = [];
|
||||||
|
foreach ($ids as $instanzID) {
|
||||||
|
$detail = $this->verbraucherDetail(
|
||||||
|
$instanzID,
|
||||||
|
$grund,
|
||||||
|
$cache[(string) $instanzID] ?? null
|
||||||
|
);
|
||||||
|
$nichtGeregelt[] = $detail;
|
||||||
|
$stoerungen[] = $detail['Name'] . ': ' . $grund . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setzeDiagnosewert('VerbraucherAnzahl', count($ids));
|
||||||
|
$this->setzeDiagnosewert('VerbraucherVerfuegbar', 0);
|
||||||
|
$this->setzeDiagnosewert('Verbraucherstatus', json_encode([
|
||||||
|
'Betriebsart' => ManagerRegler::BETRIEBSART_INAKTIV,
|
||||||
|
'Synchronisiert' => false,
|
||||||
|
'Verbraucher' => [],
|
||||||
|
'NichtGeregelt' => $nichtGeregelt,
|
||||||
|
], JSON_THROW_ON_ERROR));
|
||||||
|
$this->setzeDiagnosewert(
|
||||||
|
'NichtGeregelteGeraete',
|
||||||
|
$this->nichtGeregelteGeraeteText($nichtGeregelt)
|
||||||
|
);
|
||||||
|
$this->aktualisiereStoerungen([], $stoerungen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed>|null $cacheEintrag
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
private function verbraucherDetail(
|
||||||
|
int $instanzID,
|
||||||
|
string $grund,
|
||||||
|
?array $cacheEintrag
|
||||||
|
): array {
|
||||||
|
$name = 'Instanz ' . $instanzID;
|
||||||
|
$typ = 'Unbekannter Verbraucher';
|
||||||
|
$instanzStatus = null;
|
||||||
|
if (IPS_InstanceExists($instanzID)) {
|
||||||
|
$name = IPS_GetName($instanzID);
|
||||||
|
$instanz = IPS_GetInstance($instanzID);
|
||||||
|
$instanzStatus = (int) ($instanz['InstanceStatus'] ?? 0);
|
||||||
|
$modulID = strtoupper((string) ($instanz['ModuleInfo']['ModuleID'] ?? ''));
|
||||||
|
$typ = self::VERBRAUCHER_LIZENZEN[$modulID]['Name'] ?? $typ;
|
||||||
|
}
|
||||||
|
|
||||||
|
$daten = is_array($cacheEintrag['Daten'] ?? null)
|
||||||
|
? $cacheEintrag['Daten']
|
||||||
|
: [];
|
||||||
|
$empfangenAm = is_int($cacheEintrag['EmpfangenAm'] ?? null)
|
||||||
|
? $cacheEintrag['EmpfangenAm']
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'InstanzID' => $instanzID,
|
||||||
|
'Name' => $name,
|
||||||
|
'Typ' => $typ,
|
||||||
|
'Grund' => $grund,
|
||||||
|
'InstanzStatus' => $instanzStatus,
|
||||||
|
'LetzteMeldung' => $empfangenAm !== null ? date(DATE_ATOM, $empfangenAm) : null,
|
||||||
|
'GemeldeteBetriebsart' => is_string($daten['Betriebsart'] ?? null)
|
||||||
|
? $daten['Betriebsart']
|
||||||
|
: null,
|
||||||
|
'Verfuegbar' => is_bool($daten['Verfuegbar'] ?? null)
|
||||||
|
? $daten['Verfuegbar']
|
||||||
|
: null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<array<string, mixed>> $nichtGeregelt
|
||||||
|
*/
|
||||||
|
private function nichtGeregelteGeraeteText(array $nichtGeregelt): string
|
||||||
|
{
|
||||||
|
if ($nichtGeregelt === []) {
|
||||||
|
return 'Alle aktiven Verbraucher werden geregelt.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$zeilen = [];
|
||||||
|
foreach ($nichtGeregelt as $detail) {
|
||||||
|
$teile = [
|
||||||
|
(string) ($detail['Name'] ?? 'Unbekanntes Geraet'),
|
||||||
|
(string) ($detail['Typ'] ?? 'Unbekannter Typ'),
|
||||||
|
(string) ($detail['Grund'] ?? 'Grund unbekannt'),
|
||||||
|
];
|
||||||
|
if (is_string($detail['LetzteMeldung'] ?? null)) {
|
||||||
|
$teile[] = 'letzte Meldung: ' . $detail['LetzteMeldung'];
|
||||||
|
}
|
||||||
|
if (is_bool($detail['Verfuegbar'] ?? null)) {
|
||||||
|
$teile[] = 'verfuegbar: ' . ($detail['Verfuegbar'] ? 'ja' : 'nein');
|
||||||
|
}
|
||||||
|
$zeilen[] = implode(' | ', $teile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\n", $zeilen);
|
||||||
|
}
|
||||||
|
|
||||||
/** @return list<int> */
|
/** @return list<int> */
|
||||||
private function aktiveVerbraucherIDs(): array
|
private function aktiveVerbraucherIDs(): array
|
||||||
|
{
|
||||||
|
$ids = $this->konfigurierteAktiveVerbraucherIDs();
|
||||||
|
$this->pruefeVerbraucherlizenzen($ids);
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<int> */
|
||||||
|
private function konfigurierteAktiveVerbraucherIDs(): array
|
||||||
{
|
{
|
||||||
if (!$this->ReadPropertyBoolean('AutomatischeSuche')) {
|
if (!$this->ReadPropertyBoolean('AutomatischeSuche')) {
|
||||||
return $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
return $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
||||||
@@ -521,6 +721,64 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
return $this->leseAktiveVerbraucherIDs('AutomatischeVerbraucherZuordnung');
|
return $this->leseAktiveVerbraucherIDs('AutomatischeVerbraucherZuordnung');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<int> $ids
|
||||||
|
*/
|
||||||
|
private function pruefeVerbraucherlizenzen(array $ids): void
|
||||||
|
{
|
||||||
|
[$mengen, $namen] = $this->verbraucherLizenzbelegung($ids);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Lizenzpruefung::pruefeVerbrauchermengen($this->leseLizenzLease(), $mengen);
|
||||||
|
} catch (InvalidArgumentException $fehler) {
|
||||||
|
foreach ($mengen as $kennung => $verwendet) {
|
||||||
|
$lizenziert = Lizenzpruefung::berechtigungsMenge(
|
||||||
|
$this->leseLizenzLease(),
|
||||||
|
$kennung
|
||||||
|
);
|
||||||
|
if ($verwendet > $lizenziert) {
|
||||||
|
throw new InvalidArgumentException(sprintf(
|
||||||
|
'%s: %d aktiviert, aber nur %d lizenziert. Bitte Auswahl reduzieren oder Lizenz erweitern.',
|
||||||
|
$namen[$kennung],
|
||||||
|
$verwendet,
|
||||||
|
$lizenziert
|
||||||
|
), 0, $fehler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw $fehler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<int> $ids
|
||||||
|
* @return array{0: array<string, int>, 1: array<string, string>}
|
||||||
|
*/
|
||||||
|
private function verbraucherLizenzbelegung(array $ids): array
|
||||||
|
{
|
||||||
|
$mengen = [];
|
||||||
|
$namen = [];
|
||||||
|
foreach ($ids as $instanzID) {
|
||||||
|
if (!IPS_InstanceExists($instanzID)) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'Die Verbraucherinstanz ' . $instanzID . ' existiert nicht.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$instanz = IPS_GetInstance($instanzID);
|
||||||
|
$modulID = strtoupper((string) ($instanz['ModuleInfo']['ModuleID'] ?? ''));
|
||||||
|
$lizenz = self::VERBRAUCHER_LIZENZEN[$modulID] ?? null;
|
||||||
|
if (!is_array($lizenz)) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'Instanz ' . $instanzID . ' ist kein lizenzierbarer Enelix-Verbraucher.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$kennung = $lizenz['Katalog'];
|
||||||
|
$mengen[$kennung] = ($mengen[$kennung] ?? 0) + 1;
|
||||||
|
$namen[$kennung] = $lizenz['Name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$mengen, $namen];
|
||||||
|
}
|
||||||
|
|
||||||
/** @return list<int> */
|
/** @return list<int> */
|
||||||
private function leseAktiveVerbraucherIDs(string $property): array
|
private function leseAktiveVerbraucherIDs(string $property): array
|
||||||
{
|
{
|
||||||
@@ -579,7 +837,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
|
|
||||||
$suchbereichID ??= $this->ReadPropertyInteger('SuchbereichID');
|
$suchbereichID ??= $this->ReadPropertyInteger('SuchbereichID');
|
||||||
$werte = [];
|
$werte = [];
|
||||||
foreach (self::VERBRAUCHER_MODUL_IDS as $modulID) {
|
foreach (array_keys(self::VERBRAUCHER_LIZENZEN) as $modulID) {
|
||||||
foreach (IPS_GetInstanceListByModuleID($modulID) as $instanzID) {
|
foreach (IPS_GetInstanceListByModuleID($modulID) as $instanzID) {
|
||||||
if (!$this->istImSuchbereich($instanzID, $suchbereichID)) {
|
if (!$this->istImSuchbereich($instanzID, $suchbereichID)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -743,6 +1001,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
80
|
80
|
||||||
);
|
);
|
||||||
$this->RegisterVariableString('Verbraucherstatus', 'Verbraucherstatus', '', 90);
|
$this->RegisterVariableString('Verbraucherstatus', 'Verbraucherstatus', '', 90);
|
||||||
|
$this->RegisterVariableString(
|
||||||
|
'NichtGeregelteGeraete',
|
||||||
|
'Nicht geregelte Geraete',
|
||||||
|
'',
|
||||||
|
95
|
||||||
|
);
|
||||||
$this->RegisterVariableString('Monatsgrenzen', 'Monatsgrenzen', '', 100);
|
$this->RegisterVariableString('Monatsgrenzen', 'Monatsgrenzen', '', 100);
|
||||||
$this->RegisterVariableString('Prognosestatus', 'Prognosestatus', '', 110);
|
$this->RegisterVariableString('Prognosestatus', 'Prognosestatus', '', 110);
|
||||||
$this->RegisterVariableString('SDLStatus', 'SDL-Status', '', 120);
|
$this->RegisterVariableString('SDLStatus', 'SDL-Status', '', 120);
|
||||||
@@ -796,23 +1060,59 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$gespeicherterHash = $this->ReadAttributeString('LizenzcodeHash');
|
$gespeicherterHash = $this->ReadAttributeString('LizenzcodeHash');
|
||||||
$lease = $this->leseLizenzLease();
|
$lease = $this->leseLizenzLease();
|
||||||
$codePasst = $gespeicherterHash !== '' && hash_equals($gespeicherterHash, $codeHash);
|
$codePasst = $gespeicherterHash !== '' && hash_equals($gespeicherterHash, $codeHash);
|
||||||
|
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
||||||
|
$basisGueltig = $codePasst && Lizenzpruefung::istLeaseGueltig(
|
||||||
|
$lease,
|
||||||
|
$installationID,
|
||||||
|
0
|
||||||
|
);
|
||||||
$gueltig = $codePasst && Lizenzpruefung::istLeaseGueltig(
|
$gueltig = $codePasst && Lizenzpruefung::istLeaseGueltig(
|
||||||
$lease,
|
$lease,
|
||||||
$installationID,
|
$installationID,
|
||||||
$this->ReadPropertyInteger('Lastspitzenmodus')
|
$lastspitzenmodus
|
||||||
);
|
);
|
||||||
$faellig = !$gueltig || Lizenzpruefung::erneuerungFaellig($lease);
|
$berechtigungenVeraltet = $basisGueltig
|
||||||
|
&& !$this->lizenzBerechtigungenPassen($lease, $lastspitzenmodus);
|
||||||
|
$routineFaellig = (!$gueltig && !$berechtigungenVeraltet)
|
||||||
|
|| Lizenzpruefung::erneuerungFaellig($lease);
|
||||||
$jetzt = time();
|
$jetzt = time();
|
||||||
|
|
||||||
if (!$erzwingen
|
if (!$erzwingen) {
|
||||||
&& (!$faellig || $jetzt < $this->ReadAttributeInteger('LizenzNaechsterVersuch'))
|
if (!$routineFaellig && !$berechtigungenVeraltet) {
|
||||||
) {
|
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
||||||
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
|
||||||
|
|
||||||
return $gueltig;
|
return $gueltig;
|
||||||
|
}
|
||||||
|
if ($routineFaellig
|
||||||
|
&& $jetzt < $this->ReadAttributeInteger('LizenzNaechsterVersuch')
|
||||||
|
) {
|
||||||
|
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
||||||
|
|
||||||
|
return $gueltig;
|
||||||
|
}
|
||||||
|
if ($berechtigungenVeraltet
|
||||||
|
&& $jetzt < $this->ReadAttributeInteger(
|
||||||
|
'LizenzBerechtigungenNaechsterVersuch'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
||||||
|
|
||||||
|
return $gueltig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->WriteAttributeInteger('LizenzNaechsterVersuch', $jetzt + self::LIZENZ_RETRY_SEKUNDEN);
|
if ($routineFaellig || $erzwingen) {
|
||||||
|
$this->WriteAttributeInteger(
|
||||||
|
'LizenzNaechsterVersuch',
|
||||||
|
$jetzt + self::LIZENZ_RETRY_SEKUNDEN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($berechtigungenVeraltet || $erzwingen) {
|
||||||
|
$this->WriteAttributeInteger(
|
||||||
|
'LizenzBerechtigungenNaechsterVersuch',
|
||||||
|
$jetzt + self::LIZENZ_RETRY_SEKUNDEN
|
||||||
|
);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$neueLease = $this->rufeLizenzserverAuf($normalisiert, $installationID);
|
$neueLease = $this->rufeLizenzserverAuf($normalisiert, $installationID);
|
||||||
Lizenzpruefung::pruefeLease(
|
Lizenzpruefung::pruefeLease(
|
||||||
@@ -825,9 +1125,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
json_encode($neueLease, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES)
|
json_encode($neueLease, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES)
|
||||||
);
|
);
|
||||||
$this->WriteAttributeString('LizenzcodeHash', $codeHash);
|
$this->WriteAttributeString('LizenzcodeHash', $codeHash);
|
||||||
|
$naechsteErneuerung = Lizenzpruefung::erneuernAb($neueLease);
|
||||||
|
$this->WriteAttributeInteger('LizenzNaechsterVersuch', $naechsteErneuerung);
|
||||||
$this->WriteAttributeInteger(
|
$this->WriteAttributeInteger(
|
||||||
'LizenzNaechsterVersuch',
|
'LizenzBerechtigungenNaechsterVersuch',
|
||||||
Lizenzpruefung::erneuernAb($neueLease)
|
$naechsteErneuerung
|
||||||
);
|
);
|
||||||
$this->WriteAttributeString('LizenzLetzterFehler', '');
|
$this->WriteAttributeString('LizenzLetzterFehler', '');
|
||||||
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
||||||
@@ -860,6 +1162,108 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function peakShavingLizenziert(): bool
|
||||||
|
{
|
||||||
|
$lizenzcode = Lizenzpruefung::normalisiereCode(
|
||||||
|
$this->ReadPropertyString('Lizenzcode')
|
||||||
|
);
|
||||||
|
if (!Lizenzpruefung::istLizenzcodeGueltig($lizenzcode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gespeicherterHash = $this->ReadAttributeString('LizenzcodeHash');
|
||||||
|
if ($gespeicherterHash === ''
|
||||||
|
|| !hash_equals($gespeicherterHash, hash('sha256', $lizenzcode))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lease = $this->leseLizenzLease();
|
||||||
|
if (!Lizenzpruefung::istLeaseGueltig(
|
||||||
|
$lease,
|
||||||
|
$this->ReadAttributeString('LizenzInstallationID'),
|
||||||
|
0
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lizenzpruefung::berechtigungsMenge(
|
||||||
|
$lease,
|
||||||
|
Lizenzpruefung::MANAGER_PEAK
|
||||||
|
) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $lease
|
||||||
|
*/
|
||||||
|
private function lizenzBerechtigungenPassen(array $lease, int $lastspitzenmodus): bool
|
||||||
|
{
|
||||||
|
if ($lastspitzenmodus !== 0
|
||||||
|
&& Lizenzpruefung::berechtigungsMenge(
|
||||||
|
$lease,
|
||||||
|
Lizenzpruefung::MANAGER_PEAK
|
||||||
|
) < 1
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
[$mengen] = $this->verbraucherLizenzbelegung(
|
||||||
|
$this->konfigurierteAktiveVerbraucherIDs()
|
||||||
|
);
|
||||||
|
Lizenzpruefung::pruefeVerbrauchermengen($lease, $mengen);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (Throwable $fehler) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<array{caption: string, value: int}>
|
||||||
|
*/
|
||||||
|
private function lastspitzenOptionen(bool $lizenziert): array
|
||||||
|
{
|
||||||
|
$optionen = [[
|
||||||
|
'caption' => $lizenziert
|
||||||
|
? 'Aus (Peak-Shaving-Lizenz verfuegbar)'
|
||||||
|
: 'Aus (Peak-Shaving-Lizenz fehlt)',
|
||||||
|
'value' => 0,
|
||||||
|
]];
|
||||||
|
if ($lizenziert) {
|
||||||
|
$optionen[] = ['caption' => 'Konstant', 'value' => 1];
|
||||||
|
$optionen[] = ['caption' => 'Monatlich', 'value' => 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $optionen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function aktualisiereLastspitzenformular(): void
|
||||||
|
{
|
||||||
|
$lizenziert = $this->peakShavingLizenziert();
|
||||||
|
$modus = $lizenziert ? $this->ReadPropertyInteger('Lastspitzenmodus') : 0;
|
||||||
|
$this->UpdateFormField(
|
||||||
|
'Lastspitzenmodus',
|
||||||
|
'options',
|
||||||
|
json_encode($this->lastspitzenOptionen($lizenziert), JSON_THROW_ON_ERROR)
|
||||||
|
);
|
||||||
|
$this->UpdateFormField('Lastspitzenmodus', 'value', $modus);
|
||||||
|
$this->UpdateFormField(
|
||||||
|
'Lastspitzengrenze',
|
||||||
|
'visible',
|
||||||
|
$lizenziert && $modus === 1
|
||||||
|
);
|
||||||
|
$this->UpdateFormField(
|
||||||
|
'MonatsgrenzenUmschalten',
|
||||||
|
'visible',
|
||||||
|
$lizenziert && $modus === 2
|
||||||
|
);
|
||||||
|
if (!$lizenziert || $modus !== 2) {
|
||||||
|
$this->SetBuffer('MonatsgrenzenSichtbar', '0');
|
||||||
|
$this->UpdateFormField('Monatsgrenzen', 'visible', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function lizenzStatustext(?string $lizenzcode = null): string
|
private function lizenzStatustext(?string $lizenzcode = null): string
|
||||||
{
|
{
|
||||||
$code = Lizenzpruefung::normalisiereCode(
|
$code = Lizenzpruefung::normalisiereCode(
|
||||||
@@ -886,12 +1290,16 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
|||||||
$this->ReadAttributeString('LizenzInstallationID'),
|
$this->ReadAttributeString('LizenzInstallationID'),
|
||||||
$this->ReadPropertyInteger('Lastspitzenmodus')
|
$this->ReadPropertyInteger('Lastspitzenmodus')
|
||||||
);
|
);
|
||||||
|
$this->aktiveVerbraucherIDs();
|
||||||
$status = ($lease['development'] ?? false) === true
|
$status = ($lease['development'] ?? false) === true
|
||||||
? 'Aktiv (Entwicklung)'
|
? 'Aktiv (Entwicklung) - unbeschraenkt gueltig.'
|
||||||
: 'Aktiv';
|
: 'Aktiv - unbeschraenkt gueltig.';
|
||||||
$status .= ' bis ' . date('d.m.Y H:i', Lizenzpruefung::offlineBis($lease));
|
|
||||||
if ($fehler !== '') {
|
if ($fehler !== '') {
|
||||||
$status .= '; Erneuerung fehlgeschlagen: ' . $fehler;
|
$status .= ' Online-Pruefung fehlgeschlagen; lokale Freigabe endet am '
|
||||||
|
. date('d.m.Y H:i', Lizenzpruefung::offlineBis($lease))
|
||||||
|
. ', sofern keine Verbindung hergestellt wird. '
|
||||||
|
. 'Die gekaufte Lizenz bleibt unbeschraenkt gueltig. Fehler: '
|
||||||
|
. $fehler;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $status;
|
return $status;
|
||||||
|
|||||||
@@ -82,6 +82,62 @@ final class Lizenzpruefung
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert die aufsummierte aktive Berechtigung fuer einen Katalogeintrag.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $lease
|
||||||
|
*/
|
||||||
|
public static function berechtigungsMenge(array $lease, string $kennung): int
|
||||||
|
{
|
||||||
|
$berechtigungen = $lease['entitlements'] ?? null;
|
||||||
|
if (!is_array($berechtigungen)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$menge = 0;
|
||||||
|
foreach ($berechtigungen as $berechtigung) {
|
||||||
|
if (!is_array($berechtigung)
|
||||||
|
|| ($berechtigung['status'] ?? null) !== 'active'
|
||||||
|
|| !is_int($berechtigung['quantity'] ?? null)
|
||||||
|
|| $berechtigung['quantity'] < 1
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$berechtigungsKennung = $berechtigung['catalog_key']
|
||||||
|
?? $berechtigung['sku']
|
||||||
|
?? null;
|
||||||
|
if ($berechtigungsKennung === $kennung) {
|
||||||
|
$menge += $berechtigung['quantity'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $lease
|
||||||
|
* @param array<string, int> $verwendeteMengen
|
||||||
|
*/
|
||||||
|
public static function pruefeVerbrauchermengen(array $lease, array $verwendeteMengen): void
|
||||||
|
{
|
||||||
|
foreach ($verwendeteMengen as $kennung => $verwendet) {
|
||||||
|
if ($verwendet < 0) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'Die verwendete Menge fuer ' . $kennung . ' darf nicht negativ sein.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$lizenziert = self::berechtigungsMenge($lease, $kennung);
|
||||||
|
if ($verwendet > $lizenziert) {
|
||||||
|
throw new InvalidArgumentException(sprintf(
|
||||||
|
'Lizenzkontingent fuer %s ueberschritten: %d verwendet, %d lizenziert.',
|
||||||
|
$kennung,
|
||||||
|
$verwendet,
|
||||||
|
$lizenziert
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $lease
|
* @param array<string, mixed> $lease
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -104,6 +104,75 @@ final class LizenzpruefungTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testZweiLizenzierteBoilerWerdenFreigegeben(): void
|
||||||
|
{
|
||||||
|
$lease = $this->lease('manager_standard');
|
||||||
|
$lease['entitlements'][] = [
|
||||||
|
'sku' => 'ENX-BOILER-MULTI',
|
||||||
|
'catalog_key' => 'boiler_multi',
|
||||||
|
'quantity' => 2,
|
||||||
|
'status' => 'active',
|
||||||
|
];
|
||||||
|
|
||||||
|
self::assertSame(2, Lizenzpruefung::berechtigungsMenge($lease, 'boiler_multi'));
|
||||||
|
Lizenzpruefung::pruefeVerbrauchermengen($lease, ['boiler_multi' => 2]);
|
||||||
|
|
||||||
|
self::assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDritterBoilerBeiZweiLizenzenWirdAbgelehnt(): void
|
||||||
|
{
|
||||||
|
$lease = $this->lease('manager_standard');
|
||||||
|
$lease['entitlements'][] = [
|
||||||
|
'sku' => 'ENX-BOILER-MULTI',
|
||||||
|
'catalog_key' => 'boiler_multi',
|
||||||
|
'quantity' => 2,
|
||||||
|
'status' => 'active',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage(
|
||||||
|
'Lizenzkontingent fuer boiler_multi ueberschritten: 3 verwendet, 2 lizenziert.'
|
||||||
|
);
|
||||||
|
Lizenzpruefung::pruefeVerbrauchermengen($lease, ['boiler_multi' => 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testVerbraucherkontingenteWerdenJeTypSummiertUndGetrenntGeprueft(): void
|
||||||
|
{
|
||||||
|
$lease = $this->lease('manager_standard');
|
||||||
|
$lease['entitlements'] = array_merge($lease['entitlements'], [
|
||||||
|
[
|
||||||
|
'catalog_key' => 'boiler_multi',
|
||||||
|
'quantity' => 1,
|
||||||
|
'status' => 'active',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'catalog_key' => 'boiler_multi',
|
||||||
|
'quantity' => 1,
|
||||||
|
'status' => 'active',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'catalog_key' => 'battery',
|
||||||
|
'quantity' => 1,
|
||||||
|
'status' => 'active',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'catalog_key' => 'battery',
|
||||||
|
'quantity' => 10,
|
||||||
|
'status' => 'revoked',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertSame(2, Lizenzpruefung::berechtigungsMenge($lease, 'boiler_multi'));
|
||||||
|
self::assertSame(1, Lizenzpruefung::berechtigungsMenge($lease, 'battery'));
|
||||||
|
Lizenzpruefung::pruefeVerbrauchermengen($lease, [
|
||||||
|
'boiler_multi' => 2,
|
||||||
|
'battery' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
public function testLizenzcodeWirdWieAufDemServerNormalisiert(): void
|
public function testLizenzcodeWirdWieAufDemServerNormalisiert(): void
|
||||||
{
|
{
|
||||||
self::assertSame(
|
self::assertSame(
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ final class ManagerModulstrukturTest extends TestCase
|
|||||||
'LoggingEin',
|
'LoggingEin',
|
||||||
'Lizenzcode',
|
'Lizenzcode',
|
||||||
'LizenzPruefen',
|
'LizenzPruefen',
|
||||||
|
'LizenzVerwalten',
|
||||||
'LizenzInstallationID',
|
'LizenzInstallationID',
|
||||||
'LizenzInformation',
|
'LizenzInformation',
|
||||||
'VerbraucherAktualisieren',
|
'VerbraucherAktualisieren',
|
||||||
@@ -69,6 +70,8 @@ final class ManagerModulstrukturTest extends TestCase
|
|||||||
self::assertStringContainsString($bereich, $json);
|
self::assertStringContainsString($bereich, $json);
|
||||||
}
|
}
|
||||||
self::assertSame('Lizenzierung', $formular['elements'][0]['caption']);
|
self::assertSame('Lizenzierung', $formular['elements'][0]['caption']);
|
||||||
|
self::assertStringContainsString('https://license.enelix.ch', $json);
|
||||||
|
self::assertStringContainsString('"link":true', $json);
|
||||||
self::assertStringContainsString(
|
self::assertStringContainsString(
|
||||||
"'SuchbereichID' => \$SuchbereichID",
|
"'SuchbereichID' => \$SuchbereichID",
|
||||||
$json
|
$json
|
||||||
@@ -111,6 +114,44 @@ final class ManagerModulstrukturTest extends TestCase
|
|||||||
self::assertStringContainsString("RegisterAttributeString('LizenzcodeHash'", $inhalt);
|
self::assertStringContainsString("RegisterAttributeString('LizenzcodeHash'", $inhalt);
|
||||||
self::assertStringContainsString('STATUS_LIZENZ_UNGUELTIG', $inhalt);
|
self::assertStringContainsString('STATUS_LIZENZ_UNGUELTIG', $inhalt);
|
||||||
self::assertStringContainsString('aktualisiereLizenzfreigabe(', $inhalt);
|
self::assertStringContainsString('aktualisiereLizenzfreigabe(', $inhalt);
|
||||||
|
self::assertStringContainsString('pruefeVerbraucherlizenzen(', $inhalt);
|
||||||
|
self::assertStringContainsString('lizenzBerechtigungenPassen(', $inhalt);
|
||||||
|
self::assertStringContainsString('peakShavingLizenziert(', $inhalt);
|
||||||
|
self::assertStringContainsString('Aus (Peak-Shaving-Lizenz fehlt)', $inhalt);
|
||||||
|
self::assertStringContainsString('Aus (Peak-Shaving-Lizenz verfuegbar)', $inhalt);
|
||||||
|
self::assertStringContainsString(
|
||||||
|
'Konstant und Monatlich benoetigen eine Peak-Shaving-Lizenz.',
|
||||||
|
$inhalt
|
||||||
|
);
|
||||||
|
foreach (['battery', 'buffer_storage', 'ev_charger', 'consumer_single', 'boiler_multi'] as $katalog) {
|
||||||
|
self::assertStringContainsString("'Katalog' => '" . $katalog . "'", $inhalt);
|
||||||
|
}
|
||||||
|
foreach ([
|
||||||
|
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
|
||||||
|
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
||||||
|
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
|
||||||
|
'{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}',
|
||||||
|
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}',
|
||||||
|
'{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}',
|
||||||
|
] as $modulID) {
|
||||||
|
self::assertStringContainsString("'" . $modulID . "' =>", $inhalt);
|
||||||
|
}
|
||||||
|
self::assertStringContainsString("'Name' => 'Pufferspeicher'", $inhalt);
|
||||||
|
self::assertStringContainsString("'Name' => 'Batteriespeicher'", $inhalt);
|
||||||
|
self::assertStringContainsString(
|
||||||
|
'Bitte Auswahl reduzieren oder Lizenz erweitern.',
|
||||||
|
$inhalt
|
||||||
|
);
|
||||||
|
foreach ([
|
||||||
|
"'NichtGeregelt'",
|
||||||
|
"'NichtGeregelteGeraete'",
|
||||||
|
"'InstanzStatus'",
|
||||||
|
"'LetzteMeldung'",
|
||||||
|
"'GemeldeteBetriebsart'",
|
||||||
|
"'Verfuegbar'",
|
||||||
|
] as $detailfeld) {
|
||||||
|
self::assertStringContainsString($detailfeld, $inhalt);
|
||||||
|
}
|
||||||
self::assertStringNotContainsString("'publicKey' =>", $inhalt);
|
self::assertStringNotContainsString("'publicKey' =>", $inhalt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ return static function (TestContext $test): void {
|
|||||||
if ($lizenzcode === '') {
|
if ($lizenzcode === '') {
|
||||||
$test->runCase('Manager bleibt ohne Lizenz sicher gesperrt', static function (
|
$test->runCase('Manager bleibt ohne Lizenz sicher gesperrt', static function (
|
||||||
TestContext $test
|
TestContext $test
|
||||||
) use ($managerId): void {
|
) use ($managerId, $verbraucherstatus): void {
|
||||||
IPS_RequestAction($managerId, 'Aktiv', true);
|
IPS_RequestAction($managerId, 'Aktiv', true);
|
||||||
IPS_RequestAction($managerId, 'Regeln', true);
|
IPS_RequestAction($managerId, 'Regeln', true);
|
||||||
$test->assertInstanceStatus($managerId, 203);
|
$test->assertInstanceStatus($managerId, 203);
|
||||||
@@ -171,6 +171,21 @@ return static function (TestContext $test): void {
|
|||||||
'Inaktiv',
|
'Inaktiv',
|
||||||
GetValue($test->objectByIdent('Betriebsart', $managerId))
|
GetValue($test->objectByIdent('Betriebsart', $managerId))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$daten = $verbraucherstatus();
|
||||||
|
$test->assertSame(false, $daten['Synchronisiert'] ?? null);
|
||||||
|
$test->assertSame(3, count($daten['NichtGeregelt'] ?? []));
|
||||||
|
foreach ($daten['NichtGeregelt'] as $detail) {
|
||||||
|
$test->assertTrue(is_int($detail['InstanzID'] ?? null));
|
||||||
|
$test->assertTrue(is_string($detail['Name'] ?? null));
|
||||||
|
$test->assertTrue(is_string($detail['Typ'] ?? null));
|
||||||
|
$test->assertSame('Lizenz nicht freigegeben', $detail['Grund'] ?? null);
|
||||||
|
}
|
||||||
|
$detailtext = (string) GetValue(
|
||||||
|
$test->objectByIdent('NichtGeregelteGeraete', $managerId)
|
||||||
|
);
|
||||||
|
$test->assertTrue(str_contains($detailtext, 'Boiler'));
|
||||||
|
$test->assertTrue(str_contains($detailtext, 'Lizenz nicht freigegeben'));
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user