feat: Lizenzkontingente im Manager durchsetzen
This commit is contained in:
+8
-1
@@ -26,6 +26,13 @@
|
||||
"name": "LizenzPruefen",
|
||||
"caption": "Lizenz pruefen und binden",
|
||||
"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": 201, "icon": "inactive", "caption": "Netzleistungsmessung fehlt oder ist veraltet"},
|
||||
{"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_RETRY_SEKUNDEN = 3600;
|
||||
private const VM_UPDATE = 10603;
|
||||
private const VERBRAUCHER_MODUL_IDS = [
|
||||
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}',
|
||||
'{15879A4E-D0C2-4495-83DE-46E1E462591E}',
|
||||
'{A31C9274-54F7-4BD2-9804-7AF23E86C4D1}',
|
||||
'{0D94913C-0F31-4C29-A685-6EB4AE58E55D}',
|
||||
'{32F65988-BE55-4FD6-9FFF-CF1C4C8628F8}',
|
||||
'{C92D5EEF-9632-47A5-9659-4B02BF40FBE9}',
|
||||
'{437FB683-517F-4FEC-8CCB-FE6B0A62B69E}',
|
||||
private const VERBRAUCHER_LIZENZEN = [
|
||||
'{B7C54AF4-AD7D-4FE4-B75D-203693906251}' => [
|
||||
'Katalog' => 'boiler_multi',
|
||||
'Name' => 'Boiler mehrstufig',
|
||||
],
|
||||
'{15879A4E-D0C2-4495-83DE-46E1E462591E}' => [
|
||||
'Katalog' => 'consumer_single',
|
||||
'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 = [
|
||||
1 => 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni',
|
||||
@@ -41,6 +62,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
'VerbraucherAnzahl',
|
||||
'VerbraucherVerfuegbar',
|
||||
'Verbraucherstatus',
|
||||
'NichtGeregelteGeraete',
|
||||
'Monatsgrenzen',
|
||||
'Prognosestatus',
|
||||
'SDLStatus',
|
||||
@@ -90,6 +112,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->RegisterAttributeString('LizenzLease', '{}');
|
||||
$this->RegisterAttributeString('LizenzcodeHash', '');
|
||||
$this->RegisterAttributeInteger('LizenzNaechsterVersuch', 0);
|
||||
$this->RegisterAttributeInteger('LizenzBerechtigungenNaechsterVersuch', 0);
|
||||
$this->RegisterAttributeString('LizenzLetzterFehler', '');
|
||||
if ($this->ReadAttributeString('LizenzInstallationID') === '') {
|
||||
$this->WriteAttributeString('LizenzInstallationID', $this->erzeugeUuidV4());
|
||||
@@ -133,6 +156,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->SetStatus(self::STATUS_LIZENZ_UNGUELTIG);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -146,7 +177,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
);
|
||||
$automatisch = $this->ReadPropertyBoolean('AutomatischeSuche');
|
||||
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
||||
$monatsgrenzenSichtbar = $lastspitzenmodus === 2
|
||||
$peakShavingLizenziert = $this->peakShavingLizenziert();
|
||||
$monatsgrenzenSichtbar = $peakShavingLizenziert
|
||||
&& $lastspitzenmodus === 2
|
||||
&& $this->GetBuffer('MonatsgrenzenSichtbar') === '1';
|
||||
|
||||
$this->setzeFormularParameter(
|
||||
@@ -181,17 +214,24 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
'values',
|
||||
$this->automatischeVerbraucherFuerFormular()
|
||||
);
|
||||
$lastspitzenOptionen = $this->lastspitzenOptionen($peakShavingLizenziert);
|
||||
$this->setzeFormularParameter(
|
||||
$formular['elements'],
|
||||
'Lastspitzenmodus',
|
||||
'options',
|
||||
$lastspitzenOptionen
|
||||
);
|
||||
$this->setzeFormularParameter(
|
||||
$formular['elements'],
|
||||
'Lastspitzengrenze',
|
||||
'visible',
|
||||
$lastspitzenmodus === 1
|
||||
$peakShavingLizenziert && $lastspitzenmodus === 1
|
||||
);
|
||||
$this->setzeFormularParameter(
|
||||
$formular['elements'],
|
||||
'MonatsgrenzenUmschalten',
|
||||
'visible',
|
||||
$lastspitzenmodus === 2
|
||||
$peakShavingLizenziert && $lastspitzenmodus === 2
|
||||
);
|
||||
$this->setzeFormularParameter(
|
||||
$formular['elements'],
|
||||
@@ -242,6 +282,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
}
|
||||
$this->aktualisiereLizenzfreigabe($wert, true);
|
||||
$this->UpdateFormField('LizenzInformation', 'caption', $this->lizenzStatustext($wert));
|
||||
$this->aktualisiereLastspitzenformular();
|
||||
return;
|
||||
|
||||
case 'FormAutomatischeSuche':
|
||||
@@ -277,6 +318,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
|
||||
case 'FormLastspitzenmodus':
|
||||
$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('MonatsgrenzenUmschalten', 'visible', $modus === 2);
|
||||
if ($modus !== 2) {
|
||||
@@ -346,6 +395,17 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
if (!$this->aktualisiereLizenzfreigabe($this->ReadPropertyString('Lizenzcode'), false)) {
|
||||
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||
$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);
|
||||
return;
|
||||
}
|
||||
@@ -358,6 +418,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
if (!$aktiv || !$netzleistungGueltig) {
|
||||
$this->SetValue('Betriebsart', ManagerRegler::BETRIEBSART_INAKTIV);
|
||||
$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);
|
||||
return;
|
||||
}
|
||||
@@ -385,8 +448,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
}
|
||||
|
||||
$stoerungen = [];
|
||||
$nichtGeregelt = [];
|
||||
$synchronisiert = true;
|
||||
$verbraucher = $this->aktuelleVerbraucher($stoerungen, $betriebsart, $synchronisiert);
|
||||
$verbraucher = $this->aktuelleVerbraucher(
|
||||
$stoerungen,
|
||||
$nichtGeregelt,
|
||||
$betriebsart,
|
||||
$synchronisiert
|
||||
);
|
||||
$this->setzeDiagnosewert('WirksameLastspitzengrenze', $lastspitzengrenze ?? 0.0);
|
||||
if (!$synchronisiert) {
|
||||
$this->setzeDiagnosewert('Verteilbudget', 0.0);
|
||||
@@ -394,7 +463,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
'Betriebsart' => $betriebsart,
|
||||
'Synchronisiert' => false,
|
||||
'Verbraucher' => $verbraucher,
|
||||
'NichtGeregelt' => $nichtGeregelt,
|
||||
], JSON_THROW_ON_ERROR));
|
||||
$this->setzeDiagnosewert(
|
||||
'NichtGeregelteGeraete',
|
||||
$this->nichtGeregelteGeraeteText($nichtGeregelt)
|
||||
);
|
||||
$this->aktualisiereStoerungen($verbraucher, $stoerungen);
|
||||
$this->SetStatus(self::STATUS_AKTIV);
|
||||
return;
|
||||
@@ -415,7 +489,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
'Synchronisiert' => true,
|
||||
'Restabweichung_W' => $ergebnis['Restabweichung_W'],
|
||||
'Verbraucher' => $verbraucher,
|
||||
'NichtGeregelt' => [],
|
||||
], JSON_THROW_ON_ERROR));
|
||||
$this->setzeDiagnosewert(
|
||||
'NichtGeregelteGeraete',
|
||||
'Alle aktiven Verbraucher werden geregelt.'
|
||||
);
|
||||
|
||||
$letzteSollwerte = $this->leseJsonAttribut('LetzteSollwerte');
|
||||
foreach ($ergebnis['Sollwerte'] as $instanzID => $sollleistung) {
|
||||
@@ -457,10 +536,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
|
||||
/**
|
||||
* @param list<string> $stoerungen
|
||||
* @param list<array<string, mixed>> $nichtGeregelt
|
||||
* @return list<array{InstanzID: int, Daten: array<string, mixed>}>
|
||||
*/
|
||||
private function aktuelleVerbraucher(
|
||||
array &$stoerungen,
|
||||
array &$nichtGeregelt,
|
||||
string $betriebsart,
|
||||
bool &$synchronisiert
|
||||
): array {
|
||||
@@ -483,11 +564,14 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
|
||||
if ($grund !== '') {
|
||||
$synchronisiert = false;
|
||||
$stoerungen[] = $grund . ' von Instanz ' . $instanzID . '.';
|
||||
$detail = $this->verbraucherDetail($instanzID, $grund, $eintrag);
|
||||
$nichtGeregelt[] = $detail;
|
||||
$stoerungen[] = $detail['Name'] . ': ' . $grund . '.';
|
||||
try {
|
||||
$this->sendeManagerdaten($instanzID, $betriebsart, null);
|
||||
} catch (Throwable $fehler) {
|
||||
$stoerungen[] = 'Betriebsart an Instanz ' . $instanzID . ': ' . $fehler->getMessage();
|
||||
$stoerungen[] = $detail['Name'] . ': Betriebsart konnte nicht uebermittelt werden: '
|
||||
. $fehler->getMessage();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -500,8 +584,124 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
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> */
|
||||
private function aktiveVerbraucherIDs(): array
|
||||
{
|
||||
$ids = $this->konfigurierteAktiveVerbraucherIDs();
|
||||
$this->pruefeVerbraucherlizenzen($ids);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/** @return list<int> */
|
||||
private function konfigurierteAktiveVerbraucherIDs(): array
|
||||
{
|
||||
if (!$this->ReadPropertyBoolean('AutomatischeSuche')) {
|
||||
return $this->leseAktiveVerbraucherIDs('VerbraucherZuordnung');
|
||||
@@ -521,6 +721,64 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
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> */
|
||||
private function leseAktiveVerbraucherIDs(string $property): array
|
||||
{
|
||||
@@ -579,7 +837,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
|
||||
$suchbereichID ??= $this->ReadPropertyInteger('SuchbereichID');
|
||||
$werte = [];
|
||||
foreach (self::VERBRAUCHER_MODUL_IDS as $modulID) {
|
||||
foreach (array_keys(self::VERBRAUCHER_LIZENZEN) as $modulID) {
|
||||
foreach (IPS_GetInstanceListByModuleID($modulID) as $instanzID) {
|
||||
if (!$this->istImSuchbereich($instanzID, $suchbereichID)) {
|
||||
continue;
|
||||
@@ -743,6 +1001,12 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
80
|
||||
);
|
||||
$this->RegisterVariableString('Verbraucherstatus', 'Verbraucherstatus', '', 90);
|
||||
$this->RegisterVariableString(
|
||||
'NichtGeregelteGeraete',
|
||||
'Nicht geregelte Geraete',
|
||||
'',
|
||||
95
|
||||
);
|
||||
$this->RegisterVariableString('Monatsgrenzen', 'Monatsgrenzen', '', 100);
|
||||
$this->RegisterVariableString('Prognosestatus', 'Prognosestatus', '', 110);
|
||||
$this->RegisterVariableString('SDLStatus', 'SDL-Status', '', 120);
|
||||
@@ -796,23 +1060,59 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$gespeicherterHash = $this->ReadAttributeString('LizenzcodeHash');
|
||||
$lease = $this->leseLizenzLease();
|
||||
$codePasst = $gespeicherterHash !== '' && hash_equals($gespeicherterHash, $codeHash);
|
||||
$lastspitzenmodus = $this->ReadPropertyInteger('Lastspitzenmodus');
|
||||
$basisGueltig = $codePasst && Lizenzpruefung::istLeaseGueltig(
|
||||
$lease,
|
||||
$installationID,
|
||||
0
|
||||
);
|
||||
$gueltig = $codePasst && Lizenzpruefung::istLeaseGueltig(
|
||||
$lease,
|
||||
$installationID,
|
||||
$this->ReadPropertyInteger('Lastspitzenmodus')
|
||||
$lastspitzenmodus
|
||||
);
|
||||
$faellig = !$gueltig || Lizenzpruefung::erneuerungFaellig($lease);
|
||||
$berechtigungenVeraltet = $basisGueltig
|
||||
&& !$this->lizenzBerechtigungenPassen($lease, $lastspitzenmodus);
|
||||
$routineFaellig = (!$gueltig && !$berechtigungenVeraltet)
|
||||
|| Lizenzpruefung::erneuerungFaellig($lease);
|
||||
$jetzt = time();
|
||||
|
||||
if (!$erzwingen
|
||||
&& (!$faellig || $jetzt < $this->ReadAttributeInteger('LizenzNaechsterVersuch'))
|
||||
) {
|
||||
$this->setzeDiagnosewert('Lizenzstatus', $this->lizenzStatustext($lizenzcode));
|
||||
if (!$erzwingen) {
|
||||
if (!$routineFaellig && !$berechtigungenVeraltet) {
|
||||
$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 {
|
||||
$neueLease = $this->rufeLizenzserverAuf($normalisiert, $installationID);
|
||||
Lizenzpruefung::pruefeLease(
|
||||
@@ -825,9 +1125,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
json_encode($neueLease, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
$this->WriteAttributeString('LizenzcodeHash', $codeHash);
|
||||
$naechsteErneuerung = Lizenzpruefung::erneuernAb($neueLease);
|
||||
$this->WriteAttributeInteger('LizenzNaechsterVersuch', $naechsteErneuerung);
|
||||
$this->WriteAttributeInteger(
|
||||
'LizenzNaechsterVersuch',
|
||||
Lizenzpruefung::erneuernAb($neueLease)
|
||||
'LizenzBerechtigungenNaechsterVersuch',
|
||||
$naechsteErneuerung
|
||||
);
|
||||
$this->WriteAttributeString('LizenzLetzterFehler', '');
|
||||
$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
|
||||
{
|
||||
$code = Lizenzpruefung::normalisiereCode(
|
||||
@@ -886,12 +1290,16 @@ class Manager extends IPSModule implements ManagerSchnittstelle
|
||||
$this->ReadAttributeString('LizenzInstallationID'),
|
||||
$this->ReadPropertyInteger('Lastspitzenmodus')
|
||||
);
|
||||
$this->aktiveVerbraucherIDs();
|
||||
$status = ($lease['development'] ?? false) === true
|
||||
? 'Aktiv (Entwicklung)'
|
||||
: 'Aktiv';
|
||||
$status .= ' bis ' . date('d.m.Y H:i', Lizenzpruefung::offlineBis($lease));
|
||||
? 'Aktiv (Entwicklung) - unbeschraenkt gueltig.'
|
||||
: 'Aktiv - unbeschraenkt gueltig.';
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user