*/ private const DIAGNOSE_VARIABLEN = [ 'Istleistung', 'Leistungsquelle', 'Sollleistung', 'SollwertGueltig', 'Verfuegbar', 'AenderungMoeglich', 'Stoerung', 'Stoertext', 'LetzterGeraetebefehl', 'LeistungsangebotDiagnose', ]; public function Create(): void { parent::Create(); $this->registriereVerbraucherBasis(); $this->RegisterPropertyInteger('Geraetetyp', 0); $this->RegisterPropertyString('Geraeteadresse', ''); $this->RegisterPropertyString('GeraeteID', ''); $this->RegisterPropertyString('Seriennummer', ''); $this->RegisterPropertyString('Benutzername', ''); $this->RegisterPropertyString('Passwort', ''); $this->RegisterPropertyInteger('MaximalerLadestrom', 16); $this->RegisterPropertyInteger('Abfrageintervall', 5); $this->RegisterPropertyBoolean('Ladefreigabe', true); $this->RegisterPropertyBoolean('Solarladen', true); $this->RegisterPropertyBoolean('DiagnosevariablenAnzeigen', false); // Ausschliesslich fuer den automatisierten Symcon-Funktionstest. $this->RegisterPropertyBoolean('Testmodus', false); $this->RegisterPropertyString('Testantwort', ''); $this->RegisterVariableBoolean('FahrzeugVerbunden', 'Fahrzeug verbunden', '~Switch', 100); $this->RegisterVariableBoolean('FahrzeugGeladen', 'Fahrzeug geladen', '~Switch', 110); $this->RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 120); $this->RegisterVariableFloat('Ladestrom', 'Ladestrom', '', 130); $this->RegisterVariableInteger('Phasenzahl', 'Phasenzahl', '', 140); $this->RegisterAttributeBoolean('InitialwerteGesetzt', false); $this->RegisterAttributeBoolean('KonfigurationLadefreigabe', false); $this->RegisterAttributeBoolean('KonfigurationSolarladen', true); $this->RegisterAttributeBoolean('ZustandLadefreigabe', false); $this->RegisterAttributeBoolean('ZustandSolarladen', true); $this->RegisterAttributeBoolean('ZustandFahrzeugVerbunden', false); $this->RegisterAttributeBoolean('ZustandFahrzeugGeladen', false); $this->RegisterAttributeInteger('ZustandFahrzeugstatus', 0); $this->RegisterAttributeFloat('ZustandLadestrom', 0.0); $this->RegisterAttributeInteger('ZustandPhasenzahl', 0); $this->RegisterAttributeFloat('ZustandIstleistung', 0.0); $this->RegisterAttributeInteger('ZustandSollleistung', 0); $this->RegisterAttributeBoolean('ZustandSollwertGueltig', false); $this->RegisterAttributeBoolean('ZustandVerfuegbar', false); $this->RegisterAttributeBoolean('ZustandAenderungMoeglich', false); $this->RegisterAttributeBoolean('ZustandStoerung', false); $this->RegisterAttributeString('ZustandStoertext', ''); $this->RegisterAttributeString('Leistungsangebot', '[0]'); $this->RegisterAttributeString('Betriebsart', Nachrichtenvertrag::BETRIEBSART_PV); $this->RegisterAttributeInteger('LetzteManagerID', 0); $this->RegisterAttributeInteger('LetzteVorgabeZeit', 0); $this->RegisterAttributeInteger('LetzterGesetzterStrom', -1); $this->RegisterTimer( 'Statuszyklus', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Statuszyklus', false);" ); $this->RegisterTimer( 'Meldezyklus', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Melden', false);" ); $this->RegisterTimer( 'RueckmeldungVerzoegert', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Melden', true);" ); $this->RegisterTimer( 'VorgabeTimeout', 0, "IPS_RequestAction(\$_IPS['TARGET'], 'VorgabeTimeout', false);" ); } public function ApplyChanges(): void { parent::ApplyChanges(); $this->initialisiereLokaleEinstellungen(); $this->aktualisiereVariablen(); try { $this->pruefeKonfiguration(); } catch (Throwable $fehler) { $this->deaktiviereTimer(); $this->setzeZustand('Verfuegbar', false); $this->setzeZustand('AenderungMoeglich', false); $this->setzeStoerung($fehler->getMessage()); $this->SetStatus(self::STATUS_KONFIGURATION_UNGUELTIG); $this->protokolliere('Konfiguration', $fehler->getMessage()); return; } $this->SetTimerInterval('Statuszyklus', $this->ReadPropertyInteger('Abfrageintervall') * 1000); $this->SetTimerInterval('Meldezyklus', $this->ReadPropertyInteger('Meldeintervall') * 1000); $this->aktualisiere(true); } public function RequestAction($ident, $wert): void { switch ($ident) { case 'Aktiv': $this->SetValue('Aktiv', (bool) $wert); if (!(bool) $wert) { $this->setzeZustand('SollwertGueltig', false); } $this->aktualisiere(true); return; case 'Ladefreigabe': case 'Solarladen': $this->WriteAttributeBoolean('Zustand' . $ident, (bool) $wert); $this->setzeSichtbareVariable($ident, (bool) $wert); $this->setzeZustand('SollwertGueltig', false); $this->aktualisiere(true); return; case 'Statuszyklus': $this->aktualisiere(true); return; case 'VorgabeTimeout': $this->SetTimerInterval('VorgabeTimeout', 0); $this->setzeZustand('SollwertGueltig', false); $this->aktualisiere(true); return; case 'Melden': if ((bool) $wert) { $this->SetTimerInterval('RueckmeldungVerzoegert', 0); } $this->aktualisiere(false); $this->sendeVerbraucherdaten(); return; case 'ManagerdatenEmpfangen': if (!is_string($wert)) { throw new InvalidArgumentException('Managerdaten muessen als JSON uebergeben werden.'); } $daten = json_decode($wert, true, 512, JSON_THROW_ON_ERROR); if (!is_array($daten)) { throw new InvalidArgumentException('Managerdaten muessen ein JSON-Objekt sein.'); } $this->ManagerdatenEmpfangen($daten); return; } throw new InvalidArgumentException('Unbekannte Aktion: ' . $ident); } /** @param array $daten */ public function ManagerdatenEmpfangen(array $daten): void { Nachrichtenvertrag::pruefeManagerdaten($daten); if ($daten['Kopf']['EmpfaengerID'] !== $this->InstanceID) { throw new InvalidArgumentException('Managerdaten sind an eine andere Instanz adressiert.'); } $managerID = $daten['Kopf']['AbsenderID']; if (!in_array($managerID, $this->zugeordneteManagerIDs(), true)) { throw new InvalidArgumentException('Der Manager hat diese Ladestation nicht aktiv zugeordnet.'); } $this->WriteAttributeString('Betriebsart', $daten['Betriebsart']); $this->aktualisiere(false, false); $sollleistung = $daten['Sollleistung_W']; if ($sollleistung === null) { if ((bool) $this->leseZustand('SollwertGueltig') && !in_array((int) $this->leseZustand('Sollleistung'), $this->leseLeistungsangebot(), true) ) { $this->setzeZustand('SollwertGueltig', false); $this->aktualisiere(false, false); } $this->SetTimerInterval('RueckmeldungVerzoegert', 100); return; } if (!in_array($sollleistung, $this->leseLeistungsangebot(), true)) { throw new InvalidArgumentException( 'Sollleistung_W liegt nicht im aktuell gemeldeten Leistungsangebot.' ); } $this->WriteAttributeInteger('LetzteManagerID', $managerID); $this->WriteAttributeInteger('LetzteVorgabeZeit', time()); $this->setzeZustand('Sollleistung', $sollleistung); $this->setzeZustand('SollwertGueltig', true); $this->SetTimerInterval('VorgabeTimeout', $this->ReadPropertyInteger('VorgabeTimeout') * 1000); $this->aktualisiere(false, false); $this->SetTimerInterval('RueckmeldungVerzoegert', 100); } private function aktualisiere(bool $meldungPlanen, bool $statusLesen = true): void { try { if ($statusLesen) { $this->leseGeraetestatus(); } $aktiv = (bool) $this->GetValue('Aktiv'); $ladefreigabe = $this->ReadAttributeBoolean('ZustandLadefreigabe'); $verbunden = $this->ReadAttributeBoolean('ZustandFahrzeugVerbunden'); $geladen = $this->ReadAttributeBoolean('ZustandFahrzeugGeladen'); $phasenzahl = $this->ReadAttributeInteger('ZustandPhasenzahl'); $maximalstrom = $this->ReadPropertyInteger('MaximalerLadestrom'); $solarladen = $this->ReadAttributeBoolean('ZustandSolarladen'); $peakbetrieb = $this->ReadAttributeString('Betriebsart') === Nachrichtenvertrag::BETRIEBSART_PEAK; $verfuegbar = LadestationRegler::leistungsangebot( $aktiv, $ladefreigabe, $verbunden, $geladen, $phasenzahl, $maximalstrom, $solarladen, false ) !== [0]; $angebot = LadestationRegler::leistungsangebot( $aktiv, $ladefreigabe, $verbunden, $geladen, $phasenzahl, $maximalstrom, $solarladen, $peakbetrieb ); $angebotJson = json_encode($angebot, JSON_THROW_ON_ERROR); $this->WriteAttributeString('Leistungsangebot', $angebotJson); $this->setzeSichtbareVariable('LeistungsangebotDiagnose', $angebotJson); $this->setzeZustand('Verfuegbar', $verfuegbar); $this->setzeZustand('AenderungMoeglich', $verfuegbar && count($angebot) > 1); $sollleistung = $this->bestimmeWirksameSollleistung($angebot); $this->setzeLadestrom($sollleistung); $this->setzeStoerung(''); $this->SetStatus(self::STATUS_AKTIV); } catch (Throwable $fehler) { $this->setzeZustand('Verfuegbar', false); $this->setzeZustand('AenderungMoeglich', false); $this->setzeStoerung($fehler->getMessage()); $this->SetStatus(self::STATUS_KOMMUNIKATIONSFEHLER); $this->protokolliere('Geraetekommunikation', $fehler->getMessage()); } if ($meldungPlanen) { $this->SetTimerInterval('RueckmeldungVerzoegert', 100); } } private function leseGeraetestatus(): void { $transport = new LadestationTransport( fn (array $anfrage): string => $this->fuehreHttpAnfrageAus($anfrage) ); $antwort = $transport->statusLesen( $this->ReadPropertyInteger('Geraetetyp'), $this->geraetekonfiguration() ); $rohstatus = LadestationAdapter::dekodiereStatus( $this->ReadPropertyInteger('Geraetetyp'), $antwort ); $status = LadestationRegler::normalisiereStatus( $rohstatus, $this->ReadAttributeBoolean('ZustandFahrzeugVerbunden'), $this->ReadAttributeBoolean('ZustandFahrzeugGeladen'), $this->ReadAttributeInteger('LetzterGesetzterStrom') >= 6 ); foreach ($status as $ident => $wert) { $this->setzeZustand($ident, $wert); } } /** @param list $angebot */ private function bestimmeWirksameSollleistung(array $angebot): int { if ((bool) $this->leseZustand('SollwertGueltig')) { $sollleistung = (int) $this->leseZustand('Sollleistung'); if (in_array($sollleistung, $angebot, true)) { return $sollleistung; } $this->setzeZustand('SollwertGueltig', false); } if (!$this->ReadAttributeBoolean('ZustandSolarladen') && $angebot !== [0]) { return $angebot[count($angebot) - 1]; } return 0; } private function setzeLadestrom(int $leistung): void { $phasenzahl = $this->ReadAttributeInteger('ZustandPhasenzahl'); $strom = $leistung === 0 ? 0 : LadestationRegler::stromFuerLeistung($leistung, $phasenzahl); if ($strom === $this->ReadAttributeInteger('LetzterGesetzterStrom')) { return; } $transport = new LadestationTransport( fn (array $anfrage): string => $this->fuehreHttpAnfrageAus($anfrage) ); $transport->ladestromSetzen( $this->ReadPropertyInteger('Geraetetyp'), $this->geraetekonfiguration(), $strom ); $this->WriteAttributeInteger('LetzterGesetzterStrom', $strom); } /** * @param array $anfrage */ private function fuehreHttpAnfrageAus(array $anfrage): string { $protokoll = [ 'Methode' => $anfrage['Methode'], 'URL' => $anfrage['URL'], ]; $this->setzeSichtbareVariable( 'LetzterGeraetebefehl', json_encode($protokoll, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) ); if ($this->ReadPropertyBoolean('Testmodus')) { $url = (string) $anfrage['URL']; if (str_ends_with($url, '/api/status') || str_ends_with($url, '/mqtt?payload=') || str_contains($url, '/pico/charging/') ) { return $this->ReadPropertyString('Testantwort'); } return '{}'; } $curl = curl_init(); if ($curl === false) { throw new RuntimeException('HTTP-Anfrage konnte nicht initialisiert werden.'); } curl_setopt($curl, CURLOPT_URL, (string) $anfrage['URL']); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($curl, CURLOPT_TIMEOUT, 10); if ($anfrage['Methode'] === 'POST') { curl_setopt($curl, CURLOPT_POST, true); } if (isset($anfrage['Benutzername'], $anfrage['Passwort'])) { curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt( $curl, CURLOPT_USERPWD, (string) $anfrage['Benutzername'] . ':' . (string) $anfrage['Passwort'] ); } $antwort = curl_exec($curl); if ($antwort === false) { $fehler = curl_error($curl); curl_close($curl); throw new RuntimeException('HTTP-Anfrage fehlgeschlagen: ' . $fehler); } $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); if ($status >= 400) { throw new RuntimeException('Geraet antwortet mit HTTP-Status ' . $status . '.'); } return (string) $antwort; } /** @return array */ private function geraetekonfiguration(): array { return [ 'Geraeteadresse' => $this->ReadPropertyString('Geraeteadresse'), 'GeraeteID' => $this->ReadPropertyString('GeraeteID'), 'Seriennummer' => $this->ReadPropertyString('Seriennummer'), 'Benutzername' => $this->ReadPropertyString('Benutzername'), 'Passwort' => $this->ReadPropertyString('Passwort'), ]; } private function sendeVerbraucherdaten(): void { foreach ($this->zugeordneteManagerIDs() as $managerID) { $daten = $this->baueVerbraucherdaten($managerID); Nachrichtenvertrag::pruefeVerbraucherdaten($daten); try { IPS_RequestAction( $managerID, 'VerbraucherdatenEmpfangen', json_encode($daten, JSON_THROW_ON_ERROR) ); } catch (Throwable $fehler) { $this->protokolliere('Managerkommunikation', $fehler->getMessage()); } } } /** @return array */ private function baueVerbraucherdaten(int $managerID): array { $stoerung = (bool) $this->leseZustand('Stoerung'); return [ 'Kopf' => [ 'Version' => Nachrichtenvertrag::VERSION, 'AbsenderID' => $this->InstanceID, 'EmpfaengerID' => $managerID, 'Zeitpunkt' => time(), ], 'Betriebsart' => $this->ReadAttributeString('Betriebsart'), 'PrioritaetPV' => $this->ReadPropertyInteger('PrioritaetPV'), 'PrioritaetPeak' => $this->ReadPropertyInteger('PrioritaetPeak'), 'Leistungswerte_W' => $this->leseLeistungsangebot(), 'AenderungMoeglich' => (bool) $this->leseZustand('AenderungMoeglich'), 'Verfuegbar' => (bool) $this->leseZustand('Verfuegbar'), 'Istleistung_W' => (float) $this->leseZustand('Istleistung'), 'Leistungsquelle' => Nachrichtenvertrag::LEISTUNGSQUELLE_GEMESSEN, 'Zustand' => [ [ 'Kennung' => 'Sollleistung_W', 'Art' => 'Sollwert', 'Wert' => (bool) $this->leseZustand('SollwertGueltig') ? (int) $this->leseZustand('Sollleistung') : null, 'Einheit' => 'W', ], [ 'Kennung' => 'FahrzeugVerbunden', 'Art' => 'Status', 'Wert' => (bool) $this->leseZustand('FahrzeugVerbunden'), 'Einheit' => '', ], [ 'Kennung' => 'FahrzeugGeladen', 'Art' => 'Status', 'Wert' => (bool) $this->leseZustand('FahrzeugGeladen'), 'Einheit' => '', ], [ 'Kennung' => 'Fahrzeugstatus', 'Art' => 'Status', 'Wert' => (int) $this->leseZustand('Fahrzeugstatus'), 'Einheit' => '', ], [ 'Kennung' => 'Phasenzahl', 'Art' => 'Status', 'Wert' => (int) $this->leseZustand('Phasenzahl'), 'Einheit' => '', ], [ 'Kennung' => 'Ladestrom_A', 'Art' => 'Istwert', 'Wert' => (float) $this->leseZustand('Ladestrom'), 'Einheit' => 'A', ], [ 'Kennung' => 'Ladefreigabe', 'Art' => 'Status', 'Wert' => $this->ReadAttributeBoolean('ZustandLadefreigabe'), 'Einheit' => '', ], [ 'Kennung' => 'Solarladen', 'Art' => 'Status', 'Wert' => $this->ReadAttributeBoolean('ZustandSolarladen'), 'Einheit' => '', ], [ 'Kennung' => 'Ladefehler', 'Art' => 'Stoerung', 'Wert' => $stoerung, 'Einheit' => '', 'Text' => (string) $this->leseZustand('Stoertext'), ], ], ]; } /** @return list */ private function zugeordneteManagerIDs(): array { $ergebnis = []; foreach (IPS_GetInstanceListByModuleID(self::MANAGER_MODULE_ID) as $managerID) { try { $automatisch = (bool) IPS_GetProperty($managerID, 'AutomatischeSuche'); $property = $automatisch ? 'AutomatischeVerbraucherZuordnung' : 'VerbraucherZuordnung'; $zuordnung = $this->leseManagerZuordnung($managerID, $property); if ($automatisch && $zuordnung === []) { $zuordnung = $this->leseManagerZuordnung($managerID, 'VerbraucherZuordnung'); } } catch (Throwable $fehler) { continue; } foreach ($zuordnung as $eintrag) { if (!is_array($eintrag) || ($eintrag['Aktiv'] ?? false) !== true) { continue; } $instanzID = $eintrag['InstanzID'] ?? $eintrag['Verbraucher'] ?? null; if ($instanzID === $this->InstanceID) { $ergebnis[] = (int) $managerID; break; } } } return array_values(array_unique($ergebnis)); } /** @return array */ private function leseManagerZuordnung(int $managerID, string $property): array { $zuordnung = json_decode( (string) IPS_GetProperty($managerID, $property), true, 512, JSON_THROW_ON_ERROR ); return is_array($zuordnung) ? $zuordnung : []; } private function pruefeKonfiguration(): void { foreach (['PrioritaetPV', 'PrioritaetPeak'] as $property) { if ($this->ReadPropertyInteger($property) < 0) { throw new InvalidArgumentException($property . ' muss mindestens 0 sein.'); } } foreach (['Meldeintervall', 'VorgabeTimeout', 'Abfrageintervall'] as $property) { if ($this->ReadPropertyInteger($property) <= 0) { throw new InvalidArgumentException($property . ' muss groesser als 0 sein.'); } } $maximalstrom = $this->ReadPropertyInteger('MaximalerLadestrom'); if ($maximalstrom < 6 || $maximalstrom > 32) { throw new InvalidArgumentException('MaximalerLadestrom muss zwischen 6 und 32 A liegen.'); } $geraetetyp = $this->ReadPropertyInteger('Geraetetyp'); $konfiguration = $this->geraetekonfiguration(); LadestationAdapter::statusAnfrage($geraetetyp, $konfiguration); LadestationAdapter::steuerAnfragen($geraetetyp, $konfiguration, 0); } private function initialisiereLokaleEinstellungen(): void { $initialisiert = $this->ReadAttributeBoolean('InitialwerteGesetzt'); $ladefreigabe = $this->ReadPropertyBoolean('Ladefreigabe'); $solarladen = $this->ReadPropertyBoolean('Solarladen'); if (!$initialisiert || $ladefreigabe !== $this->ReadAttributeBoolean('KonfigurationLadefreigabe') ) { $this->WriteAttributeBoolean('ZustandLadefreigabe', $ladefreigabe); } if (!$initialisiert || $solarladen !== $this->ReadAttributeBoolean('KonfigurationSolarladen') ) { $this->WriteAttributeBoolean('ZustandSolarladen', $solarladen); } $this->WriteAttributeBoolean('KonfigurationLadefreigabe', $ladefreigabe); $this->WriteAttributeBoolean('KonfigurationSolarladen', $solarladen); $this->WriteAttributeBoolean('InitialwerteGesetzt', true); } private function aktualisiereVariablen(): void { if ($this->ReadPropertyBoolean('EinstellungenInVisu')) { $this->RegisterVariableBoolean('Ladefreigabe', 'Ladefreigabe', '~Switch', 150); $this->RegisterVariableBoolean('Solarladen', 'Solarladen', '~Switch', 160); $this->EnableAction('Ladefreigabe'); $this->EnableAction('Solarladen'); $this->SetValue('Ladefreigabe', $this->ReadAttributeBoolean('ZustandLadefreigabe')); $this->SetValue('Solarladen', $this->ReadAttributeBoolean('ZustandSolarladen')); } else { $this->entferneVariable('Ladefreigabe'); $this->entferneVariable('Solarladen'); } if ($this->ReadPropertyBoolean('DiagnosevariablenAnzeigen')) { $this->registriereVerbraucherDiagnose(); $this->RegisterVariableString('LetzterGeraetebefehl', 'Letzter Geraetebefehl', '', 200); $this->RegisterVariableString('LeistungsangebotDiagnose', 'Leistungsangebot', '', 210); $this->SetValue( 'LeistungsangebotDiagnose', $this->ReadAttributeString('Leistungsangebot') ); foreach (self::DIAGNOSE_VARIABLEN as $ident) { if (!in_array($ident, ['LetzterGeraetebefehl', 'LeistungsangebotDiagnose'], true)) { $this->setzeSichtbareVariable($ident, $this->leseZustand($ident)); } } } else { foreach (self::DIAGNOSE_VARIABLEN as $ident) { $this->entferneVariable($ident); } } } private function entferneVariable(string $ident): void { $id = @$this->GetIDForIdent($ident); if (is_int($id) && $id > 0 && IPS_VariableExists($id)) { $this->UnregisterVariable($ident); } } /** @param mixed $wert */ private function setzeZustand(string $ident, $wert): void { switch ($ident) { case 'FahrzeugVerbunden': case 'FahrzeugGeladen': case 'SollwertGueltig': case 'Verfuegbar': case 'AenderungMoeglich': case 'Stoerung': $this->WriteAttributeBoolean('Zustand' . $ident, (bool) $wert); break; case 'Fahrzeugstatus': case 'Phasenzahl': case 'Sollleistung': $this->WriteAttributeInteger('Zustand' . $ident, (int) $wert); break; case 'Ladestrom_A': $ident = 'Ladestrom'; $this->WriteAttributeFloat('ZustandLadestrom', (float) $wert); break; case 'Istleistung_W': $ident = 'Istleistung'; $this->WriteAttributeFloat('ZustandIstleistung', (float) $wert); break; case 'Stoertext': $this->WriteAttributeString('ZustandStoertext', (string) $wert); break; default: throw new LogicException('Unbekannter Zustand: ' . $ident); } $this->setzeSichtbareVariable($ident, $wert); if ($ident === 'Istleistung') { $this->setzeSichtbareVariable( 'Leistungsquelle', Nachrichtenvertrag::LEISTUNGSQUELLE_GEMESSEN ); } } /** @return mixed */ private function leseZustand(string $ident) { if ($ident === 'Ladefreigabe' || $ident === 'Solarladen') { return $this->ReadAttributeBoolean('Zustand' . $ident); } if (in_array($ident, [ 'FahrzeugVerbunden', 'FahrzeugGeladen', 'SollwertGueltig', 'Verfuegbar', 'AenderungMoeglich', 'Stoerung', ], true)) { return $this->ReadAttributeBoolean('Zustand' . $ident); } if (in_array($ident, ['Fahrzeugstatus', 'Phasenzahl', 'Sollleistung'], true)) { return $this->ReadAttributeInteger('Zustand' . $ident); } if ($ident === 'Ladestrom' || $ident === 'Istleistung') { return $this->ReadAttributeFloat('Zustand' . $ident); } if ($ident === 'Stoertext') { return $this->ReadAttributeString('ZustandStoertext'); } if ($ident === 'Leistungsquelle') { return Nachrichtenvertrag::LEISTUNGSQUELLE_GEMESSEN; } throw new LogicException('Unbekannter Zustand: ' . $ident); } /** @param mixed $wert */ private function setzeSichtbareVariable(string $ident, $wert): void { $id = @$this->GetIDForIdent($ident); if (is_int($id) && $id > 0 && IPS_VariableExists($id)) { $this->SetValue($ident, $wert); } } /** @return list */ private function leseLeistungsangebot(): array { $angebot = json_decode( $this->ReadAttributeString('Leistungsangebot'), true, 512, JSON_THROW_ON_ERROR ); return is_array($angebot) ? array_map('intval', $angebot) : [0]; } private function setzeStoerung(string $text): void { $this->setzeZustand('Stoerung', $text !== ''); $this->setzeZustand('Stoertext', $text); } private function deaktiviereTimer(): void { foreach (['Statuszyklus', 'Meldezyklus', 'RueckmeldungVerzoegert', 'VorgabeTimeout'] as $timer) { $this->SetTimerInterval($timer, 0); } } private function protokolliere(string $bereich, string $nachricht): void { if (!$this->ReadPropertyBoolean('LoggingEin')) { return; } $this->SendDebug($bereich, $nachricht, 0); } }